diff options
1049 files changed, 73848 insertions, 11463 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 fbbb04b60c..05ca0b1140 100644 --- a/.gitignore +++ b/.gitignore @@ -29,6 +29,7 @@ /libtool /libtool.orig /changelog-auto +/test-driver /Makefile /Makefile.in @@ -59,6 +60,7 @@ *.cg.json *.cg.dot *.cg.svg +*.xref ### gcov outputs diff --git a/Makefile.am b/Makefile.am index 90c8407010..0dff83e505 100644 --- a/Makefile.am +++ b/Makefile.am @@ -158,6 +158,8 @@ include bfdd/subdir.am include yang/subdir.am include yang/libyang_plugins/subdir.am include vrrpd/subdir.am +include pceplib/subdir.am +include pceplib/test/subdir.am include pathd/subdir.am include vtysh/subdir.am @@ -187,8 +189,16 @@ EXTRA_DIST += \ \ python/clidef.py \ python/clippy/__init__.py \ + python/clippy/elf.py \ + python/clippy/uidhash.py \ python/makevars.py \ python/makefile.py \ + python/tiabwarfo.py \ + python/xrelfo.py \ + python/test_xrelfo.py \ + python/runtests.py \ + \ + python/xrefstructs.json \ \ redhat/frr.logrotate \ redhat/frr.pam \ 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 895ede7040..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); @@ -265,8 +265,7 @@ babel_get_myid(void) return; } - flog_err(EC_BABEL_CONFIG, - "Warning: couldn't find router id -- using random value."); + flog_err(EC_BABEL_CONFIG, "Couldn't find router id -- using random value."); rc = read_random_bytes(myid, 8); if(rc < 0) { 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/message.c b/babeld/message.c index edb9806011..5c2e29d8b3 100644 --- a/babeld/message.c +++ b/babeld/message.c @@ -746,10 +746,9 @@ flushbuf(struct interface *ifp) if(rc < 0) flog_err(EC_BABEL_PACKET, "send: %s", safe_strerror(errno)); } else { - flog_err(EC_BABEL_PACKET, - "Warning: bucket full, dropping packet to %s.", - ifp->name); - } + flog_err(EC_BABEL_PACKET, "Bucket full, dropping packet to %s.", + ifp->name); + } } VALGRIND_MAKE_MEM_UNDEFINED(babel_ifp->sendbuf, babel_ifp->bufsize); babel_ifp->buffered = 0; @@ -1009,10 +1008,10 @@ flush_unicast(int dofree) flog_err(EC_BABEL_PACKET, "send(unicast): %s", safe_strerror(errno)); } else { - flog_err(EC_BABEL_PACKET, - "Warning: bucket full, dropping unicast packet to %s if %s.", - format_address(unicast_neighbour->address), - unicast_neighbour->ifp->name); + flog_err(EC_BABEL_PACKET, + "Bucket full, dropping unicast packet to %s if %s.", + format_address(unicast_neighbour->address), + unicast_neighbour->ifp->name); } done: diff --git a/babeld/route.c b/babeld/route.c index 0f6f6486f2..dfd0bfab89 100644 --- a/babeld/route.c +++ b/babeld/route.c @@ -399,15 +399,17 @@ install_route(struct babel_route *route) return; if(!route_feasible(route)) - flog_err(EC_BABEL_ROUTE, "WARNING: installing unfeasible route (this shouldn't happen)."); + flog_err(EC_BABEL_ROUTE, + "Installing unfeasible route (this shouldn't happen)."); i = find_route_slot(route->src->prefix, route->src->plen, NULL); assert(i >= 0 && i < route_slots); if(routes[i] != route && routes[i]->installed) { - flog_err(EC_BABEL_ROUTE, - "WARNING: attempting to install duplicate route (this shouldn't happen)."); - return; + flog_err( + EC_BABEL_ROUTE, + "Attempting to install duplicate route (this shouldn't happen)."); + return; } rc = kernel_route(ROUTE_ADD, route->src->prefix, route->src->plen, @@ -463,7 +465,8 @@ switch_routes(struct babel_route *old, struct babel_route *new) return; if(!route_feasible(new)) - flog_err(EC_BABEL_ROUTE, "WARNING: switching to unfeasible route (this shouldn't happen)."); + flog_err(EC_BABEL_ROUTE, + "Switching to unfeasible route (this shouldn't happen)."); rc = kernel_route(ROUTE_MODIFY, old->src->prefix, old->src->plen, old->nexthop, old->neigh->ifp->ifindex, 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 3e45bf0e04..234fc6d397 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 @@ -85,12 +85,13 @@ struct bfd_profile *bfd_profile_lookup(const char *name) static void bfd_profile_set_default(struct bfd_profile *bp) { - bp->admin_shutdown = true; + bp->admin_shutdown = false; bp->detection_multiplier = BFD_DEFDETECTMULT; bp->echo_mode = false; bp->passive = false; bp->minimum_ttl = BFD_DEF_MHOP_TTL; - bp->min_echo_rx = BFD_DEF_REQ_MIN_ECHO; + bp->min_echo_rx = BFD_DEF_REQ_MIN_ECHO_RX; + bp->min_echo_tx = BFD_DEF_DES_MIN_ECHO_TX; bp->min_rx = BFD_DEFREQUIREDMINRX; bp->min_tx = BFD_DEFDESIREDMINTX; } @@ -179,13 +180,19 @@ void bfd_session_apply(struct bfd_session *bs) /* We can only apply echo options on single hop sessions. */ if (!CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) { - /* Configure remote echo if it was default. */ - if (bs->peer_profile.min_echo_rx == BFD_DEF_REQ_MIN_ECHO) - bs->timers.required_min_echo = bp->min_echo_rx; + /* Configure echo timers if they were default. */ + if (bs->peer_profile.min_echo_rx == BFD_DEF_REQ_MIN_ECHO_RX) + bs->timers.required_min_echo_rx = bp->min_echo_rx; else - bs->timers.required_min_echo = + bs->timers.required_min_echo_rx = bs->peer_profile.min_echo_rx; + if (bs->peer_profile.min_echo_tx == BFD_DEF_DES_MIN_ECHO_TX) + bs->timers.desired_min_echo_tx = bp->min_echo_tx; + else + bs->timers.desired_min_echo_tx = + bs->peer_profile.min_echo_tx; + /* Toggle echo if default value. */ if (bs->peer_profile.echo_mode == false) bfd_set_echo(bs, bp->echo_mode); @@ -206,7 +213,7 @@ void bfd_session_apply(struct bfd_session *bs) bfd_set_passive_mode(bs, bs->peer_profile.passive); /* Toggle 'no shutdown' if default value. */ - if (bs->peer_profile.admin_shutdown) + if (bs->peer_profile.admin_shutdown == false) bfd_set_shutdown(bs, bp->admin_shutdown); else bfd_set_shutdown(bs, bs->peer_profile.admin_shutdown); @@ -494,8 +501,10 @@ void ptm_bfd_echo_stop(struct bfd_session *bfd) void ptm_bfd_echo_start(struct bfd_session *bfd) { bfd->echo_detect_TO = (bfd->remote_detect_mult * bfd->echo_xmt_TO); - if (bfd->echo_detect_TO > 0) + if (bfd->echo_detect_TO > 0) { + bfd_echo_recvtimer_update(bfd); ptm_bfd_echo_xmt_TO(bfd); + } } void ptm_bfd_sess_up(struct bfd_session *bfd) @@ -700,7 +709,8 @@ struct bfd_session *bfd_session_new(void) bs->timers.desired_min_tx = BFD_DEFDESIREDMINTX; bs->timers.required_min_rx = BFD_DEFREQUIREDMINRX; - bs->timers.required_min_echo = BFD_DEF_REQ_MIN_ECHO; + bs->timers.required_min_echo_rx = BFD_DEF_REQ_MIN_ECHO_RX; + bs->timers.desired_min_echo_tx = BFD_DEF_DES_MIN_ECHO_TX; bs->detect_mult = BFD_DEFDETECTMULT; bs->mh_ttl = BFD_DEF_MHOP_TTL; bs->ses_state = PTM_BFD_DOWN; @@ -769,9 +779,14 @@ static void _bfd_session_update(struct bfd_session *bs, bs->peer_profile.detection_multiplier = bs->detect_mult; } - if (bpc->bpc_has_echointerval) { - bs->timers.required_min_echo = bpc->bpc_echointerval * 1000; - bs->peer_profile.min_echo_rx = bs->timers.required_min_echo; + if (bpc->bpc_has_echorecvinterval) { + bs->timers.required_min_echo_rx = bpc->bpc_echorecvinterval * 1000; + bs->peer_profile.min_echo_rx = bs->timers.required_min_echo_rx; + } + + if (bpc->bpc_has_echotxinterval) { + bs->timers.desired_min_echo_tx = bpc->bpc_echotxinterval * 1000; + bs->peer_profile.min_echo_tx = bs->timers.desired_min_echo_tx; } if (bpc->bpc_has_label) @@ -1189,10 +1204,10 @@ void bs_echo_timer_handler(struct bfd_session *bs) * RFC 5880, Section 6.8.9. */ old_timer = bs->echo_xmt_TO; - if (bs->remote_timers.required_min_echo > bs->timers.required_min_echo) + if (bs->remote_timers.required_min_echo > bs->timers.desired_min_echo_tx) bs->echo_xmt_TO = bs->remote_timers.required_min_echo; else - bs->echo_xmt_TO = bs->timers.required_min_echo; + bs->echo_xmt_TO = bs->timers.desired_min_echo_tx; if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO_ACTIVE) == 0 || old_timer != bs->echo_xmt_TO) @@ -1252,12 +1267,12 @@ void bs_final_handler(struct bfd_session *bs) * TODO: support sending/counting more packets inside detection * timeout. */ - if (bs->remote_timers.required_min_rx > bs->timers.desired_min_tx) + if (bs->timers.required_min_rx > bs->remote_timers.desired_min_tx) bs->detect_TO = bs->remote_detect_mult - * bs->remote_timers.required_min_rx; + * bs->timers.required_min_rx; else bs->detect_TO = bs->remote_detect_mult - * bs->timers.desired_min_tx; + * bs->remote_timers.desired_min_tx; /* Apply new receive timer immediately. */ bfd_recvtimer_update(bs); diff --git a/bfdd/bfd.h b/bfdd/bfd.h index 7c537b40d0..a86c1bb9f3 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; @@ -215,6 +215,8 @@ struct bfd_profile { /** Echo mode (only applies to single hop). */ bool echo_mode; + /** Desired echo transmission interval (in microseconds). */ + uint32_t min_echo_tx; /** Minimum required echo receive interval (in microseconds). */ uint32_t min_echo_rx; @@ -228,6 +230,13 @@ TAILQ_HEAD(bfdproflist, bfd_profile); /* bfd_session shortcut label forwarding. */ struct peer_label; +struct bfd_config_timers { + uint32_t desired_min_tx; + uint32_t required_min_rx; + uint32_t desired_min_echo_tx; + uint32_t required_min_echo_rx; +}; + /* * Session state information */ @@ -251,7 +260,7 @@ struct bfd_session { struct bfd_profile peer_profile; /* Timers */ - struct bfd_timers timers; + struct bfd_config_timers timers; struct bfd_timers cur_timers; uint64_t detect_TO; struct thread *echo_recvtimer_ev; @@ -332,7 +341,8 @@ TAILQ_HEAD(obslist, bfd_session_observer); #define BFD_DEFDETECTMULT 3 #define BFD_DEFDESIREDMINTX (300 * 1000) /* microseconds. */ #define BFD_DEFREQUIREDMINRX (300 * 1000) /* microseconds. */ -#define BFD_DEF_REQ_MIN_ECHO (50 * 1000) /* microseconds. */ +#define BFD_DEF_DES_MIN_ECHO_TX (50 * 1000) /* microseconds. */ +#define BFD_DEF_REQ_MIN_ECHO_RX (50 * 1000) /* microseconds. */ #define BFD_DEF_SLOWTX (1000 * 1000) /* microseconds. */ /** Minimum multi hop TTL. */ #define BFD_DEF_MHOP_TTL 254 diff --git a/bfdd/bfd_packet.c b/bfdd/bfd_packet.c index 12bb52cf67..c871e2abe1 100644 --- a/bfdd/bfd_packet.c +++ b/bfdd/bfd_packet.c @@ -267,7 +267,7 @@ void ptm_bfd_snd(struct bfd_session *bfd, int fbit) cp.timers.required_min_rx = htonl(bfd->cur_timers.required_min_rx); } - cp.timers.required_min_echo = htonl(bfd->timers.required_min_echo); + cp.timers.required_min_echo = htonl(bfd->timers.required_min_echo_rx); if (_ptm_bfd_send(bfd, NULL, &cp, BFD_PKT_LEN) != 0) return; diff --git a/bfdd/bfdctl.h b/bfdd/bfdctl.h index e1cff9a31c..c4b2e80306 100644 --- a/bfdd/bfdctl.h +++ b/bfdd/bfdctl.h @@ -47,7 +47,8 @@ struct sockaddr_any { #define BPC_DEF_DETECTMULTIPLIER 3 #define BPC_DEF_RECEIVEINTERVAL 300 /* milliseconds */ #define BPC_DEF_TRANSMITINTERVAL 300 /* milliseconds */ -#define BPC_DEF_ECHOINTERVAL 50 /* milliseconds */ +#define BPC_DEF_ECHORECEIVEINTERVAL 50 /* milliseconds */ +#define BPC_DEF_ECHOTRANSMITINTERVAL 50 /* milliseconds */ /* Peer status */ enum bfd_peer_status { @@ -81,8 +82,11 @@ struct bfd_peer_cfg { bool bpc_has_txinterval; uint64_t bpc_txinterval; - bool bpc_has_echointerval; - uint64_t bpc_echointerval; + bool bpc_has_echorecvinterval; + uint64_t bpc_echorecvinterval; + + bool bpc_has_echotxinterval; + uint64_t bpc_echotxinterval; bool bpc_has_minimum_ttl; uint8_t bpc_minimum_ttl; 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 b9e7903613..ba80b2363f 100644 --- a/bfdd/bfdd_cli.c +++ b/bfdd/bfdd_cli.c @@ -57,6 +57,12 @@ bfd_cli_is_single_hop(struct vty *vty) return strstr(VTY_CURR_XPATH, "/single-hop") != NULL; } +static bool +bfd_cli_is_profile(struct vty *vty) +{ + return strstr(VTY_CURR_XPATH, "/bfd/profile") != NULL; +} + /* * Functions. */ @@ -117,10 +123,14 @@ DEFPY_YANG_NOSH( char source_str[INET6_ADDRSTRLEN + 32]; char xpath[XPATH_MAXLEN], xpath_srcaddr[XPATH_MAXLEN + 32]; - if (multihop) + if (multihop) { + if (!local_address_str) { + vty_out(vty, "%% local-address is required when using multihop\n"); + return CMD_WARNING_CONFIG_FAILED; + } snprintf(source_str, sizeof(source_str), "[source-addr='%s']", local_address_str); - else + } else source_str[0] = 0; slen = snprintf(xpath, sizeof(xpath), @@ -264,7 +274,7 @@ void bfd_cli_show_shutdown(struct vty *vty, struct lyd_node *dnode, bool show_defaults) { if (show_defaults) - vty_out(vty, " shutdown\n"); + vty_out(vty, " no shutdown\n"); else vty_out(vty, " %sshutdown\n", yang_dnode_get_bool(dnode, NULL) ? "" : "no "); @@ -418,11 +428,15 @@ DEFPY_YANG( NO_STR "Configure echo mode\n") { - if (!bfd_cli_is_single_hop(vty)) { + if (!bfd_cli_is_profile(vty) && !bfd_cli_is_single_hop(vty)) { vty_out(vty, "%% Echo mode is only available for single hop sessions.\n"); return CMD_WARNING_CONFIG_FAILED; } + if (!no && !bglobal.bg_use_dplane) { + vty_out(vty, "%% Current implementation of echo mode works only when the peer is also FRR.\n"); + } + nb_cli_enqueue_change(vty, "./echo-mode", NB_OP_MODIFY, no ? "false" : "true"); return nb_cli_apply_changes(vty, NULL); @@ -441,12 +455,35 @@ void bfd_cli_show_echo(struct vty *vty, struct lyd_node *dnode, DEFPY_YANG( bfd_peer_echo_interval, bfd_peer_echo_interval_cmd, "echo-interval (10-60000)$interval", - "Configure peer echo interval\n" - "Configure peer echo interval value in milliseconds\n") + "Configure peer echo intervals\n" + "Configure peer echo rx/tx intervals value in milliseconds\n") +{ + char value[32]; + + if (!bfd_cli_is_profile(vty) && !bfd_cli_is_single_hop(vty)) { + vty_out(vty, "%% Echo mode is only available for single hop sessions.\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + snprintf(value, sizeof(value), "%ld", interval * 1000); + nb_cli_enqueue_change(vty, "./desired-echo-transmission-interval", + NB_OP_MODIFY, value); + nb_cli_enqueue_change(vty, "./required-echo-receive-interval", + NB_OP_MODIFY, value); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY_YANG( + bfd_peer_echo_transmit_interval, bfd_peer_echo_transmit_interval_cmd, + "echo transmit-interval (10-60000)$interval", + "Configure peer echo intervals\n" + "Configure desired transmit interval\n" + "Configure interval value in milliseconds\n") { char value[32]; - if (!bfd_cli_is_single_hop(vty)) { + if (!bfd_cli_is_profile(vty) && !bfd_cli_is_single_hop(vty)) { vty_out(vty, "%% Echo mode is only available for single hop sessions.\n"); return CMD_WARNING_CONFIG_FAILED; } @@ -458,17 +495,61 @@ DEFPY_YANG( return nb_cli_apply_changes(vty, NULL); } -void bfd_cli_show_echo_interval(struct vty *vty, struct lyd_node *dnode, - bool show_defaults) +void bfd_cli_show_desired_echo_transmission_interval(struct vty *vty, + struct lyd_node *dnode, bool show_defaults) { uint32_t value; if (show_defaults) - vty_out(vty, " echo-interval %d\n", - BFD_DEF_REQ_MIN_ECHO); + vty_out(vty, " echo transmit-interval %d\n", + BFD_DEF_DES_MIN_ECHO_TX); else { value = yang_dnode_get_uint32(dnode, NULL); - vty_out(vty, " echo-interval %u\n", value / 1000); + vty_out(vty, " echo transmit-interval %u\n", value / 1000); + } +} + +DEFPY_YANG( + bfd_peer_echo_receive_interval, bfd_peer_echo_receive_interval_cmd, + "echo receive-interval <disabled$disabled|(10-60000)$interval>", + "Configure peer echo intervals\n" + "Configure required receive interval\n" + "Disable echo packets receive\n" + "Configure interval value in milliseconds\n") +{ + char value[32]; + + if (!bfd_cli_is_profile(vty) && !bfd_cli_is_single_hop(vty)) { + vty_out(vty, "%% Echo mode is only available for single hop sessions.\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + if (disabled) + snprintf(value, sizeof(value), "0"); + else + snprintf(value, sizeof(value), "%ld", interval * 1000); + + nb_cli_enqueue_change(vty, "./required-echo-receive-interval", + NB_OP_MODIFY, value); + + return nb_cli_apply_changes(vty, NULL); +} + +void bfd_cli_show_required_echo_receive_interval(struct vty *vty, + struct lyd_node *dnode, bool show_defaults) +{ + uint32_t value; + + if (show_defaults) + vty_out(vty, " echo receive-interval %d\n", + BFD_DEF_REQ_MIN_ECHO_RX); + else { + value = yang_dnode_get_uint32(dnode, NULL); + if (value) + vty_out(vty, " echo receive-interval %u\n", + value / 1000); + else + vty_out(vty, " echo receive-interval disabled\n"); } } @@ -565,6 +646,21 @@ ALIAS_YANG(bfd_peer_echo_interval, bfd_profile_echo_interval_cmd, "Configure peer echo interval\n" "Configure peer echo interval value in milliseconds\n") +ALIAS_YANG( + bfd_peer_echo_transmit_interval, bfd_profile_echo_transmit_interval_cmd, + "echo transmit-interval (10-60000)$interval", + "Configure peer echo intervals\n" + "Configure desired transmit interval\n" + "Configure interval value in milliseconds\n") + +ALIAS_YANG( + bfd_peer_echo_receive_interval, bfd_profile_echo_receive_interval_cmd, + "echo receive-interval <disabled$disabled|(10-60000)$interval>", + "Configure peer echo intervals\n" + "Configure required receive interval\n" + "Disable echo packets receive\n" + "Configure interval value in milliseconds\n") + DEFPY_YANG(bfd_peer_profile, bfd_peer_profile_cmd, "[no] profile BFDPROF$pname", NO_STR @@ -622,6 +718,8 @@ bfdd_cli_init(void) install_element(BFD_PEER_NODE, &bfd_peer_tx_cmd); install_element(BFD_PEER_NODE, &bfd_peer_echo_cmd); install_element(BFD_PEER_NODE, &bfd_peer_echo_interval_cmd); + install_element(BFD_PEER_NODE, &bfd_peer_echo_transmit_interval_cmd); + install_element(BFD_PEER_NODE, &bfd_peer_echo_receive_interval_cmd); install_element(BFD_PEER_NODE, &bfd_peer_profile_cmd); install_element(BFD_PEER_NODE, &bfd_peer_passive_cmd); install_element(BFD_PEER_NODE, &bfd_peer_minimum_ttl_cmd); @@ -642,6 +740,8 @@ bfdd_cli_init(void) install_element(BFD_PROFILE_NODE, &bfd_profile_shutdown_cmd); install_element(BFD_PROFILE_NODE, &bfd_profile_echo_cmd); install_element(BFD_PROFILE_NODE, &bfd_profile_echo_interval_cmd); + install_element(BFD_PROFILE_NODE, &bfd_profile_echo_transmit_interval_cmd); + install_element(BFD_PROFILE_NODE, &bfd_profile_echo_receive_interval_cmd); install_element(BFD_PROFILE_NODE, &bfd_profile_passive_cmd); install_element(BFD_PROFILE_NODE, &bfd_profile_minimum_ttl_cmd); install_element(BFD_PROFILE_NODE, &no_bfd_profile_minimum_ttl_cmd); diff --git a/bfdd/bfdd_nb.c b/bfdd/bfdd_nb.c index 64ba3cf811..29a9b5f2d5 100644 --- a/bfdd/bfdd_nb.c +++ b/bfdd/bfdd_nb.c @@ -103,8 +103,15 @@ const struct frr_yang_module_info frr_bfdd_info = { .xpath = "/frr-bfdd:bfdd/bfd/profile/desired-echo-transmission-interval", .cbs = { .modify = bfdd_bfd_profile_desired_echo_transmission_interval_modify, - .cli_show = bfd_cli_show_echo_interval, - } + .cli_show = bfd_cli_show_desired_echo_transmission_interval, + } + }, + { + .xpath = "/frr-bfdd:bfdd/bfd/profile/required-echo-receive-interval", + .cbs = { + .modify = bfdd_bfd_profile_required_echo_receive_interval_modify, + .cli_show = bfd_cli_show_required_echo_receive_interval, + } }, { .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop", @@ -179,7 +186,14 @@ const struct frr_yang_module_info frr_bfdd_info = { .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/desired-echo-transmission-interval", .cbs = { .modify = bfdd_bfd_sessions_single_hop_desired_echo_transmission_interval_modify, - .cli_show = bfd_cli_show_echo_interval, + .cli_show = bfd_cli_show_desired_echo_transmission_interval, + } + }, + { + .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/required-echo-receive-interval", + .cbs = { + .modify = bfdd_bfd_sessions_single_hop_required_echo_receive_interval_modify, + .cli_show = bfd_cli_show_required_echo_receive_interval, } }, { diff --git a/bfdd/bfdd_nb.h b/bfdd/bfdd_nb.h index fbd557b6b1..874e98691f 100644 --- a/bfdd/bfdd_nb.h +++ b/bfdd/bfdd_nb.h @@ -43,6 +43,8 @@ int bfdd_bfd_profile_minimum_ttl_destroy(struct nb_cb_destroy_args *args); int bfdd_bfd_profile_echo_mode_modify(struct nb_cb_modify_args *args); int bfdd_bfd_profile_desired_echo_transmission_interval_modify( struct nb_cb_modify_args *args); +int bfdd_bfd_profile_required_echo_receive_interval_modify( + struct nb_cb_modify_args *args); int bfdd_bfd_sessions_single_hop_create(struct nb_cb_create_args *args); int bfdd_bfd_sessions_single_hop_destroy(struct nb_cb_destroy_args *args); const void * @@ -71,6 +73,8 @@ int bfdd_bfd_sessions_single_hop_echo_mode_modify( struct nb_cb_modify_args *args); int bfdd_bfd_sessions_single_hop_desired_echo_transmission_interval_modify( struct nb_cb_modify_args *args); +int bfdd_bfd_sessions_single_hop_required_echo_receive_interval_modify( + struct nb_cb_modify_args *args); struct yang_data * bfdd_bfd_sessions_single_hop_stats_local_discriminator_get_elem( struct nb_cb_get_elem_args *args); @@ -209,8 +213,10 @@ void bfd_cli_show_shutdown(struct vty *vty, struct lyd_node *dnode, bool show_defaults); void bfd_cli_show_echo(struct vty *vty, struct lyd_node *dnode, bool show_defaults); -void bfd_cli_show_echo_interval(struct vty *vty, struct lyd_node *dnode, - bool show_defaults); +void bfd_cli_show_desired_echo_transmission_interval( + struct vty *vty, struct lyd_node *dnode, bool show_defaults); +void bfd_cli_show_required_echo_receive_interval( + struct vty *vty, struct lyd_node *dnode, bool show_defaults); void bfd_cli_show_profile(struct vty *vty, struct lyd_node *dnode, bool show_defaults); void bfd_cli_peer_profile_show(struct vty *vty, struct lyd_node *dnode, diff --git a/bfdd/bfdd_nb_config.c b/bfdd/bfdd_nb_config.c index fe6a0b7905..26bce4f357 100644 --- a/bfdd/bfdd_nb_config.c +++ b/bfdd/bfdd_nb_config.c @@ -55,36 +55,87 @@ static void bfd_session_get_key(bool mhop, const struct lyd_node *dnode, gen_bfd_key(bk, &psa, &lsa, mhop, ifname, vrfname); } -static int bfd_session_create(enum nb_event event, const struct lyd_node *dnode, - union nb_resource *resource, bool mhop) +struct session_iter { + int count; + bool wildcard; +}; + +static int session_iter_cb(const struct lyd_node *dnode, void *arg) +{ + struct session_iter *iter = arg; + const char *ifname; + + ifname = yang_dnode_get_string(dnode, "./interface"); + + if (strmatch(ifname, "*")) + iter->wildcard = true; + + iter->count++; + + return YANG_ITER_CONTINUE; +} + +static int bfd_session_create(struct nb_cb_create_args *args, bool mhop) { + const struct lyd_node *sess_dnode; + struct session_iter iter; struct bfd_session *bs; + const char *source; + const char *dest; const char *ifname; + const char *vrfname; struct bfd_key bk; struct prefix p; - switch (event) { + switch (args->event) { case NB_EV_VALIDATE: /* * When `dest-addr` is IPv6 and link-local we must * require interface name, otherwise we can't figure * which interface to use to send the packets. */ - yang_dnode_get_prefix(&p, dnode, "./dest-addr"); + yang_dnode_get_prefix(&p, args->dnode, "./dest-addr"); - ifname = yang_dnode_get_string(dnode, "./interface"); + ifname = yang_dnode_get_string(args->dnode, "./interface"); if (p.family == AF_INET6 && IN6_IS_ADDR_LINKLOCAL(&p.u.prefix6) && strcmp(ifname, "*") == 0) { - zlog_warn( - "%s: when using link-local you must specify an interface.", - __func__); + snprintf( + args->errmsg, args->errmsg_len, + "When using link-local you must specify an interface"); + return NB_ERR_VALIDATION; + } + + iter.count = 0; + iter.wildcard = false; + + sess_dnode = yang_dnode_get_parent(args->dnode, "sessions"); + + dest = yang_dnode_get_string(args->dnode, "./dest-addr"); + vrfname = yang_dnode_get_string(args->dnode, "./vrf"); + + if (mhop) { + source = yang_dnode_get_string(args->dnode, "./source-addr"); + + yang_dnode_iterate(session_iter_cb, &iter, sess_dnode, + "./multi-hop[source-addr='%s'][dest-addr='%s'][vrf='%s']", + source, dest, vrfname); + } else { + yang_dnode_iterate(session_iter_cb, &iter, sess_dnode, + "./single-hop[dest-addr='%s'][vrf='%s']", + dest, vrfname); + } + + if (iter.wildcard && iter.count > 1) { + snprintf( + args->errmsg, args->errmsg_len, + "It is not allowed to configure the same peer with and without ifname"); return NB_ERR_VALIDATION; } break; case NB_EV_PREPARE: - bfd_session_get_key(mhop, dnode, &bk); + bfd_session_get_key(mhop, args->dnode, &bk); bs = bfd_key_lookup(bk); /* This session was already configured by another daemon. */ @@ -93,14 +144,14 @@ static int bfd_session_create(enum nb_event event, const struct lyd_node *dnode, SET_FLAG(bs->flags, BFD_SESS_FLAG_CONFIG); bs->refcount++; - resource->ptr = bs; + args->resource->ptr = bs; break; } bs = bfd_session_new(); /* Fill the session key. */ - bfd_session_get_key(mhop, dnode, &bs->key); + bfd_session_get_key(mhop, args->dnode, &bs->key); /* Set configuration flags. */ bs->refcount = 1; @@ -110,23 +161,23 @@ static int bfd_session_create(enum nb_event event, const struct lyd_node *dnode, if (bs->key.family == AF_INET6) SET_FLAG(bs->flags, BFD_SESS_FLAG_IPV6); - resource->ptr = bs; + args->resource->ptr = bs; break; case NB_EV_APPLY: - bs = resource->ptr; + bs = args->resource->ptr; /* Only attempt to registrate if freshly allocated. */ if (bs->discrs.my_discr == 0 && bs_registrate(bs) == NULL) return NB_ERR_RESOURCE; - nb_running_set_entry(dnode, bs); + nb_running_set_entry(args->dnode, bs); break; case NB_EV_ABORT: - bs = resource->ptr; + bs = args->resource->ptr; if (bs->refcount <= 1) - bfd_session_free(resource->ptr); + bfd_session_free(bs); break; } @@ -432,17 +483,57 @@ int bfdd_bfd_profile_echo_mode_modify(struct nb_cb_modify_args *args) } /* - * XPath: /frr-bfdd:bfdd/bfd/profile/desired-echo-echo-transmission-interval + * XPath: /frr-bfdd:bfdd/bfd/profile/desired-echo-transmission-interval */ int bfdd_bfd_profile_desired_echo_transmission_interval_modify( struct nb_cb_modify_args *args) { struct bfd_profile *bp; + uint32_t min_tx; + + switch (args->event) { + case NB_EV_VALIDATE: + min_tx = yang_dnode_get_uint32(args->dnode, NULL); + if (min_tx < 10000 || min_tx > 60000000) + return NB_ERR_VALIDATION; + break; + + case NB_EV_PREPARE: + /* NOTHING */ + break; + + case NB_EV_APPLY: + min_tx = yang_dnode_get_uint32(args->dnode, NULL); + bp = nb_running_get_entry(args->dnode, NULL, true); + if (bp->min_echo_tx == min_tx) + return NB_OK; + + bp->min_echo_tx = min_tx; + bfd_profile_update(bp); + break; + + case NB_EV_ABORT: + /* NOTHING */ + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-bfdd:bfdd/bfd/profile/required-echo-receive-interval + */ +int bfdd_bfd_profile_required_echo_receive_interval_modify( + struct nb_cb_modify_args *args) +{ + struct bfd_profile *bp; uint32_t min_rx; switch (args->event) { case NB_EV_VALIDATE: min_rx = yang_dnode_get_uint32(args->dnode, NULL); + if (min_rx == 0) + return NB_OK; if (min_rx < 10000 || min_rx > 60000000) return NB_ERR_VALIDATION; break; @@ -474,8 +565,7 @@ int bfdd_bfd_profile_desired_echo_transmission_interval_modify( */ int bfdd_bfd_sessions_single_hop_create(struct nb_cb_create_args *args) { - return bfd_session_create(args->event, args->dnode, args->resource, - false); + return bfd_session_create(args, false); } int bfdd_bfd_sessions_single_hop_destroy(struct nb_cb_destroy_args *args) @@ -739,7 +829,46 @@ int bfdd_bfd_sessions_single_hop_desired_echo_transmission_interval_modify( case NB_EV_APPLY: bs = nb_running_get_entry(args->dnode, NULL, true); - if (echo_interval == bs->timers.required_min_echo) + if (echo_interval == bs->timers.desired_min_echo_tx) + return NB_OK; + + bs->peer_profile.min_echo_tx = echo_interval; + bfd_session_apply(bs); + break; + + case NB_EV_ABORT: + /* NOTHING */ + break; + } + + return NB_OK; +} + +/* + * XPath: + * /frr-bfdd:bfdd/bfd/sessions/single-hop/required-echo-receive-interval + */ +int bfdd_bfd_sessions_single_hop_required_echo_receive_interval_modify( + struct nb_cb_modify_args *args) +{ + uint32_t echo_interval = yang_dnode_get_uint32(args->dnode, NULL); + struct bfd_session *bs; + + switch (args->event) { + case NB_EV_VALIDATE: + if (echo_interval == 0) + return NB_OK; + if (echo_interval < 10000 || echo_interval > 60000000) + return NB_ERR_VALIDATION; + break; + + case NB_EV_PREPARE: + /* NOTHING */ + break; + + case NB_EV_APPLY: + bs = nb_running_get_entry(args->dnode, NULL, true); + if (echo_interval == bs->timers.required_min_echo_rx) return NB_OK; bs->peer_profile.min_echo_rx = echo_interval; @@ -759,8 +888,7 @@ int bfdd_bfd_sessions_single_hop_desired_echo_transmission_interval_modify( */ int bfdd_bfd_sessions_multi_hop_create(struct nb_cb_create_args *args) { - return bfd_session_create(args->event, args->dnode, args->resource, - true); + return bfd_session_create(args, true); } int bfdd_bfd_sessions_multi_hop_destroy(struct nb_cb_destroy_args *args) diff --git a/bfdd/bfdd_vty.c b/bfdd/bfdd_vty.c index 53e23cf6c2..a03fb9f216 100644 --- a/bfdd/bfdd_vty.c +++ b/bfdd/bfdd_vty.c @@ -158,8 +158,16 @@ static void _display_peer(struct vty *vty, struct bfd_session *bs) bs->timers.required_min_rx / 1000); vty_out(vty, "\t\t\tTransmission interval: %ums\n", bs->timers.desired_min_tx / 1000); - vty_out(vty, "\t\t\tEcho transmission interval: %ums\n", - bs->timers.required_min_echo / 1000); + if (bs->timers.required_min_echo_rx != 0) + vty_out(vty, "\t\t\tEcho receive interval: %ums\n", + bs->timers.required_min_echo_rx / 1000); + else + vty_out(vty, "\t\t\tEcho receive interval: disabled\n"); + if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO)) + vty_out(vty, "\t\t\tEcho transmission interval: %ums\n", + bs->timers.desired_min_echo_tx / 1000); + else + vty_out(vty, "\t\t\tEcho transmission interval: disabled\n"); vty_out(vty, "\t\tRemote timers:\n"); vty_out(vty, "\t\t\tDetect-multiplier: %u\n", @@ -168,8 +176,11 @@ static void _display_peer(struct vty *vty, struct bfd_session *bs) bs->remote_timers.required_min_rx / 1000); vty_out(vty, "\t\t\tTransmission interval: %ums\n", bs->remote_timers.desired_min_tx / 1000); - vty_out(vty, "\t\t\tEcho transmission interval: %ums\n", - bs->remote_timers.required_min_echo / 1000); + if (bs->remote_timers.required_min_echo != 0) + vty_out(vty, "\t\t\tEcho receive interval: %ums\n", + bs->remote_timers.required_min_echo / 1000); + else + vty_out(vty, "\t\t\tEcho receive interval: disabled\n"); vty_out(vty, "\n"); } @@ -245,11 +256,13 @@ static struct json_object *__display_peer_json(struct bfd_session *bs) bs->timers.required_min_rx / 1000); json_object_int_add(jo, "transmit-interval", bs->timers.desired_min_tx / 1000); + json_object_int_add(jo, "echo-receive-interval", + bs->timers.required_min_echo_rx / 1000); if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO)) - json_object_int_add(jo, "echo-interval", - bs->timers.required_min_echo / 1000); + json_object_int_add(jo, "echo-transmit-interval", + bs->timers.desired_min_echo_tx / 1000); else - json_object_int_add(jo, "echo-interval", 0); + json_object_int_add(jo, "echo-transmit-interval", 0); json_object_int_add(jo, "detect-multiplier", bs->detect_mult); @@ -257,7 +270,7 @@ static struct json_object *__display_peer_json(struct bfd_session *bs) bs->remote_timers.required_min_rx / 1000); json_object_int_add(jo, "remote-transmit-interval", bs->remote_timers.desired_min_tx / 1000); - json_object_int_add(jo, "remote-echo-interval", + json_object_int_add(jo, "remote-echo-receive-interval", bs->remote_timers.required_min_echo / 1000); json_object_int_add(jo, "remote-detect-multiplier", bs->remote_detect_mult); @@ -840,11 +853,12 @@ static int bfd_configure_peer(struct bfd_peer_cfg *bpc, bool mhop, memset(bpc, 0, sizeof(*bpc)); /* Defaults */ - bpc->bpc_shutdown = true; + bpc->bpc_shutdown = false; bpc->bpc_detectmultiplier = BPC_DEF_DETECTMULTIPLIER; bpc->bpc_recvinterval = BPC_DEF_RECEIVEINTERVAL; bpc->bpc_txinterval = BPC_DEF_TRANSMITINTERVAL; - bpc->bpc_echointerval = BPC_DEF_ECHOINTERVAL; + bpc->bpc_echorecvinterval = BPC_DEF_ECHORECEIVEINTERVAL; + bpc->bpc_echotxinterval = BPC_DEF_ECHOTRANSMITINTERVAL; bpc->bpc_lastevent = monotime(NULL); /* Safety check: when no error buf is provided len must be zero. */ diff --git a/bfdd/bfddp_packet.h b/bfdd/bfddp_packet.h index 8865baef6a..4ece94f577 100644 --- a/bfdd/bfddp_packet.h +++ b/bfdd/bfddp_packet.h @@ -163,6 +163,11 @@ struct bfddp_session { */ uint32_t min_rx; /** + * Minimum desired echo transmission interval (in microseconds) + * without jitter. + */ + uint32_t min_echo_tx; + /** * Required minimum echo receive interval rate (in microseconds) * without jitter. */ diff --git a/bfdd/config.c b/bfdd/config.c index b71670f012..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 @@ -135,7 +135,8 @@ static int parse_list(struct json_object *jo, enum peer_list_type plt, bpc.bpc_detectmultiplier = BFD_DEFDETECTMULT; bpc.bpc_recvinterval = BFD_DEFREQUIREDMINRX; bpc.bpc_txinterval = BFD_DEFDESIREDMINTX; - bpc.bpc_echointerval = BFD_DEF_REQ_MIN_ECHO; + bpc.bpc_echorecvinterval = BFD_DEF_REQ_MIN_ECHO_RX; + bpc.bpc_echotxinterval = BFD_DEF_DES_MIN_ECHO_TX; switch (plt) { case PLT_IPV4: @@ -250,11 +251,16 @@ static int parse_peer_config(struct json_object *jo, struct bfd_peer_cfg *bpc) bpc->bpc_has_txinterval = true; zlog_debug(" transmit-interval: %" PRIu64, bpc->bpc_txinterval); - } else if (strcmp(key, "echo-interval") == 0) { - bpc->bpc_echointerval = json_object_get_int64(jo_val); - bpc->bpc_has_echointerval = true; - zlog_debug(" echo-interval: %" PRIu64, - bpc->bpc_echointerval); + } else if (strcmp(key, "echo-receive-interval") == 0) { + bpc->bpc_echorecvinterval = json_object_get_int64(jo_val); + bpc->bpc_has_echorecvinterval = true; + zlog_debug(" echo-receive-interval: %" PRIu64, + bpc->bpc_echorecvinterval); + } else if (strcmp(key, "echo-transmit-interval") == 0) { + bpc->bpc_echotxinterval = json_object_get_int64(jo_val); + bpc->bpc_has_echotxinterval = true; + zlog_debug(" echo-transmit-interval: %" PRIu64, + bpc->bpc_echotxinterval); } else if (strcmp(key, "create-only") == 0) { bpc->bpc_createonly = json_object_get_boolean(jo_val); zlog_debug(" create-only: %s", @@ -463,8 +469,10 @@ char *config_notify_config(const char *op, struct bfd_session *bs) bs->timers.required_min_rx / 1000); json_object_int_add(resp, "transmit-interval", bs->timers.desired_min_tx / 1000); - json_object_int_add(resp, "echo-interval", - bs->timers.required_min_echo / 1000); + json_object_int_add(resp, "echo-receive-interval", + bs->timers.required_min_echo_rx / 1000); + json_object_int_add(resp, "echo-transmit-interval", + bs->timers.desired_min_echo_tx / 1000); json_object_int_add(resp, "remote-detect-multiplier", bs->remote_detect_mult); @@ -472,7 +480,7 @@ char *config_notify_config(const char *op, struct bfd_session *bs) bs->remote_timers.required_min_rx / 1000); json_object_int_add(resp, "remote-transmit-interval", bs->remote_timers.desired_min_tx / 1000); - json_object_int_add(resp, "remote-echo-interval", + json_object_int_add(resp, "remote-echo-receive-interval", bs->remote_timers.required_min_echo / 1000); if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO)) diff --git a/bfdd/dplane.c b/bfdd/dplane.c index 66b79f3b13..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 @@ -765,7 +766,8 @@ static void _bfd_dplane_session_fill(const struct bfd_session *bs, msg->data.session.lid = htonl(bs->discrs.my_discr); msg->data.session.min_tx = htonl(bs->timers.desired_min_tx); msg->data.session.min_rx = htonl(bs->timers.required_min_rx); - msg->data.session.min_echo_rx = htonl(bs->timers.required_min_echo); + msg->data.session.min_echo_tx = htonl(bs->timers.desired_min_echo_tx); + msg->data.session.min_echo_rx = htonl(bs->timers.required_min_echo_rx); } static int _bfd_dplane_add_session(struct bfd_dplane_ctx *bdc, diff --git a/bfdd/ptm_adapter.c b/bfdd/ptm_adapter.c index 0c70600f20..4135e5fb49 100644 --- a/bfdd/ptm_adapter.c +++ b/bfdd/ptm_adapter.c @@ -492,9 +492,6 @@ static void bfdd_dest_register(struct stream *msg, vrf_id_t vrf_id) "ptm-add-dest: failed to create BFD session"); return; } - - /* Protocol created peers are 'no shutdown' by default. */ - bs->peer_profile.admin_shutdown = false; } else { /* * BFD session was already created, we are just updating the 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.c b/bgpd/bgp_attr.c index dc8cc81042..f658b0d0f0 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -2133,19 +2133,11 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args, } stream_get(&attr->mp_nexthop_local, s, IPV6_MAX_BYTELEN); if (!IN6_IS_ADDR_LINKLOCAL(&attr->mp_nexthop_local)) { - char buf1[INET6_ADDRSTRLEN]; - char buf2[INET6_ADDRSTRLEN]; - if (bgp_debug_update(peer, NULL, NULL, 1)) zlog_debug( - "%s sent next-hops %s and %s. Ignoring non-LL value", - peer->host, - inet_ntop(AF_INET6, - &attr->mp_nexthop_global, - buf1, INET6_ADDRSTRLEN), - inet_ntop(AF_INET6, - &attr->mp_nexthop_local, buf2, - INET6_ADDRSTRLEN)); + "%s sent next-hops %pI6 and %pI6. Ignoring non-LL value", + peer->host, &attr->mp_nexthop_global, + &attr->mp_nexthop_local); attr->mp_nexthop_len = IPV6_MAX_BYTELEN; } @@ -2344,16 +2336,10 @@ bgp_attr_ext_communities(struct bgp_attr_parser_args *args) /* Extract the Rmac, if any */ if (bgp_attr_rmac(attr, &attr->rmac)) { - if (bgp_debug_update(peer, NULL, NULL, 1) && - bgp_mac_exist(&attr->rmac)) { - char buf1[ETHER_ADDR_STRLEN]; - - zlog_debug("%s: router mac %s is self mac", - __func__, - prefix_mac2str(&attr->rmac, buf1, - sizeof(buf1))); - } - + if (bgp_debug_update(peer, NULL, NULL, 1) + && bgp_mac_exist(&attr->rmac)) + zlog_debug("%s: router mac %pEA is self mac", __func__, + &attr->rmac); } /* Get the tunnel type from encap extended community */ @@ -3103,7 +3089,7 @@ bgp_attr_parse_ret_t bgp_attr_parse(struct peer *peer, struct attr *attr, * a stack buffer, since they perform bounds checking * and we are working with untrusted data. */ - unsigned char ndata[BGP_MAX_PACKET_SIZE]; + unsigned char ndata[peer->max_packet_size]; memset(ndata, 0x00, sizeof(ndata)); size_t lfl = CHECK_FLAG(flag, BGP_ATTR_FLAG_EXTLEN) ? 2 : 1; 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 c976632678..ec71264081 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -57,8 +57,8 @@ /* * Definitions and external declarations. */ -DEFINE_QOBJ_TYPE(bgpevpn) -DEFINE_QOBJ_TYPE(bgp_evpn_es) +DEFINE_QOBJ_TYPE(bgpevpn); +DEFINE_QOBJ_TYPE(bgp_evpn_es); /* @@ -592,9 +592,6 @@ static int bgp_zebra_send_remote_macip(struct bgp *bgp, struct bgpevpn *vpn, { struct stream *s; int ipa_len; - char buf1[ETHER_ADDR_STRLEN]; - char buf2[INET6_ADDRSTRLEN]; - char buf3[INET6_ADDRSTRLEN]; static struct in_addr zero_remote_vtep_ip; /* Check socket. */ @@ -649,14 +646,10 @@ static int bgp_zebra_send_remote_macip(struct bgp *bgp, struct bgpevpn *vpn, if (bgp_debug_zebra(NULL)) zlog_debug( - "Tx %s MACIP, VNI %u MAC %s IP %s flags 0x%x seq %u remote VTEP %s", + "Tx %s MACIP, VNI %u MAC %pEA IP %pIA flags 0x%x seq %u remote VTEP %pI4", add ? "ADD" : "DEL", vpn->vni, - prefix_mac2str(&p->prefix.macip_addr.mac, - buf1, sizeof(buf1)), - ipaddr2str(&p->prefix.macip_addr.ip, - buf3, sizeof(buf3)), flags, seq, - inet_ntop(AF_INET, &remote_vtep_ip, buf2, - sizeof(buf2))); + &p->prefix.macip_addr.mac, &p->prefix.macip_addr.ip, + flags, seq, &remote_vtep_ip); return zclient_send_message(zclient); } @@ -1319,16 +1312,11 @@ static int update_evpn_type5_route(struct bgp *bgp_vrf, struct prefix_evpn *evp, vrf_id_to_name(bgp_vrf->vrf_id), evp); } - if (bgp_debug_zebra(NULL)) { - char buf[ETHER_ADDR_STRLEN]; - char buf2[INET6_ADDRSTRLEN]; - - zlog_debug("VRF %s type-5 route evp %pFX RMAC %s nexthop %s", - vrf_id_to_name(bgp_vrf->vrf_id), evp, - prefix_mac2str(&attr.rmac, buf, sizeof(buf)), - inet_ntop(AF_INET, &attr.nexthop, buf2, - INET_ADDRSTRLEN)); - } + if (bgp_debug_zebra(NULL)) + zlog_debug( + "VRF %s type-5 route evp %pFX RMAC %pEA nexthop %pI4", + vrf_id_to_name(bgp_vrf->vrf_id), evp, &attr.rmac, + &attr.nexthop); attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; @@ -1725,16 +1713,13 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn, } if (bgp_debug_zebra(NULL)) { - char buf[ETHER_ADDR_STRLEN]; char buf3[ESI_STR_LEN]; zlog_debug( - "VRF %s vni %u type-2 route evp %pFX RMAC %s nexthop %pI4 esi %s", + "VRF %s vni %u type-2 route evp %pFX RMAC %pEA nexthop %pI4 esi %s", vpn->bgp_vrf ? vrf_id_to_name(vpn->bgp_vrf->vrf_id) : " ", - vpn->vni, p, - prefix_mac2str(&attr.rmac, buf, sizeof(buf)), - &attr.mp_nexthop_global_in, + vpn->vni, p, &attr.rmac, &attr.mp_nexthop_global_in, esi_to_str(esi, buf3, sizeof(buf3))); } /* router mac is only needed for type-2 routes here. */ @@ -2004,16 +1989,13 @@ static void bgp_evpn_update_type2_route_entry(struct bgp *bgp, seq = mac_mobility_seqnum(local_pi->attr); if (bgp_debug_zebra(NULL)) { - char buf[ETHER_ADDR_STRLEN]; char buf3[ESI_STR_LEN]; zlog_debug( - "VRF %s vni %u evp %pFX RMAC %s nexthop %pI4 esi %s esf 0x%x from %s", + "VRF %s vni %u evp %pFX RMAC %pEA nexthop %pI4 esi %s esf 0x%x from %s", vpn->bgp_vrf ? vrf_id_to_name(vpn->bgp_vrf->vrf_id) : " ", - vpn->vni, evp, - prefix_mac2str(&attr.rmac, buf, sizeof(buf)), - &attr.mp_nexthop_global_in, + vpn->vni, evp, &attr.rmac, &attr.mp_nexthop_global_in, esi_to_str(&attr.esi, buf3, sizeof(buf3)), attr.es_flags, caller); } @@ -5300,18 +5282,14 @@ int bgp_evpn_local_macip_add(struct bgp *bgp, vni_t vni, struct ethaddr *mac, /* Create EVPN type-2 route and schedule for processing. */ build_evpn_type2_prefix(&p, mac, ip); if (update_evpn_route(bgp, vpn, &p, flags, seq, esi)) { - char buf[ETHER_ADDR_STRLEN]; - char buf2[INET6_ADDRSTRLEN]; - flog_err( EC_BGP_EVPN_ROUTE_CREATE, - "%u:Failed to create Type-2 route, VNI %u %s MAC %s IP %s (flags: 0x%x)", + "%u:Failed to create Type-2 route, VNI %u %s MAC %pEA IP %pIA (flags: 0x%x)", bgp->vrf_id, vpn->vni, CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY) ? "sticky gateway" : "", - prefix_mac2str(mac, buf, sizeof(buf)), - ipaddr2str(ip, buf2, sizeof(buf2)), flags); + mac, ip, flags); return -1; } @@ -5396,23 +5374,16 @@ int bgp_evpn_local_l3vni_add(vni_t l3vni, vrf_id_t vrf_id, if (is_zero_mac(&bgp_vrf->evpn_info->pip_rmac_static)) memcpy(&bgp_vrf->evpn_info->pip_rmac, svi_rmac, ETH_ALEN); - if (bgp_debug_zebra(NULL)) { - char buf[ETHER_ADDR_STRLEN]; - char buf1[ETHER_ADDR_STRLEN]; - char buf2[ETHER_ADDR_STRLEN]; - - zlog_debug("VRF %s vni %u pip %s RMAC %s sys RMAC %s static RMAC %s is_anycast_mac %s", - vrf_id_to_name(bgp_vrf->vrf_id), - bgp_vrf->l3vni, - bgp_vrf->evpn_info->advertise_pip ? "enable" - : "disable", - prefix_mac2str(&bgp_vrf->rmac, buf, sizeof(buf)), - prefix_mac2str(&bgp_vrf->evpn_info->pip_rmac, - buf1, sizeof(buf1)), - prefix_mac2str(&bgp_vrf->evpn_info->pip_rmac_static, - buf2, sizeof(buf2)), - is_anycast_mac ? "Enable" : "Disable"); - } + if (bgp_debug_zebra(NULL)) + zlog_debug( + "VRF %s vni %u pip %s RMAC %pEA sys RMAC %pEA static RMAC %pEA is_anycast_mac %s", + vrf_id_to_name(bgp_vrf->vrf_id), bgp_vrf->l3vni, + bgp_vrf->evpn_info->advertise_pip ? "enable" + : "disable", + &bgp_vrf->rmac, &bgp_vrf->evpn_info->pip_rmac, + &bgp_vrf->evpn_info->pip_rmac_static, + is_anycast_mac ? "Enable" : "Disable"); + /* set the right filter - are we using l3vni only for prefix routes? */ if (filter) { SET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_L3VNI_PREFIX_ROUTES_ONLY); diff --git a/bgpd/bgp_evpn_mh.c b/bgpd/bgp_evpn_mh.c index 2dec0863c0..123c46f12f 100644 --- a/bgpd/bgp_evpn_mh.c +++ b/bgpd/bgp_evpn_mh.c @@ -74,6 +74,7 @@ bgp_evpn_es_path_update_on_vtep_chg(struct bgp_evpn_es_vtep *es_vtep, bool active); esi_t zero_esi_buf, *zero_esi = &zero_esi_buf; +static int bgp_evpn_run_consistency_checks(struct thread *t); /****************************************************************************** * per-ES (Ethernet Segment) routing table @@ -1621,21 +1622,18 @@ static void bgp_evpn_es_remote_info_re_eval(struct bgp_evpn_es *es) } } -/* Process ES link oper-down by withdrawing ES-EAD and ESR */ -static void bgp_evpn_local_es_down(struct bgp *bgp, - struct bgp_evpn_es *es) +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); +} + +static void bgp_evpn_local_es_deactivate(struct bgp *bgp, + struct bgp_evpn_es *es) { struct prefix_evpn p; int ret; - if (!CHECK_FLAG(es->flags, BGP_EVPNES_OPER_UP)) - return; - - UNSET_FLAG(es->flags, BGP_EVPNES_OPER_UP); - - if (BGP_DEBUG(evpn_mh, EVPN_MH_ES)) - zlog_debug("local es %s down", es->esi_str); - /* withdraw ESR */ /* Delete and withdraw locally learnt ES route */ build_evpn_type4_prefix(&p, &es->esi, es->originator_ip); @@ -1661,21 +1659,28 @@ static void bgp_evpn_local_es_down(struct bgp *bgp, } } -/* Process ES link oper-up by generating ES-EAD and ESR */ -static void bgp_evpn_local_es_up(struct bgp *bgp, struct bgp_evpn_es *es, - bool regen_esr) +/* Process ES link oper-down by withdrawing ES-EAD and ESR */ +static void bgp_evpn_local_es_down(struct bgp *bgp, struct bgp_evpn_es *es) { - struct prefix_evpn p; - bool regen_ead = false; + bool old_active; - if (!CHECK_FLAG(es->flags, BGP_EVPNES_OPER_UP)) { - if (BGP_DEBUG(evpn_mh, EVPN_MH_ES)) - zlog_debug("local es %s up", es->esi_str); + if (!CHECK_FLAG(es->flags, BGP_EVPNES_OPER_UP)) + return; - SET_FLAG(es->flags, BGP_EVPNES_OPER_UP); - regen_esr = true; - regen_ead = true; - } + old_active = bgp_evpn_local_es_is_active(es); + UNSET_FLAG(es->flags, BGP_EVPNES_OPER_UP); + + if (BGP_DEBUG(evpn_mh, EVPN_MH_ES)) + zlog_debug("local es %s down", es->esi_str); + + if (old_active) + bgp_evpn_local_es_deactivate(bgp, es); +} + +static void bgp_evpn_local_es_activate(struct bgp *bgp, struct bgp_evpn_es *es, + bool regen_ead, bool regen_esr) +{ + struct prefix_evpn p; if (regen_esr) { if (BGP_DEBUG(evpn_mh, EVPN_MH_ES)) @@ -1697,7 +1702,62 @@ static void bgp_evpn_local_es_up(struct bgp *bgp, struct bgp_evpn_es *es, /* generate EAD-ES */ build_evpn_type1_prefix(&p, BGP_EVPN_AD_ES_ETH_TAG, &es->esi, es->originator_ip); - bgp_evpn_type1_route_update(bgp, es, NULL, &p); + (void)bgp_evpn_type1_route_update(bgp, es, NULL, &p); + } +} + +/* Process ES link oper-up by generating ES-EAD and ESR */ +static void bgp_evpn_local_es_up(struct bgp *bgp, struct bgp_evpn_es *es, + bool regen_esr) +{ + bool regen_ead = false; + bool active = false; + + if (!CHECK_FLAG(es->flags, BGP_EVPNES_OPER_UP)) { + if (BGP_DEBUG(evpn_mh, EVPN_MH_ES)) + zlog_debug("local es %s up", es->esi_str); + + SET_FLAG(es->flags, BGP_EVPNES_OPER_UP); + regen_esr = true; + regen_ead = true; + } + + active = bgp_evpn_local_es_is_active(es); + if (active && (regen_ead || regen_esr)) + bgp_evpn_local_es_activate(bgp, es, regen_ead, regen_esr); +} + +/* If an ethernet segment is in LACP bypass we cannot advertise + * reachability to it i.e. EAD-per-ES and ESR is not advertised in + * bypass state. + * PS: EAD-per-EVI will continue to be advertised + */ +static void bgp_evpn_local_es_bypass_update(struct bgp *bgp, + struct bgp_evpn_es *es, bool bypass) +{ + bool old_bypass = !!(es->flags & BGP_EVPNES_BYPASS); + bool old_active; + bool new_active; + + if (bypass == old_bypass) + return; + + old_active = bgp_evpn_local_es_is_active(es); + if (bypass) + SET_FLAG(es->flags, BGP_EVPNES_BYPASS); + else + UNSET_FLAG(es->flags, BGP_EVPNES_BYPASS); + + if (BGP_DEBUG(evpn_mh, EVPN_MH_ES)) + zlog_debug("local es %s bypass %s", es->esi_str, + bypass ? "set" : "clear"); + + new_active = bgp_evpn_local_es_is_active(es); + if (old_active != new_active) { + if (new_active) + bgp_evpn_local_es_activate(bgp, es, true, true); + else + bgp_evpn_local_es_deactivate(bgp, es); } } @@ -1757,7 +1817,7 @@ int bgp_evpn_local_es_del(struct bgp *bgp, esi_t *esi) */ int bgp_evpn_local_es_add(struct bgp *bgp, esi_t *esi, struct in_addr originator_ip, bool oper_up, - uint16_t df_pref) + uint16_t df_pref, bool bypass) { char buf[ESI_STR_LEN]; struct bgp_evpn_es *es; @@ -1780,8 +1840,9 @@ int bgp_evpn_local_es_add(struct bgp *bgp, esi_t *esi, } if (BGP_DEBUG(evpn_mh, EVPN_MH_ES)) - zlog_debug("add local es %s orig-ip %pI4 df_pref %u", es->esi_str, - &originator_ip, df_pref); + zlog_debug("add local es %s orig-ip %pI4 df_pref %u %s", + es->esi_str, &originator_ip, df_pref, + bypass ? "bypass" : ""); es->originator_ip = originator_ip; if (df_pref != es->df_pref) { @@ -1802,6 +1863,8 @@ int bgp_evpn_local_es_add(struct bgp *bgp, esi_t *esi, if (bgp_mh_info->ead_evi_adv_for_down_links) bgp_evpn_local_type1_evi_route_add(bgp, es); + bgp_evpn_local_es_bypass_update(bgp, es, bypass); + /* If the ES link is operationally up generate EAD-ES. EAD-EVI * can be generated even if the link is inactive. */ @@ -1952,6 +2015,8 @@ static void bgp_evpn_es_show_entry(struct vty *vty, char vtep_str[ES_VTEP_LIST_STR_SZ + BGP_EVPN_VTEPS_FLAG_STR_SZ]; type_str[0] = '\0'; + if (es->flags & BGP_EVPNES_BYPASS) + strlcat(type_str, "B", sizeof(type_str)); if (es->flags & BGP_EVPNES_LOCAL) strlcat(type_str, "L", sizeof(type_str)); if (es->flags & BGP_EVPNES_REMOTE) @@ -1986,13 +2051,17 @@ static void bgp_evpn_es_show_entry_detail(struct vty *vty, /* Add the "brief" info first */ bgp_evpn_es_show_entry(vty, es, json); - if (es->flags & (BGP_EVPNES_OPER_UP | BGP_EVPNES_ADV_EVI)) { + if (es->flags + & (BGP_EVPNES_OPER_UP | BGP_EVPNES_ADV_EVI + | BGP_EVPNES_BYPASS)) { json_flags = json_object_new_array(); if (es->flags & BGP_EVPNES_OPER_UP) json_array_string_add(json_flags, "up"); if (es->flags & BGP_EVPNES_ADV_EVI) json_array_string_add(json_flags, "advertiseEVI"); + if (es->flags & BGP_EVPNES_BYPASS) + json_array_string_add(json_flags, "bypass"); json_object_object_add(json, "flags", json_flags); } json_object_string_add(json, "originator_ip", @@ -2045,6 +2114,8 @@ static void bgp_evpn_es_show_entry_detail(struct vty *vty, if (es->flags & BGP_EVPNES_LOCAL) vty_out(vty, " Local ES DF preference: %u\n", es->df_pref); + if (es->flags & BGP_EVPNES_BYPASS) + vty_out(vty, " LACP bypass: on\n"); vty_out(vty, " VNI Count: %d\n", listcount(es->es_evi_list)); vty_out(vty, " Remote VNI Count: %d\n", es->remote_es_evi_cnt); @@ -2084,7 +2155,7 @@ void bgp_evpn_es_show(struct vty *vty, bool uj, bool detail) } else { if (!detail) { vty_out(vty, - "ES Flags: L local, R remote, I inconsistent\n"); + "ES Flags: B - bypass, L local, R remote, I inconsistent\n"); vty_out(vty, "VTEP Flags: E ESR/Type-4, A active nexthop\n"); vty_out(vty, @@ -2973,7 +3044,7 @@ static void bgp_evpn_local_es_evi_do_del(struct bgp_evpn_es_evi *es_evi) if (bgp) { /* update EAD-ES with new list of VNIs */ - if (CHECK_FLAG(es->flags, BGP_EVPNES_OPER_UP)) { + if (bgp_evpn_local_es_is_active(es)) { 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)) @@ -3098,7 +3169,7 @@ int bgp_evpn_local_es_evi_add(struct bgp *bgp, esi_t *esi, vni_t vni) /* update EAD-ES */ build_evpn_type1_prefix(&p, BGP_EVPN_AD_ES_ETH_TAG, &es->esi, es->originator_ip); - if (CHECK_FLAG(es->flags, BGP_EVPNES_OPER_UP)) { + if (bgp_evpn_local_es_is_active(es)) { if (bgp_evpn_type1_route_update(bgp, es, NULL, &p)) flog_err(EC_BGP_EVPN_ROUTE_CREATE, "%u: EAD-ES route creation failure for ESI %s VNI %u", @@ -3508,6 +3579,19 @@ void bgp_evpn_es_evi_show_vni(struct vty *vty, vni_t vni, * show commands) at this point. A more drastic action can be executed (based * on user config) in the future. */ +static void bgp_evpn_es_cons_checks_timer_start(void) +{ + if (!bgp_mh_info->consistency_checking || bgp_mh_info->t_cons_check) + return; + + if (BGP_DEBUG(evpn_mh, EVPN_MH_ES)) + zlog_debug("periodic consistency checking started"); + + thread_add_timer(bm->master, bgp_evpn_run_consistency_checks, NULL, + BGP_EVPN_CONS_CHECK_INTERVAL, + &bgp_mh_info->t_cons_check); +} + /* queue up the es for background consistency checks */ static void bgp_evpn_es_cons_checks_pend_add(struct bgp_evpn_es *es) { @@ -3519,6 +3603,10 @@ static void bgp_evpn_es_cons_checks_pend_add(struct bgp_evpn_es *es) /* already queued for consistency checking */ return; + /* start the periodic timer for consistency checks if it is not + * already running */ + bgp_evpn_es_cons_checks_timer_start(); + SET_FLAG(es->flags, BGP_EVPNES_CONS_CHECK_PEND); listnode_init(&es->pend_es_listnode, es); listnode_add_after(bgp_mh_info->pend_es_list, @@ -3737,11 +3825,6 @@ void bgp_evpn_mh_init(void) bgp_mh_info->install_l3nhg = false; bgp_mh_info->host_routes_use_l3nhg = BGP_EVPN_MH_USE_ES_L3NHG_DEF; - if (bgp_mh_info->consistency_checking) - thread_add_timer(bm->master, bgp_evpn_run_consistency_checks, - NULL, BGP_EVPN_CONS_CHECK_INTERVAL, - &bgp_mh_info->t_cons_check); - memset(&zero_esi_buf, 0, sizeof(esi_t)); } @@ -3757,9 +3840,46 @@ void bgp_evpn_mh_finish(void) es_next) { bgp_evpn_es_local_info_clear(es); } - thread_cancel(&bgp_mh_info->t_cons_check); + if (bgp_mh_info->t_cons_check) + thread_cancel(&bgp_mh_info->t_cons_check); list_delete(&bgp_mh_info->local_es_list); list_delete(&bgp_mh_info->pend_es_list); XFREE(MTYPE_BGP_EVPN_MH_INFO, bgp_mh_info); } + +/* This function is called when disable-ead-evi-rx knob flaps */ +void bgp_evpn_switch_ead_evi_rx(void) +{ + struct bgp *bgp; + struct bgp_evpn_es *es; + struct bgp_evpn_es_evi *es_evi; + struct listnode *evi_node = NULL; + struct listnode *evi_next = NULL; + struct bgp_evpn_es_evi_vtep *vtep; + struct listnode *vtep_node = NULL; + struct listnode *vtep_next = NULL; + + bgp = bgp_get_evpn(); + if (!bgp) + return; + + /* + * Process all the remote es_evi_vteps and reevaluate if the es_evi_vtep + * is active. + */ + RB_FOREACH(es, bgp_es_rb_head, &bgp_mh_info->es_rb_tree) { + if (!CHECK_FLAG(es->flags, BGP_EVPNES_REMOTE)) + continue; + + for (ALL_LIST_ELEMENTS(es->es_evi_list, evi_node, evi_next, + es_evi)) { + if (!CHECK_FLAG(es_evi->flags, BGP_EVPNES_EVI_REMOTE)) + continue; + + for (ALL_LIST_ELEMENTS(es_evi->es_evi_vtep_list, + vtep_node, vtep_next, vtep)) + bgp_evpn_es_evi_vtep_re_eval_active(bgp, vtep); + } + } +} diff --git a/bgpd/bgp_evpn_mh.h b/bgpd/bgp_evpn_mh.h index 6199113e87..1053e3f022 100644 --- a/bgpd/bgp_evpn_mh.h +++ b/bgpd/bgp_evpn_mh.h @@ -29,7 +29,6 @@ #define BGP_EVPN_AD_EVI_ETH_TAG 0 #define BGP_EVPNES_INCONS_STR_SZ 80 -#define BGP_EVPN_FLAG_STR_SZ 5 #define BGP_EVPN_VTEPS_FLAG_STR_SZ (BGP_EVPN_FLAG_STR_SZ * ES_VTEP_MAX_CNT) #define BGP_EVPN_CONS_CHECK_INTERVAL 60 @@ -62,6 +61,10 @@ struct bgp_evpn_es { #define BGP_EVPNES_ADV_EVI (1 << 3) /* consistency checks pending */ #define BGP_EVPNES_CONS_CHECK_PEND (1 << 4) + /* ES is in LACP bypass mode - don't advertise EAD-ES or ESR */ +#define BGP_EVPNES_BYPASS (1 << 5) + /* bits needed for printing the flags + null */ +#define BGP_EVPN_FLAG_STR_SZ 7 /* memory used for adding the es to bgp->es_rb_tree */ RB_ENTRY(bgp_evpn_es) rb_node; @@ -122,9 +125,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); @@ -340,7 +343,7 @@ int bgp_evpn_type4_route_process(struct peer *peer, afi_t afi, safi_t safi, uint32_t addpath_id); extern int bgp_evpn_local_es_add(struct bgp *bgp, esi_t *esi, struct in_addr originator_ip, bool oper_up, - uint16_t df_pref); + uint16_t df_pref, bool bypass); extern int bgp_evpn_local_es_del(struct bgp *bgp, esi_t *esi); extern int bgp_evpn_local_es_evi_add(struct bgp *bgp, esi_t *esi, vni_t vni); extern int bgp_evpn_local_es_evi_del(struct bgp *bgp, esi_t *esi, vni_t vni); @@ -373,5 +376,6 @@ extern bool bgp_evpn_path_es_use_nhg(struct bgp *bgp_vrf, 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); #endif /* _FRR_BGP_EVPN_MH_H */ diff --git a/bgpd/bgp_evpn_private.h b/bgpd/bgp_evpn_private.h index 77b3746344..ff4970af41 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 diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index 5b0b3bb6e5..b101589a79 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -3767,7 +3767,12 @@ DEFPY (bgp_evpn_ead_evi_rx_disable, NO_STR "Activate PE on EAD-ES even if EAD-EVI is not received\n") { - bgp_mh_info->ead_evi_rx = no? true :false; + bool ead_evi_rx = no? true :false; + + if (ead_evi_rx != bgp_mh_info->ead_evi_rx) { + bgp_mh_info->ead_evi_rx = ead_evi_rx; + bgp_evpn_switch_ead_evi_rx(); + } return CMD_SUCCESS; } @@ -4803,7 +4808,7 @@ DEFPY_HIDDEN(test_es_add, vtep_ip = bgp->router_id; ret = bgp_evpn_local_es_add(bgp, &esi, vtep_ip, oper_up, - EVPN_MH_DF_PREF_MIN); + EVPN_MH_DF_PREF_MIN, false); if (ret == -1) { vty_out(vty, "%%Failed to add ES\n"); return CMD_WARNING; diff --git a/bgpd/bgp_filter.c b/bgpd/bgp_filter.c index 3162579688..5d1a7a98d7 100644 --- a/bgpd/bgp_filter.c +++ b/bgpd/bgp_filter.c @@ -62,6 +62,9 @@ struct as_filter { regex_t *reg; char *reg_str; + + /* Sequence number. */ + int64_t seq; }; /* AS path filter list. */ @@ -77,6 +80,38 @@ struct as_list { struct as_filter *tail; }; + +/* Calculate new sequential number. */ +static int64_t bgp_alist_new_seq_get(struct as_list *list) +{ + int64_t maxseq; + int64_t newseq; + struct as_filter *entry; + + maxseq = 0; + + for (entry = list->head; entry; entry = entry->next) { + if (maxseq < entry->seq) + maxseq = entry->seq; + } + + newseq = ((maxseq / 5) * 5) + 5; + + return (newseq > UINT_MAX) ? UINT_MAX : newseq; +} + +/* Return as-list entry which has same seq number. */ +static struct as_filter *bgp_aslist_seq_check(struct as_list *list, int64_t seq) +{ + struct as_filter *entry; + + for (entry = list->head; entry; entry = entry->next) + if (entry->seq == seq) + return entry; + + return NULL; +} + /* as-path access-list 10 permit AS1. */ static struct as_list_master as_list_master = {{NULL, NULL}, @@ -125,17 +160,69 @@ static struct as_filter *as_filter_lookup(struct as_list *aslist, return NULL; } +static void as_filter_entry_replace(struct as_list *list, + struct as_filter *replace, + struct as_filter *entry) +{ + if (replace->next) { + entry->next = replace->next; + replace->next->prev = entry; + } else { + entry->next = NULL; + list->tail = entry; + } + + if (replace->prev) { + entry->prev = replace->prev; + replace->prev->next = entry; + } else { + entry->prev = NULL; + list->head = entry; + } + + as_filter_free(replace); +} + static void as_list_filter_add(struct as_list *aslist, struct as_filter *asfilter) { - asfilter->next = NULL; - asfilter->prev = aslist->tail; + struct as_filter *point; + struct as_filter *replace; - if (aslist->tail) - aslist->tail->next = asfilter; - else - aslist->head = asfilter; - aslist->tail = asfilter; + if (aslist->tail && asfilter->seq > aslist->tail->seq) + point = NULL; + else { + replace = bgp_aslist_seq_check(aslist, asfilter->seq); + if (replace) { + as_filter_entry_replace(aslist, replace, asfilter); + return; + } + + /* Check insert point. */ + for (point = aslist->head; point; point = point->next) + if (point->seq >= asfilter->seq) + break; + } + + asfilter->next = point; + + if (point) { + if (point->prev) + point->prev->next = asfilter; + else + aslist->head = asfilter; + + asfilter->prev = point->prev; + point->prev = asfilter; + } else { + if (aslist->tail) + aslist->tail->next = asfilter; + else + aslist->head = asfilter; + + asfilter->prev = aslist->tail; + aslist->tail = asfilter; + } /* Run hook function. */ if (as_list_master.add_hook) @@ -391,11 +478,13 @@ bool config_bgp_aspath_validate(const char *regstr) } DEFUN(as_path, bgp_as_path_cmd, - "bgp as-path access-list WORD <deny|permit> LINE...", + "bgp as-path access-list WORD [seq (0-4294967295)] <deny|permit> LINE...", BGP_STR "BGP autonomous system path filter\n" "Specify an access list name\n" "Regular expression access list name\n" + "Sequence number of an entry\n" + "Sequence number\n" "Specify packets to reject\n" "Specify packets to forward\n" "A regular-expression (1234567890_^|[,{}() ]$*+.?-\\) to match the BGP AS paths\n") @@ -406,11 +495,15 @@ DEFUN(as_path, bgp_as_path_cmd, struct as_list *aslist; regex_t *regex; char *regstr; + int64_t seqnum = ASPATH_SEQ_NUMBER_AUTO; /* Retrieve access list name */ argv_find(argv, argc, "WORD", &idx); char *alname = argv[idx]->arg; + if (argv_find(argv, argc, "(0-4294967295)", &idx)) + seqnum = (int64_t)atol(argv[idx]->arg); + /* Check the filter type. */ type = argv_find(argv, argc, "deny", &idx) ? AS_FILTER_DENY : AS_FILTER_PERMIT; @@ -439,6 +532,11 @@ DEFUN(as_path, bgp_as_path_cmd, /* Install new filter to the access_list. */ aslist = as_list_get(alname); + if (seqnum == ASPATH_SEQ_NUMBER_AUTO) + seqnum = bgp_alist_new_seq_get(aslist); + + asfilter->seq = seqnum; + /* Duplicate insertion check. */; if (as_list_dup_check(aslist, asfilter)) as_filter_free(asfilter); @@ -449,12 +547,14 @@ DEFUN(as_path, bgp_as_path_cmd, } DEFUN(no_as_path, no_bgp_as_path_cmd, - "no bgp as-path access-list WORD <deny|permit> LINE...", + "no bgp as-path access-list WORD [seq (0-4294967295)] <deny|permit> LINE...", NO_STR BGP_STR "BGP autonomous system path filter\n" "Specify an access list name\n" "Regular expression access list name\n" + "Sequence number of an entry\n" + "Sequence number\n" "Specify packets to reject\n" "Specify packets to forward\n" "A regular-expression (1234567890_^|[,{}() ]$*+.?-\\) to match the BGP AS paths\n") @@ -643,8 +743,11 @@ static int config_write_as_list(struct vty *vty) for (aslist = as_list_master.num.head; aslist; aslist = aslist->next) for (asfilter = aslist->head; asfilter; asfilter = asfilter->next) { - vty_out(vty, "bgp as-path access-list %s %s %s\n", - aslist->name, filter_type_str(asfilter->type), + vty_out(vty, + "bgp as-path access-list %s seq %" PRId64 + " %s %s\n", + aslist->name, asfilter->seq, + filter_type_str(asfilter->type), asfilter->reg_str); write++; } @@ -652,8 +755,11 @@ static int config_write_as_list(struct vty *vty) for (aslist = as_list_master.str.head; aslist; aslist = aslist->next) for (asfilter = aslist->head; asfilter; asfilter = asfilter->next) { - vty_out(vty, "bgp as-path access-list %s %s %s\n", - aslist->name, filter_type_str(asfilter->type), + vty_out(vty, + "bgp as-path access-list %s seq %" PRId64 + " %s %s\n", + aslist->name, asfilter->seq, + filter_type_str(asfilter->type), asfilter->reg_str); write++; } diff --git a/bgpd/bgp_filter.h b/bgpd/bgp_filter.h index 9357a2d382..66c83d97e9 100644 --- a/bgpd/bgp_filter.h +++ b/bgpd/bgp_filter.h @@ -21,6 +21,8 @@ #ifndef _QUAGGA_BGP_FILTER_H #define _QUAGGA_BGP_FILTER_H +#define ASPATH_SEQ_NUMBER_AUTO -1 + enum as_filter_type { AS_FILTER_DENY, AS_FILTER_PERMIT }; extern void bgp_filter_init(void); diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index 30e2c3d489..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 @@ -343,8 +343,8 @@ static struct peer *peer_xfer_conn(struct peer *from_peer) bgp_reads_on(peer); bgp_writes_on(peer); - thread_add_timer_msec(bm->master, bgp_process_packet, peer, 0, - &peer->t_process_packet); + thread_add_event(bm->master, bgp_process_packet, peer, 0, + &peer->t_process_packet); return (peer); } @@ -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))) { @@ -1556,13 +1557,9 @@ static int bgp_connect_success(struct peer *peer) bgp_reads_on(peer); if (bgp_debug_neighbor_events(peer)) { - char buf1[SU_ADDRSTRLEN]; - if (!CHECK_FLAG(peer->sflags, PEER_STATUS_ACCEPT_PEER)) - zlog_debug("%s open active, local address %s", - peer->host, - sockunion2str(peer->su_local, buf1, - SU_ADDRSTRLEN)); + zlog_debug("%s open active, local address %pSU", + peer->host, peer->su_local); else zlog_debug("%s passive open", peer->host); } @@ -1598,13 +1595,9 @@ static int bgp_connect_success_w_delayopen(struct peer *peer) bgp_reads_on(peer); if (bgp_debug_neighbor_events(peer)) { - char buf1[SU_ADDRSTRLEN]; - if (!CHECK_FLAG(peer->sflags, PEER_STATUS_ACCEPT_PEER)) - zlog_debug("%s open active, local address %s", - peer->host, - sockunion2str(peer->su_local, buf1, - SU_ADDRSTRLEN)); + zlog_debug("%s open active, local address %pSU", + peer->host, peer->su_local); else zlog_debug("%s passive open", peer->host); } @@ -2130,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 cd464d8c58..bcf697e153 100644 --- a/bgpd/bgp_fsm.h +++ b/bgpd/bgp_fsm.h @@ -31,7 +31,7 @@ #define BGP_TIMER_OFF(T) \ do { \ - THREAD_OFF(T); \ + THREAD_OFF((T)); \ } while (0) #define BGP_EVENT_ADD(P, E) \ @@ -44,7 +44,7 @@ #define BGP_EVENT_FLUSH(P) \ do { \ assert(peer); \ - thread_cancel_event(bm->master, (P)); \ + thread_cancel_event_ready(bm->master, (P)); \ } while (0) #define BGP_UPDATE_GROUP_TIMER_ON(T, F) \ @@ -53,10 +53,10 @@ PEER_ROUTE_ADV_DELAY(peer)) \ thread_add_timer_msec(bm->master, (F), peer, \ (BGP_DEFAULT_UPDATE_ADVERTISEMENT_TIME * 1000),\ - T); \ + (T)); \ else \ thread_add_timer_msec(bm->master, (F), peer, \ - 0, T); \ + 0, (T)); \ } while (0) \ #define BGP_MSEC_JITTER 10 @@ -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_io.c b/bgpd/bgp_io.c index 53fd3b5fe3..a696d95697 100644 --- a/bgpd/bgp_io.c +++ b/bgpd/bgp_io.c @@ -45,7 +45,7 @@ /* forward declarations */ static uint16_t bgp_write(struct peer *); -static uint16_t bgp_read(struct peer *); +static uint16_t bgp_read(struct peer *peer, int *code_p); static int bgp_process_writes(struct thread *); static int bgp_process_reads(struct thread *); static bool validate_header(struct peer *); @@ -181,6 +181,7 @@ static int bgp_process_reads(struct thread *thread) bool fatal = false; // whether fatal error occurred bool added_pkt = false; // whether we pushed onto ->ibuf /* clang-format on */ + int code; peer = THREAD_ARG(thread); @@ -190,7 +191,7 @@ static int bgp_process_reads(struct thread *thread) struct frr_pthread *fpt = bgp_pth_io; frr_with_mutex(&peer->io_mtx) { - status = bgp_read(peer); + status = bgp_read(peer, &code); } /* error checking phase */ @@ -203,6 +204,12 @@ static int bgp_process_reads(struct thread *thread) /* problem; tear down session */ more = false; fatal = true; + + /* Handle the error in the main pthread, include the + * specific state change from 'bgp_read'. + */ + thread_add_event(bm->master, bgp_packet_process_error, + peer, code, NULL); } while (more) { @@ -228,7 +235,7 @@ static int bgp_process_reads(struct thread *thread) pktsize = ntohs(pktsize); /* if this fails we are seriously screwed */ - assert(pktsize <= BGP_MAX_PACKET_SIZE); + assert(pktsize <= peer->max_packet_size); /* * If we have that much data, chuck it into its own @@ -236,6 +243,7 @@ static int bgp_process_reads(struct thread *thread) */ if (ringbuf_remain(ibw) >= pktsize) { struct stream *pkt = stream_new(pktsize); + assert(STREAM_WRITEABLE(pkt) == pktsize); assert(ringbuf_get(ibw, pkt->data, pktsize) == pktsize); stream_set_endp(pkt, pktsize); @@ -255,13 +263,13 @@ static int bgp_process_reads(struct thread *thread) /* wipe buffer just in case someone screwed up */ ringbuf_wipe(peer->ibuf_work); } else { - assert(ringbuf_space(peer->ibuf_work) >= BGP_MAX_PACKET_SIZE); + assert(ringbuf_space(peer->ibuf_work) >= peer->max_packet_size); thread_add_read(fpt->master, bgp_process_reads, peer, peer->fd, &peer->t_read); if (added_pkt) - thread_add_timer_msec(bm->master, bgp_process_packet, - peer, 0, &peer->t_process_packet); + thread_add_event(bm->master, bgp_process_packet, + peer, 0, &peer->t_process_packet); } return 0; @@ -449,60 +457,39 @@ done : { * * @return status flag (see top-of-file) */ -static uint16_t bgp_read(struct peer *peer) +static uint16_t bgp_read(struct peer *peer, int *code_p) { - size_t readsize; // how many bytes we want to read ssize_t nbytes; // how many bytes we actually read uint16_t status = 0; - static uint8_t ibw[BGP_MAX_PACKET_SIZE * BGP_READ_PACKET_MAX]; - readsize = MIN(ringbuf_space(peer->ibuf_work), sizeof(ibw)); - nbytes = read(peer->fd, ibw, readsize); + nbytes = ringbuf_read(peer->ibuf_work, peer->fd); /* EAGAIN or EWOULDBLOCK; come back later */ if (nbytes < 0 && ERRNO_IO_RETRY(errno)) { SET_FLAG(status, BGP_IO_TRANS_ERR); - /* Fatal error; tear down session */ } else if (nbytes < 0) { + /* Fatal error; tear down session */ flog_err(EC_BGP_UPDATE_RCV, "%s [Error] bgp_read_packet error: %s", peer->host, safe_strerror(errno)); - if (peer->status == Established) { - if ((CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART) - || CHECK_FLAG(peer->flags, - PEER_FLAG_GRACEFUL_RESTART_HELPER)) - && CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_MODE)) { - peer->last_reset = PEER_DOWN_NSF_CLOSE_SESSION; - SET_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT); - } else - peer->last_reset = PEER_DOWN_CLOSE_SESSION; - } + /* Handle the error in the main pthread. */ + if (code_p) + *code_p = TCP_fatal_error; - BGP_EVENT_ADD(peer, TCP_fatal_error); SET_FLAG(status, BGP_IO_FATAL_ERR); - /* Received EOF / TCP session closed */ + } else if (nbytes == 0) { + /* Received EOF / TCP session closed */ if (bgp_debug_neighbor_events(peer)) zlog_debug("%s [Event] BGP connection closed fd %d", peer->host, peer->fd); - if (peer->status == Established) { - if ((CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART) - || CHECK_FLAG(peer->flags, - PEER_FLAG_GRACEFUL_RESTART_HELPER)) - && CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_MODE)) { - peer->last_reset = PEER_DOWN_NSF_CLOSE_SESSION; - SET_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT); - } else - peer->last_reset = PEER_DOWN_CLOSE_SESSION; - } + /* Handle the error in the main pthread. */ + if (code_p) + *code_p = TCP_connection_closed; - BGP_EVENT_ADD(peer, TCP_connection_closed); SET_FLAG(status, BGP_IO_FATAL_ERR); - } else { - assert(ringbuf_put(peer->ibuf_work, ibw, nbytes) - == (size_t)nbytes); } return status; @@ -558,7 +545,7 @@ static bool validate_header(struct peer *peer) } /* Minimum packet length check. */ - if ((size < BGP_HEADER_SIZE) || (size > BGP_MAX_PACKET_SIZE) + if ((size < BGP_HEADER_SIZE) || (size > peer->max_packet_size) || (type == BGP_MSG_OPEN && size < BGP_MSG_OPEN_MIN_SIZE) || (type == BGP_MSG_UPDATE && size < BGP_MSG_UPDATE_MIN_SIZE) || (type == BGP_MSG_NOTIFY && size < BGP_MSG_NOTIFY_MIN_SIZE) diff --git a/bgpd/bgp_label.c b/bgpd/bgp_label.c index 5a31bd0243..bdab2ec36a 100644 --- a/bgpd/bgp_label.c +++ b/bgpd/bgp_label.c @@ -420,27 +420,19 @@ int bgp_nlri_parse_label(struct peer *peer, struct attr *attr, /* Check address. */ if (afi == AFI_IP6 && safi == SAFI_LABELED_UNICAST) { if (IN6_IS_ADDR_LINKLOCAL(&p.u.prefix6)) { - char buf[BUFSIZ]; - flog_err( EC_BGP_UPDATE_RCV, - "%s: IPv6 labeled-unicast NLRI is link-local address %s, ignoring", - peer->host, - inet_ntop(AF_INET6, &p.u.prefix6, buf, - BUFSIZ)); + "%s: IPv6 labeled-unicast NLRI is link-local address %pI6, ignoring", + peer->host, &p.u.prefix6); continue; } if (IN6_IS_ADDR_MULTICAST(&p.u.prefix6)) { - char buf[BUFSIZ]; - flog_err( EC_BGP_UPDATE_RCV, - "%s: IPv6 unicast NLRI is multicast address %s, ignoring", - peer->host, - inet_ntop(AF_INET6, &p.u.prefix6, buf, - BUFSIZ)); + "%s: IPv6 unicast NLRI is multicast address %pI6, ignoring", + peer->host, &p.u.prefix6); continue; } 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..2ddafd9a0c 100644 --- a/bgpd/bgp_main.c +++ b/bgpd/bgp_main.c @@ -162,6 +162,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); @@ -394,7 +397,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..9a4eb5d3bd 100644 --- a/bgpd/bgp_memory.c +++ b/bgpd/bgp_memory.c @@ -28,112 +28,112 @@ /* 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_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"); diff --git a/bgpd/bgp_memory.h b/bgpd/bgp_memory.h index 63998e95ac..7b839f1d4c 100644 --- a/bgpd/bgp_memory.h +++ b/bgpd/bgp_memory.h @@ -24,115 +24,115 @@ #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_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_mpath.c b/bgpd/bgp_mpath.c index 37639f4bce..d5fce115de 100644 --- a/bgpd/bgp_mpath.c +++ b/bgpd/bgp_mpath.c @@ -519,7 +519,6 @@ void bgp_path_info_mpath_update(struct bgp_dest *dest, struct listnode *mp_node, *mp_next_node; struct bgp_path_info *cur_mpath, *new_mpath, *next_mpath, *prev_mpath; int mpath_changed, debug; - char nh_buf[2][INET6_ADDRSTRLEN]; bool all_paths_lb; char path_buf[PATH_ADDPATH_STR_BUFFER]; @@ -630,14 +629,10 @@ void bgp_path_info_mpath_update(struct bgp_dest *dest, cur_mpath, path_buf, sizeof(path_buf)); zlog_debug( - "%pRN: remove mpath %s nexthop %s, cur count %d", + "%pRN: remove mpath %s nexthop %pI4, cur count %d", bgp_dest_to_rnode(dest), path_buf, - inet_ntop(AF_INET, - &cur_mpath->attr - ->nexthop, - nh_buf[0], - sizeof(nh_buf[0])), + &cur_mpath->attr->nexthop, mpath_count); } } @@ -664,12 +659,9 @@ void bgp_path_info_mpath_update(struct bgp_dest *dest, bgp_path_info_path_with_addpath_rx_str( cur_mpath, path_buf, sizeof(path_buf)); zlog_debug( - "%pRN: remove mpath %s nexthop %s, cur count %d", + "%pRN: remove mpath %s nexthop %pI4, cur count %d", bgp_dest_to_rnode(dest), path_buf, - inet_ntop(AF_INET, - &cur_mpath->attr->nexthop, - nh_buf[0], sizeof(nh_buf[0])), - mpath_count); + &cur_mpath->attr->nexthop, mpath_count); } cur_mpath = next_mpath; } else { @@ -715,14 +707,10 @@ void bgp_path_info_mpath_update(struct bgp_dest *dest, new_mpath, path_buf, sizeof(path_buf)); zlog_debug( - "%pRN: add mpath %s nexthop %s, cur count %d", + "%pRN: add mpath %s nexthop %pI4, cur count %d", bgp_dest_to_rnode(dest), path_buf, - inet_ntop(AF_INET, - &new_mpath->attr - ->nexthop, - nh_buf[0], - sizeof(nh_buf[0])), + &new_mpath->attr->nexthop, mpath_count); } } diff --git a/bgpd/bgp_nb_config.c b/bgpd/bgp_nb_config.c index 721ce5b5c6..0d2f84bfc4 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) @@ -3146,8 +3146,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 +3201,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 +4368,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 +4437,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 +5171,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 +5180,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, diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c index be2c474493..4821ce8ddb 100644 --- a/bgpd/bgp_network.c +++ b/bgpd/bgp_network.c @@ -233,7 +233,6 @@ int bgp_md5_unset(struct peer *peer) int bgp_set_socket_ttl(struct peer *peer, int bgp_sock) { - char buf[INET_ADDRSTRLEN]; int ret = 0; /* In case of peer is EBGP, we should set TTL for this connection. */ @@ -242,11 +241,8 @@ int bgp_set_socket_ttl(struct peer *peer, int bgp_sock) if (ret) { flog_err( EC_LIB_SOCKET, - "%s: Can't set TxTTL on peer (rtrid %s) socket, err = %d", - __func__, - inet_ntop(AF_INET, &peer->remote_id, buf, - sizeof(buf)), - errno); + "%s: Can't set TxTTL on peer (rtrid %pI4) socket, err = %d", + __func__, &peer->remote_id, errno); return ret; } } else if (peer->gtsm_hops) { @@ -258,11 +254,8 @@ int bgp_set_socket_ttl(struct peer *peer, int bgp_sock) if (ret) { flog_err( EC_LIB_SOCKET, - "%s: Can't set TxTTL on peer (rtrid %s) socket, err = %d", - __func__, - inet_ntop(AF_INET, &peer->remote_id, buf, - sizeof(buf)), - errno); + "%s: Can't set TxTTL on peer (rtrid %pI4) socket, err = %d", + __func__, &peer->remote_id, errno); return ret; } ret = sockopt_minttl(peer->su.sa.sa_family, bgp_sock, @@ -270,11 +263,8 @@ int bgp_set_socket_ttl(struct peer *peer, int bgp_sock) if (ret) { flog_err( EC_LIB_SOCKET, - "%s: Can't set MinTTL on peer (rtrid %s) socket, err = %d", - __func__, - inet_ntop(AF_INET, &peer->remote_id, buf, - sizeof(buf)), - errno); + "%s: Can't set MinTTL on peer (rtrid %pI4) socket, err = %d", + __func__, &peer->remote_id, errno); return ret; } } @@ -554,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_open.c b/bgpd/bgp_open.c index 533518cf93..7642640218 100644 --- a/bgpd/bgp_open.c +++ b/bgpd/bgp_open.c @@ -538,6 +538,22 @@ static as_t bgp_capability_as4(struct peer *peer, struct capability_header *hdr) return as4; } +static int bgp_capability_ext_message(struct peer *peer, + struct capability_header *hdr) +{ + if (hdr->length != CAPABILITY_CODE_EXT_MESSAGE_LEN) { + flog_err( + EC_BGP_PKT_OPEN, + "%s: BGP Extended Message capability has incorrect data length %d", + peer->host, hdr->length); + return -1; + } + + SET_FLAG(peer->cap, PEER_CAP_EXTENDED_MESSAGE_RCV); + + return 0; +} + static int bgp_capability_addpath(struct peer *peer, struct capability_header *hdr) { @@ -761,6 +777,7 @@ static const struct message capcode_str[] = { {CAPABILITY_CODE_ORF_OLD, "ORF (Old)"}, {CAPABILITY_CODE_FQDN, "FQDN"}, {CAPABILITY_CODE_ENHANCED_RR, "Enhanced Route Refresh"}, + {CAPABILITY_CODE_EXT_MESSAGE, "BGP Extended Message"}, {0}}; /* Minimum sizes for length field of each cap (so not inc. the header) */ @@ -778,6 +795,7 @@ static const size_t cap_minsizes[] = { [CAPABILITY_CODE_ORF_OLD] = CAPABILITY_CODE_ORF_LEN, [CAPABILITY_CODE_FQDN] = CAPABILITY_CODE_MIN_FQDN_LEN, [CAPABILITY_CODE_ENHANCED_RR] = CAPABILITY_CODE_ENHANCED_LEN, + [CAPABILITY_CODE_EXT_MESSAGE] = CAPABILITY_CODE_EXT_MESSAGE_LEN, }; /* value the capability must be a multiple of. @@ -799,6 +817,7 @@ static const size_t cap_modsizes[] = { [CAPABILITY_CODE_ORF_OLD] = 1, [CAPABILITY_CODE_FQDN] = 1, [CAPABILITY_CODE_ENHANCED_RR] = 1, + [CAPABILITY_CODE_EXT_MESSAGE] = 1, }; /** @@ -867,6 +886,7 @@ static int bgp_capability_parse(struct peer *peer, size_t length, case CAPABILITY_CODE_ENHE: case CAPABILITY_CODE_FQDN: case CAPABILITY_CODE_ENHANCED_RR: + case CAPABILITY_CODE_EXT_MESSAGE: /* Check length. */ if (caphdr.length < cap_minsizes[caphdr.code]) { zlog_info( @@ -955,6 +975,9 @@ static int bgp_capability_parse(struct peer *peer, size_t length, case CAPABILITY_CODE_ENHE: ret = bgp_capability_enhe(peer, &caphdr); break; + case CAPABILITY_CODE_EXT_MESSAGE: + ret = bgp_capability_ext_message(peer, &caphdr); + break; case CAPABILITY_CODE_FQDN: ret = bgp_capability_hostname(peer, &caphdr); break; @@ -1191,6 +1214,12 @@ int bgp_open_option_parse(struct peer *peer, uint8_t length, int *mp_capability) } } + /* Extended Message Support */ + peer->max_packet_size = + CHECK_FLAG(peer->cap, PEER_CAP_EXTENDED_MESSAGE_RCV) + ? BGP_MAX_EXTENDED_MESSAGE_PACKET_SIZE + : BGP_MAX_PACKET_SIZE; + /* Check there are no common AFI/SAFIs and send Unsupported Capability error. */ if (*mp_capability @@ -1476,6 +1505,13 @@ void bgp_open_capability(struct stream *s, struct peer *peer) local_as = peer->local_as; stream_putl(s, local_as); + /* Extended Message Support */ + SET_FLAG(peer->cap, PEER_CAP_EXTENDED_MESSAGE_ADV); + stream_putc(s, BGP_OPEN_OPT_CAP); + stream_putc(s, CAPABILITY_CODE_EXT_MESSAGE_LEN + 2); + stream_putc(s, CAPABILITY_CODE_EXT_MESSAGE); + stream_putc(s, CAPABILITY_CODE_EXT_MESSAGE_LEN); + /* AddPath */ FOREACH_AFI_SAFI (afi, safi) { if (peer->afc[afi][safi]) { diff --git a/bgpd/bgp_open.h b/bgpd/bgp_open.h index 471ac05c7c..bc6eedac85 100644 --- a/bgpd/bgp_open.h +++ b/bgpd/bgp_open.h @@ -54,6 +54,7 @@ struct graceful_restart_af { #define CAPABILITY_CODE_ENHE 5 /* Extended Next Hop Encoding */ #define CAPABILITY_CODE_REFRESH_OLD 128 /* Route Refresh Capability(cisco) */ #define CAPABILITY_CODE_ORF_OLD 130 /* Cooperative Route Filtering Capability(cisco) */ +#define CAPABILITY_CODE_EXT_MESSAGE 6 /* Extended Message Support */ /* Capability Length */ #define CAPABILITY_CODE_MP_LEN 4 @@ -66,6 +67,7 @@ struct graceful_restart_af { #define CAPABILITY_CODE_MIN_FQDN_LEN 2 #define CAPABILITY_CODE_ENHANCED_LEN 0 #define CAPABILITY_CODE_ORF_LEN 5 +#define CAPABILITY_CODE_EXT_MESSAGE_LEN 0 /* Extended Message Support */ /* Cooperative Route Filtering Capability. */ diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index c2e2de1c73..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. @@ -144,7 +144,7 @@ static struct stream *bgp_update_packet_eor(struct peer *peer, afi_t afi, zlog_debug("send End-of-RIB for %s to %s", get_afi_safi_str(afi, safi, false), peer->host); - s = stream_new(BGP_MAX_PACKET_SIZE); + s = stream_new(peer->max_packet_size); /* Make BGP update packet. */ bgp_packet_set_marker(s, BGP_MSG_UPDATE); @@ -726,7 +726,7 @@ void bgp_notify_send_with_data(struct peer *peer, uint8_t code, /* ============================================== */ /* Allocate new stream. */ - s = stream_new(BGP_MAX_PACKET_SIZE); + s = stream_new(peer->max_packet_size); /* Make notify packet. */ bgp_packet_set_marker(s, BGP_MSG_NOTIFY); @@ -864,7 +864,7 @@ void bgp_route_refresh_send(struct peer *peer, afi_t afi, safi_t safi, /* Convert AFI, SAFI to values for packet. */ bgp_map_afi_safi_int2iana(afi, safi, &pkt_afi, &pkt_safi); - s = stream_new(BGP_MAX_PACKET_SIZE); + s = stream_new(peer->max_packet_size); /* Make BGP update packet. */ if (CHECK_FLAG(peer->cap, PEER_CAP_REFRESH_NEW_RCV)) @@ -963,7 +963,7 @@ void bgp_capability_send(struct peer *peer, afi_t afi, safi_t safi, /* Convert AFI, SAFI to values for packet. */ bgp_map_afi_safi_int2iana(afi, safi, &pkt_afi, &pkt_safi); - s = stream_new(BGP_MAX_PACKET_SIZE); + s = stream_new(peer->max_packet_size); /* Make BGP update packet. */ bgp_packet_set_marker(s, BGP_MSG_CAPABILITY); @@ -2680,7 +2680,7 @@ int bgp_process_packet(struct thread *thread) frr_with_mutex(&peer->io_mtx) { // more work to do, come back later if (peer->ibuf->count > 0) - thread_add_timer_msec( + thread_add_event( bm->master, bgp_process_packet, peer, 0, &peer->t_process_packet); } @@ -2699,3 +2699,37 @@ void bgp_send_delayed_eor(struct bgp *bgp) for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) bgp_write_proceed_actions(peer); } + +/* + * Task callback to handle socket error encountered in the io pthread. We avoid + * having the io pthread try to enqueue fsm events or mess with the peer + * struct. + */ +int bgp_packet_process_error(struct thread *thread) +{ + struct peer *peer; + int code; + + peer = THREAD_ARG(thread); + code = THREAD_VAL(thread); + + if (bgp_debug_neighbor_events(peer)) + zlog_debug("%s [Event] BGP error %d on fd %d", + peer->host, peer->fd, code); + + /* Closed connection or error on the socket */ + if (peer->status == Established) { + if ((CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART) + || CHECK_FLAG(peer->flags, + PEER_FLAG_GRACEFUL_RESTART_HELPER)) + && CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_MODE)) { + peer->last_reset = PEER_DOWN_NSF_CLOSE_SESSION; + SET_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT); + } else + peer->last_reset = PEER_DOWN_CLOSE_SESSION; + } + + bgp_event_update(peer, code); + + return 0; +} diff --git a/bgpd/bgp_packet.h b/bgpd/bgp_packet.h index 525859a2da..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 @@ -83,4 +83,8 @@ extern int bgp_generate_updgrp_packets(struct thread *); extern int bgp_process_packet(struct thread *); extern void bgp_send_delayed_eor(struct bgp *bgp); + +/* Task callback to handle socket error encountered in the io pthread */ +int bgp_packet_process_error(struct thread *thread); + #endif /* _QUAGGA_BGP_PACKET_H */ 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 18a0b3fb7d..124a477248 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -95,7 +95,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)); /* Extern from bgp_dump.c */ extern const char *bgp_origin_str[]; @@ -121,7 +126,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) @@ -990,7 +995,7 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, if (newm < existm) { if (debug) zlog_debug( - "%s: %s wins over %s due to IGP metric %d < %d", + "%s: %s wins over %s due to IGP metric %u < %u", pfx_buf, new_buf, exist_buf, newm, existm); ret = 1; } @@ -998,7 +1003,7 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, if (newm > existm) { if (debug) zlog_debug( - "%s: %s loses to %s due to IGP metric %d > %d", + "%s: %s loses to %s due to IGP metric %u > %u", pfx_buf, new_buf, exist_buf, newm, existm); ret = 0; } @@ -1020,7 +1025,7 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, if (newm < existm) { if (debug) zlog_debug( - "%s: %s wins over %s due to CLUSTER_LIST length %d < %d", + "%s: %s wins over %s due to CLUSTER_LIST length %u < %u", pfx_buf, new_buf, exist_buf, newm, existm); ret = 1; @@ -1029,7 +1034,7 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, if (newm > existm) { if (debug) zlog_debug( - "%s: %s loses to %s due to CLUSTER_LIST length %d > %d", + "%s: %s loses to %s due to CLUSTER_LIST length %u > %u", pfx_buf, new_buf, exist_buf, newm, existm); ret = 0; @@ -3597,19 +3602,6 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, if (has_valid_label) assert(label != NULL); - /* The flag BGP_NODE_FIB_INSTALL_PENDING is for the following - * condition : - * Suppress fib is enabled - * BGP_OPT_NO_FIB is not enabled - * Route type is BGP_ROUTE_NORMAL (peer learnt routes) - * Route is being installed first time (BGP_NODE_FIB_INSTALLED not set) - */ - if (BGP_SUPPRESS_FIB_ENABLED(bgp) && - (sub_type == BGP_ROUTE_NORMAL) && - (!bgp_option_check(BGP_OPT_NO_FIB)) && - (!CHECK_FLAG(dest->flags, BGP_NODE_FIB_INSTALLED))) - SET_FLAG(dest->flags, BGP_NODE_FIB_INSTALL_PENDING); - /* When peer's soft reconfiguration enabled. Record input packet in Adj-RIBs-In. */ if (!soft_reconfig @@ -3791,6 +3783,19 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, evpn == NULL ? NULL : &evpn->gw_ip); } + /* The flag BGP_NODE_FIB_INSTALL_PENDING is for the following + * condition : + * Suppress fib is enabled + * BGP_OPT_NO_FIB is not enabled + * Route type is BGP_ROUTE_NORMAL (peer learnt routes) + * Route is being installed first time (BGP_NODE_FIB_INSTALLED not set) + */ + if (bgp_fibupd_safi(safi) && BGP_SUPPRESS_FIB_ENABLED(bgp) + && (sub_type == BGP_ROUTE_NORMAL) + && (!bgp_option_check(BGP_OPT_NO_FIB)) + && (!CHECK_FLAG(dest->flags, BGP_NODE_FIB_INSTALLED))) + SET_FLAG(dest->flags, BGP_NODE_FIB_INSTALL_PENDING); + attr_new = bgp_attr_intern(&new_attr); /* If maximum prefix count is configured and current prefix @@ -5250,26 +5255,18 @@ int bgp_nlri_parse_ip(struct peer *peer, struct attr *attr, /* Check address. */ if (afi == AFI_IP6 && safi == SAFI_UNICAST) { if (IN6_IS_ADDR_LINKLOCAL(&p.u.prefix6)) { - char buf[BUFSIZ]; - flog_err( EC_BGP_UPDATE_RCV, - "%s: IPv6 unicast NLRI is link-local address %s, ignoring", - peer->host, - inet_ntop(AF_INET6, &p.u.prefix6, buf, - BUFSIZ)); + "%s: IPv6 unicast NLRI is link-local address %pI6, ignoring", + peer->host, &p.u.prefix6); continue; } if (IN6_IS_ADDR_MULTICAST(&p.u.prefix6)) { - char buf[BUFSIZ]; - flog_err( EC_BGP_UPDATE_RCV, - "%s: IPv6 unicast NLRI is multicast address %s, ignoring", - peer->host, - inet_ntop(AF_INET6, &p.u.prefix6, buf, - BUFSIZ)); + "%s: IPv6 unicast NLRI is multicast address %pI6, ignoring", + peer->host, &p.u.prefix6); continue; } @@ -7554,6 +7551,21 @@ static const char *bgp_origin2str(uint8_t origin) return "n/a"; } +static const char *bgp_rpki_validation2str(int v_state) +{ + switch (v_state) { + case 1: + return "valid"; + case 2: + return "not found"; + case 3: + return "invalid"; + default: + break; + } + return "ERROR"; +} + int bgp_aggregate_unset(struct bgp *bgp, struct prefix *prefix, afi_t afi, safi_t safi, char *errmsg, size_t errmsg_len) { @@ -9568,6 +9580,7 @@ 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(); @@ -10166,6 +10179,20 @@ 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 (json_paths) + json_object_string_add( + json_path, "rpkiValidationState", + bgp_rpki_validation2str(rpki_validation_state)); + else + vty_out(vty, ", validation-state: %s", + bgp_rpki_validation2str(rpki_validation_state)); + } + if (json_bestpath) json_object_object_add(json_path, "bestpath", json_bestpath); @@ -12385,6 +12412,9 @@ static int bgp_table_stats_walker(struct thread *t) case AFI_IP6: space = IPV6_MAX_BITLEN; break; + case AFI_L2VPN: + space = EVPN_ROUTE_PREFIXLEN; + break; default: return 0; } diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index 766e5ade92..1dec99f085 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -550,7 +550,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) diff --git a/bgpd/bgp_rpki.c b/bgpd/bgp_rpki.c index 6bb33ff859..9344384956 100644 --- a/bgpd/bgp_rpki.c +++ b/bgpd/bgp_rpki.c @@ -60,8 +60,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_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 @@ -562,6 +562,7 @@ static int bgp_rpki_module_init(void) { lrtr_set_alloc_functions(malloc_wrapper, realloc_wrapper, free_wrapper); + hook_register(bgp_rpki_prefix_status, rpki_validate_prefix); hook_register(frr_late_init, bgp_rpki_init); hook_register(frr_early_fini, &bgp_rpki_fini); @@ -1470,4 +1471,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/bgpd/bgp_snmp.c b/bgpd/bgp_snmp.c index 71868abc5f..bc26314b50 100644 --- a/bgpd/bgp_snmp.c +++ b/bgpd/bgp_snmp.c @@ -914,4 +914,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 022a6413e2..7e3aa2a48a 100644 --- a/bgpd/bgp_table.c +++ b/bgpd/bgp_table.c @@ -205,8 +205,14 @@ static ssize_t printfrr_bd(char *buf, size_t bsz, const char *fmt, int prec, const void *ptr) { const struct bgp_dest *dest = ptr; - const struct prefix *p = bgp_dest_get_prefix(dest); + const struct prefix *p; + + if (dest) { + p = bgp_dest_get_prefix(dest); + prefix2str(p, buf, bsz); + } else { + strlcpy(buf, "NULL", bsz); + } - prefix2str(p, buf, bsz); return 2; } diff --git a/bgpd/bgp_updgrp.c b/bgpd/bgp_updgrp.c index 621a14014f..2600eda42e 100644 --- a/bgpd/bgp_updgrp.c +++ b/bgpd/bgp_updgrp.c @@ -79,8 +79,11 @@ static void update_subgroup_checkin(struct update_subgroup *subgrp, subgrp->uptime = bgp_clock(); } -static void sync_init(struct update_subgroup *subgrp) +static void sync_init(struct update_subgroup *subgrp, + struct update_group *updgrp) { + struct peer *peer = UPDGRP_PEER(updgrp); + subgrp->sync = XCALLOC(MTYPE_BGP_SYNCHRONISE, sizeof(struct bgp_synchronize)); bgp_adv_fifo_init(&subgrp->sync->update); @@ -91,7 +94,7 @@ static void sync_init(struct update_subgroup *subgrp) /* We use a larger buffer for subgrp->work in the event that: * - We RX a BGP_UPDATE where the attributes alone are just - * under BGP_MAX_PACKET_SIZE + * under 4096 or 65535 (if Extended Message capability negotiated). * - The user configures an outbound route-map that does many as-path * prepends or adds many communities. At most they can have * CMD_ARGC_MAX @@ -103,9 +106,9 @@ static void sync_init(struct update_subgroup *subgrp) * bounds * checking for every single attribute as we construct an UPDATE. */ - subgrp->work = - stream_new(BGP_MAX_PACKET_SIZE + BGP_MAX_PACKET_SIZE_OVERFLOW); - subgrp->scratch = stream_new(BGP_MAX_PACKET_SIZE); + subgrp->work = stream_new(peer->max_packet_size + + BGP_MAX_PACKET_SIZE_OVERFLOW); + subgrp->scratch = stream_new(peer->max_packet_size); } static void sync_delete(struct update_subgroup *subgrp) @@ -143,6 +146,7 @@ static void conf_copy(struct peer *dst, struct peer *src, afi_t afi, dst->flags = src->flags; dst->af_flags[afi][safi] = src->af_flags[afi][safi]; dst->pmax_out[afi][safi] = src->pmax_out[afi][safi]; + dst->max_packet_size = src->max_packet_size; XFREE(MTYPE_BGP_PEER_HOST, dst->host); dst->host = XSTRDUP(MTYPE_BGP_PEER_HOST, src->host); @@ -800,7 +804,7 @@ update_subgroup_create(struct update_group *updgrp) subgrp = XCALLOC(MTYPE_BGP_UPD_SUBGRP, sizeof(struct update_subgroup)); update_subgroup_checkin(subgrp, updgrp); subgrp->v_coalesce = (UPDGRP_INST(updgrp))->coalesce_time; - sync_init(subgrp); + sync_init(subgrp, updgrp); bpacket_queue_init(SUBGRP_PKTQ(subgrp)); bpacket_queue_add(SUBGRP_PKTQ(subgrp), NULL, NULL); TAILQ_INIT(&(subgrp->adjq)); diff --git a/bgpd/bgp_updgrp_packet.c b/bgpd/bgp_updgrp_packet.c index a13a5395b4..6418decd16 100644 --- a/bgpd/bgp_updgrp_packet.c +++ b/bgpd/bgp_updgrp_packet.c @@ -350,8 +350,6 @@ struct stream *bpacket_reformat_for_peer(struct bpacket *pkt, struct stream *s = NULL; bpacket_attr_vec *vec; struct peer *peer; - char buf[BUFSIZ]; - char buf2[BUFSIZ]; struct bgp_filter *filter; s = stream_dup(pkt->buffer); @@ -568,25 +566,24 @@ struct stream *bpacket_reformat_for_peer(struct bpacket *pkt, if (nhlen == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL || nhlen == BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL) zlog_debug( - "u%" PRIu64 ":s%" PRIu64" %s send UPDATE w/ mp_nexthops %s, %s%s", + "u%" PRIu64 ":s%" PRIu64 + " %s send UPDATE w/ mp_nexthops %pI6, %pI6%s", PAF_SUBGRP(paf)->update_group->id, PAF_SUBGRP(paf)->id, peer->host, - inet_ntop(AF_INET6, mod_v6nhg, buf, - BUFSIZ), - inet_ntop(AF_INET6, mod_v6nhl, buf2, - BUFSIZ), + mod_v6nhg, mod_v6nhl, (nhlen == BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL ? " and RD" : "")); else - zlog_debug("u%" PRIu64 ":s%" PRIu64" %s send UPDATE w/ mp_nexthop %s%s", - PAF_SUBGRP(paf)->update_group->id, - PAF_SUBGRP(paf)->id, peer->host, - inet_ntop(AF_INET6, mod_v6nhg, buf, - BUFSIZ), - (nhlen == BGP_ATTR_NHLEN_VPNV6_GLOBAL - ? " and RD" - : "")); + zlog_debug( + "u%" PRIu64 ":s%" PRIu64 + " %s send UPDATE w/ mp_nexthop %pI6%s", + PAF_SUBGRP(paf)->update_group->id, + PAF_SUBGRP(paf)->id, peer->host, + mod_v6nhg, + (nhlen == BGP_ATTR_NHLEN_VPNV6_GLOBAL + ? " and RD" + : "")); } } else if (paf->afi == AFI_L2VPN) { struct in_addr v4nh, *mod_v4nh; @@ -898,11 +895,13 @@ next: packet = stream_dup(s); bgp_packet_set_size(packet); if (bgp_debug_update(NULL, NULL, subgrp->update_group, 0)) - zlog_debug("u%" PRIu64 ":s%" PRIu64" send UPDATE len %zd numpfx %d", - subgrp->update_group->id, subgrp->id, - (stream_get_endp(packet) - - stream_get_getp(packet)), - num_pfx); + zlog_debug( + "u%" PRIu64 ":s%" PRIu64 + " send UPDATE len %zd (max message len: %hu) numpfx %d", + subgrp->update_group->id, subgrp->id, + (stream_get_endp(packet) + - stream_get_getp(packet)), + peer->max_packet_size, num_pfx); pkt = bpacket_queue_add(SUBGRP_PKTQ(subgrp), packet, &vecarr); stream_reset(s); stream_reset(snlri); @@ -1128,7 +1127,7 @@ void subgroup_default_update_packet(struct update_subgroup *subgrp, tx_id_buf, attrstr); } - s = stream_new(BGP_MAX_PACKET_SIZE); + s = stream_new(peer->max_packet_size); /* Make BGP update packet. */ bgp_packet_set_marker(s, BGP_MSG_UPDATE); @@ -1206,7 +1205,7 @@ void subgroup_default_withdraw_packet(struct update_subgroup *subgrp) tx_id_buf); } - s = stream_new(BGP_MAX_PACKET_SIZE); + s = stream_new(peer->max_packet_size); /* Make BGP update packet. */ bgp_packet_set_marker(s, BGP_MSG_UPDATE); diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 9e8065691e..a016265d6e 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -24,6 +24,7 @@ #include "lib/json.h" #include "lib_errors.h" #include "lib/zclient.h" +#include "lib/printfrr.h" #include "prefix.h" #include "plist.h" #include "buffer.h" @@ -85,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." @@ -739,7 +740,7 @@ int bgp_nb_errmsg_return(char *errmsg, size_t errmsg_len, int ret) str = "Operation not allowed on a directly connected neighbor"; break; case BGP_ERR_PEER_SAFI_CONFLICT: - str = GR_INVALID; + str = "Cannot activate peer for both 'ipv4 unicast' and 'ipv4 labeled-unicast'"; break; case BGP_ERR_GR_INVALID_CMD: str = "The Graceful Restart command used is not valid at this moment."; @@ -831,7 +832,7 @@ int bgp_vty_return(struct vty *vty, int ret) str = "Operation not allowed on a directly connected neighbor"; break; case BGP_ERR_PEER_SAFI_CONFLICT: - str = GR_INVALID; + str = "Cannot activate peer for both 'ipv4 unicast' and 'ipv4 labeled-unicast'"; break; case BGP_ERR_GR_INVALID_CMD: str = "The Graceful Restart command used is not valid at this moment."; @@ -3726,6 +3727,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, @@ -4367,10 +4391,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; @@ -4387,16 +4411,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, @@ -6138,10 +6156,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, @@ -6158,10 +6194,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, @@ -12971,6 +13025,28 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, "received"); } + /* Extended Message Support */ + if (CHECK_FLAG(p->cap, + PEER_CAP_EXTENDED_MESSAGE_ADV) + && CHECK_FLAG( + p->cap, + PEER_CAP_EXTENDED_MESSAGE_RCV)) + json_object_string_add( + json_cap, "extendedMessage", + "advertisedAndReceived"); + else if (CHECK_FLAG( + p->cap, + PEER_CAP_EXTENDED_MESSAGE_ADV)) + json_object_string_add( + json_cap, "extendedMessage", + "advertised"); + else if (CHECK_FLAG( + p->cap, + PEER_CAP_EXTENDED_MESSAGE_RCV)) + json_object_string_add( + json_cap, "extendedMessage", + "received"); + /* AddPath */ if (CHECK_FLAG(p->cap, PEER_CAP_ADDPATH_RCV) || CHECK_FLAG(p->cap, @@ -13449,6 +13525,29 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, vty_out(vty, "\n"); } + /* Extended Message Support */ + if (CHECK_FLAG(p->cap, + PEER_CAP_EXTENDED_MESSAGE_RCV) + || CHECK_FLAG( + p->cap, + PEER_CAP_EXTENDED_MESSAGE_ADV)) { + vty_out(vty, " Extended Message:"); + if (CHECK_FLAG( + p->cap, + PEER_CAP_EXTENDED_MESSAGE_ADV)) + vty_out(vty, " advertised"); + if (CHECK_FLAG( + p->cap, + PEER_CAP_EXTENDED_MESSAGE_RCV)) + vty_out(vty, " %sreceived", + CHECK_FLAG( + p->cap, + PEER_CAP_EXTENDED_MESSAGE_ADV) + ? "and " + : ""); + vty_out(vty, "\n"); + } + /* AddPath */ if (CHECK_FLAG(p->cap, PEER_CAP_ADDPATH_RCV) || CHECK_FLAG(p->cap, @@ -14312,7 +14411,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. */ @@ -15419,7 +15519,8 @@ DEFPY(show_ip_bgp_instance_updgrps_adj_s, return CMD_SUCCESS; } -static int bgp_show_one_peer_group(struct vty *vty, struct peer_group *group) +static int bgp_show_one_peer_group(struct vty *vty, struct peer_group *group, + json_object *json) { struct listnode *node, *nnode; struct prefix *range; @@ -15428,64 +15529,143 @@ static int bgp_show_one_peer_group(struct vty *vty, struct peer_group *group) afi_t afi; safi_t safi; const char *peer_status; - const char *af_str; int lr_count; int dynamic; - int af_cfgd; + bool af_cfgd; + json_object *json_peer_group = NULL; + json_object *json_peer_group_afc = NULL; + json_object *json_peer_group_members = NULL; + json_object *json_peer_group_dynamic = NULL; + json_object *json_peer_group_dynamic_af = NULL; + json_object *json_peer_group_ranges = NULL; conf = group->conf; + if (json) { + json_peer_group = json_object_new_object(); + json_peer_group_afc = json_object_new_array(); + } + if (conf->as_type == AS_SPECIFIED || conf->as_type == AS_EXTERNAL) { - vty_out(vty, "\nBGP peer-group %s, remote AS %u\n", - group->name, conf->as); + if (json) + json_object_int_add(json_peer_group, "remoteAs", + conf->as); + else + vty_out(vty, "\nBGP peer-group %s, remote AS %u\n", + group->name, conf->as); } else if (conf->as_type == AS_INTERNAL) { - vty_out(vty, "\nBGP peer-group %s, remote AS %u\n", - group->name, group->bgp->as); + if (json) + json_object_int_add(json_peer_group, "remoteAs", + group->bgp->as); + else + vty_out(vty, "\nBGP peer-group %s, remote AS %u\n", + group->name, group->bgp->as); } else { - vty_out(vty, "\nBGP peer-group %s\n", group->name); + if (!json) + vty_out(vty, "\nBGP peer-group %s\n", group->name); } - if ((group->bgp->as == conf->as) || (conf->as_type == AS_INTERNAL)) - vty_out(vty, " Peer-group type is internal\n"); - else - vty_out(vty, " Peer-group type is external\n"); + if ((group->bgp->as == conf->as) || (conf->as_type == AS_INTERNAL)) { + if (json) + json_object_string_add(json_peer_group, "type", + "internal"); + else + vty_out(vty, " Peer-group type is internal\n"); + } else { + if (json) + json_object_string_add(json_peer_group, "type", + "external"); + else + vty_out(vty, " Peer-group type is external\n"); + } /* Display AFs configured. */ - vty_out(vty, " Configured address-families:"); + if (!json) + vty_out(vty, " Configured address-families:"); + FOREACH_AFI_SAFI (afi, safi) { if (conf->afc[afi][safi]) { - af_cfgd = 1; - vty_out(vty, " %s;", get_afi_safi_str(afi, safi, false)); + af_cfgd = true; + if (json) + json_object_array_add( + json_peer_group_afc, + json_object_new_string(get_afi_safi_str( + afi, safi, false))); + else + vty_out(vty, " %s;", + get_afi_safi_str(afi, safi, false)); } } - if (!af_cfgd) - vty_out(vty, " none\n"); - else - vty_out(vty, "\n"); + + if (json) { + json_object_object_add(json_peer_group, + "addressFamiliesConfigured", + json_peer_group_afc); + } else { + if (!af_cfgd) + vty_out(vty, " none\n"); + else + vty_out(vty, "\n"); + } /* Display listen ranges (for dynamic neighbors), if any */ for (afi = AFI_IP; afi < AFI_MAX; afi++) { - if (afi == AFI_IP) - af_str = "IPv4"; - else if (afi == AFI_IP6) - af_str = "IPv6"; - else - af_str = "???"; lr_count = listcount(group->listen_range[afi]); if (lr_count) { - vty_out(vty, " %d %s listen range(s)\n", lr_count, - af_str); - + if (json) { + if (!json_peer_group_dynamic) + json_peer_group_dynamic = + json_object_new_object(); + + json_peer_group_dynamic_af = + json_object_new_object(); + json_peer_group_ranges = + json_object_new_array(); + json_object_int_add(json_peer_group_dynamic_af, + "count", lr_count); + } else { + vty_out(vty, " %d %s listen range(s)\n", + lr_count, afi2str(afi)); + } for (ALL_LIST_ELEMENTS(group->listen_range[afi], node, - nnode, range)) - vty_out(vty, " %pFX\n", range); + nnode, range)) { + if (json) { + char buf[BUFSIZ]; + + snprintfrr(buf, sizeof(buf), "%pFX", + range); + + json_object_array_add( + json_peer_group_ranges, + json_object_new_string(buf)); + } else { + vty_out(vty, " %pFX\n", range); + } + } + + if (json) { + json_object_object_add( + json_peer_group_dynamic_af, "ranges", + json_peer_group_ranges); + + json_object_object_add( + json_peer_group_dynamic, afi2str(afi), + json_peer_group_dynamic_af); + } } } + if (json_peer_group_dynamic) + json_object_object_add(json_peer_group, "dynamicRanges", + json_peer_group_dynamic); + /* Display group members and their status */ if (listcount(group->peer)) { - vty_out(vty, " Peer-group members:\n"); + if (json) + json_peer_group_members = json_object_new_object(); + else + vty_out(vty, " Peer-group members:\n"); for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) { if (CHECK_FLAG(peer->flags, PEER_FLAG_SHUTDOWN) || CHECK_FLAG(peer->bgp->flags, BGP_FLAG_SHUTDOWN)) @@ -15498,65 +15678,106 @@ static int bgp_show_one_peer_group(struct vty *vty, struct peer_group *group) peer->status, NULL); dynamic = peer_dynamic_neighbor(peer); - vty_out(vty, " %s %s %s \n", peer->host, - dynamic ? "(dynamic)" : "", peer_status); + + if (json) { + json_object *json_peer_group_member = + json_object_new_object(); + + json_object_string_add(json_peer_group_member, + "status", peer_status); + + if (dynamic) + json_object_boolean_true_add( + json_peer_group_member, + "dynamic"); + + json_object_object_add(json_peer_group_members, + peer->host, + json_peer_group_member); + } else { + vty_out(vty, " %s %s %s \n", peer->host, + dynamic ? "(dynamic)" : "", + peer_status); + } } + if (json) + json_object_object_add(json_peer_group, "members", + json_peer_group_members); } + if (json) + json_object_object_add(json, group->name, json_peer_group); + return CMD_SUCCESS; } static int bgp_show_peer_group_vty(struct vty *vty, const char *name, - const char *group_name) + const char *group_name, bool uj) { struct bgp *bgp; struct listnode *node, *nnode; struct peer_group *group; bool found = false; + json_object *json = NULL; + + if (uj) + json = json_object_new_object(); bgp = name ? bgp_lookup_by_name(name) : bgp_get_default(); if (!bgp) { - vty_out(vty, "%% BGP instance not found\n"); + if (uj) { + vty_out(vty, "%s\n", + json_object_to_json_string_ext( + json, JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } else { + vty_out(vty, "%% BGP instance not found\n"); + } + return CMD_WARNING; } for (ALL_LIST_ELEMENTS(bgp->group, node, nnode, group)) { if (group_name) { if (strmatch(group->name, group_name)) { - bgp_show_one_peer_group(vty, group); + bgp_show_one_peer_group(vty, group, json); found = true; break; } } else { - bgp_show_one_peer_group(vty, group); + bgp_show_one_peer_group(vty, group, json); } } - if (group_name && !found) + if (group_name && !found && !uj) vty_out(vty, "%% No such peer-group\n"); + 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 (show_ip_bgp_peer_groups, - show_ip_bgp_peer_groups_cmd, - "show [ip] bgp [<view|vrf> VIEWVRFNAME] peer-group [PGNAME]", - SHOW_STR - IP_STR - BGP_STR - BGP_INSTANCE_HELP_STR - "Detailed information on BGP peer groups\n" - "Peer group name\n") +DEFUN(show_ip_bgp_peer_groups, show_ip_bgp_peer_groups_cmd, + "show [ip] bgp [<view|vrf> VIEWVRFNAME] peer-group [PGNAME] [json]", + SHOW_STR IP_STR BGP_STR BGP_INSTANCE_HELP_STR + "Detailed information on BGP peer groups\n" + "Peer group name\n" JSON_STR) { char *vrf, *pg; int idx = 0; + bool uj = use_json(argc, argv); vrf = argv_find(argv, argc, "VIEWVRFNAME", &idx) ? argv[idx]->arg : NULL; pg = argv_find(argv, argc, "PGNAME", &idx) ? argv[idx]->arg : NULL; - return bgp_show_peer_group_vty(vty, vrf, pg); + return bgp_show_peer_group_vty(vty, vrf, pg, uj); } @@ -16598,11 +16819,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)) @@ -16799,18 +17017,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); @@ -17244,6 +17480,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", @@ -17914,6 +18154,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); @@ -19060,7 +19304,7 @@ static void community_list_perror(struct vty *vty, int ret) /*community-list standard */ DEFUN (community_list_standard, bgp_community_list_standard_cmd, - "bgp community-list <(1-99)|standard WORD> [seq (1-4294967295)] <deny|permit> AA:NN...", + "bgp community-list <(1-99)|standard WORD> [seq (0-4294967295)] <deny|permit> AA:NN...", BGP_STR COMMUNITY_LIST_STR "Community list number (standard)\n" @@ -19078,7 +19322,7 @@ DEFUN (community_list_standard, int style = COMMUNITY_LIST_STANDARD; int idx = 0; - argv_find(argv, argc, "(1-4294967295)", &idx); + argv_find(argv, argc, "(0-4294967295)", &idx); if (idx) seq = argv[idx]->arg; @@ -19107,7 +19351,7 @@ DEFUN (community_list_standard, DEFUN (no_community_list_standard_all, no_bgp_community_list_standard_all_cmd, - "no bgp community-list <(1-99)|standard WORD> [seq (1-4294967295)] <deny|permit> AA:NN...", + "no bgp community-list <(1-99)|standard WORD> [seq (0-4294967295)] <deny|permit> AA:NN...", NO_STR BGP_STR COMMUNITY_LIST_STR @@ -19127,7 +19371,7 @@ DEFUN (no_community_list_standard_all, char *seq = NULL; int idx = 0; - argv_find(argv, argc, "(1-4294967295)", &idx); + argv_find(argv, argc, "(0-4294967295)", &idx); if (idx) seq = argv[idx]->arg; @@ -19173,7 +19417,7 @@ ALIAS(no_community_list_standard_all, no_bgp_community_list_standard_all_list_cm /*community-list expanded */ DEFUN (community_list_expanded_all, bgp_community_list_expanded_all_cmd, - "bgp community-list <(100-500)|expanded WORD> [seq (1-4294967295)] <deny|permit> AA:NN...", + "bgp community-list <(100-500)|expanded WORD> [seq (0-4294967295)] <deny|permit> AA:NN...", BGP_STR COMMUNITY_LIST_STR "Community list number (expanded)\n" @@ -19191,7 +19435,7 @@ DEFUN (community_list_expanded_all, int style = COMMUNITY_LIST_EXPANDED; int idx = 0; - argv_find(argv, argc, "(1-4294967295)", &idx); + argv_find(argv, argc, "(0-4294967295)", &idx); if (idx) seq = argv[idx]->arg; @@ -19221,7 +19465,7 @@ DEFUN (community_list_expanded_all, DEFUN (no_community_list_expanded_all, no_bgp_community_list_expanded_all_cmd, - "no bgp community-list <(100-500)|expanded WORD> [seq (1-4294967295)] <deny|permit> AA:NN...", + "no bgp community-list <(100-500)|expanded WORD> [seq (0-4294967295)] <deny|permit> AA:NN...", NO_STR BGP_STR COMMUNITY_LIST_STR @@ -19241,7 +19485,7 @@ DEFUN (no_community_list_expanded_all, int style = COMMUNITY_LIST_EXPANDED; int idx = 0; - argv_find(argv, argc, "(1-4294967295)", &idx); + argv_find(argv, argc, "(0-4294967295)", &idx); if (idx) seq = argv[idx]->arg; @@ -19394,7 +19638,7 @@ static int lcommunity_list_set_vty(struct vty *vty, int argc, char *cl_name; char *seq = NULL; - if (argv_find(argv, argc, "(1-4294967295)", &idx)) + if (argv_find(argv, argc, "(0-4294967295)", &idx)) seq = argv[idx]->arg; idx = 0; @@ -19443,7 +19687,7 @@ static int lcommunity_list_unset_vty(struct vty *vty, int argc, int idx = 0; char *seq = NULL; - if (argv_find(argv, argc, "(1-4294967295)", &idx)) + if (argv_find(argv, argc, "(0-4294967295)", &idx)) seq = argv[idx]->arg; idx = 0; @@ -19491,7 +19735,7 @@ static int lcommunity_list_unset_vty(struct vty *vty, int argc, DEFUN (lcommunity_list_standard, bgp_lcommunity_list_standard_cmd, - "bgp large-community-list (1-99) [seq (1-4294967295)] <deny|permit> AA:BB:CC...", + "bgp large-community-list (1-99) [seq (0-4294967295)] <deny|permit> AA:BB:CC...", BGP_STR LCOMMUNITY_LIST_STR "Large Community list number (standard)\n" @@ -19507,7 +19751,7 @@ DEFUN (lcommunity_list_standard, DEFUN (lcommunity_list_expanded, bgp_lcommunity_list_expanded_cmd, - "bgp large-community-list (100-500) [seq (1-4294967295)] <deny|permit> LINE...", + "bgp large-community-list (100-500) [seq (0-4294967295)] <deny|permit> LINE...", BGP_STR LCOMMUNITY_LIST_STR "Large Community list number (expanded)\n" @@ -19523,7 +19767,7 @@ DEFUN (lcommunity_list_expanded, DEFUN (lcommunity_list_name_standard, bgp_lcommunity_list_name_standard_cmd, - "bgp large-community-list standard WORD [seq (1-4294967295)] <deny|permit> AA:BB:CC...", + "bgp large-community-list standard WORD [seq (0-4294967295)] <deny|permit> AA:BB:CC...", BGP_STR LCOMMUNITY_LIST_STR "Specify standard large-community-list\n" @@ -19540,7 +19784,7 @@ DEFUN (lcommunity_list_name_standard, DEFUN (lcommunity_list_name_expanded, bgp_lcommunity_list_name_expanded_cmd, - "bgp large-community-list expanded WORD [seq (1-4294967295)] <deny|permit> LINE...", + "bgp large-community-list expanded WORD [seq (0-4294967295)] <deny|permit> LINE...", BGP_STR LCOMMUNITY_LIST_STR "Specify expanded large-community-list\n" @@ -19597,7 +19841,7 @@ DEFUN (no_lcommunity_list_name_expanded_all, DEFUN (no_lcommunity_list_standard, no_bgp_lcommunity_list_standard_cmd, - "no bgp large-community-list (1-99) [seq (1-4294967295)] <deny|permit> AA:AA:NN...", + "no bgp large-community-list (1-99) [seq (0-4294967295)] <deny|permit> AA:AA:NN...", NO_STR BGP_STR LCOMMUNITY_LIST_STR @@ -19614,7 +19858,7 @@ DEFUN (no_lcommunity_list_standard, DEFUN (no_lcommunity_list_expanded, no_bgp_lcommunity_list_expanded_cmd, - "no bgp large-community-list (100-500) [seq (1-4294967295)] <deny|permit> LINE...", + "no bgp large-community-list (100-500) [seq (0-4294967295)] <deny|permit> LINE...", NO_STR BGP_STR LCOMMUNITY_LIST_STR @@ -19631,7 +19875,7 @@ DEFUN (no_lcommunity_list_expanded, DEFUN (no_lcommunity_list_name_standard, no_bgp_lcommunity_list_name_standard_cmd, - "no bgp large-community-list standard WORD [seq (1-4294967295)] <deny|permit> AA:AA:NN...", + "no bgp large-community-list standard WORD [seq (0-4294967295)] <deny|permit> AA:AA:NN...", NO_STR BGP_STR LCOMMUNITY_LIST_STR @@ -19649,7 +19893,7 @@ DEFUN (no_lcommunity_list_name_standard, DEFUN (no_lcommunity_list_name_expanded, no_bgp_lcommunity_list_name_expanded_cmd, - "no bgp large-community-list expanded WORD [seq (1-4294967295)] <deny|permit> LINE...", + "no bgp large-community-list expanded WORD [seq (0-4294967295)] <deny|permit> LINE...", NO_STR BGP_STR LCOMMUNITY_LIST_STR @@ -19751,7 +19995,7 @@ DEFUN (show_lcommunity_list_arg, DEFUN (extcommunity_list_standard, bgp_extcommunity_list_standard_cmd, - "bgp extcommunity-list <(1-99)|standard WORD> [seq (1-4294967295)] <deny|permit> AA:NN...", + "bgp extcommunity-list <(1-99)|standard WORD> [seq (0-4294967295)] <deny|permit> AA:NN...", BGP_STR EXTCOMMUNITY_LIST_STR "Extended Community list number (standard)\n" @@ -19774,7 +20018,7 @@ DEFUN (extcommunity_list_standard, argv_find(argv, argc, "WORD", &idx); cl_number_or_name = argv[idx]->arg; - if (argv_find(argv, argc, "(1-4294967295)", &idx)) + if (argv_find(argv, argc, "(0-4294967295)", &idx)) seq = argv[idx]->arg; direct = argv_find(argv, argc, "permit", &idx) ? COMMUNITY_PERMIT @@ -19797,7 +20041,7 @@ DEFUN (extcommunity_list_standard, DEFUN (extcommunity_list_name_expanded, bgp_extcommunity_list_name_expanded_cmd, - "bgp extcommunity-list <(100-500)|expanded WORD> [seq (1-4294967295)] <deny|permit> LINE...", + "bgp extcommunity-list <(100-500)|expanded WORD> [seq (0-4294967295)] <deny|permit> LINE...", BGP_STR EXTCOMMUNITY_LIST_STR "Extended Community list number (expanded)\n" @@ -19819,7 +20063,7 @@ DEFUN (extcommunity_list_name_expanded, argv_find(argv, argc, "WORD", &idx); cl_number_or_name = argv[idx]->arg; - if (argv_find(argv, argc, "(1-4294967295)", &idx)) + if (argv_find(argv, argc, "(0-4294967295)", &idx)) seq = argv[idx]->arg; direct = argv_find(argv, argc, "permit", &idx) ? COMMUNITY_PERMIT @@ -19842,7 +20086,7 @@ DEFUN (extcommunity_list_name_expanded, DEFUN (no_extcommunity_list_standard_all, no_bgp_extcommunity_list_standard_all_cmd, - "no bgp extcommunity-list <(1-99)|standard WORD> [seq (1-4294967295)] <deny|permit> AA:NN...", + "no bgp extcommunity-list <(1-99)|standard WORD> [seq (0-4294967295)] <deny|permit> AA:NN...", NO_STR BGP_STR EXTCOMMUNITY_LIST_STR @@ -19862,7 +20106,7 @@ DEFUN (no_extcommunity_list_standard_all, char *seq = NULL; int idx = 0; - if (argv_find(argv, argc, "(1-4294967295)", &idx)) + if (argv_find(argv, argc, "(0-4294967295)", &idx)) seq = argv[idx]->arg; idx = 0; @@ -19906,7 +20150,7 @@ ALIAS(no_extcommunity_list_standard_all, DEFUN (no_extcommunity_list_expanded_all, no_bgp_extcommunity_list_expanded_all_cmd, - "no bgp extcommunity-list <(100-500)|expanded WORD> [seq (1-4294967295)] <deny|permit> LINE...", + "no bgp extcommunity-list <(100-500)|expanded WORD> [seq (0-4294967295)] <deny|permit> LINE...", NO_STR BGP_STR EXTCOMMUNITY_LIST_STR @@ -19926,7 +20170,7 @@ DEFUN (no_extcommunity_list_expanded_all, char *seq = NULL; int idx = 0; - if (argv_find(argv, argc, "(1-4294967295)", &idx)) + if (argv_find(argv, argc, "(0-4294967295)", &idx)) seq = argv[idx]->arg; idx = 0; 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 d397a5241a..0a12e719ce 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) { @@ -942,12 +931,9 @@ static bool bgp_table_map_apply(struct route_map *map, const struct prefix *p, if (bgp_debug_zebra(p)) { if (p->family == AF_INET) { - char buf[2][INET_ADDRSTRLEN]; zlog_debug( - "Zebra rmap deny: IPv4 route %pFX nexthop %s", - p, - inet_ntop(AF_INET, &path->attr->nexthop, buf[1], - sizeof(buf[1]))); + "Zebra rmap deny: IPv4 route %pFX nexthop %pI4", + p, &path->attr->nexthop); } if (p->family == AF_INET6) { char buf[2][INET6_ADDRSTRLEN]; @@ -2660,6 +2646,7 @@ static int bgp_zebra_process_local_es_add(ZAPI_CALLBACK_ARGS) char buf[ESI_STR_LEN]; struct in_addr originator_ip; uint8_t active; + uint8_t bypass; uint16_t df_pref; bgp = bgp_lookup_by_vrf_id(vrf_id); @@ -2671,14 +2658,16 @@ static int bgp_zebra_process_local_es_add(ZAPI_CALLBACK_ARGS) originator_ip.s_addr = stream_get_ipv4(s); active = stream_getc(s); df_pref = stream_getw(s); + bypass = stream_getc(s); if (BGP_DEBUG(zebra, ZEBRA)) zlog_debug( - "Rx add ESI %s originator-ip %pI4 active %u df_pref %u", - esi_to_str(&esi, buf, sizeof(buf)), - &originator_ip, active, df_pref); + "Rx add ESI %s originator-ip %pI4 active %u df_pref %u %s", + esi_to_str(&esi, buf, sizeof(buf)), &originator_ip, + active, df_pref, bypass ? "bypass" : ""); - bgp_evpn_local_es_add(bgp, &esi, originator_ip, active, df_pref); + bgp_evpn_local_es_add(bgp, &esi, originator_ip, active, df_pref, + !!bypass); return 0; } @@ -2739,14 +2728,12 @@ static int bgp_zebra_process_local_es_evi(ZAPI_CALLBACK_ARGS) static int bgp_zebra_process_local_l3vni(ZAPI_CALLBACK_ARGS) { int filter = 0; - char buf[ETHER_ADDR_STRLEN]; vni_t l3vni = 0; struct ethaddr svi_rmac, vrr_rmac = {.octet = {0} }; struct in_addr originator_ip; struct stream *s; ifindex_t svi_ifindex; bool is_anycast_mac = false; - char buf1[ETHER_ADDR_STRLEN]; memset(&svi_rmac, 0, sizeof(struct ethaddr)); memset(&originator_ip, 0, sizeof(struct in_addr)); @@ -2761,13 +2748,12 @@ static int bgp_zebra_process_local_l3vni(ZAPI_CALLBACK_ARGS) is_anycast_mac = stream_getl(s); if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("Rx L3-VNI ADD VRF %s VNI %u RMAC svi-mac %s vrr-mac %s filter %s svi-if %u", - vrf_id_to_name(vrf_id), l3vni, - prefix_mac2str(&svi_rmac, buf, sizeof(buf)), - prefix_mac2str(&vrr_rmac, buf1, - sizeof(buf1)), - filter ? "prefix-routes-only" : "none", - svi_ifindex); + zlog_debug( + "Rx L3-VNI ADD VRF %s VNI %u RMAC svi-mac %pEA vrr-mac %pEA filter %s svi-if %u", + vrf_id_to_name(vrf_id), l3vni, &svi_rmac, + &vrr_rmac, + filter ? "prefix-routes-only" : "none", + svi_ifindex); bgp_evpn_local_l3vni_add(l3vni, vrf_id, &svi_rmac, &vrr_rmac, originator_ip, filter, svi_ifindex, @@ -2827,8 +2813,6 @@ static int bgp_zebra_process_local_macip(ZAPI_CALLBACK_ARGS) struct ethaddr mac; struct ipaddr ip; int ipa_len; - char buf[ETHER_ADDR_STRLEN]; - char buf1[INET6_ADDRSTRLEN]; uint8_t flags = 0; uint32_t seqnum = 0; int state = 0; @@ -2868,11 +2852,11 @@ static int bgp_zebra_process_local_macip(ZAPI_CALLBACK_ARGS) return 0; if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("%u:Recv MACIP %s f 0x%x MAC %s IP %s VNI %u seq %u state %d ESI %s", - vrf_id, (cmd == ZEBRA_MACIP_ADD) ? "Add" : "Del", - flags, prefix_mac2str(&mac, buf, sizeof(buf)), - ipaddr2str(&ip, buf1, sizeof(buf1)), vni, seqnum, - state, esi_to_str(&esi, buf2, sizeof(buf2))); + zlog_debug( + "%u:Recv MACIP %s f 0x%x MAC %pEA IP %pIA VNI %u seq %u state %d ESI %s", + vrf_id, (cmd == ZEBRA_MACIP_ADD) ? "Add" : "Del", flags, + &mac, &ip, vni, seqnum, state, + esi_to_str(&esi, buf2, sizeof(buf2))); if (cmd == ZEBRA_MACIP_ADD) return bgp_evpn_local_macip_add(bgp, vni, &mac, &ip, diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 07ca247ee6..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); @@ -1345,6 +1347,7 @@ struct peer *peer_new(struct bgp *bgp) peer->bgp = bgp_lock(bgp); peer = peer_lock(peer); /* initial reference */ peer->password = NULL; + peer->max_packet_size = BGP_MAX_EXTENDED_MESSAGE_PACKET_SIZE; /* Set default flags. */ FOREACH_AFI_SAFI (afi, safi) { @@ -1379,7 +1382,7 @@ struct peer *peer_new(struct bgp *bgp) /* We use a larger buffer for peer->obuf_work in the event that: * - We RX a BGP_UPDATE where the attributes alone are just - * under BGP_MAX_PACKET_SIZE + * under BGP_MAX_EXTENDED_MESSAGE_PACKET_SIZE. * - The user configures an outbound route-map that does many as-path * prepends or adds many communities. At most they can have * CMD_ARGC_MAX args in a route-map so there is a finite limit on how @@ -1389,12 +1392,12 @@ struct peer *peer_new(struct bgp *bgp) * bounds checking for every single attribute as we construct an * UPDATE. */ - peer->obuf_work = - stream_new(BGP_MAX_PACKET_SIZE + BGP_MAX_PACKET_SIZE_OVERFLOW); - peer->ibuf_work = - ringbuf_new(BGP_MAX_PACKET_SIZE * BGP_READ_PACKET_MAX); + peer->obuf_work = stream_new(BGP_MAX_EXTENDED_MESSAGE_PACKET_SIZE + + BGP_MAX_PACKET_SIZE_OVERFLOW); + peer->ibuf_work = ringbuf_new(BGP_MAX_EXTENDED_MESSAGE_PACKET_SIZE + * BGP_READ_PACKET_MAX); - peer->scratch = stream_new(BGP_MAX_PACKET_SIZE); + peer->scratch = stream_new(BGP_MAX_EXTENDED_MESSAGE_PACKET_SIZE); bgp_sync_init(peer); @@ -1467,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 */ @@ -1682,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) { @@ -1746,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 */ @@ -1877,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; @@ -1945,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; @@ -2202,7 +2213,7 @@ int peer_activate(struct peer *peer, afi_t afi, safi_t safi) /* If this is the first peer to be activated for this * afi/labeled-unicast recalc bestpaths to trigger label allocation */ - if (safi == SAFI_LABELED_UNICAST + if (ret != BGP_ERR_PEER_SAFI_CONFLICT && safi == SAFI_LABELED_UNICAST && !bgp->allocate_mpls_labels[afi][SAFI_UNICAST]) { if (BGP_DEBUG(zebra, ZEBRA)) @@ -2385,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. @@ -2561,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; @@ -2667,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. */ @@ -2757,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); @@ -2995,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); @@ -3007,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]) @@ -3806,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; @@ -7686,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 e79dccdab8..6270542178 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,7 @@ 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) enum global_mode GLOBAL_GR_FSM[BGP_GLOBAL_GR_MODE] [BGP_GLOBAL_GR_EVENT_CMD]; @@ -710,14 +713,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 { @@ -859,6 +862,7 @@ typedef enum { #define BGP_MARKER_SIZE 16 #define BGP_HEADER_SIZE 19 #define BGP_MAX_PACKET_SIZE 4096 +#define BGP_MAX_EXTENDED_MESSAGE_PACKET_SIZE 65535 #define BGP_MAX_PACKET_SIZE_OVERFLOW 1024 /* @@ -1122,6 +1126,8 @@ struct peer { #define PEER_CAP_HOSTNAME_RCV (1U << 16) /* hostname received */ #define PEER_CAP_ENHANCED_RR_ADV (1U << 17) /* enhanced rr advertised */ #define PEER_CAP_ENHANCED_RR_RCV (1U << 18) /* enhanced rr received */ +#define PEER_CAP_EXTENDED_MESSAGE_ADV (1U << 19) +#define PEER_CAP_EXTENDED_MESSAGE_RCV (1U << 20) /* Capability flags (reset in bgp_stop) */ uint32_t af_cap[AFI_MAX][SAFI_MAX]; @@ -1554,8 +1560,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; @@ -1564,13 +1591,16 @@ struct peer { /* Sender side AS path loop detection. */ bool as_path_loop_detection; + /* Extended Message Support */ + uint16_t max_packet_size; + /* Conditional advertisement */ 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) \ @@ -1916,8 +1946,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, @@ -1985,7 +2014,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); @@ -2358,13 +2387,18 @@ 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)); + void peer_nsf_stop(struct peer *peer); #endif /* _QUAGGA_BGPD_H */ 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..3991f7d1ed 100644 --- a/bgpd/subdir.am +++ b/bgpd/subdir.am @@ -220,7 +220,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 diff --git a/configure.ac b/configure.ac index f3d1f38986..44d68f4845 100755 --- a/configure.ac +++ b/configure.ac @@ -301,6 +301,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 +309,7 @@ else AC_C_FLAG([-O2]) fi fi + AM_CONDITIONAL([DEV_BUILD], [test "$enable_dev_build" = "yes"]) dnl always want these CFLAGS @@ -794,6 +796,20 @@ fi # AS_IF([test "$host" = "$build"], [ + AC_CHECK_HEADER([gelf.h], [], [ + AC_MSG_ERROR([libelf headers are required for building clippy. (Host only when cross-compiling.)]) + ]) + AC_CHECK_LIB([elf], [elf_memory], [], [ + AC_MSG_ERROR([libelf is required for building clippy. (Host only when cross-compiling.)]) + ]) + + AC_CHECK_LIB([elf], [elf_getdata_rawchunk], [ + AC_DEFINE([HAVE_ELF_GETDATA_RAWCHUNK], [1], [Have elf_getdata_rawchunk()]) + ]) + AC_CHECK_LIB([elf], [gelf_getnote], [ + AC_DEFINE([HAVE_GELF_GETNOTE], [1], [Have gelf_getnote()]) + ]) + FRR_PYTHON_DEV ], [ FRR_PYTHON @@ -1709,12 +1725,10 @@ fi AS_IF([test "$enable_pathd" != "no"], [ AC_DEFINE([HAVE_PATHD], [1], [pathd]) -]) - -AS_IF([test "$enable_pcep" != "no"], [ AC_DEFINE([HAVE_PATHD_PCEP], [1], [pathd-pcep]) ]) + if test "$ac_cv_lib_json_c_json_object_get" = "no" -a "$BFDD" = "bfdd"; then AC_MSG_ERROR(["you must use json-c library to use bfdd"]) fi @@ -2536,15 +2550,14 @@ AM_CONDITIONAL([HAVE_PROTOBUF], [test "$enable_protobuf" = "yes"]) AM_CONDITIONAL([HAVE_PROTOBUF3], [$PROTO3]) dnl PCEP plugin -AM_CONDITIONAL([HAVE_PATHD_PCEP], [test "$enable_pcep" = "yes"]) -AS_IF([test "$enable_pcep" = "yes"], [ - AC_CHECK_LIB([pcep_pcc], [initialize_pcc], [ - PATHD_PCEP_LIBS="-lpcep_pcc" - ],[ - AC_MSG_ERROR([PCEP library libpcep_pcc not found]) - ]) - AC_SUBST([PATHD_PCEP_LIBS]) -]) +AS_IF([test "$enable_pathd" != "no"], [ + AC_SUBST([PATHD_PCEP_LIBS], ["pceplib/libpcep_pcc.la"]) + AC_SUBST([PATHD_PCEP_INCL], ["-I./pceplib "]) + ]) +AC_CHECK_LIB([cunit], [CU_initialize_registry], [pcep_cunit=yes],[pcep_cunit=no]) +AM_CONDITIONAL([PATHD_PCEP_TEST], [test "x${pcep_cunit}" = xyes]) +AC_CHECK_PROG(VALGRIND_CHECK, valgrind, yes) +AM_CONDITIONAL([HAVE_VALGRIND_PCEP], [test "$VALGRIND_CHECK" = "yes"]) dnl daemons AM_CONDITIONAL([VTYSH], [test "$VTYSH" = "vtysh"]) @@ -2569,6 +2582,7 @@ AM_CONDITIONAL([STATICD], [test "$enable_staticd" != "no"]) AM_CONDITIONAL([FABRICD], [test "$enable_fabricd" != "no"]) AM_CONDITIONAL([VRRPD], [test "$enable_vrrpd" != "no"]) AM_CONDITIONAL([PATHD], [test "$enable_pathd" != "no"]) +AM_CONDITIONAL([PATHD_PCEP], [test "$enable_pathd" != "no"]) AC_CONFIG_FILES([Makefile],[ test "$enable_dev_build" = "yes" && makefile_devbuild="--dev-build" diff --git a/debian/control b/debian/control index b9e96b55d0..7a08cbbdb0 100644 --- a/debian/control +++ b/debian/control @@ -13,6 +13,7 @@ Build-Depends: bison, install-info, libc-ares-dev, libcap-dev, + libelf-dev, libjson-c-dev | libjson0-dev, libpam0g-dev | libpam-dev, libpcre3-dev, diff --git a/debian/frr.install b/debian/frr.install index cefc3135b2..9972b579f0 100644 --- a/debian/frr.install +++ b/debian/frr.install @@ -11,6 +11,7 @@ usr/lib/*/frr/modules/dplane_fpm_nl.so usr/lib/*/frr/modules/zebra_cumulus_mlag.so usr/lib/*/frr/modules/zebra_fpm.so usr/lib/*/frr/modules/zebra_irdp.so +usr/lib/*/frr/modules/pathd_pcep.so usr/lib/frr/*.sh usr/lib/frr/*d usr/lib/frr/watchfrr diff --git a/doc/developer/building-frr-for-archlinux.rst b/doc/developer/building-frr-for-archlinux.rst index f62add5963..e589a9f724 100644 --- a/doc/developer/building-frr-for-archlinux.rst +++ b/doc/developer/building-frr-for-archlinux.rst @@ -11,7 +11,7 @@ Installing Dependencies git autoconf automake libtool make cmake pcre readline texinfo \ pkg-config pam json-c bison flex python-pytest \ c-ares python systemd python2-ipaddress python-sphinx \ - systemd-libs net-snmp perl libcap + systemd-libs net-snmp perl libcap libelf .. include:: building-libyang.rst diff --git a/doc/developer/building-frr-for-centos6.rst b/doc/developer/building-frr-for-centos6.rst index b730a5ee32..5d3be492de 100644 --- a/doc/developer/building-frr-for-centos6.rst +++ b/doc/developer/building-frr-for-centos6.rst @@ -45,7 +45,8 @@ Add packages: sudo yum install git autoconf automake libtool make \ readline-devel texinfo net-snmp-devel groff pkgconfig \ - json-c-devel pam-devel flex epel-release c-ares-devel libcap-devel + json-c-devel pam-devel flex epel-release c-ares-devel libcap-devel \ + elfutils-libelf-devel Install newer version of bison (CentOS 6 package source is too old) from CentOS 7: diff --git a/doc/developer/building-frr-for-centos7.rst b/doc/developer/building-frr-for-centos7.rst index eb97150d67..8d0aea943c 100644 --- a/doc/developer/building-frr-for-centos7.rst +++ b/doc/developer/building-frr-for-centos7.rst @@ -21,7 +21,8 @@ Add packages: sudo yum install git autoconf automake libtool make \ readline-devel texinfo net-snmp-devel groff pkgconfig \ json-c-devel pam-devel bison flex pytest c-ares-devel \ - python-devel systemd-devel python-sphinx libcap-devel + python-devel systemd-devel python-sphinx libcap-devel \ + elfutils-libelf-devel .. include:: building-libyang.rst diff --git a/doc/developer/building-frr-for-centos8.rst b/doc/developer/building-frr-for-centos8.rst index 75beb53378..77fe489358 100644 --- a/doc/developer/building-frr-for-centos8.rst +++ b/doc/developer/building-frr-for-centos8.rst @@ -14,7 +14,8 @@ Add packages: sudo dnf install --enablerepo=PowerTools git autoconf pcre-devel \ automake libtool make readline-devel texinfo net-snmp-devel pkgconfig \ groff pkgconfig json-c-devel pam-devel bison flex python2-pytest \ - c-ares-devel python2-devel systemd-devel libcap-devel + c-ares-devel python2-devel systemd-devel libcap-devel \ + elfutils-libelf-devel .. include:: building-libyang.rst diff --git a/doc/developer/building-frr-for-debian8.rst b/doc/developer/building-frr-for-debian8.rst index c12bf46f8d..51dd07c42a 100644 --- a/doc/developer/building-frr-for-debian8.rst +++ b/doc/developer/building-frr-for-debian8.rst @@ -18,7 +18,7 @@ Add packages: sudo apt-get install git autoconf automake libtool make \ libreadline-dev texinfo libjson-c-dev pkg-config bison flex python3-pip \ libc-ares-dev python3-dev python3-sphinx build-essential libsystemd-dev \ - libsnmp-dev libcap-dev + libsnmp-dev libcap-dev libelf-dev Install newer pytest (>3.0) from pip diff --git a/doc/developer/building-frr-for-debian9.rst b/doc/developer/building-frr-for-debian9.rst index f976b9f49a..919b010314 100644 --- a/doc/developer/building-frr-for-debian9.rst +++ b/doc/developer/building-frr-for-debian9.rst @@ -11,7 +11,7 @@ Add packages: sudo apt-get install git autoconf automake libtool make \ libreadline-dev texinfo libjson-c-dev pkg-config bison flex \ libc-ares-dev python3-dev python3-pytest python3-sphinx build-essential \ - libsnmp-dev libsystemd-dev libcap-dev + libsnmp-dev libsystemd-dev libcap-dev libelf-dev .. include:: building-libyang.rst diff --git a/doc/developer/building-frr-for-fedora.rst b/doc/developer/building-frr-for-fedora.rst index 4ab59490fd..5fecd8a826 100644 --- a/doc/developer/building-frr-for-fedora.rst +++ b/doc/developer/building-frr-for-fedora.rst @@ -14,7 +14,8 @@ Installing Dependencies sudo dnf install git autoconf automake libtool make \ readline-devel texinfo net-snmp-devel groff pkgconfig json-c-devel \ pam-devel python3-pytest bison flex c-ares-devel python3-devel \ - python3-sphinx perl-core patch systemd-devel libcap-devel + python3-sphinx perl-core patch systemd-devel libcap-devel \ + elfutils-libelf-devel .. include:: building-libyang.rst diff --git a/doc/developer/building-frr-for-opensuse.rst b/doc/developer/building-frr-for-opensuse.rst index 5ed714a67e..4e886e9c25 100644 --- a/doc/developer/building-frr-for-opensuse.rst +++ b/doc/developer/building-frr-for-opensuse.rst @@ -13,7 +13,8 @@ Installing Dependencies zypper in git autoconf automake libtool make \ readline-devel texinfo net-snmp-devel groff pkgconfig libjson-c-devel\ pam-devel python3-pytest bison flex c-ares-devel python3-devel\ - python3-Sphinx perl patch systemd-devel libcap-devel libyang-devel + python3-Sphinx perl patch systemd-devel libcap-devel libyang-devel \ + libelf-devel Building & Installing FRR ------------------------- diff --git a/doc/developer/building-frr-for-ubuntu1404.rst b/doc/developer/building-frr-for-ubuntu1404.rst index cc54415266..2711e92b6f 100644 --- a/doc/developer/building-frr-for-ubuntu1404.rst +++ b/doc/developer/building-frr-for-ubuntu1404.rst @@ -14,7 +14,7 @@ Installing Dependencies git autoconf automake libtool make libreadline-dev texinfo \ pkg-config libpam0g-dev libjson-c-dev bison flex python3-pytest \ libc-ares-dev python3-dev python3-sphinx install-info build-essential \ - libsnmp-dev perl libcap-dev + libsnmp-dev perl libcap-dev libelf-dev .. include:: building-libyang.rst diff --git a/doc/developer/building-frr-for-ubuntu1604.rst b/doc/developer/building-frr-for-ubuntu1604.rst index 63c6f8648c..2cb9536f9b 100644 --- a/doc/developer/building-frr-for-ubuntu1604.rst +++ b/doc/developer/building-frr-for-ubuntu1604.rst @@ -14,7 +14,8 @@ Installing Dependencies git autoconf automake libtool make libreadline-dev texinfo \ pkg-config libpam0g-dev libjson-c-dev bison flex python3-pytest \ libc-ares-dev python3-dev libsystemd-dev python-ipaddress python3-sphinx \ - install-info build-essential libsystemd-dev libsnmp-dev perl libcap-dev + install-info build-essential libsystemd-dev libsnmp-dev perl libcap-dev \ + libelf-dev .. include:: building-libyang.rst diff --git a/doc/developer/building-frr-for-ubuntu1804.rst b/doc/developer/building-frr-for-ubuntu1804.rst index 9d85957d88..eb3991c139 100644 --- a/doc/developer/building-frr-for-ubuntu1804.rst +++ b/doc/developer/building-frr-for-ubuntu1804.rst @@ -14,7 +14,8 @@ Installing Dependencies git autoconf automake libtool make libreadline-dev texinfo \ pkg-config libpam0g-dev libjson-c-dev bison flex python3-pytest \ libc-ares-dev python3-dev libsystemd-dev python-ipaddress python3-sphinx \ - install-info build-essential libsystemd-dev libsnmp-dev perl libcap-dev + install-info build-essential libsystemd-dev libsnmp-dev perl libcap-dev \ + libelf-dev .. include:: building-libyang.rst diff --git a/doc/developer/building-frr-for-ubuntu2004.rst b/doc/developer/building-frr-for-ubuntu2004.rst index f7f8c63e5b..ffc05a6841 100644 --- a/doc/developer/building-frr-for-ubuntu2004.rst +++ b/doc/developer/building-frr-for-ubuntu2004.rst @@ -15,7 +15,7 @@ Installing Dependencies pkg-config libpam0g-dev libjson-c-dev bison flex python3-pytest \ libc-ares-dev python3-dev libsystemd-dev python-ipaddress python3-sphinx \ install-info build-essential libsystemd-dev libsnmp-dev perl \ - libcap-dev python2 + libcap-dev python2 libelf-dev Note that Ubuntu 20 no longer installs python 2.x, so it must be installed explicitly. Ensure that your system has a symlink named @@ -27,7 +27,7 @@ ubuntu apt repositories; in order to install it: .. code-block:: shell - curl https://bootstrap.pypa.io/get-pip.py --output get-pip.py + curl https://bootstrap.pypa.io/2.7/get-pip.py --output get-pip.py sudo python2 ./get-pip.py # And verify the installation diff --git a/doc/developer/cross-compiling.rst b/doc/developer/cross-compiling.rst index 339e00c921..3bf78f7633 100644 --- a/doc/developer/cross-compiling.rst +++ b/doc/developer/cross-compiling.rst @@ -189,7 +189,7 @@ later on to FRR. One may get burned when compiling gRPC if the ``protoc`` version on the build machine differs from the version of ``protoc`` being linked to during a gRPC build. The error messages from this defect look like: -.. code-block:: terminal +.. code-block:: shell gens/src/proto/grpc/channelz/channelz.pb.h: In member function ‘void grpc::channelz::v1::ServerRef::set_name(const char*, size_t)’: gens/src/proto/grpc/channelz/channelz.pb.h:9127:64: error: ‘EmptyDefault’ is not a member of ‘google::protobuf::internal::ArenaStringPtr’ 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/images/PCEPlib_design.jpg b/doc/developer/images/PCEPlib_design.jpg Binary files differnew file mode 100644 index 0000000000..41aada3774 --- /dev/null +++ b/doc/developer/images/PCEPlib_design.jpg diff --git a/doc/developer/images/PCEPlib_internal_deps.jpg b/doc/developer/images/PCEPlib_internal_deps.jpg Binary files differnew file mode 100644 index 0000000000..8380021b31 --- /dev/null +++ b/doc/developer/images/PCEPlib_internal_deps.jpg diff --git a/doc/developer/images/PCEPlib_socket_comm.jpg b/doc/developer/images/PCEPlib_socket_comm.jpg Binary files differnew file mode 100644 index 0000000000..3d62a462f2 --- /dev/null +++ b/doc/developer/images/PCEPlib_socket_comm.jpg diff --git a/doc/developer/images/PCEPlib_threading_model.jpg b/doc/developer/images/PCEPlib_threading_model.jpg Binary files differnew file mode 100644 index 0000000000..afe91c2407 --- /dev/null +++ b/doc/developer/images/PCEPlib_threading_model.jpg diff --git a/doc/developer/images/PCEPlib_threading_model_frr_infra.jpg b/doc/developer/images/PCEPlib_threading_model_frr_infra.jpg Binary files differnew file mode 100644 index 0000000000..5648a9d788 --- /dev/null +++ b/doc/developer/images/PCEPlib_threading_model_frr_infra.jpg diff --git a/doc/developer/images/PCEPlib_timers.jpg b/doc/developer/images/PCEPlib_timers.jpg Binary files differnew file mode 100644 index 0000000000..a178ee9c6f --- /dev/null +++ b/doc/developer/images/PCEPlib_timers.jpg diff --git a/doc/developer/index.rst b/doc/developer/index.rst index 8e7913419f..46fd8f612e 100644 --- a/doc/developer/index.rst +++ b/doc/developer/index.rst @@ -19,4 +19,5 @@ FRRouting Developer's Guide zebra vtysh path + pceplib link-state 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 cf3aa8d17f..a35e60619c 100644 --- a/doc/developer/logging.rst +++ b/doc/developer/logging.rst @@ -71,6 +71,10 @@ Extensions +-----------+--------------------------+----------------------------------------------+ | ``%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)`` | 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/pceplib.rst b/doc/developer/pceplib.rst new file mode 100644 index 0000000000..774617dfe5 --- /dev/null +++ b/doc/developer/pceplib.rst @@ -0,0 +1,781 @@ +.. _pceplib: + +******* +PCEPlib +******* + +Overview +======== + +The PCEPlib is a PCEP implementation library that can be used by either a PCE +or PCC. + +Currently, only the FRR pathd has been implemented as a PCC with the PCEPlib. +The PCEPlib is able to simultaneously connect to multiple PCEP peers and can +maintain persistent PCEP connections. + + +PCEPlib compliance +================== + +The PCEPlib implements version 1 of the PCEP protocol, according to `RFC 5440 <https://tools.ietf.org/html/rfc5440>`_. + +Additionally, the PCEPlib implements the following PCEP extensions: + +- `RFC 8281 <https://tools.ietf.org/html/rfc8281>`_ PCE initiated for PCE-Initiated LSP Setup +- `RFC 8231 <https://tools.ietf.org/html/rfc8231>`_ Extensions for Stateful PCE +- `RFC 8232 <https://tools.ietf.org/html/rfc8232>`_ Optimizations of Label Switched Path State Synchronization Procedures for a Stateful PCE +- `RFC 8282 <https://tools.ietf.org/html/rfc8282>`_ Extensions to PCEP for Inter-Layer MPLS and GMPLS Traffic Engineering +- `RFC 8408 <https://tools.ietf.org/html/rfc8408>`_ Conveying Path Setup Type in PCE Communication Protocol (PCEP) Messages +- `draft-ietf-pce-segment-routing-07 <https://tools.ietf.org/html/draft-ietf-pce-segment-routing-07>`_, + `draft-ietf-pce-segment-routing-16 <https://tools.ietf.org/html/draft-ietf-pce-segment-routing-16>`_, + `RFC 8664 <https://tools.ietf.org/html/rfc8664>`_ Segment routing protocol extensions +- `RFC 7470 <https://tools.ietf.org/html/rfc7470>`_ Conveying Vendor-Specific Constraints +- `Draft-ietf-pce-association-group-10 <https://tools.ietf.org/html/draft-ietf-pce-association-group-10>`_ + Establishing Relationships Between Sets of Label Switched Paths +- `Draft-barth-pce-segment-routing-policy-cp-04 <https://tools.ietf.org/html/draft-barth-pce-segment-routing-policy-cp-04>`_ + Segment Routing Policy Candidate Paths + + +PCEPlib Architecture +==================== + +The PCEPlib is comprised of the following modules, each of which will be +detailed in the following sections. + +- **pcep_messages** + - PCEP messages, objects, and TLVs implementations + +- **pcep_pcc** + - PCEPlib public PCC API with a sample PCC binary + +- **pcep_session_logic** + - PCEP Session handling + +- **pcep_socket_comm** + - Socket communications + +- **pcep_timers** + - PCEP timers + +- **pcep_utils** + - Internal utilities used by the PCEPlib modules. + +The interaction of these modules can be seen in the following diagram. + +PCEPlib Architecture: + +.. image:: images/PCEPlib_design.jpg + + +PCEP Session Logic library +-------------------------- + +The PCEP Session Logic library orchestrates calls to the rest of the PCC libraries. + +PCEP Session Logic library responsibilities: + +- Handle messages received from "PCEP Socket Comm" +- Create and manage "PCEP Session" objects +- Set timers and react to timer expirations +- Manage counters + +The PCEP Session Logic library will have 2 main triggers controlled by a +pthread condition variable: + +- Timer expirations - ``on_timer_expire()`` callback +- Messages received from PCEP SocketComm - ``message_received()`` callback + +The counters are created and managed using the ``pcep_utils/pcep_utils_counters.h`` +counters library. The following are the different counter groups managed: + +- **COUNTER_SUBGROUP_ID_RX_MSG** +- **COUNTER_SUBGROUP_ID_TX_MSG** +- **COUNTER_SUBGROUP_ID_RX_OBJ** +- **COUNTER_SUBGROUP_ID_TX_OBJ** +- **COUNTER_SUBGROUP_ID_RX_SUBOBJ** +- **COUNTER_SUBGROUP_ID_TX_SUBOBJ** +- **COUNTER_SUBGROUP_ID_RX_RO_SR_SUBOBJ** +- **COUNTER_SUBGROUP_ID_TX_RO_SR_SUBOBJ** +- **COUNTER_SUBGROUP_ID_RX_TLV** +- **COUNTER_SUBGROUP_ID_TX_TLV** +- **COUNTER_SUBGROUP_ID_EVENT** + +The counters can be obtained and reset as explained later in the PCEPlib PCC API. + +PCEP Socket Comm library +------------------------ + +PCEP communication can be configured to be handled internally in this simple +library. When this library is instantiated by the PCEP Session Logic, callbacks +are provided to handle received messages and error conditions. + +The following diagram illustrates how the library works. + +PCEPlib Socket Comm: + +.. image:: images/PCEPlib_socket_comm.jpg + + +PCEP Timers library +------------------- + +Timers can be configured to be handled internally by this library. When this +library is instantiated by the PCEP Session Logic, callbacks are provided to +ha:0 +ndle timer expirations. The following timers are implemented and handled, +according to `RFC 5440 <https://tools.ietf.org/html/rfc5440>`_. + +- Open KeepWait (fixed at 60 seconds) + - Set once the PCC sends an Open, and if it expires before receiving a KeepAlive or PCErr, then the PCC should send a PCErr and close the TCP connection + +- Keepalive timer + - How often the PCC should send Keepalive messages to the PCE (and vice-versa) + - The timer will be reset after any message is sent: any message serves as a Keepalive + +- DeadTimer + - If no messages are received before expiration, the session is declared as down + - Reset everytime any message is received + +- PCReq request timer + - How long the PCC waits for the PCE to reply to PCReq messages. + +PCEPlib Timers: + +.. image:: images/PCEPlib_timers.jpg + + +PCEP Messages library +--------------------- + +The PCEP Messages library has all of the implemented PCEP messages, objects, +TLVs, and related functionality. + +The following header files can be used for creating and handling received PCEP +entities. + +- pcep-messages.h +- pcep-objects.h +- pcep-tlvs.h + + +PCEP Messages ++++++++++++++ + +The following PCEP messages can be created and received: + +- ``struct pcep_message* pcep_msg_create_open(...);`` +- ``struct pcep_message* pcep_msg_create_open_with_tlvs(...);`` +- ``struct pcep_message* pcep_msg_create_request(...);`` +- ``struct pcep_message* pcep_msg_create_request_ipv6(...);`` +- ``struct pcep_message* pcep_msg_create_reply(...);`` +- ``struct pcep_message* pcep_msg_create_close(...);`` +- ``struct pcep_message* pcep_msg_create_error(...);`` +- ``struct pcep_message* pcep_msg_create_error_with_objects(...);`` +- ``struct pcep_message* pcep_msg_create_keepalive(...);`` +- ``struct pcep_message* pcep_msg_create_report(...);`` +- ``struct pcep_message* pcep_msg_create_update(...);`` +- ``struct pcep_message* pcep_msg_create_initiate(...);`` + +Refer to ``pcep_messages/include/pcep-messages.h`` and the API section +below for more details. + + +PCEP Objects +++++++++++++ + +The following PCEP objects can be created and received: + +- ``struct pcep_object_open* pcep_obj_create_open(...);`` +- ``struct pcep_object_rp* pcep_obj_create_rp(...);`` +- ``struct pcep_object_notify* pcep_obj_create_notify(...);`` +- ``struct pcep_object_nopath* pcep_obj_create_nopath(...);`` +- ``struct pcep_object_association_ipv4* pcep_obj_create_association_ipv4(...);`` +- ``struct pcep_object_association_ipv6* pcep_obj_create_association_ipv6(...);`` +- ``struct pcep_object_endpoints_ipv4* pcep_obj_create_endpoint_ipv4(...);`` +- ``struct pcep_object_endpoints_ipv6* pcep_obj_create_endpoint_ipv6(...);`` +- ``struct pcep_object_bandwidth* pcep_obj_create_bandwidth(...);`` +- ``struct pcep_object_metric* pcep_obj_create_metric(...);`` +- ``struct pcep_object_lspa* pcep_obj_create_lspa(...);`` +- ``struct pcep_object_svec* pcep_obj_create_svec(...);`` +- ``struct pcep_object_error* pcep_obj_create_error(...);`` +- ``struct pcep_object_close* pcep_obj_create_close(...);`` +- ``struct pcep_object_srp* pcep_obj_create_srp(...);`` +- ``struct pcep_object_lsp* pcep_obj_create_lsp(...);`` +- ``struct pcep_object_vendor_info* pcep_obj_create_vendor_info(...);`` +- ``struct pcep_object_ro* pcep_obj_create_ero(...);`` +- ``struct pcep_object_ro* pcep_obj_create_rro(...);`` +- ``struct pcep_object_ro* pcep_obj_create_iro(...);`` +- ``struct pcep_ro_subobj_ipv4* pcep_obj_create_ro_subobj_ipv4(...);`` +- ``struct pcep_ro_subobj_ipv6* pcep_obj_create_ro_subobj_ipv6(...);`` +- ``struct pcep_ro_subobj_unnum* pcep_obj_create_ro_subobj_unnum(...);`` +- ``struct pcep_ro_subobj_32label* pcep_obj_create_ro_subobj_32label(...);`` +- ``struct pcep_ro_subobj_asn* pcep_obj_create_ro_subobj_asn(...);`` +- ``struct pcep_ro_subobj_sr* pcep_obj_create_ro_subobj_sr_nonai(...);`` +- ``struct pcep_ro_subobj_sr* pcep_obj_create_ro_subobj_sr_ipv4_node(...);`` +- ``struct pcep_ro_subobj_sr* pcep_obj_create_ro_subobj_sr_ipv6_node(...);`` +- ``struct pcep_ro_subobj_sr* pcep_obj_create_ro_subobj_sr_ipv4_adj(...);`` +- ``struct pcep_ro_subobj_sr* pcep_obj_create_ro_subobj_sr_ipv6_adj(...);`` +- ``struct pcep_ro_subobj_sr* pcep_obj_create_ro_subobj_sr_unnumbered_ipv4_adj(...);`` +- ``struct pcep_ro_subobj_sr* pcep_obj_create_ro_subobj_sr_linklocal_ipv6_adj(...);`` + +Refer to ``pcep_messages/include/pcep-objects.h`` and the API section +below for more details. + + +PCEP TLVs ++++++++++ + +The following PCEP TLVs (Tag, Length, Value) can be created and received: + +- Open Object TLVs + - ``struct pcep_object_tlv_stateful_pce_capability* pcep_tlv_create_stateful_pce_capability(...);`` + - ``struct pcep_object_tlv_lsp_db_version* pcep_tlv_create_lsp_db_version(...);`` + - ``struct pcep_object_tlv_speaker_entity_identifier* pcep_tlv_create_speaker_entity_id(...);`` + - ``struct pcep_object_tlv_path_setup_type* pcep_tlv_create_path_setup_type(...);`` + - ``struct pcep_object_tlv_path_setup_type_capability* pcep_tlv_create_path_setup_type_capability(...);`` + - ``struct pcep_object_tlv_sr_pce_capability* pcep_tlv_create_sr_pce_capability(...);`` + +- LSP Object TLVs + - ``struct pcep_object_tlv_ipv4_lsp_identifier* pcep_tlv_create_ipv4_lsp_identifiers(...);`` + - ``struct pcep_object_tlv_ipv6_lsp_identifier* pcep_tlv_create_ipv6_lsp_identifiers(...);`` + - ``struct pcep_object_tlv_symbolic_path_name* pcep_tlv_create_symbolic_path_name(...);`` + - ``struct pcep_object_tlv_lsp_error_code* pcep_tlv_create_lsp_error_code(...);`` + - ``struct pcep_object_tlv_rsvp_error_spec* pcep_tlv_create_rsvp_ipv4_error_spec(...);`` + - ``struct pcep_object_tlv_rsvp_error_spec* pcep_tlv_create_rsvp_ipv6_error_spec(...);`` + - ``struct pcep_object_tlv_nopath_vector* pcep_tlv_create_nopath_vector(...);`` + - ``struct pcep_object_tlv_vendor_info* pcep_tlv_create_vendor_info(...);`` + - ``struct pcep_object_tlv_arbitrary* pcep_tlv_create_tlv_arbitrary(...);`` + +- SRPAG (SR Association Group) TLVs + - ``struct pcep_object_tlv_srpag_pol_id *pcep_tlv_create_srpag_pol_id_ipv4(...);`` + - ``struct pcep_object_tlv_srpag_pol_id *pcep_tlv_create_srpag_pol_id_ipv6(...);`` + - ``struct pcep_object_tlv_srpag_pol_name *pcep_tlv_create_srpag_pol_name(...);`` + - ``struct pcep_object_tlv_srpag_cp_id *pcep_tlv_create_srpag_cp_id(...);`` + - ``struct pcep_object_tlv_srpag_cp_pref *pcep_tlv_create_srpag_cp_pref(...);`` + +Refer to ``pcep_messages/include/pcep-tlvs.h`` and the API section +below for more details. + + +PCEP PCC +-------- + +This module has a Public PCC API library (explained in detail later) and a +sample PCC binary. The APIs in this library encapsulate other PCEPlib libraries +for simplicity. With this API, the PCEPlib PCC can be started and stopped, and +the PCEPlib event queue can be accessed. The PCEP Messages library is not +encapsulated, and should be used directly. + + +Internal Dependencies +--------------------- + +The following diagram illustrates the internal PCEPlib library dependencies. + +PCEPlib internal dependencies: + +.. image:: images/PCEPlib_internal_deps.jpg + + +External Dependencies +--------------------- + +Originally the PCEPlib was based on the open source `libpcep project <https://www.acreo.se/open-software-libpcep>`_, +but that dependency has been reduced to just one source file (pcep-tools.[ch]). + + +PCEPlib Threading model +----------------------- + +The PCEPlib can be run in stand-alone mode whereby a thread is launched for +timers and socket comm, as is illustrated in the following diagram. + +PCEPlib Threading model: + +.. image:: images/PCEPlib_threading_model.jpg + +The PCEPlib can also be configured to use an external timers and socket +infrastructure like the FRR threads and tasks. In this case, no internal +threads are launched for timers and socket comm, as is illustrated in the +following diagram. + +PCEPlib Threading model with external infra: + +.. image:: images/PCEPlib_threading_model_frr_infra.jpg + + +Building +-------- + +The autotools build system is used and integrated with the frr build system. + +Testing +------- + +The Unit Tests for an individual library are executed with the ``make check`` +command. The Unit Test binary will be written to the project ``build`` directory. +All Unit Tests are executed with Valgrind, and any memory issues reported by +Valgrind will cause the Unit Test to fail. + + +PCEPlib PCC API +=============== + +The following sections describe the PCEPlib PCC API. + + +PCEPlib PCC Initialization and Destruction +------------------------------------------ + +The PCEPlib can be initialized to handle memory, timers, and socket comm +internally in what is called stand-alone mode, or with an external +infrastructure, like FRR. + +PCEPlib PCC Initialization and Destruction in stand-alone mode +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +PCEPlib PCC initialization and destruction functions: + +- ``bool initialize_pcc();`` +- ``bool initialize_pcc_wait_for_completion();`` +- ``bool destroy_pcc();`` + +The PCC can be initialized with either ``initialize_pcc()`` or +``initialize_pcc_wait_for_completion()``. + +- ``initialize_pcc_wait_for_completion()`` blocks until ``destroy_pcc()`` + is called from a separate pthread. +- ``initialize_pcc()`` is non-blocking and will be stopped when + ``destroy_pcc()`` is called. + +Both initialize functions will launch 3 pthreads: + +- 1 Timer pthread +- 1 SocketComm pthread +- 1 SessionLogic pthread + +When ``destroy_pcc()`` is called, all pthreads will be stopped and all +resources will be released. + +All 3 functions return true upon success, and false otherwise. + +PCEPlib PCC Initialization and Destruction with FRR infrastructure +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +PCEPlib PCC initialization and destruction functions: + +- ``bool initialize_pcc_infra(struct pceplib_infra_config *infra_config);`` +- ``bool destroy_pcc();`` + +The ``pceplib_infra_config`` struct has the following fields: + +- **void *pceplib_infra_mt** + - FRR Memory type pointer for infra related memory management + +- **void *pceplib_messages_mt** + - FRR Memory type pointer for PCEP messages related memory management + +- **pceplib_malloc_func mfunc** + - FRR malloc function pointer + +- **pceplib_calloc_func cfunc** + - FRR calloc function pointer + +- **pceplib_realloc_func rfunc** + - FRR realloc function pointer + +- **pceplib_strdup_func sfunc** + - FRR strdup function pointer + +- **pceplib_free_func ffunc** + - FRR free function pointer + +- **void *external_infra_data** + - FRR data used by FRR timers and sockets infrastructure + +- **ext_timer_create timer_create_func** + - FRR timer create function pointer + +- **ext_timer_cancel timer_cancel_func** + - FRR timer cancel function pointer + +- **ext_socket_write socket_write_func** + - FRR socket write function pointer, indicating fd is ready to be written to + +- **ext_socket_read socket_read_func** + - FRR socket write function pointer, indicating fd is ready to be read from + + +PCEPlib PCC configuration +------------------------- + +PCEPlib PCC configuratoin functions: + +- ``pcep_configuration *create_default_pcep_configuration();`` +- ``void destroy_pcep_configuration(pcep_configuration *config);`` + +A ``pcep_configuration`` object with default values is created with +``create_default_pcep_configuration()``. These values can be tailored to +specific use cases. + +Created ``pcep_configuration`` objects are destroyed with +``destroy_pcep_configuration()``. + + +PCEPlib PCC configuration paramaters +++++++++++++++++++++++++++++++++++++ + +The ``pcep_configuration`` object is defined in ``pcep_session_logic/include/pcep_session_logic.h`` +The attributes in the ``pcep_configuration`` object are detailed as follows. + +PCEP Connection parameters: + +- **dst_pcep_port** + - Defaults to 0, in which case the default PCEP TCP destination port + 4189 will be used. + - Set to use a specific PCEP TCP destination port. + +- **src_pcep_port** + - Defaults to 0, in which case the default PCEP TCP source port + 4189 will be used. + - Set to use a specific PCEP TCP source port. + +- **Source IP** + - Defaults to IPv4 INADDR_ANY + - Set **src_ip.src_ipv4** and **is_src_ipv6=false** to set the source IPv4. + - Set **src_ip.src_ipv6** and **is_src_ipv6=true** to set the source IPv6. + +- **socket_connect_timeout_millis** + - Maximum amount of time to wait to connect to the PCE TCP socket + before failing, in milliseconds. + +PCEP Versioning: + +- **pcep_msg_versioning->draft_ietf_pce_segment_routing_07** + - Defaults to false, in which case draft 16 versioning will be used. + - Set to true to use draft 07 versioning. + +PCEP Open Message Parameters: + +- **keep_alive_seconds** + - Sent to PCE in PCEP Open Msg + - Recommended value = 30, Minimum value = 1 + - Disabled by setting value = 0 + +- **dead_timer_seconds** + - Sent to PCE in PCEP Open Msg + - Recommended value = 4 * keepalive timer value + +- Supported value ranges for PCEP Open Message received from the PCE + - **min_keep_alive_seconds**, **max_keep_alive_seconds** + - **min_dead_timer_seconds**, **max_dead_timer_seconds** + +- **request_time_seconds** + - When a PCC sends a PcReq to a PCE, the amount of time a PCC will + wait for a PcRep reply from the PCE. + +- **max_unknown_requests** + - If a PCC/PCE receives PCRep/PCReq messages with unknown requests + at a rate equal or greater than MAX-UNKNOWN-REQUESTS per minute, + the PCC/PCE MUST send a PCEP CLOSE message. + - Recommended value = 5 + +- **max_unknown_messages** + - If a PCC/PCE receives unrecognized messages at a rate equal or + greater than MAX-UNKNOWN-MESSAGES per minute, the PCC/PCE MUST + send a PCEP CLOSE message + - Recommended value = 5 + +Stateful PCE Capability TLV configuration parameters (RFC 8231, 8232, 8281, and +draft-ietf-pce-segment-routing-16): + +- **support_stateful_pce_lsp_update** + - If this flag is true, then a Stateful PCE Capability TLV will + be added to the PCEP Open object, with the LSP Update Capability + U-flag set true. + - The rest of these parameters are used to configure the Stateful + PCE Capability TLV + +- **support_pce_lsp_instantiation** + - Sets the I-flag true, indicating the PCC allows instantiation + of an LSP by a PCE. + +- **support_include_db_version** + - Sets the S-bit true, indicating the PCC will include the + LSP-DB-VERSION TLV in each LSP object. See lsp_db_version below. + +- **support_lsp_triggered_resync** + - Sets the T-bit true, indicating the PCE can trigger resynchronization + of LSPs at any point in the life of the session. + +- **support_lsp_delta_sync** + - Sets the D-bit true, indicating the PCEP speaker allows incremental + (delta) State Synchronization. + +- **support_pce_triggered_initial_sync** + - Sets the F-bit true, indicating the PCE SHOULD trigger initial (first) + State Synchronization + +LSP DB Version TLV configuration parameters: + +- **lsp_db_version** + - If this parameter has a value other than 0, and the above + support_include_db_version flag is true, then an LSP DB + Version TLV will be added to the PCEP Open object. + - This parameter should only be set if LSP-DB survived a restart + and is available. + - This value will be copied over to the pcep_session upon initialization. + +SR PCE Capability sub-TLV configuration parameters (draft-ietf-pce-segment-routing-16): + +- **support_sr_te_pst** + - If this flag is true, then an SR PCE Capability sub-TLV will be + added to a Path Setup type Capability TLV, which will be added + to the PCEP Open object. + - The PST used in the Path Setup type Capability will be 1, + indicating the Path is setup using Segment Routing Traffic Engineering. + +Only set the following fields if the **support_sr_te_pst** flag is true. + +- **pcc_can_resolve_nai_to_sid** + - Sets the N-flag true, indicating that the PCC is capable of resolving + a Node or Adjacency Identifier to a SID + +- **max_sid_depth** + - If set other than 0, then the PCC imposes a limit on the Maximum + SID depth. + - If this parameter is other than 0, then the X bit will be true, + and the parameter value will be set in the MSD field. + + +PCEPlib PCC connections +----------------------- + +PCEPlib PCC connect and disconnect functions: + +- ``pcep_session *connect_pce(pcep_configuration *config, struct in_addr *pce_ip);`` +- ``pcep_session *connect_pce_ipv6(pcep_configuration *config, struct in6_addr *pce_ip);`` +- ``void disconnect_pce(pcep_session *session);`` + +When connecting to a PCE, a ``pcep_session`` will be returned on success, NULL +otherwise. + +Refer to the above PCC configuration parameters section for setting the source +and destination PCEP TCP ports, and the source IP address and version. + + +PCEP Messages, Objects, and TLVs +-------------------------------- + +The PCEP messages, objects, and TLVs created in the PCEPlib are high-level API +structures, meaning they need to be encoded before being sent on-the-wire, and +the raw data received needs to be decoded into these structures. This makes +using these objects much easier for the library consumer, since they do not +need to know the detailed raw format of the PCEP entities. + + +PCEP Messages ++++++++++++++ + +Received messages (in the ``pcep_event`` explained below) are of type +``pcep_message``, which have the following fields: + +- ``struct pcep_message_header *msg_header;`` + - Defines the PCEP version and message type + +- ``double_linked_list *obj_list;`` + - A double linked list of the message objects + - Each entry is a pointer to a ``struct pcep_object_header``, and + using the ``object_class`` and ``object_type`` fields, the pointer + can be cast to the appropriate object structure to access the + rest of the object fields + +- ``uint8_t *encoded_message;`` + - This field is only populated for received messages or once the + ``pcep_encode_message()`` function has been called on the message. + - This field is a pointer to the raw PCEP data for the entire + message, including all objects and TLVs. + +- ``uint16_t encoded_message_length;`` + - This field is only populated for received messages or once the + ``pcep_encode_message()`` function has been called on the message. + - This field is the length of the entire raw message, including + all objects and TLVs. + - This field is in host byte order. + + +PCEP Objects +++++++++++++ + +A PCEP message has a double linked list of pointers to ``struct pcep_object_header`` +structures, which have the following fields: + +- ``enum pcep_object_classes object_class;`` +- ``enum pcep_object_types object_type;`` +- ``bool flag_p;`` + - PCC Processing rule bit: When set, the object MUST be taken into + account, when cleared the object is optional + +- ``bool flag_i;`` + - PCE Ignore bit: indicates to a PCC whether or not an optional + object was processed + +- ``double_linked_list *tlv_list;`` + - A double linked list of the object TLVs + - Each entry is a pointer to a ``struct pcep_object_tlv_header``, and + using the TLV type field, the pointer can be cast to the + appropriate TLV structure to access the rest of the TLV fields + +- ``uint8_t *encoded_object;`` + - This field is only populated for received objects or once the + ``pcep_encode_object()`` (called by ``pcep_encode_message()``) + function has been called on the object. + - Pointer into the encoded_message field (from the pcep_message) + where the raw object PCEP data starts. + +- ``uint16_t encoded_object_length;`` + - This field is only populated for received objects or once the + ``pcep_encode_object()`` (called by ``pcep_encode_message()``) + function has been called on the object. + - This field is the length of the entire raw TLV + - This field is in host byte order. + +The object class and type can be used to cast the ``struct pcep_object_header`` +pointer to the appropriate object structure so the specific object fields can +be accessed. + + +PCEP TLVs ++++++++++ + +A PCEP object has a double linked list of pointers to ``struct pcep_object_tlv_header`` +structures, which have the following fields: + +- ``enum pcep_object_tlv_types type;`` +- ``uint8_t *encoded_tlv;`` + - This field is only populated for received TLVs or once the + ``pcep_encode_tlv()`` (called by ``pcep_encode_message()``) + function has been called on the TLV. + - Pointer into the encoded_message field (from the pcep_message) + where the raw TLV PCEP data starts. + +- ``uint16_t encoded_tlv_length;`` + - This field is only populated for received TLVs or once the + ``pcep_encode_tlv()`` (called by ``pcep_encode_message()``) + function has been called on the TLV. + - This field is the length of the entire raw TLV + - This field is in host byte order. + + +Memory management ++++++++++++++++++ + +Any of the PCEPlib Message Library functions that receive a pointer to a +``double_linked_list``, ``pcep_object_header``, or ``pcep_object_tlv_header``, +transfer the ownership of the entity to the PCEPlib. The memory will be freed +internally when the encapsulating structure is freed. If the memory for any of +these is freed by the caller, then there will be a double memory free error +when the memory is freed internally in the PCEPlib. + +Any of the PCEPlib Message Library functions that receive either a pointer to a +``struct in_addr`` or ``struct in6_addr`` will allocate memory for the IP +address internally and copy the IP address. It is the responsibility of the +caller to manage the memory for the IP address passed into the PCEPlib Message +Library functions. + +For messages received via the event queue (explained below), the message will +be freed when the event is freed by calling ``destroy_pcep_event()``. + +When sending messages, the message will be freed internally in the PCEPlib when +the ``send_message()`` ``pcep_pcc`` API function when the ``free_after_send`` flag +is set true. + +To manually delete a message, call the ``pcep_msg_free_message()`` function. +Internally, this will call ``pcep_obj_free_object()`` and ``pcep_obj_free_tlv()`` +appropriately. + + +Sending a PCEP Report message +----------------------------- + +This section shows how to send a PCEP Report messages from the PCC to the PCE, +and serves as an example of how to send other messages. Refer to the sample +PCC binary located in ``pcep_pcc/src/pcep_pcc.c`` for code examples os sending +a PCEP Report message. + +The Report message must have at least an SRP, LSP, and ERO object. + +The PCEP Report message objects are created with the following APIs: + +- ``struct pcep_object_srp *pcep_obj_create_srp(...);`` +- ``struct pcep_object_lsp *pcep_obj_create_lsp(...);`` +- ``struct pcep_object_ro *pcep_obj_create_ero(...);`` + - Create ero subobjects with the ``pcep_obj_create_ro_subobj_*(...);`` functions + +PCEP Report message is created with the following API: + +- ``struct pcep_header *pcep_msg_create_report(double_linked_list *report_object_list);`` + +A PCEP report messages is sent with the following API: + +- ``void send_message(pcep_session *session, pcep_message *message, bool free_after_send);`` + + +PCEPlib Received event queue +---------------------------- + +PCEP events and messages of interest to the PCEPlib consumer will be stored +internally in a message queue for retrieval. + +The following are the event types: + +- **MESSAGE_RECEIVED** +- **PCE_CLOSED_SOCKET** +- **PCE_SENT_PCEP_CLOSE** +- **PCE_DEAD_TIMER_EXPIRED** +- **PCE_OPEN_KEEP_WAIT_TIMER_EXPIRED** +- **PCC_CONNECTED_TO_PCE** +- **PCC_CONNECTION_FAILURE** +- **PCC_PCEP_SESSION_CLOSED** +- **PCC_RCVD_INVALID_OPEN** +- **PCC_SENT_INVALID_OPEN** +- **PCC_RCVD_MAX_INVALID_MSGS** +- **PCC_RCVD_MAX_UNKOWN_MSGS** + +The following PCEP messages will not be posted on the message queue, as they +are handled internally in the library: + +- **Open** +- **Keep Alive** +- **Close** + +Received event queue API: + +- ``bool event_queue_is_empty();`` + - Returns true if the queue is empty, false otherwise + +- ``uint32_t event_queue_num_events_available();`` + - Return the number of events on the queue, 0 if empty + +- ``struct pcep_event *event_queue_get_event();`` + - Return the next event on the queue, NULL if empty + - The ``message`` pointer will only be non-NULL if ``event_type`` + is ``MESSAGE_RECEIVED`` + +- ``void destroy_pcep_event(struct pcep_event *event);`` + - Free the PCEP Event resources, including the PCEP message if present + + +PCEPlib Counters +---------------- + +The PCEPlib counters are managed in the ``pcep_session_logic`` library, and can +be accessed in the ``pcep_session_counters`` field of the ``pcep_session`` structure. +There are 2 API functions to manage the counters: + +- ``void dump_pcep_session_counters(pcep_session *session);`` + - Dump all of the counters to the logs + +- ``void reset_pcep_session_counters(pcep_session *session);`` + diff --git a/doc/developer/scripting.rst b/doc/developer/scripting.rst index b0413619ab..708f65ff7d 100644 --- a/doc/developer/scripting.rst +++ b/doc/developer/scripting.rst @@ -271,7 +271,7 @@ has). For example, here is the encoder function for ``struct prefix``: This function pushes a single value onto the Lua stack. It is a table whose equivalent in Lua is: -.. code-block:: +.. code-block:: c { ["network"] = "1.2.3.4/24", ["prefixlen"] = 24, ["family"] = 2 } diff --git a/doc/developer/subdir.am b/doc/developer/subdir.am index f7e4486ef0..d16420c7e7 100644 --- a/doc/developer/subdir.am +++ b/doc/developer/subdir.am @@ -57,6 +57,7 @@ dev_RSTFILES = \ doc/developer/tracing.rst \ doc/developer/testing.rst \ doc/developer/topotests-snippets.rst \ + doc/developer/topotests-markers.rst \ doc/developer/topotests.rst \ doc/developer/workflow.rst \ doc/developer/xrefs.rst \ diff --git a/doc/developer/topotests.rst b/doc/developer/topotests.rst index 93d81548b2..4f58ee335b 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 @@ -388,11 +389,19 @@ This is the recommended test writing routine: - Format the new code using `black <https://github.com/psf/black>`_ - Create a Pull Request -.. Note:: +Some things to keep in mind: + +- BGP tests MUST use generous convergence timeouts - you must ensure + that any test involving BGP uses a convergence timeout of at least + 130 seconds. +- Topotests are run on a range of Linux versions: if your test + requires some OS-specific capability (like mpls support, or vrf + support), there are test functions available in the libraries that + will help you determine whether your test should run or be skipped. +- Avoid including unstable data in your test: don't rely on link-local + addresses or ifindex values, for example, because these can change + from run to run. - BGP tests MUST use generous convergence timeouts - you must ensure - that any test involving BGP uses a convergence timeout of at least - 130 seconds. Topotest File Hierarchy """"""""""""""""""""""" @@ -795,7 +804,7 @@ Requirements: - Use `black <https://github.com/psf/black>`_ code formatter before creating a pull request. This ensures we have a unified code style. - Mark test modules with pytest markers depending on the daemons used during the - tests (s. Markers) + tests (see :ref:`topotests-markers`) Tips: diff --git a/doc/developer/tracing.rst b/doc/developer/tracing.rst index 71f7b4ac49..ae4d621a8e 100644 --- a/doc/developer/tracing.rst +++ b/doc/developer/tracing.rst @@ -62,113 +62,113 @@ use your tracer as usual. To see available USDT probes:: - readelf -n /usr/lib/frr/bgpd + readelf -n /usr/lib/frr/bgpd Example:: - root@host ~> readelf -n /usr/lib/frr/bgpd - - Displaying notes found in: .note.ABI-tag - Owner Data size Description - GNU 0x00000010 NT_GNU_ABI_TAG (ABI version tag) - OS: Linux, ABI: 3.2.0 - - Displaying notes found in: .note.gnu.build-id - Owner Data size Description - GNU 0x00000014 NT_GNU_BUILD_ID (unique build ID bitstring) - Build ID: 4f42933a69dcb42a519bc459b2105177c8adf55d - - Displaying notes found in: .note.stapsdt - Owner Data size Description - stapsdt 0x00000045 NT_STAPSDT (SystemTap probe descriptors) - Provider: frr_bgp - Name: packet_read - Location: 0x000000000045ee48, Base: 0x00000000005a09d2, Semaphore: 0x0000000000000000 - Arguments: 8@-96(%rbp) 8@-104(%rbp) - stapsdt 0x00000047 NT_STAPSDT (SystemTap probe descriptors) - Provider: frr_bgp - Name: open_process - Location: 0x000000000047c43b, Base: 0x00000000005a09d2, Semaphore: 0x0000000000000000 - Arguments: 8@-224(%rbp) 2@-226(%rbp) - stapsdt 0x00000049 NT_STAPSDT (SystemTap probe descriptors) - Provider: frr_bgp - Name: update_process - Location: 0x000000000047c4bf, Base: 0x00000000005a09d2, Semaphore: 0x0000000000000000 - Arguments: 8@-208(%rbp) 2@-210(%rbp) - stapsdt 0x0000004f NT_STAPSDT (SystemTap probe descriptors) - Provider: frr_bgp - Name: notification_process - Location: 0x000000000047c557, Base: 0x00000000005a09d2, Semaphore: 0x0000000000000000 - Arguments: 8@-192(%rbp) 2@-194(%rbp) - stapsdt 0x0000004c NT_STAPSDT (SystemTap probe descriptors) - Provider: frr_bgp - Name: keepalive_process - Location: 0x000000000047c5db, Base: 0x00000000005a09d2, Semaphore: 0x0000000000000000 - Arguments: 8@-176(%rbp) 2@-178(%rbp) - stapsdt 0x0000004a NT_STAPSDT (SystemTap probe descriptors) - Provider: frr_bgp - Name: refresh_process - Location: 0x000000000047c673, Base: 0x00000000005a09d2, Semaphore: 0x0000000000000000 - Arguments: 8@-160(%rbp) 2@-162(%rbp) - stapsdt 0x0000004d NT_STAPSDT (SystemTap probe descriptors) - Provider: frr_bgp - Name: capability_process - Location: 0x000000000047c6f7, Base: 0x00000000005a09d2, Semaphore: 0x0000000000000000 - Arguments: 8@-144(%rbp) 2@-146(%rbp) - stapsdt 0x0000006f NT_STAPSDT (SystemTap probe descriptors) - Provider: frr_bgp - Name: output_filter - Location: 0x000000000048e33a, Base: 0x00000000005a09d2, Semaphore: 0x0000000000000000 - Arguments: 8@-144(%rbp) 8@-152(%rbp) 4@-156(%rbp) 4@-160(%rbp) 8@-168(%rbp) - stapsdt 0x0000007d NT_STAPSDT (SystemTap probe descriptors) - Provider: frr_bgp - Name: process_update - Location: 0x0000000000491f10, Base: 0x00000000005a09d2, Semaphore: 0x0000000000000000 - Arguments: 8@-800(%rbp) 8@-808(%rbp) 4@-812(%rbp) 4@-816(%rbp) 4@-820(%rbp) 8@-832(%rbp) - stapsdt 0x0000006e NT_STAPSDT (SystemTap probe descriptors) - Provider: frr_bgp - Name: input_filter - Location: 0x00000000004940ed, Base: 0x00000000005a09d2, Semaphore: 0x0000000000000000 - Arguments: 8@-144(%rbp) 8@-152(%rbp) 4@-156(%rbp) 4@-160(%rbp) 8@-168(%rbp) + root@host ~> readelf -n /usr/lib/frr/bgpd + + Displaying notes found in: .note.ABI-tag + Owner Data size Description + GNU 0x00000010 NT_GNU_ABI_TAG (ABI version tag) + OS: Linux, ABI: 3.2.0 + + Displaying notes found in: .note.gnu.build-id + Owner Data size Description + GNU 0x00000014 NT_GNU_BUILD_ID (unique build ID bitstring) + Build ID: 4f42933a69dcb42a519bc459b2105177c8adf55d + + Displaying notes found in: .note.stapsdt + Owner Data size Description + stapsdt 0x00000045 NT_STAPSDT (SystemTap probe descriptors) + Provider: frr_bgp + Name: packet_read + Location: 0x000000000045ee48, Base: 0x00000000005a09d2, Semaphore: 0x0000000000000000 + Arguments: 8@-96(%rbp) 8@-104(%rbp) + stapsdt 0x00000047 NT_STAPSDT (SystemTap probe descriptors) + Provider: frr_bgp + Name: open_process + Location: 0x000000000047c43b, Base: 0x00000000005a09d2, Semaphore: 0x0000000000000000 + Arguments: 8@-224(%rbp) 2@-226(%rbp) + stapsdt 0x00000049 NT_STAPSDT (SystemTap probe descriptors) + Provider: frr_bgp + Name: update_process + Location: 0x000000000047c4bf, Base: 0x00000000005a09d2, Semaphore: 0x0000000000000000 + Arguments: 8@-208(%rbp) 2@-210(%rbp) + stapsdt 0x0000004f NT_STAPSDT (SystemTap probe descriptors) + Provider: frr_bgp + Name: notification_process + Location: 0x000000000047c557, Base: 0x00000000005a09d2, Semaphore: 0x0000000000000000 + Arguments: 8@-192(%rbp) 2@-194(%rbp) + stapsdt 0x0000004c NT_STAPSDT (SystemTap probe descriptors) + Provider: frr_bgp + Name: keepalive_process + Location: 0x000000000047c5db, Base: 0x00000000005a09d2, Semaphore: 0x0000000000000000 + Arguments: 8@-176(%rbp) 2@-178(%rbp) + stapsdt 0x0000004a NT_STAPSDT (SystemTap probe descriptors) + Provider: frr_bgp + Name: refresh_process + Location: 0x000000000047c673, Base: 0x00000000005a09d2, Semaphore: 0x0000000000000000 + Arguments: 8@-160(%rbp) 2@-162(%rbp) + stapsdt 0x0000004d NT_STAPSDT (SystemTap probe descriptors) + Provider: frr_bgp + Name: capability_process + Location: 0x000000000047c6f7, Base: 0x00000000005a09d2, Semaphore: 0x0000000000000000 + Arguments: 8@-144(%rbp) 2@-146(%rbp) + stapsdt 0x0000006f NT_STAPSDT (SystemTap probe descriptors) + Provider: frr_bgp + Name: output_filter + Location: 0x000000000048e33a, Base: 0x00000000005a09d2, Semaphore: 0x0000000000000000 + Arguments: 8@-144(%rbp) 8@-152(%rbp) 4@-156(%rbp) 4@-160(%rbp) 8@-168(%rbp) + stapsdt 0x0000007d NT_STAPSDT (SystemTap probe descriptors) + Provider: frr_bgp + Name: process_update + Location: 0x0000000000491f10, Base: 0x00000000005a09d2, Semaphore: 0x0000000000000000 + Arguments: 8@-800(%rbp) 8@-808(%rbp) 4@-812(%rbp) 4@-816(%rbp) 4@-820(%rbp) 8@-832(%rbp) + stapsdt 0x0000006e NT_STAPSDT (SystemTap probe descriptors) + Provider: frr_bgp + Name: input_filter + Location: 0x00000000004940ed, Base: 0x00000000005a09d2, Semaphore: 0x0000000000000000 + Arguments: 8@-144(%rbp) 8@-152(%rbp) 4@-156(%rbp) 4@-160(%rbp) 8@-168(%rbp) To see available LTTng probes, run the target, create a session and then:: - lttng list --userspace | grep frr + lttng list --userspace | grep frr Example:: - root@host ~> lttng list --userspace | grep frr - PID: 11157 - Name: /usr/lib/frr/bgpd - frr_libfrr:route_node_get (loglevel: TRACE_DEBUG_LINE (13)) (type: tracepoint) - frr_libfrr:list_sort (loglevel: TRACE_DEBUG_LINE (13)) (type: tracepoint) - frr_libfrr:list_delete_node (loglevel: TRACE_DEBUG_LINE (13)) (type: tracepoint) - frr_libfrr:list_remove (loglevel: TRACE_DEBUG_LINE (13)) (type: tracepoint) - frr_libfrr:list_add (loglevel: TRACE_DEBUG_LINE (13)) (type: tracepoint) - frr_libfrr:memfree (loglevel: TRACE_DEBUG_LINE (13)) (type: tracepoint) - frr_libfrr:memalloc (loglevel: TRACE_DEBUG_LINE (13)) (type: tracepoint) - frr_libfrr:frr_pthread_stop (loglevel: TRACE_DEBUG_LINE (13)) (type: tracepoint) - frr_libfrr:frr_pthread_run (loglevel: TRACE_DEBUG_LINE (13)) (type: tracepoint) - frr_libfrr:thread_call (loglevel: TRACE_INFO (6)) (type: tracepoint) - frr_libfrr:thread_cancel_async (loglevel: TRACE_INFO (6)) (type: tracepoint) - frr_libfrr:thread_cancel (loglevel: TRACE_INFO (6)) (type: tracepoint) - frr_libfrr:schedule_write (loglevel: TRACE_INFO (6)) (type: tracepoint) - frr_libfrr:schedule_read (loglevel: TRACE_INFO (6)) (type: tracepoint) - frr_libfrr:schedule_event (loglevel: TRACE_INFO (6)) (type: tracepoint) - frr_libfrr:schedule_timer (loglevel: TRACE_INFO (6)) (type: tracepoint) - frr_libfrr:hash_release (loglevel: TRACE_INFO (6)) (type: tracepoint) - frr_libfrr:hash_insert (loglevel: TRACE_INFO (6)) (type: tracepoint) - frr_libfrr:hash_get (loglevel: TRACE_INFO (6)) (type: tracepoint) - frr_bgp:output_filter (loglevel: TRACE_INFO (6)) (type: tracepoint) - frr_bgp:input_filter (loglevel: TRACE_INFO (6)) (type: tracepoint) - frr_bgp:process_update (loglevel: TRACE_INFO (6)) (type: tracepoint) - frr_bgp:packet_read (loglevel: TRACE_INFO (6)) (type: tracepoint) - frr_bgp:refresh_process (loglevel: TRACE_INFO (6)) (type: tracepoint) - frr_bgp:capability_process (loglevel: TRACE_INFO (6)) (type: tracepoint) - frr_bgp:notification_process (loglevel: TRACE_INFO (6)) (type: tracepoint) - frr_bgp:update_process (loglevel: TRACE_INFO (6)) (type: tracepoint) - frr_bgp:keepalive_process (loglevel: TRACE_INFO (6)) (type: tracepoint) - frr_bgp:open_process (loglevel: TRACE_INFO (6)) (type: tracepoint) + root@host ~> lttng list --userspace | grep frr + PID: 11157 - Name: /usr/lib/frr/bgpd + frr_libfrr:route_node_get (loglevel: TRACE_DEBUG_LINE (13)) (type: tracepoint) + frr_libfrr:list_sort (loglevel: TRACE_DEBUG_LINE (13)) (type: tracepoint) + frr_libfrr:list_delete_node (loglevel: TRACE_DEBUG_LINE (13)) (type: tracepoint) + frr_libfrr:list_remove (loglevel: TRACE_DEBUG_LINE (13)) (type: tracepoint) + frr_libfrr:list_add (loglevel: TRACE_DEBUG_LINE (13)) (type: tracepoint) + frr_libfrr:memfree (loglevel: TRACE_DEBUG_LINE (13)) (type: tracepoint) + frr_libfrr:memalloc (loglevel: TRACE_DEBUG_LINE (13)) (type: tracepoint) + frr_libfrr:frr_pthread_stop (loglevel: TRACE_DEBUG_LINE (13)) (type: tracepoint) + frr_libfrr:frr_pthread_run (loglevel: TRACE_DEBUG_LINE (13)) (type: tracepoint) + frr_libfrr:thread_call (loglevel: TRACE_INFO (6)) (type: tracepoint) + frr_libfrr:thread_cancel_async (loglevel: TRACE_INFO (6)) (type: tracepoint) + frr_libfrr:thread_cancel (loglevel: TRACE_INFO (6)) (type: tracepoint) + frr_libfrr:schedule_write (loglevel: TRACE_INFO (6)) (type: tracepoint) + frr_libfrr:schedule_read (loglevel: TRACE_INFO (6)) (type: tracepoint) + frr_libfrr:schedule_event (loglevel: TRACE_INFO (6)) (type: tracepoint) + frr_libfrr:schedule_timer (loglevel: TRACE_INFO (6)) (type: tracepoint) + frr_libfrr:hash_release (loglevel: TRACE_INFO (6)) (type: tracepoint) + frr_libfrr:hash_insert (loglevel: TRACE_INFO (6)) (type: tracepoint) + frr_libfrr:hash_get (loglevel: TRACE_INFO (6)) (type: tracepoint) + frr_bgp:output_filter (loglevel: TRACE_INFO (6)) (type: tracepoint) + frr_bgp:input_filter (loglevel: TRACE_INFO (6)) (type: tracepoint) + frr_bgp:process_update (loglevel: TRACE_INFO (6)) (type: tracepoint) + frr_bgp:packet_read (loglevel: TRACE_INFO (6)) (type: tracepoint) + frr_bgp:refresh_process (loglevel: TRACE_INFO (6)) (type: tracepoint) + frr_bgp:capability_process (loglevel: TRACE_INFO (6)) (type: tracepoint) + frr_bgp:notification_process (loglevel: TRACE_INFO (6)) (type: tracepoint) + frr_bgp:update_process (loglevel: TRACE_INFO (6)) (type: tracepoint) + frr_bgp:keepalive_process (loglevel: TRACE_INFO (6)) (type: tracepoint) + frr_bgp:open_process (loglevel: TRACE_INFO (6)) (type: tracepoint) When using LTTng, you can also get zlogs as trace events by enabling the ``lttng_ust_tracelog:*`` event class. diff --git a/doc/developer/workflow.rst b/doc/developer/workflow.rst index 71e2b00448..abdbea5a9c 100644 --- a/doc/developer/workflow.rst +++ b/doc/developer/workflow.rst @@ -1229,9 +1229,9 @@ towards making documentation easier to use, write and maintain. CLI Commands ^^^^^^^^^^^^ -When documenting CLI please use a combination of the ``.. index::`` and -``.. clicmd::`` directives. For example, the command :clicmd:`show pony` would -be documented as follows: +When documenting CLI please use the ``.. clicmd::`` directive. This directive +will format the command and generate index entries automatically. For example, +the command :clicmd:`show pony` would be documented as follows: .. code-block:: rest @@ -1252,6 +1252,7 @@ be documented as follows: hjw |_>|> /_] // /_] /_] + When documented this way, CLI commands can be cross referenced with the ``:clicmd:`` inline markup like so: @@ -1262,8 +1263,27 @@ When documented this way, CLI commands can be cross referenced with the This is very helpful for users who want to quickly remind themselves what a particular command does. -When documenting a cli that has a ``no`` form, please do not include -the ``no`` in the ``.. index::`` line. +When documenting a cli that has a ``no`` form, please do not include the ``no`` +form. I.e. ``no show pony`` would not be documented anywhere. Since most +commands have ``no`` forms, users should be able to infer these or get help +from vtysh's completions. + +When documenting commands that have lots of possible variants, just document +the single command in summary rather than enumerating each possible variant. +E.g. for ``show pony [foo|bar]``, do not: + +.. code-block:: rest + + .. clicmd:: show pony + .. clicmd:: show pony foo + .. clicmd:: show pony bar + +Do: + +.. code-block:: rest + + .. clicmd:: show pony [foo|bar] + Configuration Snippets ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/doc/developer/xrefs.rst b/doc/developer/xrefs.rst index 6a0794d41b..e8e07dfe1d 100644 --- a/doc/developer/xrefs.rst +++ b/doc/developer/xrefs.rst @@ -20,8 +20,6 @@ To verify xrefs have been included in a binary or dynamic library, run ``readelf -n binary``. For individual object files, it's ``readelf -S object.o | grep xref_array`` instead. -An extraction tool will be added in a future commit. - Structure and contents ---------------------- @@ -168,3 +166,50 @@ entry point. for C++ code when compiled by GCC. A workaround is present for runtime functionality, but to extract the xrefs from a C++ source file, it needs to be built with clang (or a future fixed version of GCC) instead. + +Extraction tool +--------------- + +The FRR source contains a matching tool to extract xref data from compiled ELF +binaries in ``python/xrelfo.py``. This tool uses CPython extensions +implemented in ``clippy`` and must therefore be executed with that. + +``xrelfo.py`` processes input from one or more ELF file (.o, .so, executable), +libtool object (.lo, .la, executable wrapper script) or JSON (output from +``xrelfo.py``) and generates an output JSON file. During standard FRR build, +it is invoked on all binaries and libraries and the result is combined into +``frr.json``. + +ELF files from any operating system, CPU architecture and endianness can be +processed on any host. Any issues with this are bugs in ``xrelfo.py`` +(or clippy's ELF code.) + +``xrelfo.py`` also performs some sanity checking, particularly on log +messages. The following options are available: + +.. option:: -o OUTPUT + + Filename to write JSON output to. As a convention, a ``.xref`` filename + extension is used. + +.. option:: -Wlog-format + + Performs extra checks on log message format strings, particularly checks + for ``\t`` and ``\n`` characters (which should not be used in log messages). + +.. option:: -Wlog-args + + Generates cleanup hints for format string arguments where + :c:func:`printfrr()` extensions could be used, e.g. replacing ``inet_ntoa`` + with ``%pI4``. + +.. option:: --profile + + Runs the Python profiler to identify hotspots in the ``xrelfo.py`` code. + +``xrelfo.py`` uses information about C structure definitions saved in +``python/xrefstructs.json``. This file is included with the FRR sources and +only needs to be regenerated when some of the ``struct xref_*`` definitions +are changed (which should be almost never). The file is written by +``python/tiabwarfo.py``, which uses ``pahole`` to extract the necessary data +from DWARF information. diff --git a/doc/user/babeld.rst b/doc/user/babeld.rst index 62d50d5d65..e6d4aa5c97 100644 --- a/doc/user/babeld.rst +++ b/doc/user/babeld.rst @@ -34,26 +34,17 @@ Configuration of *babeld* is done in its configuration file Babel configuration =================== -.. index:: router babel -.. clicmd:: [no] router babel +.. clicmd:: router babel Enable or disable Babel routing. -.. index:: babel resend-delay (20-655340) -.. clicmd:: [no] babel resend-delay (20-655340) - - Specifies the time after which important messages are resent when - avoiding a black-hole. The default is 2000 ms. - -.. index:: babel diversity -.. clicmd:: [no] babel diversity +.. clicmd:: babel diversity Enable or disable routing using radio frequency diversity. This is highly recommended in networks with many wireless nodes. If you enable this, you will probably want to set `babel diversity-factor` and `babel channel` below. -.. index:: babel diversity-factor (1-256) .. clicmd:: babel diversity-factor (1-256) @@ -63,12 +54,10 @@ Babel configuration no role in route selection; you will probably want to set that to 128 or less on nodes with multiple independent radios. -.. index:: network IFNAME -.. clicmd:: [no] network IFNAME +.. clicmd:: network IFNAME Enable or disable Babel on the given interface. -.. index:: babel <wired|wireless> .. clicmd:: babel <wired|wireless> @@ -77,8 +66,7 @@ Babel configuration Specifying `wireless` (the default) is always correct, but may cause slower convergence and extra routing traffic. -.. index:: babel split-horizon -.. clicmd:: [no] babel split-horizon +.. clicmd:: babel split-horizon Specifies whether to perform split-horizon on the interface. Specifying ``no babel split-horizon`` is always correct, while ``babel @@ -88,7 +76,6 @@ Babel configuration interfaces. This flag is reset when the wired/wireless status of an interface is changed. -.. index:: babel hello-interval (20-655340) .. clicmd:: babel hello-interval (20-655340) @@ -97,7 +84,6 @@ Babel configuration on wireless links, the link quality value is reestimated at every hello interval. The default is 4000 ms. -.. index:: babel update-interval (20-655340) .. clicmd:: babel update-interval (20-655340) @@ -105,7 +91,6 @@ Babel configuration Babel makes extensive use of triggered updates, this can be set to fairly high values on links with little packet loss. The default is 20000 ms. -.. index:: babel channel .. clicmd:: babel channel (1-254) .. clicmd:: babel channel interfering @@ -121,7 +106,6 @@ Babel configuration interfaces. This is reset when the wired/wireless status of an interface is changed. -.. index:: babel rxcost (1-65534) .. clicmd:: babel rxcost (1-65534) @@ -136,7 +120,6 @@ Babel configuration networks, acting directly on the cost using route maps is a better technique. -.. index:: babel rtt-decay (1-256) .. clicmd:: babel rtt-decay (1-256) @@ -144,7 +127,6 @@ Babel configuration RTT samples, in units of 1/256. Higher values discard old samples faster. The default is 42. -.. index:: babel rtt-min (1-65535) .. clicmd:: babel rtt-min (1-65535) @@ -152,14 +134,12 @@ Babel configuration increase the cost to a neighbour. The additional cost is linear in (rtt - rtt-min). The default is 100 ms. -.. index:: babel rtt-max (1-65535) .. clicmd:: babel rtt-max (1-65535) This specifies the maximum RTT, in milliseconds, above which we don't increase the cost to a neighbour. The default is 120 ms. -.. index:: babel max-rtt-penalty (0-65535) .. clicmd:: babel max-rtt-penalty (0-65535) @@ -167,14 +147,12 @@ Babel configuration when the RTT is higher or equal than rtt-max. The default is 0, which effectively disables the use of a RTT-based cost. -.. index:: babel enable-timestamps -.. clicmd:: [no] babel enable-timestamps +.. clicmd:: babel enable-timestamps Enable or disable sending timestamps with each Hello and IHU message in order to compute RTT values. The default is `no babel enable-timestamps`. -.. index:: babel resend-delay (20-655340) .. clicmd:: babel resend-delay (20-655340) @@ -182,7 +160,6 @@ Babel configuration update will be resent. The default is 2000 ms. You probably don't want to tweak this value. -.. index:: babel smoothing-half-life (0-65534) .. clicmd:: babel smoothing-half-life (0-65534) @@ -196,9 +173,8 @@ Babel configuration Babel redistribution ==================== -.. index:: redistribute <ipv4|ipv6> KIND -.. clicmd:: [no] redistribute <ipv4|ipv6> KIND +.. clicmd:: redistribute <ipv4|ipv6> KIND Specify which kind of routes should be redistributed into Babel. @@ -209,50 +185,40 @@ Show Babel information These commands dump various parts of *babeld*'s internal state. -.. index:: show babel route .. clicmd:: show babel route -.. index:: show babel route A.B.C.D .. clicmd:: show babel route A.B.C.D -.. index:: show babel route X:X::X:X .. clicmd:: show babel route X:X::X:X -.. index:: show babel route A.B.C.D/M .. clicmd:: show babel route A.B.C.D/M -.. index:: show babel route X:X::X:X/M .. clicmd:: show babel route X:X::X:X/M -.. index:: show babel interface .. clicmd:: show babel interface -.. index:: show babel interface IFNAME .. clicmd:: show babel interface IFNAME -.. index:: show babel neighbor .. clicmd:: show babel neighbor -.. index:: show babel parameters .. clicmd:: show babel parameters Babel debugging commands ======================== -.. index:: simple: debug babel KIND simple: no debug babel KIND -.. clicmd:: [no] debug babel KIND +.. clicmd:: debug babel KIND Enable or disable debugging messages of a given kind. ``KIND`` can be one of: diff --git a/doc/user/basic.rst b/doc/user/basic.rst index 1ca3ca3cf2..5cbd3692dc 100644 --- a/doc/user/basic.rst +++ b/doc/user/basic.rst @@ -11,13 +11,9 @@ The following sections discuss commands common to all the routing daemons. Config Commands =============== -.. index:: Configuration files for running the software -.. index:: Files for running configurations -.. index:: Modifying the herd's behavior -.. index:: Getting the herd running In a config file, you can write the debugging options, a vty's password, routing daemon configurations, a log file name, and so forth. This information @@ -60,25 +56,21 @@ If desired, you can specify a config file using the :option:`-f` or Basic Config Commands --------------------- -.. index:: hostname HOSTNAME .. clicmd:: hostname HOSTNAME Set hostname of the router. -.. index:: password PASSWORD -.. clicmd:: [no] password PASSWORD +.. clicmd:: password PASSWORD Set password for vty interface. The ``no`` form of the command deletes the password. If there is no password, a vty won't accept connections. -.. index:: enable password PASSWORD -.. clicmd:: [no] enable password PASSWORD +.. clicmd:: enable password PASSWORD Set enable password. The ``no`` form of the command deletes the enable password. -.. index:: log trap LEVEL -.. clicmd:: [no] log trap LEVEL +.. clicmd:: log trap LEVEL These commands are deprecated and are present only for historical compatibility. The log trap command sets the current logging level for all @@ -88,9 +80,8 @@ Basic Config Commands future logging commands to debugging, but it does not change the logging level of existing logging destinations. -.. index:: log stdout [LEVEL] -.. clicmd:: [no] log stdout LEVEL +.. clicmd:: log stdout LEVEL Enable logging output to stdout. If the optional second argument specifying the logging level is not present, the default logging level (typically @@ -109,8 +100,7 @@ Basic Config Commands terminal output. Use a log file and ``tail -f`` if this rare chance is inacceptable to your setup. -.. index:: log file FILENAME [LEVEL] -.. clicmd:: [no] log file [FILENAME [LEVEL]] +.. clicmd:: log file [FILENAME [LEVEL]] If you want to log into a file, please specify ``filename`` as in this example: @@ -124,16 +114,14 @@ Basic Config Commands deprecated ``log trap`` command) will be used. The ``no`` form of the command disables logging to a file. -.. index:: log syslog [LEVEL] -.. clicmd:: [no] log syslog [LEVEL] +.. clicmd:: log syslog [LEVEL] Enable logging output to syslog. If the optional second argument specifying the logging level is not present, the default logging level (typically debugging, but can be changed using the deprecated ``log trap`` command) will be used. The ``no`` form of the command disables logging to syslog. -.. index:: log monitor [LEVEL] -.. clicmd:: [no] log monitor [LEVEL] +.. clicmd:: log monitor [LEVEL] Enable logging output to vty terminals that have enabled logging using the ``terminal monitor`` command. By default, monitor logging is enabled at the @@ -143,15 +131,13 @@ Basic Config Commands level (typically debugging) will be used. The ``no`` form of the command disables logging to terminal monitors. -.. index:: log facility [FACILITY] -.. clicmd:: [no] log facility [FACILITY] +.. clicmd:: log facility [FACILITY] This command changes the facility used in syslog messages. The default facility is ``daemon``. The ``no`` form of the command resets the facility to the default ``daemon`` facility. -.. index:: log record-priority -.. clicmd:: [no] log record-priority +.. clicmd:: log record-priority To include the severity in all messages logged to a file, to stdout, or to a terminal monitor (i.e. anything except syslog), @@ -161,8 +147,7 @@ Basic Config Commands versions of syslogd can be configured to include the facility and level in the messages emitted. -.. index:: log timestamp precision (0-6) -.. clicmd:: [no] log timestamp precision [(0-6)] +.. clicmd:: log timestamp precision [(0-6)] This command sets the precision of log message timestamps to the given number of digits after the decimal point. Currently, the value must be in @@ -177,8 +162,7 @@ Basic Config Commands In this example, the precision is set to provide timestamps with millisecond accuracy. -.. index:: log commands -.. clicmd:: [no] log commands +.. clicmd:: log commands This command enables the logging of all commands typed by a user to all enabled log destinations. The note that logging includes full command lines, @@ -186,8 +170,7 @@ Basic Config Commands is used to start the daemon then this command is turned on by default and cannot be turned off and the [no] form of the command is dissallowed. -.. index:: log-filter WORD [DAEMON] -.. clicmd:: [no] log-filter WORD [DAEMON] +.. clicmd:: log-filter WORD [DAEMON] This command forces logs to be filtered on a specific string. A log message will only be printed if it matches on one of the filters in the log-filter @@ -200,55 +183,41 @@ Basic Config Commands Log filters prevent this but you should still expect a small performance hit due to filtering each of all those logs. -.. index:: log-filter clear [DAEMON] .. clicmd:: log-filter clear [DAEMON] This command clears all current filters in the log-filter table. Can be daemon independent. -.. index:: service password-encryption .. clicmd:: service password-encryption Encrypt password. -.. index:: service advanced-vty .. clicmd:: service advanced-vty Enable advanced mode VTY. -.. index:: service terminal-length (0-512) .. clicmd:: service terminal-length (0-512) Set system wide line configuration. This configuration command applies to all VTY interfaces. -.. index:: line vty .. clicmd:: line vty Enter vty configuration mode. -.. index:: banner motd default .. clicmd:: banner motd default Set default motd string. -.. index:: banner motd file FILE .. clicmd:: banner motd file FILE Set motd string from file. The file must be in directory specified under ``--sysconfdir``. -.. index:: banner motd line LINE .. clicmd:: banner motd line LINE Set motd string from an input. -.. index:: banner motd -.. clicmd:: no banner motd - - No motd banner string will be printed. - -.. index:: exec-timeout MINUTE [SECOND] .. clicmd:: exec-timeout MINUTE [SECOND] Set VTY connection timeout value. When only one argument is specified @@ -256,13 +225,9 @@ Basic Config Commands used for timeout value in seconds. Default timeout value is 10 minutes. When timeout value is zero, it means no timeout. -.. index:: exec-timeout -.. clicmd:: no exec-timeout - - Do not perform timeout at all. This command is as same as - ``exec-timeout 0 0``. + Not setting this, or setting the values to 0 0, means a timeout will not be + enabled. -.. index:: access-class ACCESS-LIST .. clicmd:: access-class ACCESS-LIST Restrict vty connections with an access list. @@ -440,55 +405,45 @@ Puppet, etc.), upgrade considerations differ somewhat: Terminal Mode Commands ====================== -.. index:: write terminal .. clicmd:: write terminal Displays the current configuration to the vty interface. -.. index:: write file .. clicmd:: write file Write current configuration to configuration file. -.. index:: configure [terminal] .. clicmd:: configure [terminal] Change to configuration mode. This command is the first step to configuration. -.. index:: terminal length (0-512) .. clicmd:: terminal length (0-512) Set terminal display length to ``(0-512)``. If length is 0, no display control is performed. -.. index:: who .. clicmd:: who Show a list of currently connected vty sessions. -.. index:: list .. clicmd:: list List all available commands. -.. index:: show version .. clicmd:: show version Show the current version of |PACKAGE_NAME| and its build host information. -.. index:: show logging .. clicmd:: show logging Shows the current configuration of the logging system. This includes the status of all logging destinations. -.. index:: show log-filter .. clicmd:: show log-filter Shows the current log filters applied to each daemon. -.. index:: show memory .. clicmd:: show memory Show information on how much memory is used for which specific things in @@ -549,18 +504,15 @@ Terminal Mode Commands When executing this command from ``vtysh``, each of the daemons' memory usage is printed sequentially. -.. index:: show history .. clicmd:: show history Dump the vtysh cli history. -.. index:: logmsg LEVEL MESSAGE .. clicmd:: logmsg LEVEL MESSAGE Send a message to all logging destinations that are enabled for messages of the given severity. -.. index:: find COMMAND... .. clicmd:: find COMMAND... This command performs a simple substring search across all defined commands @@ -589,7 +541,6 @@ Terminal Mode Commands .. _common-show-commands: -.. index:: show thread cpu .. clicmd:: show thread cpu [r|w|t|e|x] This command displays system run statistics for all the different event @@ -598,7 +549,6 @@ Terminal Mode Commands (e)vent and e(x)ecute thread event types. If you have compiled with disable-cpu-time then this command will not show up. -.. index:: show thread poll .. clicmd:: show thread poll This command displays FRR's poll data. It allows a glimpse into how diff --git a/doc/user/bfd.rst b/doc/user/bfd.rst index 6c83ffa19a..6f797f7cc1 100644 --- a/doc/user/bfd.rst +++ b/doc/user/bfd.rst @@ -90,12 +90,10 @@ may also be specified (:ref:`common-invocation-options`). BFDd Commands ============= -.. index:: bfd .. clicmd:: bfd Opens the BFD daemon configuration node. -.. index:: peer <A.B.C.D|X:X::X:X> [{multihop|local-address <A.B.C.D|X:X::X:X>|interface IFNAME|vrf NAME}] .. clicmd:: peer <A.B.C.D|X:X::X:X> [{multihop|local-address <A.B.C.D|X:X::X:X>|interface IFNAME|vrf NAME}] Creates and configures a new BFD peer to listen and talk to. @@ -113,41 +111,27 @@ BFDd Commands `vrf` selects which domain we want to use. -.. index:: peer <A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname|vrf NAME$vrf_name}] -.. clicmd:: no peer <A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname|vrf NAME$vrf_name}] - Stops and removes the selected peer. - - -.. index:: profile WORD .. clicmd:: profile WORD Creates a peer profile that can be configured in multiple peers. + Deleting the profile will cause all peers using it to reset to the default + values. -.. index:: profile WORD -.. clicmd:: no profile WORD - - Deletes a peer profile. Any peer using the profile will have their - configurations reset to the default values. - -.. index:: show bfd [vrf NAME] peers [json] .. clicmd:: show bfd [vrf NAME] peers [json] Show all configured BFD peers information and current status. -.. index:: show bfd [vrf NAME$vrf_name] peer <WORD$label|<A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname}]> [json] .. clicmd:: show bfd [vrf NAME$vrf_name] peer <WORD$label|<A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname}]> [json] Show status for a specific BFD peer. -.. index:: show bfd [vrf NAME] peers brief [json] .. clicmd:: show bfd [vrf NAME] peers brief [json] Show all configured BFD peers information and current status in brief. -.. index:: show bfd distributed .. clicmd:: show bfd distributed Show the BFD data plane (distributed BFD) statistics. @@ -160,7 +144,6 @@ Peer / Profile Configuration BFD peers and profiles share the same BFD session configuration commands. -.. index:: detect-multiplier (2-255) .. clicmd:: detect-multiplier (2-255) Configures the detection multiplier to determine packet loss. The @@ -173,29 +156,32 @@ BFD peers and profiles share the same BFD session configuration commands. detect failures only after 900 milliseconds without receiving packets. -.. index:: receive-interval (10-60000) .. clicmd:: receive-interval (10-60000) Configures the minimum interval that this system is capable of receiving control packets. The default value is 300 milliseconds. -.. index:: transmit-interval (10-60000) .. clicmd:: transmit-interval (10-60000) The minimum transmission interval (less jitter) that this system wants to use to send BFD control packets. Defaults to 300ms. -.. index:: echo-interval (10-60000) -.. clicmd:: echo-interval (10-60000) +.. clicmd:: echo receive-interval <disabled|(10-60000)> + + Configures the minimum interval that this system is capable of + receiving echo packets. Disabled means that this system doesn't want + to receive echo packets. The default value is 50 milliseconds. + +.. clicmd:: echo transmit-interval (10-60000) - Configures the minimal echo receive transmission interval that this - system is capable of handling. + The minimum transmission interval (less jitter) that this system + wants to use to send BFD echo packets. Defaults to 50ms. -.. index:: echo-mode -.. clicmd:: [no] echo-mode +.. clicmd:: echo-mode Enables or disables the echo transmission mode. This mode is disabled - by default. + by default. If you are not using distributed BFD then echo mode works + only when the peer is also FRR. It is recommended that the transmission interval of control packets to be increased after enabling echo-mode to reduce bandwidth usage. @@ -204,15 +190,13 @@ BFD peers and profiles share the same BFD session configuration commands. Echo mode is not supported on multi-hop setups (see :rfc:`5883` section 3). -.. index:: shutdown -.. clicmd:: [no] shutdown +.. clicmd:: shutdown Enables or disables the peer. When the peer is disabled an 'administrative down' message is sent to the remote peer. -.. index:: passive-mode -.. clicmd:: [no] passive-mode +.. clicmd:: passive-mode Mark session as passive: a passive session will not attempt to start the connection and will wait for control packets from peer before it @@ -224,8 +208,7 @@ BFD peers and profiles share the same BFD session configuration commands. The default is active-mode (or ``no passive-mode``). -.. index:: minimum-ttl (1-254) -.. clicmd:: [no] minimum-ttl (1-254) +.. clicmd:: minimum-ttl (1-254) For multi hop sessions only: configure the minimum expected TTL for an incoming BFD control packet. @@ -241,14 +224,12 @@ BFD peers and profiles share the same BFD session configuration commands. BFD Peer Specific Commands -------------------------- -.. index:: label WORD .. clicmd:: label WORD Labels a peer with the provided word. This word can be referenced later on other daemons to refer to a specific peer. -.. index:: profile BFDPROF .. clicmd:: profile BFDPROF Configure peer to use the profile configurations. @@ -270,7 +251,6 @@ BGP BFD Configuration The following commands are available inside the BGP configuration node. -.. index:: neighbor <A.B.C.D|X:X::X:X|WORD> bfd .. clicmd:: neighbor <A.B.C.D|X:X::X:X|WORD> bfd Listen for BFD events registered on the same target as this BGP @@ -278,12 +258,7 @@ The following commands are available inside the BGP configuration node. the connection with its neighbor and, when it goes back up, notify BGP to try to connect to it. -.. index:: neighbor <A.B.C.D|X:X::X:X|WORD> bfd -.. clicmd:: no neighbor <A.B.C.D|X:X::X:X|WORD> bfd - Removes any notification registration for this neighbor. - -.. index:: neighbor <A.B.C.D|X:X::X:X|WORD> bfd check-control-plane-failure .. clicmd:: neighbor <A.B.C.D|X:X::X:X|WORD> bfd check-control-plane-failure Allow to write CBIT independence in BFD outgoing packets. Also allow to @@ -293,26 +268,16 @@ The following commands are available inside the BGP configuration node. This is the case when graceful restart is enabled, and it is wished to ignore the BD event while waiting for the remote router to restart. -.. index:: neighbor <A.B.C.D|X:X::X:X|WORD> bfd check-control-plane-failure -.. clicmd:: no neighbor <A.B.C.D|X:X::X:X|WORD> bfd check-control-plane-failure - - Disallow to write CBIT independence in BFD outgoing packets. Also disallow - to ignore BFD down notification. This is the default behaviour. + Disabling this disables presence of CBIT independence in BFD outgoing + packets and pays attention to BFD down notifications. This is the default. -.. index:: neighbor <A.B.C.D|X:X::X:X|WORD> bfd profile BFDPROF .. clicmd:: neighbor <A.B.C.D|X:X::X:X|WORD> bfd profile BFDPROF Same as command ``neighbor <A.B.C.D|X:X::X:X|WORD> bfd``, but applies the BFD profile to the sessions it creates or that already exist. -.. index:: neighbor <A.B.C.D|X:X::X:X|WORD> bfd profile BFDPROF -.. clicmd:: no neighbor <A.B.C.D|X:X::X:X|WORD> bfd profile BFDPROF - - Removes the BFD profile configuration from peer session(s). - - .. _bfd-isis-peer-config: IS-IS BFD Configuration @@ -320,31 +285,20 @@ IS-IS BFD Configuration The following commands are available inside the interface configuration node. -.. index:: isis bfd .. clicmd:: isis bfd Listen for BFD events on peers created on the interface. Every time a new neighbor is found a BFD peer is created to monitor the link status for fast convergence. -.. index:: isis bfd -.. clicmd:: no isis bfd - - Removes any notification registration for this interface peers. - Note that there will be just one BFD session per interface. In case both IPv4 and IPv6 support are configured then just a IPv6 based session is created. -.. index:: isis bfd profile BFDPROF .. clicmd:: isis bfd profile BFDPROF Use a BFD profile BFDPROF as provided in the BFD configuration. -.. index:: isis bfd profile BFDPROF -.. clicmd:: no isis bfd profile BFDPROF - - Removes any BFD profile if present. .. _bfd-ospf-peer-config: @@ -353,17 +307,16 @@ OSPF BFD Configuration The following commands are available inside the interface configuration node. -.. index:: ip ospf bfd .. clicmd:: ip ospf bfd Listen for BFD events on peers created on the interface. Every time a new neighbor is found a BFD peer is created to monitor the link status for fast convergence. -.. index:: ip ospf bfd -.. clicmd:: no ip ospf bfd +.. clicmd:: ip ospf bfd profile BFDPROF - Removes any notification registration for this interface peers. + Same as command ``ip ospf bfd``, but applies the BFD profile to the sessions + it creates or that already exist. .. _bfd-ospf6-peer-config: @@ -373,18 +326,12 @@ OSPF6 BFD Configuration The following commands are available inside the interface configuration node. -.. index:: ipv6 ospf6 bfd .. clicmd:: ipv6 ospf6 bfd Listen for BFD events on peers created on the interface. Every time a new neighbor is found a BFD peer is created to monitor the link status for fast convergence. -.. index:: ipv6 ospf6 bfd -.. clicmd:: no ipv6 ospf6 bfd - - Removes any notification registration for this interface peers. - .. _bfd-pim-peer-config: @@ -393,18 +340,12 @@ PIM BFD Configuration The following commands are available inside the interface configuration node. -.. index:: ip pim bfd .. clicmd:: ip pim bfd Listen for BFD events on peers created on the interface. Every time a new neighbor is found a BFD peer is created to monitor the link status for fast convergence. -.. index:: ip pim bfd -.. clicmd:: no ip pim bfd - - Removes any notification registration for this interface peers. - .. _bfd-configuration: @@ -516,12 +457,13 @@ You can inspect the current BFD peer status with the following commands: Detect-multiplier: 3 Receive interval: 300ms Transmission interval: 300ms + Echo receive interval: 50ms Echo transmission interval: disabled Remote timers: Detect-multiplier: 3 Receive interval: 300ms Transmission interval: 300ms - Echo transmission interval: 50ms + Echo receive interval: 50ms peer 192.168.1.1 label: router3-peer @@ -536,12 +478,13 @@ You can inspect the current BFD peer status with the following commands: Detect-multiplier: 3 Receive interval: 300ms Transmission interval: 300ms + Echo receive interval: 50ms Echo transmission interval: disabled Remote timers: Detect-multiplier: 3 Receive interval: 300ms Transmission interval: 300ms - Echo transmission interval: 50ms + Echo receive interval: 50ms frr# show bfd peer 192.168.1.1 BFD Peer: @@ -558,15 +501,16 @@ You can inspect the current BFD peer status with the following commands: Detect-multiplier: 3 Receive interval: 300ms Transmission interval: 300ms + Echo receive interval: 50ms Echo transmission interval: disabled Remote timers: Detect-multiplier: 3 Receive interval: 300ms Transmission interval: 300ms - Echo transmission interval: 50ms + Echo receive interval: 50ms frr# show bfd peer 192.168.0.1 json - {"multihop":false,"peer":"192.168.0.1","id":1,"remote-id":1,"status":"up","uptime":161,"diagnostic":"ok","remote-diagnostic":"ok","receive-interval":300,"transmit-interval":300,"echo-interval":50,"detect-multiplier":3,"remote-receive-interval":300,"remote-transmit-interval":300,"remote-echo-interval":50,"remote-detect-multiplier":3,"peer-type":"dynamic"} + {"multihop":false,"peer":"192.168.0.1","id":1,"remote-id":1,"status":"up","uptime":161,"diagnostic":"ok","remote-diagnostic":"ok","receive-interval":300,"transmit-interval":300,"echo-receive-interval":50,"echo-transmit-interval":0,"detect-multiplier":3,"remote-receive-interval":300,"remote-transmit-interval":300,"remote-echo-receive-interval":50,"remote-detect-multiplier":3,"peer-type":"dynamic"} You can inspect the current BFD peer status in brief with the following commands: @@ -721,8 +665,7 @@ sure you have `debugging` level enabled: You may also fine tune the debug messages by selecting one or more of the debug levels: -.. index:: debug bfd distributed -.. clicmd:: [no] debug bfd distributed +.. clicmd:: debug bfd distributed Toggle BFD data plane (distributed BFD) debugging. @@ -731,20 +674,17 @@ debug levels: * Data plane received / send messages * Connection events -.. index:: debug bfd network -.. clicmd:: [no] debug bfd network +.. clicmd:: debug bfd network Toggle network events: show messages about socket failures and unexpected BFD messages that may not belong to registered peers. -.. index:: debug bfd peer -.. clicmd:: [no] debug bfd peer +.. clicmd:: debug bfd peer Toggle peer event log messages: show messages about peer creation/removal and state changes. -.. index:: debug bfd zebra -.. clicmd:: [no] debug bfd zebra +.. clicmd:: debug bfd zebra Toggle zebra message events: show messages about interfaces, local addresses, VRF and daemon peer registrations. diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst index cb97ee22df..4433dc9e21 100644 --- a/doc/user/bgp.rst +++ b/doc/user/bgp.rst @@ -252,18 +252,11 @@ command. The AS number is an identifier for the autonomous system. The BGP protocol uses the AS number for detecting whether the BGP connection is internal or external. -.. index:: router bgp ASN .. clicmd:: router bgp ASN Enable a BGP protocol process with the specified ASN. After this statement you can input any `BGP Commands`. -.. index:: router bgp ASN -.. clicmd:: no router bgp ASN - - Destroy a BGP protocol process with the specified ASN. - -.. index:: bgp router-id A.B.C.D .. clicmd:: bgp router-id A.B.C.D This command specifies the router-ID. If *bgpd* connects to *zebra* it gets @@ -301,7 +294,6 @@ However, the same AS can be used with different VRFs. Configuration of additional autonomous systems, or of a router that targets a specific VRF, is accomplished with the following command: -.. index:: router bgp ASN vrf VRFNAME .. clicmd:: router bgp ASN vrf VRFNAME ``VRFNAME`` is matched against VRFs configured in the kernel. When ``vrf @@ -344,7 +336,6 @@ via BGP. Multiple views can be supported, and BGP view information is always independent from other routing protocols and Zebra/kernel routes. BGP views use the core instance (i.e., default VRF) for communication with peers. -.. index:: router bgp AS-NUMBER view NAME .. clicmd:: router bgp AS-NUMBER view NAME Make a new BGP view. You can use an arbitrary word for the ``NAME``. Routes @@ -363,7 +354,6 @@ the core instance (i.e., default VRF) for communication with peers. neighbor 10.0.0.3 remote-as 4 neighbor 10.0.0.4 remote-as 5 -.. index:: show [ip] bgp view NAME .. clicmd:: show [ip] bgp view NAME Display the routing table of BGP view ``NAME``. @@ -372,14 +362,12 @@ the core instance (i.e., default VRF) for communication with peers. Route Selection --------------- -.. index:: bgp bestpath as-path confed .. clicmd:: bgp bestpath as-path confed This command specifies that the length of confederation path sets and sequences should should be taken into account during the BGP best path decision process. -.. index:: bgp bestpath as-path multipath-relax .. clicmd:: bgp bestpath as-path multipath-relax This command specifies that BGP decision process should consider paths @@ -411,17 +399,14 @@ Route Selection Administrative Distance Metrics ------------------------------- -.. index:: distance bgp (1-255) (1-255) (1-255) .. clicmd:: distance bgp (1-255) (1-255) (1-255) This command change distance value of BGP. The arguments are the distance values for for external routes, internal routes and local routes respectively. -.. index:: distance (1-255) A.B.C.D/M .. clicmd:: distance (1-255) A.B.C.D/M -.. index:: distance (1-255) A.B.C.D/M WORD .. clicmd:: distance (1-255) A.B.C.D/M WORD Sets the administrative distance for a particular route. @@ -431,8 +416,7 @@ Administrative Distance Metrics Require policy on EBGP ------------------------------- -.. index:: bgp ebgp-requires-policy -.. clicmd:: [no] bgp ebgp-requires-policy +.. clicmd:: bgp ebgp-requires-policy This command requires incoming and outgoing filters to be applied for eBGP sessions as part of RFC-8212 compliance. Without the incoming @@ -480,16 +464,14 @@ Require policy on EBGP Reject routes with AS_SET or AS_CONFED_SET types ------------------------------------------------ -.. index:: bgp reject-as-sets -.. clicmd:: [no] bgp reject-as-sets +.. clicmd:: bgp reject-as-sets This command enables rejection of incoming and outgoing routes having AS_SET or AS_CONFED_SET type. Suppress duplicate updates -------------------------- -.. index:: bgp suppress-duplicates -.. clicmd:: [no] bgp suppress-duplicates +.. clicmd:: bgp suppress-duplicates For example, BGP routers can generate multiple identical announcements with empty community attributes if stripped at egress. This is an undesired behavior. @@ -499,8 +481,7 @@ Suppress duplicate updates Disable checking if nexthop is connected on EBGP sessions --------------------------------------------------------- -.. index:: bgp disable-ebgp-connected-route-check -.. clicmd:: [no] bgp disable-ebgp-connected-route-check +.. clicmd:: bgp disable-ebgp-connected-route-check This command is used to disable the connection verification process for EBGP peering sessions that are reachable by a single hop but are configured on a loopback interface or otherwise @@ -511,20 +492,17 @@ Disable checking if nexthop is connected on EBGP sessions Route Flap Dampening -------------------- -.. index:: [no] bgp dampening [(1-45) [(1-20000) (1-20000) (1-255)]] -.. clicmd:: [no] bgp dampening [(1-45) [(1-20000) (1-20000) (1-255)]] +.. clicmd:: bgp dampening [(1-45) [(1-20000) (1-20000) (1-255)]] This command enables (with optionally specified dampening parameters) or disables route-flap dampening for all routes of a BGP instance. -.. index:: [no] neighbor PEER dampening [(1-45) [(1-20000) (1-20000) (1-255)]] -.. clicmd:: [no] neighbor PEER dampening [(1-45) [(1-20000) (1-20000) (1-255)]] +.. clicmd:: neighbor PEER dampening [(1-45) [(1-20000) (1-20000) (1-255)]] This command enables (with optionally specified dampening parameters) or disables route-flap dampening for all routes learned from a BGP peer. -.. index:: [no] neighbor GROUP dampening [(1-45) [(1-20000) (1-20000) (1-255)]] -.. clicmd:: [no] neighbor GROUP dampening [(1-45) [(1-20000) (1-20000) (1-255)]] +.. clicmd:: neighbor GROUP dampening [(1-45) [(1-20000) (1-20000) (1-255)]] This command enables (with optionally specified dampening parameters) or disables route-flap dampening for all routes learned from peers of a peer @@ -769,7 +747,6 @@ topologies are at cross-purposes with each other - see the Flavel and Roughan paper above for an example. Hence the guideline that the iBGP topology should follow the IGP topology. -.. index:: bgp deterministic-med .. clicmd:: bgp deterministic-med Carry out route-selection in way that produces deterministic answers @@ -789,7 +766,6 @@ Note that there are other sources of indeterminism in the route selection process, specifically, the preference for older and already selected routes from eBGP peers, :ref:`bgp-route-selection`. -.. index:: bgp always-compare-med .. clicmd:: bgp always-compare-med Always compare the MED on routes, even when they were received from @@ -893,7 +869,6 @@ forwarding state has been preserved. The remaining bits are reserved and MUST be set to zero by the sender and ignored by the receiver. -.. index:: bgp graceful-restart preserve-fw-state .. clicmd:: bgp graceful-restart preserve-fw-state FRR gives us the option to enable/disable the "F" flag using this specific @@ -943,18 +918,15 @@ However, it MUST defer route selection for an address family until it either. that do not advertise the graceful restart capability). 2. The Selection_Deferral_Timer timeout. -.. index:: bgp graceful-restart select-defer-time (0-3600) .. clicmd:: bgp graceful-restart select-defer-time (0-3600) This is command, will set deferral time to value specified. -.. index:: bgp graceful-restart rib-stale-time (1-3600) .. clicmd:: bgp graceful-restart rib-stale-time (1-3600) This is command, will set the time for which stale routes are kept in RIB. -.. index:: bgp graceful-restart stalepath-time (1-4095) .. clicmd:: bgp graceful-restart stalepath-time (1-4095) This is command, will set the max time (in seconds) to hold onto @@ -988,13 +960,11 @@ override the global mode. BGP GR Global Mode Commands ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -.. index:: bgp graceful-restart .. clicmd:: bgp graceful-restart This command will enable BGP graceful restart ifunctionality at the global level. -.. index:: bgp graceful-restart disable .. clicmd:: bgp graceful-restart disable This command will disable both the functionality graceful restart and helper @@ -1006,19 +976,16 @@ BGP GR Global Mode Commands BGP GR Peer Mode Commands ^^^^^^^^^^^^^^^^^^^^^^^^^ -.. index:: neighbor A.B.C.D graceful-restart .. clicmd:: neighbor A.B.C.D graceful-restart This command will enable BGP graceful restart ifunctionality at the peer level. -.. index:: neighbor A.B.C.D graceful-restart-helper .. clicmd:: neighbor A.B.C.D graceful-restart-helper This command will enable BGP graceful restart helper only functionality at the peer level. -.. index:: neighbor A.B.C.D graceful-restart-disable .. clicmd:: neighbor A.B.C.D graceful-restart-disable This command will disable the entire BGP graceful restart functionality @@ -1030,8 +997,7 @@ BGP GR Peer Mode Commands Administrative Shutdown ----------------------- -.. index:: bgp shutdown [message MSG...] -.. clicmd:: [no] bgp shutdown [message MSG...] +.. clicmd:: bgp shutdown [message MSG...] Administrative shutdown of all peers of a bgp instance. Drop all BGP peers, but preserve their configurations. The peers are notified in accordance with @@ -1049,7 +1015,6 @@ Administrative Shutdown Networks -------- -.. index:: network A.B.C.D/M .. clicmd:: network A.B.C.D/M This command adds the announcement network. @@ -1066,11 +1031,8 @@ Networks routes if they aren't present in their IGP routing tables; `bgpd` doesn't care about IGP routes when announcing its routes. -.. index:: network A.B.C.D/M -.. clicmd:: no network A.B.C.D/M -.. index:: bgp network import-check -.. clicmd:: [no] bgp network import-check +.. clicmd:: bgp network import-check This configuration modifies the behavior of the network statement. If you have this configured the underlying network must exist in @@ -1085,8 +1047,7 @@ Networks IPv6 Support ------------ -.. index:: neighbor A.B.C.D activate -.. clicmd:: [no] neighbor A.B.C.D activate +.. clicmd:: neighbor A.B.C.D activate This configuration modifies whether to enable an address family for a specific neighbor. By default only the IPv4 unicast address family is @@ -1126,6 +1087,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: @@ -1137,53 +1101,41 @@ Route Aggregation Route Aggregation-IPv4 Address Family ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -.. index:: aggregate-address A.B.C.D/M .. clicmd:: aggregate-address A.B.C.D/M This command specifies an aggregate address. -.. index:: aggregate-address A.B.C.D/M route-map NAME .. clicmd:: aggregate-address A.B.C.D/M route-map NAME Apply a route-map for an aggregated prefix. -.. index:: aggregate-address A.B.C.D/M origin <egp|igp|incomplete> .. clicmd:: aggregate-address A.B.C.D/M origin <egp|igp|incomplete> Override ORIGIN for an aggregated prefix. -.. index:: aggregate-address A.B.C.D/M as-set .. clicmd:: aggregate-address A.B.C.D/M as-set This command specifies an aggregate address. Resulting routes include AS set. -.. index:: aggregate-address A.B.C.D/M summary-only .. clicmd:: aggregate-address A.B.C.D/M summary-only This command specifies an aggregate address. Aggregated routes will not be announced. -.. index:: aggregate-address A.B.C.D/M matching-MED-only .. clicmd:: aggregate-address A.B.C.D/M matching-MED-only Configure the aggregated address to only be created when the routes MED match, otherwise no aggregated route will be created. -.. index:: aggregate-address A.B.C.D/M suppress-map NAME .. clicmd:: aggregate-address A.B.C.D/M suppress-map NAME Similar to `summary-only`, but will only suppress more specific routes that are matched by the selected route-map. -.. index:: aggregate-address A.B.C.D/M -.. clicmd:: no aggregate-address A.B.C.D/M - This command removes an aggregate address. - - - This configuration example setup the aggregate-address under - ipv4 address-family. + This configuration example sets up an ``aggregate-address`` under the ipv4 + address-family. .. code-block:: frr @@ -1201,53 +1153,41 @@ Route Aggregation-IPv4 Address Family Route Aggregation-IPv6 Address Family ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -.. index:: aggregate-address X:X::X:X/M .. clicmd:: aggregate-address X:X::X:X/M This command specifies an aggregate address. -.. index:: aggregate-address X:X::X:X/M route-map NAME .. clicmd:: aggregate-address X:X::X:X/M route-map NAME Apply a route-map for an aggregated prefix. -.. index:: aggregate-address X:X::X:X/M origin <egp|igp|incomplete> .. clicmd:: aggregate-address X:X::X:X/M origin <egp|igp|incomplete> Override ORIGIN for an aggregated prefix. -.. index:: aggregate-address X:X::X:X/M as-set .. clicmd:: aggregate-address X:X::X:X/M as-set This command specifies an aggregate address. Resulting routes include AS set. -.. index:: aggregate-address X:X::X:X/M summary-only .. clicmd:: aggregate-address X:X::X:X/M summary-only This command specifies an aggregate address. Aggregated routes will not be announced. -.. index:: aggregate-address X:X::X:X/M matching-MED-only .. clicmd:: aggregate-address X:X::X:X/M matching-MED-only Configure the aggregated address to only be created when the routes MED match, otherwise no aggregated route will be created. -.. index:: aggregate-address X:X::X:X/M suppress-map NAME .. clicmd:: aggregate-address X:X::X:X/M suppress-map NAME Similar to `summary-only`, but will only suppress more specific routes that are matched by the selected route-map. -.. index:: aggregate-address X:X::X:X/M -.. clicmd:: no aggregate-address X:X::X:X/M - This command removes an aggregate address. - - - This configuration example setup the aggregate-address under - ipv6 address-family. + This configuration example sets up an ``aggregate-address`` under the ipv6 + address-family. .. code-block:: frr @@ -1259,50 +1199,27 @@ Route Aggregation-IPv6 Address Family aggregate-address 50::0/64 route-map aggr-rmap exit-address-family + .. _bgp-redistribute-to-bgp: Redistribution -------------- -.. index:: redistribute kernel -.. clicmd:: redistribute kernel - - Redistribute kernel route to BGP process. - -.. index:: redistribute static -.. clicmd:: redistribute static +Redistribution configuration should be placed under the ``address-family`` +section for the specific AF to redistribute into. Protocol availability for +redistribution is determined by BGP AF; for example, you cannot redistribute +OSPFv3 into ``address-family ipv4 unicast`` as OSPFv3 supports IPv6. - Redistribute static route to BGP process. +.. clicmd:: redistribute <babel|connected|eigrp|isis|kernel|openfabric|ospf|ospf6|rip|ripng|sharp|static|table> [metric (0-4294967295)] [route-map WORD] -.. index:: redistribute connected -.. clicmd:: redistribute connected +Redistribute routes from other protocols into BGP. - Redistribute connected route to BGP process. - -.. index:: redistribute rip -.. clicmd:: redistribute rip - - Redistribute RIP route to BGP process. - -.. index:: redistribute ospf -.. clicmd:: redistribute ospf - - Redistribute OSPF route to BGP process. - -.. index:: redistribute vnc -.. clicmd:: redistribute vnc - - Redistribute VNC routes to BGP process. - -.. index:: redistribute vnc-direct .. clicmd:: redistribute vnc-direct Redistribute VNC direct (not via zebra) routes to BGP process. -.. index:: bgp update-delay MAX-DELAY .. clicmd:: bgp update-delay MAX-DELAY -.. index:: bgp update-delay MAX-DELAY ESTABLISH-WAIT .. clicmd:: bgp update-delay MAX-DELAY ESTABLISH-WAIT This feature is used to enable read-only mode on BGP process restart or when @@ -1334,10 +1251,8 @@ Redistribution Default max-delay is 0, i.e. the feature is off by default. -.. index:: update-delay MAX-DELAY .. clicmd:: update-delay MAX-DELAY -.. index:: update-delay MAX-DELAY ESTABLISH-WAIT .. clicmd:: update-delay MAX-DELAY ESTABLISH-WAIT This feature is used to enable read-only mode on BGP process restart or when @@ -1368,7 +1283,6 @@ Redistribution Default max-delay is 0, i.e. the feature is off by default. -.. index:: table-map ROUTE-MAP-NAME .. clicmd:: table-map ROUTE-MAP-NAME This feature is used to apply a route-map on route updates from BGP to @@ -1390,7 +1304,6 @@ Peers Defining Peers ^^^^^^^^^^^^^^ -.. index:: neighbor PEER remote-as ASN .. clicmd:: neighbor PEER remote-as ASN Creates a new neighbor whose remote-as is ASN. PEER can be an IPv4 address @@ -1408,22 +1321,19 @@ Defining Peers can't find neighbor 10.0.0.1 -.. index:: neighbor PEER remote-as internal .. clicmd:: neighbor PEER remote-as internal Create a peer as you would when you specify an ASN, except that if the peers ASN is different than mine as specified under the :clicmd:`router bgp ASN` command the connection will be denied. -.. index:: neighbor PEER remote-as external .. clicmd:: neighbor PEER remote-as external Create a peer as you would when you specify an ASN, except that if the peers ASN is the same as mine as specified under the :clicmd:`router bgp ASN` command the connection will be denied. -.. index:: bgp listen range <A.B.C.D/M|X:X::X:X/M> peer-group PGNAME -.. clicmd:: [no] bgp listen range <A.B.C.D/M|X:X::X:X/M> peer-group PGNAME +.. clicmd:: bgp listen range <A.B.C.D/M|X:X::X:X/M> peer-group PGNAME Accept connections from any peers in the specified prefix. Configuration from the specified peer-group is used to configure these peers. @@ -1446,8 +1356,7 @@ Defining Peers ``net.core.optmem_max`` to allow the kernel to allocate the necessary option memory. -.. index:: coalesce-time (0-4294967295) -.. clicmd:: [no] coalesce-time (0-4294967295) +.. clicmd:: coalesce-time (0-4294967295) The time in milliseconds that BGP will delay before deciding what peers can be put into an update-group together in order to generate a single @@ -1458,8 +1367,7 @@ Defining Peers Configuring Peers ^^^^^^^^^^^^^^^^^ -.. index:: neighbor PEER shutdown [message MSG...] [rtt (1-65535) [count (1-255)]] -.. clicmd:: [no] neighbor PEER shutdown [message MSG...] [rtt (1-65535) [count (1-255)]] +.. clicmd:: neighbor PEER shutdown [message MSG...] [rtt (1-65535) [count (1-255)]] Shutdown the peer. We can delete the neighbor's configuration by ``no neighbor PEER remote-as ASN`` but all configuration of the neighbor @@ -1474,14 +1382,12 @@ Configuring Peers Additional ``count`` parameter is the number of keepalive messages to count before shutdown the peer if round-trip-time becomes higher than defined. -.. index:: neighbor PEER disable-connected-check -.. clicmd:: [no] neighbor PEER disable-connected-check +.. clicmd:: neighbor PEER disable-connected-check Allow peerings between directly connected eBGP peers using loopback addresses. -.. index:: neighbor PEER ebgp-multihop -.. clicmd:: [no] neighbor PEER ebgp-multihop +.. clicmd:: neighbor PEER ebgp-multihop Specifying ``ebgp-multihop`` allows sessions with eBGP neighbors to establish when they are multiple hops away. When the neighbor is not @@ -1491,13 +1397,11 @@ Configuring Peers If the peer's IP address is not in the RIB and is reachable via the default route, then you have to enable ``ip nht resolve-via-default``. -.. index:: neighbor PEER description ... -.. clicmd:: [no] neighbor PEER description ... +.. clicmd:: neighbor PEER description ... Set description of the peer. -.. index:: neighbor PEER version VERSION -.. clicmd:: [no] neighbor PEER version VERSION +.. clicmd:: neighbor PEER version VERSION Set up the neighbor's BGP version. `version` can be `4`, `4+` or `4-`. BGP version `4` is the default value used for BGP peering. BGP version `4+` @@ -1506,8 +1410,7 @@ Configuring Peers revision 00's Multiprotocol Extensions for BGP-4. Some routing software is still using this version. -.. index:: neighbor PEER interface IFNAME -.. clicmd:: [no] neighbor PEER interface IFNAME +.. clicmd:: neighbor PEER interface IFNAME When you connect to a BGP peer over an IPv6 link-local address, you have to specify the IFNAME of the interface used for the connection. To specify @@ -1517,15 +1420,13 @@ Configuring Peers This command is deprecated and may be removed in a future release. Its use should be avoided. -.. index:: neighbor PEER next-hop-self [all] -.. clicmd:: [no] neighbor PEER next-hop-self [all] +.. clicmd:: neighbor PEER next-hop-self [all] This command specifies an announced route's nexthop as being equivalent to the address of the bgp router if it is learned via eBGP. If the optional keyword `all` is specified the modification is done also for routes learned via iBGP. -.. index:: neighbor PEER attribute-unchanged [{as-path|next-hop|med}] .. clicmd:: neighbor PEER attribute-unchanged [{as-path|next-hop|med}] This command specifies attributes to be left unchanged for advertisements @@ -1533,8 +1434,7 @@ Configuring Peers configurations, as the route-map directive to leave the next-hop unchanged is only available for ipv4. -.. index:: neighbor PEER update-source <IFNAME|ADDRESS> -.. clicmd:: [no] neighbor PEER update-source <IFNAME|ADDRESS> +.. clicmd:: neighbor PEER update-source <IFNAME|ADDRESS> Specify the IPv4 source address to use for the :abbr:`BGP` session to this neighbour, may be specified as either an IPv4 address directly or as an @@ -1548,18 +1448,15 @@ Configuring Peers neighbor bar update-source lo0 -.. index:: neighbor PEER default-originate -.. clicmd:: [no] neighbor PEER default-originate +.. clicmd:: neighbor PEER default-originate *bgpd*'s default is to not announce the default route (0.0.0.0/0) even if it is in routing table. When you want to announce default routes to the peer, use this command. -.. index:: neighbor PEER port PORT .. clicmd:: neighbor PEER port PORT -.. index:: neighbor PEER password PASSWORD -.. clicmd:: [no] neighbor PEER password PASSWORD +.. clicmd:: neighbor PEER password PASSWORD Set a MD5 password to be used with the tcp socket that is being used to connect to the remote peer. Please note if you are using this @@ -1567,16 +1464,13 @@ Configuring Peers modifying the `net.core.optmem_max` sysctl to a larger value to avoid out of memory errors from the linux kernel. -.. index:: neighbor PEER send-community .. clicmd:: neighbor PEER send-community -.. index:: neighbor PEER weight WEIGHT -.. clicmd:: [no] neighbor PEER weight WEIGHT +.. clicmd:: neighbor PEER weight WEIGHT This command specifies a default `weight` value for the neighbor's routes. -.. index:: neighbor PEER maximum-prefix NUMBER [force] -.. clicmd:: [no] neighbor PEER maximum-prefix NUMBER [force] +.. clicmd:: neighbor PEER maximum-prefix NUMBER [force] Sets a maximum number of prefixes we can receive from a given peer. If this number is exceeded, the BGP session will be destroyed. @@ -1593,16 +1487,14 @@ Configuring Peers but you want maximum-prefix to act on ALL (including filtered) prefixes. This option requires `soft-reconfiguration inbound` to be enabled for the peer. -.. index:: neighbor PEER maximum-prefix-out NUMBER -.. clicmd:: [no] neighbor PEER maximum-prefix-out NUMBER +.. clicmd:: neighbor PEER maximum-prefix-out NUMBER Sets a maximum number of prefixes we can send to a given peer. Since sent prefix count is managed by update-groups, this option creates a separate update-group for outgoing updates. -.. index:: neighbor PEER local-as AS-NUMBER [no-prepend] [replace-as] -.. clicmd:: [no] neighbor PEER local-as AS-NUMBER [no-prepend] [replace-as] +.. clicmd:: neighbor PEER local-as AS-NUMBER [no-prepend] [replace-as] Specify an alternate AS for this BGP process when interacting with the specified peer. With no modifiers, the specified local-as is prepended to @@ -1620,8 +1512,7 @@ Configuring Peers This command is only allowed for eBGP peers. -.. index:: neighbor <A.B.C.D|X:X::X:X|WORD> as-override -.. clicmd:: [no] neighbor <A.B.C.D|X:X::X:X|WORD> as-override +.. clicmd:: neighbor <A.B.C.D|X:X::X:X|WORD> as-override Override AS number of the originating router with the local AS number. @@ -1633,8 +1524,7 @@ Configuring Peers This command is only allowed for eBGP peers. -.. index:: neighbor <A.B.C.D|X:X::X:X|WORD> allowas-in [<(1-10)|origin>] -.. clicmd:: [no] neighbor <A.B.C.D|X:X::X:X|WORD> allowas-in [<(1-10)|origin>] +.. clicmd:: neighbor <A.B.C.D|X:X::X:X|WORD> allowas-in [<(1-10)|origin>] Accept incoming routes with AS path containing AS number with the same value as the current system AS. @@ -1651,28 +1541,24 @@ Configuring Peers This command is only allowed for eBGP peers. -.. index:: neighbor <A.B.C.D|X:X::X:X|WORD> addpath-tx-all-paths -.. clicmd:: [no] neighbor <A.B.C.D|X:X::X:X|WORD> addpath-tx-all-paths +.. clicmd:: neighbor <A.B.C.D|X:X::X:X|WORD> addpath-tx-all-paths Configure BGP to send all known paths to neighbor in order to preserve multi path capabilities inside a network. -.. index:: neighbor <A.B.C.D|X:X::X:X|WORD> addpath-tx-bestpath-per-AS -.. clicmd:: [no] neighbor <A.B.C.D|X:X::X:X|WORD> addpath-tx-bestpath-per-AS +.. clicmd:: neighbor <A.B.C.D|X:X::X:X|WORD> addpath-tx-bestpath-per-AS Configure BGP to send best known paths to neighbor in order to preserve multi path capabilities inside a network. -.. index:: neighbor PEER ttl-security hops NUMBER -.. clicmd:: [no] neighbor PEER ttl-security hops NUMBER +.. clicmd:: neighbor PEER ttl-security hops NUMBER This command enforces Generalized TTL Security Mechanism (GTSM), as specified in RFC 5082. With this command, only neighbors that are the specified number of hops away will be allowed to become neighbors. This command is mutually exclusive with *ebgp-multihop*. -.. index:: neighbor PEER capability extended-nexthop -.. clicmd:: [no] neighbor PEER capability extended-nexthop +.. clicmd:: neighbor PEER capability extended-nexthop Allow bgp to negotiate the extended-nexthop capability with it's peer. If you are peering over a v6 LL address then this capability is turned @@ -1680,43 +1566,43 @@ Configuring Peers turning on this command will allow BGP to install v4 routes with v6 nexthops if you do not have v4 configured on interfaces. -.. index:: bgp fast-external-failover -.. clicmd:: [no] bgp fast-external-failover +.. clicmd:: bgp fast-external-failover This command causes bgp to not take down ebgp peers immediately when a link flaps. `bgp fast-external-failover` is the default and will not be displayed as part of a `show run`. The no form of the command turns off this ability. -.. index:: bgp default ipv4-unicast -.. clicmd:: [no] bgp default ipv4-unicast +.. clicmd:: bgp default ipv4-unicast This command allows the user to specify that v4 peering is turned 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. -.. index:: bgp default show-hostname -.. clicmd:: [no] bgp default show-hostname +.. 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 outputs. It's easier to troubleshoot if you have a number of BGP peers. -.. index:: bgp default show-nexthop-hostname -.. clicmd:: [no] bgp default show-nexthop-hostname +.. clicmd:: bgp default show-nexthop-hostname This command shows the hostname of the next-hop in certain BGP commands outputs. It's easier to troubleshoot if you have a number of BGP peers and a number of routes to check. -.. index:: neighbor PEER advertisement-interval (0-600) -.. clicmd:: [no] neighbor PEER advertisement-interval (0-600) +.. clicmd:: neighbor PEER advertisement-interval (0-600) Setup the minimum route advertisement interval(mrai) for the peer in question. This number is between 0 and 600 seconds, with the default advertisement interval being 0. -.. index:: neighbor PEER timers delayopen (1-240) -.. clicmd:: [no] neighbor PEER timers delayopen (1-240) +.. clicmd:: neighbor PEER timers delayopen (1-240) This command allows the user enable the `RFC 4271 <https://tools.ietf.org/html/rfc4271/>` DelayOpenTimer with the @@ -1727,7 +1613,6 @@ Configuring Peers Displaying Information about Peers ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -.. index:: show bgp <afi> <safi> neighbors WORD bestpath-routes [json] [wide] .. clicmd:: show bgp <afi> <safi> neighbors WORD bestpath-routes [json] [wide] For the given neighbor, WORD, that is specified list the routes selected @@ -1738,32 +1623,26 @@ Displaying Information about Peers Peer Filtering ^^^^^^^^^^^^^^ -.. index:: neighbor PEER distribute-list NAME [in|out] .. clicmd:: neighbor PEER distribute-list NAME [in|out] This command specifies a distribute-list for the peer. `direct` is ``in`` or ``out``. -.. index:: neighbor PEER prefix-list NAME [in|out] .. clicmd:: neighbor PEER prefix-list NAME [in|out] -.. index:: neighbor PEER filter-list NAME [in|out] .. clicmd:: neighbor PEER filter-list NAME [in|out] -.. index:: neighbor PEER route-map NAME [in|out] .. clicmd:: neighbor PEER route-map NAME [in|out] Apply a route-map on the neighbor. `direct` must be `in` or `out`. -.. index:: bgp route-reflector allow-outbound-policy .. clicmd:: bgp route-reflector allow-outbound-policy By default, attribute modification via route-map policy out is not reflected on reflected routes. This option allows the modifications to be reflected as well. Once enabled, it affects all reflected routes. -.. index:: neighbor PEER sender-as-path-loop-detection -.. clicmd:: [no] neighbor PEER sender-as-path-loop-detection +.. clicmd:: neighbor PEER sender-as-path-loop-detection Enable the detection of sender side AS path loops and filter the bad routes before they are sent. @@ -1783,31 +1662,93 @@ indicated the originating peer. All peers not associated with a specific peer group are treated as belonging to a default peer group, and will share updates. -.. index:: neighbor WORD peer-group .. clicmd:: neighbor WORD peer-group This command defines a new peer group. -.. index:: neighbor PEER peer-group PGNAME .. clicmd:: neighbor PEER peer-group PGNAME This command bind specific peer to peer group WORD. -.. index:: neighbor PEER solo .. clicmd:: neighbor PEER solo This command is used to indicate that routes advertised by the peer should not be reflected back to the peer. This command only is only meaningful when there is a single peer defined in the peer-group. +.. clicmd:: show [ip] bgp peer-group [json] + + This command displays configured BGP peer-groups. + + .. code-block:: frr + + exit1-debian-9# show bgp peer-group + + BGP peer-group test1, remote AS 65001 + Peer-group type is external + Configured address-families: IPv4 Unicast; IPv6 Unicast; + 1 IPv4 listen range(s) + 192.168.100.0/24 + 2 IPv6 listen range(s) + 2001:db8:1::/64 + 2001:db8:2::/64 + Peer-group members: + 192.168.200.1 Active + 2001:db8::1 Active + + BGP peer-group test2 + Peer-group type is external + Configured address-families: IPv4 Unicast; + + Optional ``json`` parameter is used to display JSON output. + + .. code-block:: frr + + { + "test1":{ + "remoteAs":65001, + "type":"external", + "addressFamiliesConfigured":[ + "IPv4 Unicast", + "IPv6 Unicast" + ], + "dynamicRanges":{ + "IPv4":{ + "count":1, + "ranges":[ + "192.168.100.0\/24" + ] + }, + "IPv6":{ + "count":2, + "ranges":[ + "2001:db8:1::\/64", + "2001:db8:2::\/64" + ] + } + }, + "members":{ + "192.168.200.1":{ + "status":"Active" + }, + "2001:db8::1":{ + "status":"Active" + } + } + }, + "test2":{ + "type":"external", + "addressFamiliesConfigured":[ + "IPv4 Unicast" + ] + } + } + Capability Negotiation ^^^^^^^^^^^^^^^^^^^^^^ -.. index:: neighbor PEER strict-capability-match .. clicmd:: neighbor PEER strict-capability-match -.. index:: neighbor PEER strict-capability-match -.. clicmd:: no neighbor PEER strict-capability-match Strictly compares remote capabilities and local capabilities. If capabilities are different, send Unsupported Capability error then reset @@ -1818,8 +1759,7 @@ Capability Negotiation Negotiation. Please use *dont-capability-negotiate* command to disable the feature. -.. index:: neighbor PEER dont-capability-negotiate -.. clicmd:: [no] neighbor PEER dont-capability-negotiate +.. clicmd:: neighbor PEER dont-capability-negotiate Suppress sending Capability Negotiation as OPEN message optional parameter to the peer. This command only affects the peer is configured other than @@ -1839,11 +1779,8 @@ Capability Negotiation hostname support, AS4, Addpath, Route Refresh, ORF, Dynamic Capabilities, and graceful restart. -.. index:: neighbor PEER override-capability .. clicmd:: neighbor PEER override-capability -.. index:: neighbor PEER override-capability -.. clicmd:: no neighbor PEER override-capability Override the result of Capability Negotiation with local configuration. Ignore remote peer's capability value. @@ -1855,16 +1792,11 @@ AS Path Access Lists AS path access list is user defined AS path. -.. index:: bgp as-path access-list WORD permit|deny LINE -.. clicmd:: bgp as-path access-list WORD permit|deny LINE +.. clicmd:: bgp as-path access-list WORD [seq (0-4294967295)] permit|deny LINE This command defines a new AS path access list. -.. index:: bgp as-path access-list WORD -.. clicmd:: no bgp as-path access-list WORD -.. index:: bgp as-path access-list WORD permit|deny LINE -.. clicmd:: no bgp as-path access-list WORD permit|deny LINE .. _bgp-bogon-filter-example: @@ -1876,27 +1808,25 @@ Bogon ASN filter policy configuration example bgp as-path access-list 99 permit _0_ bgp as-path access-list 99 permit _23456_ bgp as-path access-list 99 permit _1310[0-6][0-9]_|_13107[0-1]_ + bgp as-path access-list 99 seq 20 permit ^65 .. _bgp-using-as-path-in-route-map: Using AS Path in Route Map -------------------------- -.. index:: match as-path WORD -.. clicmd:: [no] match as-path WORD +.. clicmd:: match as-path WORD For a given as-path, WORD, match it on the BGP as-path given for the prefix and if it matches do normal route-map actions. The no form of the command removes this match from the route-map. -.. index:: set as-path prepend AS-PATH -.. clicmd:: [no] set as-path prepend AS-PATH +.. clicmd:: set as-path prepend AS-PATH Prepend the given string of AS numbers to the AS_PATH of the BGP path's NLRI. The no form of this command removes this set operation from the route-map. -.. index:: set as-path prepend last-as NUM -.. clicmd:: [no] set as-path prepend last-as NUM +.. clicmd:: set as-path prepend last-as NUM Prepend the existing last AS number (the leftmost ASN) to the AS_PATH. The no form of this command removes this set operation from the route-map. @@ -2042,7 +1972,6 @@ expanded interpreted on each use expanded community lists are slower than standard lists. -.. index:: bgp community-list standard NAME permit|deny COMMUNITY .. clicmd:: bgp community-list standard NAME permit|deny COMMUNITY This command defines a new standard community list. ``COMMUNITY`` is @@ -2053,7 +1982,6 @@ expanded community list definition. When there is no matched entry, deny will be returned. When ``COMMUNITY`` is empty it matches to any routes. -.. index:: bgp community-list expanded NAME permit|deny COMMUNITY .. clicmd:: bgp community-list expanded NAME permit|deny COMMUNITY This command defines a new expanded community list. ``COMMUNITY`` is a @@ -2065,7 +1993,6 @@ expanded .. deprecated:: 5.0 It is recommended to use the more explicit versions of this command. -.. index:: bgp community-list NAME permit|deny COMMUNITY .. clicmd:: bgp community-list NAME permit|deny COMMUNITY When the community list type is not specified, the community list type is @@ -2074,15 +2001,10 @@ expanded Otherwise it is defined as an expanded community list. This feature is left for backward compatibility. Use of this feature is not recommended. + Note that all community lists share the same namespace, so it's not + necessary to specify ``standard`` or ``expanded``; these modifiers are + purely aesthetic. -.. index:: bgp community-list [standard|expanded] NAME -.. clicmd:: no bgp community-list [standard|expanded] NAME - - Deletes the community list specified by ``NAME``. All community lists share - the same namespace, so it's not necessary to specify ``standard`` or - ``expanded``; these modifiers are purely aesthetic. - -.. index:: show bgp community-list [NAME detail] .. clicmd:: show bgp community-list [NAME detail] Displays community list information. When ``NAME`` is specified the @@ -2115,13 +2037,11 @@ to 199 is expanded community list. These community lists are called as numbered community lists. On the other hand normal community lists is called as named community lists. -.. index:: bgp community-list (1-99) permit|deny COMMUNITY .. clicmd:: bgp community-list (1-99) permit|deny COMMUNITY This command defines a new community list. The argument to (1-99) defines the list identifier. -.. index:: bgp community-list (100-199) permit|deny COMMUNITY .. clicmd:: bgp community-list (100-199) permit|deny COMMUNITY This command defines a new expanded community list. The argument to @@ -2138,7 +2058,6 @@ communities attribute. The following commands can be used in route maps: -.. index:: match community WORD exact-match [exact-match] .. clicmd:: match community WORD exact-match [exact-match] This command perform match to BGP updates using community list WORD. When @@ -2147,7 +2066,6 @@ The following commands can be used in route maps: happen only when BGP updates have completely same communities value specified in the community list. -.. index:: set community <none|COMMUNITY> additive .. clicmd:: set community <none|COMMUNITY> additive This command sets the community value in BGP updates. If the attribute is @@ -2160,7 +2078,6 @@ The following commands can be used in route maps: It is not possible to set an expanded community list. -.. index:: set comm-list WORD delete .. clicmd:: set comm-list WORD delete This command remove communities value from BGP communities attribute. The @@ -2337,7 +2254,6 @@ the other is IP address based format. Extended Community Lists ^^^^^^^^^^^^^^^^^^^^^^^^ -.. index:: bgp extcommunity-list standard NAME permit|deny EXTCOMMUNITY .. clicmd:: bgp extcommunity-list standard NAME permit|deny EXTCOMMUNITY This command defines a new standard extcommunity-list. `extcommunity` is @@ -2349,7 +2265,6 @@ Extended Community Lists there is no matched entry, deny will be returned. When `extcommunity` is empty it matches to any routes. -.. index:: bgp extcommunity-list expanded NAME permit|deny LINE .. clicmd:: bgp extcommunity-list expanded NAME permit|deny LINE This command defines a new expanded extcommunity-list. `line` is a string @@ -2357,29 +2272,13 @@ Extended Community Lists expression (:ref:`bgp-regular-expressions`) to match an extended communities attribute in BGP updates. -.. index:: bgp extcommunity-list NAME -.. clicmd:: no bgp extcommunity-list NAME + Note that all extended community lists shares a single name space, so it's + not necessary to specify their type when creating or destroying them. -.. index:: bgp extcommunity-list standard NAME -.. clicmd:: no bgp extcommunity-list standard NAME - -.. index:: bgp extcommunity-list expanded NAME -.. clicmd:: no bgp extcommunity-list expanded NAME - - These commands delete extended community lists specified by `name`. All of - extended community lists shares a single name space. So extended community - lists can be removed simply specifying the name. - -.. index:: show bgp extcommunity-list -.. clicmd:: show bgp extcommunity-list - -.. index:: show bgp extcommunity-list NAME detail -.. clicmd:: show bgp extcommunity-list NAME detail +.. clicmd:: show bgp extcommunity-list [NAME detail] This command displays current extcommunity-list information. When `name` is - specified the community list's information is shown.:: - - # show bgp extcommunity-list + specified the community list's information is shown. .. _bgp-extended-communities-in-route-map: @@ -2387,20 +2286,16 @@ Extended Community Lists BGP Extended Communities in Route Map """"""""""""""""""""""""""""""""""""" -.. index:: match extcommunity WORD .. clicmd:: match extcommunity WORD -.. index:: set extcommunity rt EXTCOMMUNITY .. clicmd:: set extcommunity rt EXTCOMMUNITY This command set Route Target value. -.. index:: set extcommunity soo EXTCOMMUNITY .. clicmd:: set extcommunity soo EXTCOMMUNITY This command set Site of Origin value. -.. index:: set extcommunity bandwidth <(1-25600) | cumulative | num-multipaths> [non-transitive] .. clicmd:: set extcommunity bandwidth <(1-25600) | cumulative | num-multipaths> [non-transitive] This command sets the BGP link-bandwidth extended community for the prefix @@ -2452,7 +2347,6 @@ Large Community Lists Two types of large community lists are supported, namely `standard` and `expanded`. -.. index:: bgp large-community-list standard NAME permit|deny LARGE-COMMUNITY .. clicmd:: bgp large-community-list standard NAME permit|deny LARGE-COMMUNITY This command defines a new standard large-community-list. `large-community` @@ -2463,7 +2357,6 @@ Two types of large community lists are supported, namely `standard` and definition. When there is no matched entry, a deny will be returned. When `large-community` is empty it matches any routes. -.. index:: bgp large-community-list expanded NAME permit|deny LINE .. clicmd:: bgp large-community-list expanded NAME permit|deny LINE This command defines a new expanded large-community-list. Where `line` is a @@ -2472,29 +2365,17 @@ Two types of large community lists are supported, namely `standard` and lowest to highest. `line` can also be a regular expression which matches this Large Community attribute. -.. index:: bgp large-community-list NAME -.. clicmd:: no bgp large-community-list NAME - -.. index:: bgp large-community-list standard NAME -.. clicmd:: no bgp large-community-list standard NAME + Note that all community lists share the same namespace, so it's not + necessary to specify ``standard`` or ``expanded``; these modifiers are + purely aesthetic. -.. index:: bgp large-community-list expanded NAME -.. clicmd:: no bgp large-community-list expanded NAME - - These commands delete Large Community lists specified by `name`. All Large - Community lists share a single namespace. This means Large Community lists - can be removed by simply specifying the name. - -.. index:: show bgp large-community-list .. clicmd:: show bgp large-community-list -.. index:: show bgp large-community-list NAME detail .. clicmd:: show bgp large-community-list NAME detail This command display current large-community-list information. When `name` is specified the community list information is shown. -.. index:: show ip bgp large-community-info .. clicmd:: show ip bgp large-community-info This command displays the current large communities in use. @@ -2504,7 +2385,6 @@ Two types of large community lists are supported, namely `standard` and Large Communities in Route Map """""""""""""""""""""""""""""" -.. index:: match large-community LINE [exact-match] .. clicmd:: match large-community LINE [exact-match] Where `line` can be a simple string to match, or a regular expression. It @@ -2514,13 +2394,10 @@ Large Communities in Route Map happen only when BGP updates have completely same large communities value specified in the large community list. -.. index:: set large-community LARGE-COMMUNITY .. clicmd:: set large-community LARGE-COMMUNITY -.. index:: set large-community LARGE-COMMUNITY LARGE-COMMUNITY .. clicmd:: set large-community LARGE-COMMUNITY LARGE-COMMUNITY -.. index:: set large-community LARGE-COMMUNITY additive .. clicmd:: set large-community LARGE-COMMUNITY additive These commands are used for setting large-community values. The first @@ -2602,18 +2479,11 @@ Configuration of route leaking between a unicast VRF RIB and the VPN SAFI RIB of the default VRF is accomplished via commands in the context of a VRF address-family: -.. index:: rd vpn export AS:NN|IP:nn .. clicmd:: rd vpn export AS:NN|IP:nn Specifies the route distinguisher to be added to a route exported from the current unicast VRF to VPN. -.. index:: rd vpn export [AS:NN|IP:nn] -.. clicmd:: no rd vpn export [AS:NN|IP:nn] - - Deletes any previously-configured export route distinguisher. - -.. index:: rt vpn import|export|both RTLIST... .. clicmd:: rt vpn import|export|both RTLIST... Specifies the route-target list to be attached to a route (export) or the @@ -2624,12 +2494,6 @@ address-family: extended community values as described in :ref:`bgp-extended-communities-attribute`. -.. index:: rt vpn import|export|both [RTLIST...] -.. clicmd:: no rt vpn import|export|both [RTLIST...] - - Deletes any previously-configured import or export route-target list. - -.. index:: label vpn export (0..1048575)|auto .. clicmd:: label vpn export (0..1048575)|auto Enables an MPLS label to be attached to a route exported from the current @@ -2638,45 +2502,21 @@ address-family: is not running, or if this command is not configured, automatic label assignment will not complete, which will block corresponding route export. -.. index:: label vpn export [(0..1048575)|auto] -.. clicmd:: no label vpn export [(0..1048575)|auto] - - Deletes any previously-configured export label. - -.. index:: nexthop vpn export A.B.C.D|X:X::X:X .. clicmd:: nexthop vpn export A.B.C.D|X:X::X:X Specifies an optional nexthop value to be assigned to a route exported from the current unicast VRF to VPN. If left unspecified, the nexthop will be set to 0.0.0.0 or 0:0::0:0 (self). -.. index:: nexthop vpn export [A.B.C.D|X:X::X:X] -.. clicmd:: no nexthop vpn export [A.B.C.D|X:X::X:X] - - Deletes any previously-configured export nexthop. - -.. index:: route-map vpn import|export MAP .. clicmd:: route-map vpn import|export MAP Specifies an optional route-map to be applied to routes imported or exported between the current unicast VRF and VPN. -.. index:: route-map vpn import|export [MAP] -.. clicmd:: no route-map vpn import|export [MAP] - - Deletes any previously-configured import or export route-map. - -.. index:: import|export vpn .. clicmd:: import|export vpn Enables import or export of routes between the current unicast VRF and VPN. -.. index:: import|export vpn -.. clicmd:: no import|export vpn - - Disables import or export of routes between the current unicast VRF and VPN. - -.. index:: import vrf VRFNAME .. clicmd:: import vrf VRFNAME Shortcut syntax for specifying automatic leaking from vrf VRFNAME to @@ -2689,12 +2529,6 @@ address-family: The CLI will disallow attempts to configure incompatible leaking modes. -.. index:: import vrf VRFNAME -.. clicmd:: no import vrf VRFNAME - - Disables automatic leaking from vrf VRFNAME to the current VRF using - the VPN RIB as intermediary. - .. _bgp-evpn: @@ -2745,8 +2579,7 @@ disable the feature via configuration CLI. Once the feature is disable under bgp vrf instance or MAC-VLAN interface is not configured, all the routes follow the same behavior of using same next-hop and RMAC values. -.. index:: advertise-pip [ip <addr> [mac <addr>]] -.. clicmd:: [no] advertise-pip [ip <addr> [mac <addr>]] +.. clicmd:: advertise-pip [ip <addr> [mac <addr>]] Enables or disables advertise-pip feature, specifiy system-IP and/or system-MAC parameters. @@ -2763,11 +2596,9 @@ Ethernet Segments An Ethernet Segment can be configured by specifying a system-MAC and a local discriminatior against the bond interface on the PE (via zebra) - -.. index:: evpn mh es-id (1-16777215) -.. clicmd:: [no] evpn mh es-id (1-16777215) +.. clicmd:: evpn mh es-id (1-16777215) -.. index:: evpn mh es-sys-mac X:X:X:X:X:X -.. clicmd:: [no] evpn mh es-sys-mac X:X:X:X:X:X +.. clicmd:: evpn mh es-sys-mac X:X:X:X:X:X The sys-mac and local discriminator are used for generating a 10-byte, Type-3 Ethernet Segment ID. @@ -2790,8 +2621,7 @@ forward BUM traffic received via the overlay network. This implementation uses a preference based DF election specified by draft-ietf-bess-evpn-pref-df. The DF preference is configurable per-ES (via zebra) - -.. index:: evpn mh es-df-pref (1-16777215) -.. clicmd:: [no] evpn mh es-df-pref (1-16777215) +.. clicmd:: evpn mh es-df-pref (1-16777215) BUM traffic is rxed via the overlay by all PEs attached to a server but only the DF can forward the de-capsulated traffic to the access port. To @@ -2809,11 +2639,9 @@ ES-PE based on just the EAD-per-ES route. Note that by default we advertise and expect EAD-per-EVI routes. -.. index:: disable-ead-evi-rx -.. clicmd:: [no] disable-ead-evi-rx +.. clicmd:: disable-ead-evi-rx -.. index:: disable-ead-evi-tx -.. clicmd:: [no] disable-ead-evi-tx +.. clicmd:: disable-ead-evi-tx Fast failover """"""""""""" @@ -2827,15 +2655,13 @@ been introduced for the express purpose of efficient ES failovers. On dataplanes that support layer3 nexthop groups the feature can be turned on via the following BGP config - -.. index:: use-es-l3nhg -.. clicmd:: [no] use-es-l3nhg +.. clicmd:: use-es-l3nhg - Local ES (MAC/Neigh) failover via ES-redirect. On dataplanes that do not have support for ES-redirect the feature can be turned off via the following zebra config - -.. index:: evpn mh redirect-off -.. clicmd:: [no] evpn mh redirect-off +.. clicmd:: evpn mh redirect-off Uplink/Core tracking """""""""""""""""""" @@ -2844,8 +2670,7 @@ When all the underlay links go down the PE no longer has access to the VxLAN protodowned on the PE. A link can be setup for uplink tracking via the following zebra configuration - -.. index:: evpn mh uplink -.. clicmd:: [no] evpn mh uplink +.. clicmd:: evpn mh uplink Proxy advertisements """""""""""""""""""" @@ -2856,11 +2681,9 @@ the ES peer (PE2) goes down PE1 continues to advertise hosts learnt from PE2 for a holdtime during which it attempts to establish local reachability of the host. This holdtime is configurable via the following zebra commands - -.. index:: evpn mh neigh-holdtime (0-86400) -.. clicmd:: [no] evpn mh neigh-holdtime (0-86400) +.. clicmd:: evpn mh neigh-holdtime (0-86400) -.. index:: evpn mh mac-holdtime (0-86400) -.. clicmd:: [no] evpn mh mac-holdtime (0-86400) +.. clicmd:: evpn mh mac-holdtime (0-86400) Startup delay """"""""""""" @@ -2869,8 +2692,7 @@ and EVPN network to converge before enabling the ESs. For this duration the ES bonds are held protodown. The startup delay is configurable via the following zebra command - -.. index:: evpn mh startup-delay (0-3600) -.. clicmd:: [no] evpn mh startup-delay (0-3600) +.. clicmd:: evpn mh startup-delay (0-3600) +Support with VRF network namespace backend +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -2928,8 +2750,7 @@ advertisement to take effect is 60 seconds. The conditional advertisement can ta effect depending on when the tracked route is removed from the BGP table and when the next instance of the BGP scanner occurs. -.. index:: neighbor A.B.C.D advertise-map NAME [exist-map|non-exist-map] NAME -.. clicmd:: [no] neighbor A.B.C.D advertise-map NAME [exist-map|non-exist-map] NAME +.. clicmd:: neighbor A.B.C.D advertise-map NAME [exist-map|non-exist-map] NAME This command enables BGP scanner process to monitor routes specified by exist-map or non-exist-map command in BGP table and conditionally advertises @@ -3086,70 +2907,63 @@ When default route is not present in R2'2 BGP table, 10.139.224.0/20 and 192.0.2 Debugging --------- -.. index:: show debug .. clicmd:: show debug Show all enabled debugs. -.. index:: show bgp listeners .. clicmd:: show bgp listeners 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. -.. index:: debug bgp neighbor-events -.. clicmd:: [no] debug bgp neighbor-events +.. 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 information on BGP events such as peer connection / disconnection, session establishment / teardown, and capability negotiation. -.. index:: debug bgp updates -.. clicmd:: [no] debug bgp updates +.. clicmd:: debug bgp updates Enable or disable debugging for BGP updates. This provides information on BGP UPDATE messages transmitted and received between local and remote instances. -.. index:: debug bgp keepalives -.. clicmd:: [no] debug bgp keepalives +.. clicmd:: debug bgp keepalives Enable or disable debugging for BGP keepalives. This provides information on BGP KEEPALIVE messages transmitted and received between local and remote instances. -.. index:: debug bgp bestpath <A.B.C.D/M|X:X::X:X/M> -.. clicmd:: [no] debug bgp bestpath <A.B.C.D/M|X:X::X:X/M> +.. clicmd:: debug bgp bestpath <A.B.C.D/M|X:X::X:X/M> Enable or disable debugging for bestpath selection on the specified prefix. -.. index:: debug bgp nht -.. clicmd:: [no] debug bgp nht +.. clicmd:: debug bgp nht Enable or disable debugging of BGP nexthop tracking. -.. index:: debug bgp update-groups -.. clicmd:: [no] debug bgp update-groups +.. clicmd:: debug bgp update-groups Enable or disable debugging of dynamic update groups. This provides general information on group creation, deletion, join and prune events. -.. index:: debug bgp zebra -.. clicmd:: [no] debug bgp zebra +.. clicmd:: debug bgp zebra Enable or disable debugging of communications between *bgpd* and *zebra*. Dumping Messages and Routing Tables ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -.. index:: dump bgp all PATH [INTERVAL] .. clicmd:: dump bgp all PATH [INTERVAL] -.. index:: dump bgp all-et PATH [INTERVAL] .. clicmd:: dump bgp all-et PATH [INTERVAL] -.. index:: dump bgp all [PATH] [INTERVAL] -.. clicmd:: no dump bgp all [PATH] [INTERVAL] Dump all BGP packet and events to `path` file. If `interval` is set, a new file will be created for echo `interval` of @@ -3157,14 +2971,10 @@ Dumping Messages and Routing Tables (strftime). The type ‘all-et’ enables support for Extended Timestamp Header (:ref:`packet-binary-dump-format`). -.. index:: dump bgp updates PATH [INTERVAL] .. clicmd:: dump bgp updates PATH [INTERVAL] -.. index:: dump bgp updates-et PATH [INTERVAL] .. clicmd:: dump bgp updates-et PATH [INTERVAL] -.. index:: dump bgp updates [PATH] [INTERVAL] -.. clicmd:: no dump bgp updates [PATH] [INTERVAL] Dump only BGP updates messages to `path` file. If `interval` is set, a new file will be created for echo `interval` of @@ -3172,14 +2982,10 @@ Dumping Messages and Routing Tables (strftime). The type ‘updates-et’ enables support for Extended Timestamp Header (:ref:`packet-binary-dump-format`). -.. index:: dump bgp routes-mrt PATH .. clicmd:: dump bgp routes-mrt PATH -.. index:: dump bgp routes-mrt PATH INTERVAL .. clicmd:: dump bgp routes-mrt PATH INTERVAL -.. index:: dump bgp route-mrt [PATH] [INTERVAL] -.. clicmd:: no dump bgp route-mrt [PATH] [INTERVAL] Dump whole BGP routing table to `path`. This is heavy process. The path `path` can be set with date and time formatting (strftime). If `interval` is @@ -3195,44 +3001,36 @@ Other BGP Commands The following are available in the top level *enable* mode: -.. index:: clear bgp \* .. clicmd:: clear bgp \* Clear all peers. -.. index:: clear bgp ipv4|ipv6 \* .. clicmd:: clear bgp ipv4|ipv6 \* Clear all peers with this address-family activated. -.. index:: clear bgp ipv4|ipv6 unicast \* .. clicmd:: clear bgp ipv4|ipv6 unicast \* Clear all peers with this address-family and sub-address-family activated. -.. index:: clear bgp ipv4|ipv6 PEER .. clicmd:: clear bgp ipv4|ipv6 PEER Clear peers with address of X.X.X.X and this address-family activated. -.. index:: clear bgp ipv4|ipv6 unicast PEER .. clicmd:: clear bgp ipv4|ipv6 unicast PEER Clear peer with address of X.X.X.X and this address-family and sub-address-family activated. -.. index:: clear bgp ipv4|ipv6 PEER soft|in|out .. clicmd:: clear bgp ipv4|ipv6 PEER soft|in|out Clear peer using soft reconfiguration in this address-family. -.. index:: clear bgp ipv4|ipv6 unicast PEER soft|in|out .. clicmd:: clear bgp ipv4|ipv6 unicast PEER soft|in|out Clear peer using soft reconfiguration in this address-family and sub-address-family. The following are available in the ``router bgp`` mode: -.. index:: write-quanta (1-64) .. clicmd:: write-quanta (1-64) BGP message Tx I/O is vectored. This means that multiple packets are written @@ -3242,7 +3040,6 @@ The following are available in the ``router bgp`` mode: less 'bursty'. In practice, leave this settings on the default (64) unless you truly know what you are doing. -.. index:: read-quanta (1-10) .. clicmd:: read-quanta (1-10) Unlike Tx, BGP Rx traffic is not vectored. Packets are read off the wire one @@ -3252,7 +3049,6 @@ The following are available in the ``router bgp`` mode: The following command is available in ``config`` mode as well as in the ``router bgp`` mode: -.. index:: bgp graceful-shutdown .. clicmd:: bgp graceful-shutdown The purpose of this command is to initiate BGP Graceful Shutdown which @@ -3287,16 +3083,12 @@ daemon project, while :clicmd:`show bgp` command is the new format. The choice has been done to keep old format with IPv4 routing table, while new format displays IPv6 routing table. -.. index:: show ip bgp [all] [wide|json] .. clicmd:: show ip bgp [all] [wide|json] -.. index:: show ip bgp A.B.C.D [json] .. clicmd:: show ip bgp A.B.C.D [json] -.. index:: show bgp [all] [wide|json] .. clicmd:: show bgp [all] [wide|json] -.. index:: show bgp X:X::X:X [json] .. clicmd:: show bgp X:X::X:X [json] These commands display BGP routes. When no route is specified, the default @@ -3326,13 +3118,11 @@ displays IPv6 routing table. Some other commands provide additional options for filtering the output. -.. index:: show [ip] bgp regexp LINE .. clicmd:: show [ip] bgp regexp LINE This command displays BGP routes using AS path regular expression (:ref:`bgp-regular-expressions`). -.. index:: show [ip] bgp [all] summary [wide] [json] .. clicmd:: show [ip] bgp [all] summary [wide] [json] Show a bgp peer summary for the specified address family. @@ -3361,10 +3151,8 @@ structure is extended with :clicmd:`show bgp [afi] [safi]`. Total number of neighbors 1 exit1# -.. index:: show bgp [afi] [safi] [all] [wide|json] .. clicmd:: show bgp [afi] [safi] [all] [wide|json] -.. index:: show bgp <ipv4|ipv6> <unicast|multicast|vpn|labeled-unicast> .. clicmd:: show bgp <ipv4|ipv6> <unicast|multicast|vpn|labeled-unicast> These commands display BGP routes for the specific routing table indicated by @@ -3373,62 +3161,51 @@ structure is extended with :clicmd:`show bgp [afi] [safi]`. For EVPN prefixes, you can display the full BGP table for this AFI/SAFI using the standard `show bgp [afi] [safi]` syntax. -.. index:: show bgp l2vpn evpn route [type <macip|2|multicast|3|es|4|prefix|5>] .. 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. -.. index:: show bgp [afi] [safi] [all] summary [json] .. clicmd:: show bgp [afi] [safi] [all] summary [json] Show a bgp peer summary for the specified address family, and subsequent address-family. -.. index:: show bgp [afi] [safi] [all] summary failed [json] .. clicmd:: show bgp [afi] [safi] [all] summary failed [json] Show a bgp peer summary for peers that are not succesfully exchanging routes for the specified address family, and subsequent address-family. -.. index:: show bgp [afi] [safi] [all] summary established [json] .. clicmd:: show bgp [afi] [safi] [all] summary established [json] Show a bgp peer summary for peers that are succesfully exchanging routes for the specified address family, and subsequent address-family. -.. index:: show bgp [afi] [safi] neighbor [PEER] .. clicmd:: show bgp [afi] [safi] neighbor [PEER] This command shows information on a specific BGP peer of the relevant afi and safi selected. -.. index:: show bgp [afi] [safi] [all] dampening dampened-paths [wide|json] .. clicmd:: show bgp [afi] [safi] [all] dampening dampened-paths [wide|json] Display paths suppressed due to dampening of the selected afi and safi selected. -.. index:: show bgp [afi] [safi] [all] dampening flap-statistics [wide|json] .. clicmd:: show bgp [afi] [safi] [all] dampening flap-statistics [wide|json] Display flap statistics of routes of the selected afi and safi selected. -.. index:: show bgp [afi] [safi] statistics .. clicmd:: show bgp [afi] [safi] statistics Display statistics of routes of the selected afi and safi. -.. index:: show bgp statistics-all .. clicmd:: show bgp statistics-all Display statistics of routes of all the afi and safi. -.. index:: show [ip] bgp [afi] [safi] [all] cidr-only [wide|json] .. clicmd:: show [ip] bgp [afi] [safi] [all] cidr-only [wide|json] Display routes with non-natural netmasks. -.. index:: show [ip] bgp [afi] [safi] [all] neighbors A.B.C.D [advertised-routes|received-routes|filtered-routes] [json|wide] .. clicmd:: show [ip] bgp [afi] [safi] [all] neighbors A.B.C.D [advertised-routes|received-routes|filtered-routes] [json|wide] Display the routes advertised to a BGP neighbor or received routes @@ -3456,13 +3233,10 @@ Displaying Routes by Community Attribute The following commands allow displaying routes based on their community attribute. -.. index:: show [ip] bgp <ipv4|ipv6> [all] community [wide|json] .. clicmd:: show [ip] bgp <ipv4|ipv6> [all] community [wide|json] -.. index:: show [ip] bgp <ipv4|ipv6> [all] community COMMUNITY [wide|json] .. clicmd:: show [ip] bgp <ipv4|ipv6> [all] community COMMUNITY [wide|json] -.. index:: show [ip] bgp <ipv4|ipv6> [all] community COMMUNITY exact-match [wide|json] .. clicmd:: show [ip] bgp <ipv4|ipv6> [all] community COMMUNITY exact-match [wide|json] These commands display BGP routes which have the community attribute. @@ -3470,10 +3244,8 @@ attribute. community are displayed. When `exact-match` is specified, it display only routes that have an exact match. -.. index:: show [ip] bgp <ipv4|ipv6> community-list WORD .. clicmd:: show [ip] bgp <ipv4|ipv6> community-list WORD -.. index:: show [ip] bgp <ipv4|ipv6> community-list WORD exact-match .. clicmd:: show [ip] bgp <ipv4|ipv6> community-list WORD exact-match These commands display BGP routes for the address family specified that @@ -3493,7 +3265,6 @@ attribute. If ``json`` option is specified, output is displayed in JSON format. -.. index:: show bgp labelpool <chunks|inuse|ledger|requests|summary> [json] .. clicmd:: show bgp labelpool <chunks|inuse|ledger|requests|summary> [json] These commands display information about the BGP labelpool used for @@ -3527,16 +3298,12 @@ Displaying Routes by Large Community Attribute The following commands allow displaying routes based on their large community attribute. -.. index:: show [ip] bgp <ipv4|ipv6> large-community .. clicmd:: show [ip] bgp <ipv4|ipv6> large-community -.. index:: show [ip] bgp <ipv4|ipv6> large-community LARGE-COMMUNITY .. clicmd:: show [ip] bgp <ipv4|ipv6> large-community LARGE-COMMUNITY -.. index:: show [ip] bgp <ipv4|ipv6> large-community LARGE-COMMUNITY exact-match .. clicmd:: show [ip] bgp <ipv4|ipv6> large-community LARGE-COMMUNITY exact-match -.. index:: show [ip] bgp <ipv4|ipv6> large-community LARGE-COMMUNITY json .. clicmd:: show [ip] bgp <ipv4|ipv6> large-community LARGE-COMMUNITY json These commands display BGP routes which have the large community attribute. @@ -3545,13 +3312,10 @@ large community attribute. only routes that have an exact match. When `json` is specified, it display routes in json format. -.. index:: show [ip] bgp <ipv4|ipv6> large-community-list WORD .. clicmd:: show [ip] bgp <ipv4|ipv6> large-community-list WORD -.. index:: show [ip] bgp <ipv4|ipv6> large-community-list WORD exact-match .. clicmd:: show [ip] bgp <ipv4|ipv6> large-community-list WORD exact-match -.. index:: show [ip] bgp <ipv4|ipv6> large-community-list WORD json .. clicmd:: show [ip] bgp <ipv4|ipv6> large-community-list WORD json These commands display BGP routes for the address family specified that @@ -3565,24 +3329,19 @@ large community attribute. Displaying Routes by AS Path ---------------------------- -.. index:: show bgp ipv4|ipv6 regexp LINE .. clicmd:: show bgp ipv4|ipv6 regexp LINE This commands displays BGP routes that matches a regular expression `line` (:ref:`bgp-regular-expressions`). -.. index:: show [ip] bgp ipv4 vpn .. clicmd:: show [ip] bgp ipv4 vpn -.. index:: show [ip] bgp ipv6 vpn .. clicmd:: show [ip] bgp ipv6 vpn Print active IPV4 or IPV6 routes advertised via the VPN SAFI. -.. index:: show bgp ipv4 vpn summary .. clicmd:: show bgp ipv4 vpn summary -.. index:: show bgp ipv6 vpn summary .. clicmd:: show bgp ipv6 vpn summary Print a summary of neighbor connections for the specified AFI/SAFI combination. @@ -3590,7 +3349,6 @@ Displaying Routes by AS Path Displaying Update Group Information ----------------------------------- -.. index:: show bgp update-groups SUBGROUP-ID [advertise-queue|advertised-routes|packet-queue] .. clicmd:: show bgp update-groups [advertise-queue|advertised-routes|packet-queue] Display Information about each individual update-group being used. @@ -3600,7 +3358,6 @@ Displaying Update Group Information the list of routes we have sent to the peers in the update-group and packet-queue specifies the list of packets in the queue to be sent. -.. index:: show bgp update-groups statistics .. clicmd:: show bgp update-groups statistics Display Information about update-group events in FRR. @@ -3620,22 +3377,17 @@ When route reflectors are configured, these will reflect the routes announced by the peers configured as clients. A route reflector client is configured with: -.. index:: neighbor PEER route-reflector-client .. clicmd:: neighbor PEER route-reflector-client -.. index:: neighbor PEER route-reflector-client -.. clicmd:: no neighbor PEER route-reflector-client To avoid single points of failure, multiple route reflectors can be configured. A cluster is a collection of route reflectors and their clients, and is used by route reflectors to avoid looping. -.. index:: bgp cluster-id A.B.C.D .. clicmd:: bgp cluster-id A.B.C.D -.. index:: bgp no-rib -.. clicmd:: [no] bgp no-rib +.. clicmd:: bgp no-rib To set and unset the BGP daemon ``-n`` / ``--no_kernel`` options during runtime to disable BGP route installation to the RIB (Zebra), the ``[no] bgp no-rib`` @@ -3648,8 +3400,7 @@ starting the daemon and the configuration gets saved, the option will persist unless removed from the configuration with the negating command prior to the configuration write operation. -.. index:: bgp send-extra-data zebra -.. clicmd:: [no] bgp send-extra-data zebra +.. clicmd:: bgp send-extra-data zebra This Command turns off the ability of BGP to send extra data to zebra. In this case it's the AS-Path being used for the path. The default behavior @@ -3698,8 +3449,7 @@ status in FIB: 7. If the route which is already installed in dataplane is removed for some reason, sending withdraw message to peers is not currently supported. -.. index:: bgp suppress-fib-pending -.. clicmd:: [no] bgp suppress-fib-pending +.. clicmd:: bgp suppress-fib-pending This command is applicable at the global level and at an individual bgp level. If applied at the global level all bgp instances will @@ -3863,8 +3613,8 @@ certainly contains silly mistakes, if not serious flaws. ip prefix-list pl-peer2-network permit 192.168.2.0/24 ip prefix-list pl-peer2-network permit 172.16.1/24 ! - bgp as-path access-list asp-own-as permit ^$ - bgp as-path access-list asp-own-as permit _64512_ + bgp as-path access-list seq 5 asp-own-as permit ^$ + bgp as-path access-list seq 10 asp-own-as permit _64512_ ! ! ################################################################# ! Match communities we provide actions for, on routes receives from diff --git a/doc/user/bmp.rst b/doc/user/bmp.rst index 061800c14e..f925910d45 100644 --- a/doc/user/bmp.rst +++ b/doc/user/bmp.rst @@ -73,8 +73,7 @@ setup. There is one option that applies to the BGP instance as a whole: -.. index:: bmp mirror buffer-limit(0-4294967294) -.. clicmd:: [no] bmp mirror buffer-limit(0-4294967294) +.. clicmd:: bmp mirror buffer-limit(0-4294967294) This sets the maximum amount of memory used for buffering BGP messages (updates, keepalives, ...) for sending in BMP Route Mirroring. @@ -94,8 +93,7 @@ There is one option that applies to the BGP instance as a whole: All other configuration is managed per targets: -.. index:: bmp targets NAME -.. clicmd:: [no] bmp targets NAME +.. clicmd:: bmp targets NAME Create/delete a targets group. As implied by the plural name, targets may cover multiple outbound active BMP sessions as well as inbound passive @@ -110,8 +108,7 @@ BMP session configuration Inside a ``bmp targets`` block, the following commands control session establishment: -.. index:: bmp connect HOSTNAME port (1-65535) {min-retry MSEC|max-retry MSEC} -.. clicmd:: [no] bmp connect HOSTNAME port (1-65535) {min-retry MSEC|max-retry MSEC} +.. clicmd:: bmp connect HOSTNAME port (1-65535) {min-retry MSEC|max-retry MSEC} Add/remove an active outbound BMP session. HOSTNAME is resolved via DNS, if multiple addresses are returned they are tried in nondeterministic @@ -124,14 +121,13 @@ establishment: ``ip access-list`` and ``ipv6 access-list`` are checked for outbound connections resulting from ``bmp connect`` statements. -.. index:: bmp listener <X:X::X:X|A.B.C.D> port (1-65535) -.. clicmd:: [no] bmp listener <X:X::X:X|A.B.C.D> port (1-65535) +.. clicmd:: bmp listener <X:X::X:X|A.B.C.D> port (1-65535) Accept incoming BMP sessions on the specified address and port. You can use ``0.0.0.0`` and ``::`` to listen on all IPv4/IPv6 addresses. -.. clicmd:: [no] ip access-list NAME -.. clicmd:: [no] ipv6 access-list NAME +.. clicmd:: ip access-list NAME +.. clicmd:: ipv6 access-list NAME Restrict BMP sessions to the addresses allowed by the respective access lists. The access lists are checked for both passive and active BMP @@ -143,14 +139,12 @@ BMP data feed configuration The following commands configure what BMP messages are sent on sessions associated with a particular ``bmp targets``: -.. index:: bmp stats [interval (100-86400000)] -.. clicmd:: [no] bmp stats [interval (100-86400000)] +.. clicmd:: bmp stats [interval (100-86400000)] Send BMP Statistics (counter) messages at the specified interval (in milliseconds.) -.. index:: bmp monitor AFI SAFI <pre-policy|post-policy> -.. clicmd:: [no] bmp monitor AFI SAFI <pre-policy|post-policy> +.. clicmd:: bmp monitor AFI SAFI <pre-policy|post-policy> Perform Route Monitoring for the specified AFI and SAFI. Only IPv4 and IPv6 are currently valid for AFI, and only unicast and multicast are valid @@ -159,8 +153,7 @@ associated with a particular ``bmp targets``: All BGP neighbors are included in Route Monitoring. Options to select a subset of BGP sessions may be added in the future. -.. index:: bmp mirror -.. clicmd:: [no] bmp mirror +.. clicmd:: bmp mirror Perform Route Mirroring for all BGP neighbors. Since this provides a direct feed of BGP messages, there are no AFI/SAFI options to be diff --git a/doc/user/bugs.rst b/doc/user/bugs.rst index 2bd632e3a5..2af9e317a0 100644 --- a/doc/user/bugs.rst +++ b/doc/user/bugs.rst @@ -1,5 +1,5 @@ -.. index:: Bug Reports -.. index:: Reporting bugs +.. index:: + pair: bug reports; contact .. _bug-reports: diff --git a/doc/user/conf.py b/doc/user/conf.py index 79b37e7850..e0aec40443 100644 --- a/doc/user/conf.py +++ b/doc/user/conf.py @@ -384,7 +384,7 @@ def vparse(s): 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") + app.add_object_type("clicmd", "clicmd", indextemplate="pair: %s; configuration command") # css overrides for HTML theme # Note sphinx version differences diff --git a/doc/user/eigrpd.rst b/doc/user/eigrpd.rst index 4ce2e280c7..88d289d27e 100644 --- a/doc/user/eigrpd.rst +++ b/doc/user/eigrpd.rst @@ -65,7 +65,6 @@ Certain signals have special meanings to *eigrpd*. EIGRP Configuration =================== -.. index:: router eigrp (1-65535) [vrf NAME] .. clicmd:: router eigrp (1-65535) [vrf NAME] The `router eigrp` command is necessary to enable EIGRP. To disable EIGRP, @@ -73,17 +72,8 @@ EIGRP Configuration carrying out any of the EIGRP commands. Specify vrf NAME if you want eigrp to work within the specified vrf. -.. index:: router eigrp (1-65535) [vrf NAME] -.. clicmd:: no router eigrp (1-65535) [vrf NAME] - - Disable EIGRP. - -.. index:: network NETWORK .. clicmd:: network NETWORK -.. index:: network NETWORK -.. clicmd:: no network NETWORK - Set the EIGRP enable interface by `network`. The interfaces which have addresses matching with `network` are enabled. @@ -104,11 +94,8 @@ EIGRP Configuration ! -.. index:: passive-interface (IFNAME|default) .. clicmd:: passive-interface (IFNAME|default) -.. index:: passive-interface IFNAME -.. clicmd:: no passive-interface IFNAME This command sets the specified interface to passive mode. On passive mode interface, all receiving packets are ignored and eigrpd does not send either @@ -123,74 +110,26 @@ EIGRP Configuration How to Announce EIGRP route =========================== -.. index:: redistribute kernel -.. clicmd:: redistribute kernel - -.. index:: redistribute kernel metric (1-4294967295) (0-4294967295) (0-255) (1-255) (1-65535) -.. clicmd:: redistribute kernel metric (1-4294967295) (0-4294967295) (0-255) (1-255) (1-65535) - -.. index:: redistribute kernel -.. clicmd:: no redistribute kernel - - `redistribute kernel` redistributes routing information from kernel route - entries into the EIGRP tables. `no redistribute kernel` disables the routes. - -.. index:: redistribute static -.. clicmd:: redistribute static - -.. index:: redistribute static metric (1-4294967295) (0-4294967295) (0-255) (1-255) (1-65535) -.. clicmd:: redistribute static metric (1-4294967295) (0-4294967295) (0-255) (1-255) (1-65535) - -.. index:: redistribute static -.. clicmd:: no redistribute static - - `redistribute static` redistributes routing information from static route - entries into the EIGRP tables. `no redistribute static` disables the routes. - -.. index:: redistribute connected -.. clicmd:: redistribute connected - -.. index:: redistribute connected metric (1-4294967295) (0-4294967295) (0-255) (1-255) (1-65535) -.. clicmd:: redistribute connected metric (1-4294967295) (0-4294967295) (0-255) (1-255) (1-65535) - -.. index:: redistribute connected -.. clicmd:: no redistribute connected - - Redistribute connected routes into the EIGRP tables. `no redistribute - connected` disables the connected routes in the EIGRP tables. This command - redistribute connected of the interface which EIGRP disabled. The connected - route on EIGRP enabled interface is announced by default. - -.. index:: redistribute ospf -.. clicmd:: redistribute ospf - -.. index:: redistribute ospf metric (1-4294967295) (0-4294967295) (0-255) (1-255) (1-65535) -.. clicmd:: redistribute ospf metric (1-4294967295) (0-4294967295) (0-255) (1-255) (1-65535) - -.. index:: redistribute ospf -.. clicmd:: no redistribute ospf +Redistribute routes into EIGRP: - `redistribute ospf` redistributes routing information from ospf route - entries into the EIGRP tables. `no redistribute ospf` disables the routes. +.. clicmd:: redistribute <babel|bgp|connected|isis|kernel|openfabric|ospf|rip|sharp|static|table> [metric (1-4294967295) (0-4294967295) (0-255) (1-255) (1-65535)] -.. index:: redistribute bgp -.. clicmd:: redistribute bgp + The ``redistribute`` family of commands imports routing information from + other sources into EIGRP's tables. Redistribution may be disabled with the + ``no`` form of the commands. -.. index:: redistribute bgp metric (1-4294967295) (0-4294967295) (0-255) (1-255) (1-65535) -.. clicmd:: redistribute bgp metric (1-4294967295) (0-4294967295) (0-255) (1-255) (1-65535) + Note that connected routes on interfaces EIGRP is enabled on are announced + by default. -.. index:: redistribute bgp -.. clicmd:: no redistribute bgp + Optionally, various EIGRP metrics may be specified. These metrics will be + applied to the imported routes. - `redistribute bgp` redistributes routing information from bgp route entries - into the EIGRP tables. `no redistribute bgp` disables the routes. .. _show-eigrp-information: Show EIGRP Information ====================== -.. index:: show ip eigrp [vrf NAME] topology .. clicmd:: show ip eigrp [vrf NAME] topology Display current EIGRP status. @@ -208,7 +147,6 @@ Show EIGRP Information P 10.0.2.0/24, 1 successors, FD is 256256, serno: 0 via Connected, enp0s3 -.. index:: show ip eigrp [vrf NAME] interface .. clicmd:: show ip eigrp [vrf NAME] interface Display the list of interfaces associated with a particular eigrp @@ -225,14 +163,12 @@ EIGRP Debug Commands Debug for EIGRP protocol. -.. index:: debug eigrp packets .. clicmd:: debug eigrp packets Debug eigrp packets ``debug eigrp`` will show EIGRP packets that are sent and received. -.. index:: debug eigrp transmit .. clicmd:: debug eigrp transmit Debug eigrp transmit events @@ -240,7 +176,6 @@ Debug for EIGRP protocol. ``debug eigrp transmit`` will display detailed information about the EIGRP transmit events. -.. index:: show debugging eigrp .. clicmd:: show debugging eigrp Display *eigrpd*'s debugging option. diff --git a/doc/user/fabricd.rst b/doc/user/fabricd.rst index 17a51ccb3c..611bc1caaa 100644 --- a/doc/user/fabricd.rst +++ b/doc/user/fabricd.rst @@ -32,37 +32,21 @@ OpenFabric router To enable the OpenFabric routing protocol, an OpenFabric router needs to be created in the configuration: -.. index:: router openfabric WORD .. clicmd:: router openfabric WORD -.. index:: router openfabric WORD -.. clicmd:: no router openfabric WORD - Enable or disable the OpenFabric process by specifying the OpenFabric domain with 'WORD'. -.. index:: net XX.XXXX. ... .XXX.XX .. clicmd:: net XX.XXXX. ... .XXX.XX -.. index:: net XX.XXXX. ... .XXX.XX -.. clicmd:: no net XX.XXXX. ... .XXX.XX - Set/Unset network entity title (NET) provided in ISO format. -.. index:: domain-password [clear | md5] <password> .. clicmd:: domain-password [clear | md5] <password> -.. index:: domain-password -.. clicmd:: no domain-password - Configure the authentication password for a domain, as clear text or md5 one. -.. index:: attached-bit [receive ignore | send] .. clicmd:: attached-bit [receive ignore | send] -.. index:: attached-bit -.. clicmd:: no attached-bit - Set attached bit for inter-area traffic: - receive @@ -70,35 +54,22 @@ in the configuration: - send If L1|L2 router, set attached bit in LSP sent to L1 router -.. index:: log-adjacency-changes .. clicmd:: log-adjacency-changes -.. index:: log-adjacency-changes -.. clicmd:: no log-adjacency-changes - Log changes in adjacency state. -.. index:: set-overload-bit .. clicmd:: set-overload-bit -.. index:: set-overload-bit -.. clicmd:: no set-overload-bit Set overload bit to avoid any transit traffic. -.. index:: purge-originator .. clicmd:: purge-originator -.. index:: purge-originator -.. clicmd:: no purge-originator Enable or disable :rfc:`6232` purge originator identification. -.. index:: fabric-tier (0-14) .. clicmd:: fabric-tier (0-14) -.. index:: fabric-tier -.. clicmd:: no fabric-tier Configure a static tier number to advertise as location in the fabric @@ -107,35 +78,23 @@ in the configuration: OpenFabric Timer ================ -.. index:: lsp-gen-interval (1-120) .. clicmd:: lsp-gen-interval (1-120) -.. index:: lsp-gen-interval -.. clicmd:: no lsp-gen-interval Set minimum interval in seconds between regenerating same LSP. -.. index:: lsp-refresh-interval (1-65235) .. clicmd:: lsp-refresh-interval (1-65235) -.. index:: lsp-refresh-interval -.. clicmd:: no lsp-refresh-interval Set LSP refresh interval in seconds. -.. index:: max-lsp-lifetime (360-65535) .. clicmd:: max-lsp-lifetime (360-65535) -.. index:: max-lsp-lifetime -.. clicmd:: no max-lsp-lifetime Set LSP maximum LSP lifetime in seconds. -.. index:: spf-interval (1-120) .. clicmd:: spf-interval (1-120) -.. index:: spf-interval -.. clicmd:: no spf-interval Set minimum interval between consecutive SPF calculations in seconds. @@ -144,11 +103,8 @@ OpenFabric Timer OpenFabric interface ==================== -.. index:: ip router openfabric WORD .. clicmd:: ip router openfabric WORD -.. index:: ip router openfabric WORD -.. clicmd:: no ip router openfabric WORD .. _ip-router-openfabric-word: @@ -156,60 +112,39 @@ OpenFabric interface of OpenFabric instance must be the same as the one used to configure the routing process (see command :clicmd:`router openfabric WORD`). -.. index:: openfabric csnp-interval (1-600) .. clicmd:: openfabric csnp-interval (1-600) -.. index:: openfabric csnp-interval -.. clicmd:: no openfabric csnp-interval Set CSNP interval in seconds. -.. index:: openfabric hello-interval (1-600) .. clicmd:: openfabric hello-interval (1-600) -.. index:: openfabric hello-interval -.. clicmd:: no openfabric hello-interval Set Hello interval in seconds. -.. index:: openfabric hello-multiplier (2-100) .. clicmd:: openfabric hello-multiplier (2-100) -.. index:: openfabric hello-multiplier -.. clicmd:: no openfabric hello-multiplier Set multiplier for Hello holding time. -.. index:: openfabric metric (0-16777215) .. clicmd:: openfabric metric (0-16777215) -.. index:: openfabric metric -.. clicmd:: no openfabric metric Set interface metric value. -.. index:: openfabric passive .. clicmd:: openfabric passive -.. index:: openfabric passive -.. clicmd:: no openfabric passive Configure the passive mode for this interface. -.. index:: openfabric password [clear | md5] <password> .. clicmd:: openfabric password [clear | md5] <password> -.. index:: openfabric password -.. clicmd:: no openfabric password Configure the authentication password (clear or encoded text) for the interface. -.. index:: openfabric psnp-interval (1-120) .. clicmd:: openfabric psnp-interval (1-120) -.. index:: openfabric psnp-interval -.. clicmd:: no openfabric psnp-interval Set PSNP interval in seconds. @@ -218,56 +153,43 @@ OpenFabric interface Showing OpenFabric information ============================== -.. index:: show openfabric summary .. clicmd:: show openfabric summary Show summary information about OpenFabric. -.. index:: show openfabric hostname .. clicmd:: show openfabric hostname Show which hostnames are associated with which OpenFabric system ids. -.. index:: show openfabric interface .. clicmd:: show openfabric interface -.. index:: show openfabric interface detail .. clicmd:: show openfabric interface detail -.. index:: show openfabric interface <interface name> .. clicmd:: show openfabric interface <interface name> Show state and configuration of specified OpenFabric interface, or all interfaces if no interface is given with or without details. -.. index:: show openfabric neighbor .. clicmd:: show openfabric neighbor -.. index:: show openfabric neighbor <System Id> .. clicmd:: show openfabric neighbor <System Id> -.. index:: show openfabric neighbor detail .. clicmd:: show openfabric neighbor detail Show state and information of specified OpenFabric neighbor, or all neighbors if no system id is given with or without details. -.. index:: show openfabric database .. clicmd:: show openfabric database -.. index:: show openfabric database [detail] .. clicmd:: show openfabric database [detail] -.. index:: show openfabric database <LSP id> [detail] .. clicmd:: show openfabric database <LSP id> [detail] -.. index:: show openfabric database detail <LSP id> .. clicmd:: show openfabric database detail <LSP id> Show the OpenFabric database globally, for a specific LSP id without or with details. -.. index:: show openfabric topology .. clicmd:: show openfabric topology Show calculated OpenFabric paths and associated topology information. @@ -277,120 +199,64 @@ Showing OpenFabric information Debugging OpenFabric ==================== -.. index:: debug openfabric adj-packets .. clicmd:: debug openfabric adj-packets -.. index:: debug openfabric adj-packets -.. clicmd:: no debug openfabric adj-packets + OpenFabric Adjacency related packets. -OpenFabric Adjacency related packets. - -.. index:: debug openfabric checksum-errors .. clicmd:: debug openfabric checksum-errors -.. index:: debug openfabric checksum-errors -.. clicmd:: no debug openfabric checksum-errors - -OpenFabric LSP checksum errors. + OpenFabric LSP checksum errors. -.. index:: debug openfabric events .. clicmd:: debug openfabric events -.. index:: debug openfabric events -.. clicmd:: no debug openfabric events - -OpenFabric Events. + OpenFabric Events. -.. index:: debug openfabric local-updates .. clicmd:: debug openfabric local-updates -.. index:: debug openfabric local-updates -.. clicmd:: no debug openfabric local-updates + OpenFabric local update packets. -OpenFabric local update packets. - -.. index:: debug openfabric lsp-gen .. clicmd:: debug openfabric lsp-gen -.. index:: debug openfabric lsp-gen -.. clicmd:: no debug openfabric lsp-gen - -Generation of own LSPs. + Generation of own LSPs. -.. index:: debug openfabric lsp-sched .. clicmd:: debug openfabric lsp-sched -.. index:: debug openfabric lsp-sched -.. clicmd:: no debug openfabric lsp-sched + Debug scheduling of generation of own LSPs. -Debug scheduling of generation of own LSPs. - -.. index:: debug openfabric packet-dump .. clicmd:: debug openfabric packet-dump -.. index:: debug openfabric packet-dump -.. clicmd:: no debug openfabric packet-dump - -OpenFabric packet dump. + OpenFabric packet dump. -.. index:: debug openfabric protocol-errors .. clicmd:: debug openfabric protocol-errors -.. index:: debug openfabric protocol-errors -.. clicmd:: no debug openfabric protocol-errors - -OpenFabric LSP protocol errors. + OpenFabric LSP protocol errors. -.. index:: debug openfabric route-events .. clicmd:: debug openfabric route-events -.. index:: debug openfabric route-events -.. clicmd:: no debug openfabric route-events + OpenFabric Route related events. -OpenFabric Route related events. - -.. index:: debug openfabric snp-packets .. clicmd:: debug openfabric snp-packets -.. index:: debug openfabric snp-packets -.. clicmd:: no debug openfabric snp-packets - -OpenFabric CSNP/PSNP packets. + OpenFabric CSNP/PSNP packets. -.. index:: debug openfabric spf-events .. clicmd:: debug openfabric spf-events -.. index:: debug openfabric spf-statistics .. clicmd:: debug openfabric spf-statistics -.. index:: debug openfabric spf-triggers .. clicmd:: debug openfabric spf-triggers -.. index:: debug openfabric spf-events -.. clicmd:: no debug openfabric spf-events + OpenFabric Shortest Path First Events, Timing and Statistic Data and + triggering events. -.. index:: debug openfabric spf-statistics -.. clicmd:: no debug openfabric spf-statistics - -.. index:: debug openfabric spf-triggers -.. clicmd:: no debug openfabric spf-triggers - -OpenFabric Shortest Path First Events, Timing and Statistic Data and triggering -events. - -.. index:: debug openfabric update-packets .. clicmd:: debug openfabric update-packets -.. index:: debug openfabric update-packets -.. clicmd:: no debug openfabric update-packets + Update-related packets. -Update related packets. - -.. index:: show debugging openfabric .. clicmd:: show debugging openfabric Print which OpenFabric debug levels are active. + OpenFabric configuration example ================================ diff --git a/doc/user/filter.rst b/doc/user/filter.rst index 910da7246d..78043e779b 100644 --- a/doc/user/filter.rst +++ b/doc/user/filter.rst @@ -9,10 +9,8 @@ defined, it can be applied in any direction. IP Access List ============== -.. index:: access-list NAME [seq (1-4294967295)] permit IPV4-NETWORK .. clicmd:: access-list NAME [seq (1-4294967295)] permit IPV4-NETWORK -.. index:: access-list NAME [seq (1-4294967295)] deny IPV4-NETWORK .. clicmd:: access-list NAME [seq (1-4294967295)] deny IPV4-NETWORK seq @@ -50,10 +48,8 @@ filters to arbitrary points of prefix-list using sequential number specification If no ip prefix-list is specified, it acts as permit. If *ip prefix-list* is defined, and no match is found, default deny is applied. -.. index:: ip prefix-list NAME (permit|deny) PREFIX [le LEN] [ge LEN] .. clicmd:: ip prefix-list NAME (permit|deny) PREFIX [le LEN] [ge LEN] -.. index:: ip prefix-list NAME seq NUMBER (permit|deny) PREFIX [le LEN] [ge LEN] .. clicmd:: ip prefix-list NAME seq NUMBER (permit|deny) PREFIX [le LEN] [ge LEN] You can create *ip prefix-list* using above commands. @@ -98,88 +94,63 @@ is defined, and no match is found, default deny is applied. In the case of no le or ge command, the prefix length must match exactly the length specified in the prefix list. -.. index:: ip prefix-list NAME -.. clicmd:: no ip prefix-list NAME .. _ip-prefix-list-description: ip prefix-list description -------------------------- -.. index:: ip prefix-list NAME description DESC .. clicmd:: ip prefix-list NAME description DESC Descriptions may be added to prefix lists. This command adds a description to the prefix list. -.. index:: ip prefix-list NAME description [DESC] -.. clicmd:: no ip prefix-list NAME description [DESC] - - Deletes the description from a prefix list. It is possible to use the - command without the full description. .. _ip-prefix-list-sequential-number-control: ip prefix-list sequential number control ---------------------------------------- -.. index:: ip prefix-list sequence-number .. clicmd:: ip prefix-list sequence-number With this command, the IP prefix list sequential number is displayed. This is the default behavior. -.. index:: ip prefix-list sequence-number -.. clicmd:: no ip prefix-list sequence-number - - With this command, the IP prefix list sequential number is not - displayed. .. _showing-ip-prefix-list: Showing ip prefix-list ---------------------- -.. index:: show ip prefix-list .. clicmd:: show ip prefix-list Display all IP prefix lists. -.. index:: show ip prefix-list NAME .. clicmd:: show ip prefix-list NAME Show IP prefix list can be used with a prefix list name. -.. index:: show ip prefix-list NAME seq NUM .. clicmd:: show ip prefix-list NAME seq NUM Show IP prefix list can be used with a prefix list name and sequential number. -.. index:: show ip prefix-list NAME A.B.C.D/M .. clicmd:: show ip prefix-list NAME A.B.C.D/M If the command longer is used, all prefix lists with prefix lengths equal to or longer than the specified length will be displayed. If the command first match is used, the first prefix length match will be displayed. -.. index:: show ip prefix-list NAME A.B.C.D/M longer .. clicmd:: show ip prefix-list NAME A.B.C.D/M longer -.. index:: show ip prefix-list NAME A.B.C.D/M first-match .. clicmd:: show ip prefix-list NAME A.B.C.D/M first-match -.. index:: show ip prefix-list summary .. clicmd:: show ip prefix-list summary -.. index:: show ip prefix-list summary NAME .. clicmd:: show ip prefix-list summary NAME -.. index:: show ip prefix-list detail .. clicmd:: show ip prefix-list detail -.. index:: show ip prefix-list detail NAME .. clicmd:: show ip prefix-list detail NAME Clear counter of ip prefix-list ------------------------------- -.. index:: clear ip prefix-list [NAME [A.B.C.D/M]] .. clicmd:: clear ip prefix-list [NAME [A.B.C.D/M]] Clears the counters of all IP prefix lists. Clear IP Prefix List can be used diff --git a/doc/user/flowspec.rst b/doc/user/flowspec.rst index c303ebdba4..faf5973460 100644 --- a/doc/user/flowspec.rst +++ b/doc/user/flowspec.rst @@ -123,10 +123,8 @@ As of today, it is only possible to configure Flowspec on the default VRF. You can see Flowspec entries, by using one of the following show commands: -.. index:: show bgp ipv4 flowspec [detail | A.B.C.D] .. clicmd:: show bgp ipv4 flowspec [detail | A.B.C.D] -.. index:: show bgp ipv6 flowspec [detail | A:B::C:D] .. clicmd:: show bgp ipv6 flowspec [detail | A:B::C:D] Per-interface configuration @@ -141,8 +139,7 @@ twice the traffic, or slow down the traffic (filtering costs). To limit Flowspec to one specific interface, use the following command, under `flowspec address-family` node. -.. index:: local-install <IFNAME | any> -.. clicmd:: [no] local-install <IFNAME | any> +.. clicmd:: local-install <IFNAME | any> By default, Flowspec is activated on all interfaces. Installing it to a named interface will result in allowing only this interface. Conversely, enabling any @@ -168,8 +165,7 @@ following: - The first VRF with the matching Route Target will be selected to route traffic to. Use the following command under ipv4 unicast address-family node -.. index:: rt redirect import RTLIST... -.. clicmd:: [no] rt redirect import RTLIST... +.. clicmd:: rt redirect import RTLIST... In order to illustrate, if the Route Target configured in the Flowspec entry is ``E.F.G.H:II``, then a BGP VRF instance with the same Route Target will be set @@ -223,7 +219,6 @@ Those command rely on the filtering contexts configured from BGP, and get the statistics information retrieved from the underlying system. In other words, those statistics are retrieved from ``Netfilter``. -.. index:: show pbr ipset IPSETNAME | iptable .. clicmd:: show pbr ipset IPSETNAME | iptable ``IPSETNAME`` is the policy routing object name created by ``ipset``. About @@ -235,21 +230,18 @@ match. .. code-block:: frr -.. index:: show ip route table TABLEID .. clicmd:: show ip route table TABLEID ``TABLEID`` is the table number identifier referencing the non standard routing table used in this example. -.. index:: debug bgp flowspec -.. clicmd:: [no] debug bgp flowspec +.. clicmd:: debug bgp flowspec You can troubleshoot Flowspec, or BGP policy based routing. For instance, if you encounter some issues when decoding a Flowspec entry, you should enable :clicmd:`debug bgp flowspec`. -.. index:: debug bgp pbr [error] -.. clicmd:: [no] debug bgp pbr [error] +.. clicmd:: debug bgp pbr [error] If you fail to apply the flowspec entry into *zebra*, there should be some relationship with policy routing mechanism. Here, diff --git a/doc/user/installation.rst b/doc/user/installation.rst index a13e6ce43b..dbd95aca40 100644 --- a/doc/user/installation.rst +++ b/doc/user/installation.rst @@ -1,16 +1,16 @@ +.. index:: + single: How to install FRR + single: Installing FRR + single: Building FRR + .. _installation: Installation ============ -.. index:: How to install FRR -.. index:: Installation -.. index:: Installing FRR -.. index:: Building the system -.. index:: Making FRR - This section covers the basics of building, installing and setting up FRR. + From Packages ------------- @@ -55,14 +55,18 @@ is the release version. In addition, release tarballs are published on the GitHub releases page `here <https://github.com/FRRouting/frr/releases>`_. -Configuration -^^^^^^^^^^^^^ -.. index:: Configuration options -.. index:: Options for configuring -.. index:: Build options -.. index:: Distribution configuration -.. index:: Options to `./configure` +.. index:: + single: Configuration options + single: Options for configuring + single: Build options + single: Distribution configuration + single: Options to `./configure` + +.. _build-configuration: + +Build Configuration +^^^^^^^^^^^^^^^^^^^ FRR has an excellent configure script which automatically detects most host configurations. There are several additional configure options to customize the @@ -420,14 +424,15 @@ The `sphinx` and `pytest` dependencies can be avoided by not building documentation / not running ``make check``, but the CPython dependency is a hard dependency of the FRR build process (for the `clippy` tool.) +.. index:: + single: FRR Least-Privileges + single: FRR Privileges + .. _least-privilege-support: Least-Privilege Support """"""""""""""""""""""" -.. index:: FRR Least-Privileges -.. index:: FRR Privileges - Additionally, you may configure zebra to drop its elevated privileges shortly after startup and switch to another user. The configure script will automatically try to configure this support. There are three configure @@ -460,12 +465,14 @@ only Linux), FRR will retain only minimal capabilities required and will only raise these capabilities for brief periods. On systems without libcap, FRR will run as the user specified and only raise its UID to 0 for brief periods. + +.. index:: + pair: building; Linux + pair: configuration; Linux + Linux Notes """"""""""" -.. index:: Building on Linux boxes -.. index:: Linux configurations - There are several options available only to GNU/Linux systems. If you use GNU/Linux, make sure that the current kernel configuration is what you want. FRR will run with any kernel configuration but some recommendations do exist. diff --git a/doc/user/ipv6.rst b/doc/user/ipv6.rst index 26341f04f1..089fae39b1 100644 --- a/doc/user/ipv6.rst +++ b/doc/user/ipv6.rst @@ -17,17 +17,11 @@ no longer possible. Router Advertisement ==================== -.. index:: ipv6 nd suppress-ra -.. clicmd:: no ipv6 nd suppress-ra - - Send router advertisement messages. - -.. index:: ipv6 nd suppress-ra .. clicmd:: ipv6 nd suppress-ra - Don't send router advertisement messages. + Don't send router advertisement messages. The ``no`` form of this command + enables sending RA messages. -.. index:: ipv6 nd prefix ipv6prefix [valid-lifetime] [preferred-lifetime] [off-link] [no-autoconfig] [router-address] .. clicmd:: ipv6 nd prefix ipv6prefix [valid-lifetime] [preferred-lifetime] [off-link] [no-autoconfig] [router-address] Configuring the IPv6 prefix to include in router advertisements. Several prefix @@ -57,22 +51,19 @@ Router Advertisement Default: not set, i.e. hosts do not assume a complete IP address is placed. -.. index:: ipv6 nd ra-interval [(1-1800)] -.. clicmd:: [no] ipv6 nd ra-interval [(1-1800)] +.. clicmd:: ipv6 nd ra-interval [(1-1800)] The maximum time allowed between sending unsolicited multicast router advertisements from the interface, in seconds. Default: ``600`` -.. index:: ipv6 nd ra-interval msec (70-1800000) -.. clicmd:: [no] ipv6 nd ra-interval [msec (70-1800000)] +.. clicmd:: ipv6 nd ra-interval [msec (70-1800000)] The maximum time allowed between sending unsolicited multicast router advertisements from the interface, in milliseconds. Default: ``600000`` -.. index:: ipv6 nd ra-fast-retrans -.. clicmd:: [no] ipv6 nd ra-fast-retrans +.. clicmd:: ipv6 nd ra-fast-retrans RFC4861 states that consecutive RA packets should be sent no more frequently than three seconds apart. FRR by default allows faster @@ -83,8 +74,7 @@ Router Advertisement and neighbor establishment. Default: enabled -.. index:: ipv6 nd ra-retrans-interval (0-4294967295) -.. clicmd:: [no] ipv6 nd ra-retrans-interval [(0-4294967295)] +.. clicmd:: ipv6 nd ra-retrans-interval [(0-4294967295)] The value to be placed in the retrans timer field of router advertisements sent from the interface, in msec. Indicates the interval between router @@ -93,8 +83,7 @@ Router Advertisement msec. Default: ``0`` -.. index:: ipv6 nd ra-hop-limit (0-255) -.. clicmd:: [no] ipv6 nd ra-hop-limit [(0-255)] +.. clicmd:: ipv6 nd ra-hop-limit [(0-255)] The value to be placed in the hop count field of router advertisements sent from the interface, in hops. Indicates the maximum diameter of the network. @@ -102,8 +91,7 @@ Router Advertisement router. Must be between zero or 255 hops. Default: ``64`` -.. index:: ipv6 nd ra-lifetime (0-9000) -.. clicmd:: [no] ipv6 nd ra-lifetime [(0-9000)] +.. clicmd:: ipv6 nd ra-lifetime [(0-9000)] The value to be placed in the Router Lifetime field of router advertisements sent from the interface, in seconds. Indicates the usefulness of the router @@ -113,8 +101,7 @@ Router Advertisement (or default) and 9000 seconds. Default: ``1800`` -.. index:: ipv6 nd reachable-time (1-3600000) -.. clicmd:: [no] ipv6 nd reachable-time [(1-3600000)] +.. clicmd:: ipv6 nd reachable-time [(1-3600000)] The value to be placed in the Reachable Time field in the Router Advertisement messages sent by the router, in milliseconds. The configured @@ -122,8 +109,7 @@ Router Advertisement means unspecified (by this router). Default: ``0`` -.. index:: ipv6 nd managed-config-flag -.. clicmd:: [no] ipv6 nd managed-config-flag +.. clicmd:: ipv6 nd managed-config-flag Set/unset flag in IPv6 router advertisements which indicates to hosts that they should use managed (stateful) protocol for addresses autoconfiguration @@ -131,33 +117,28 @@ Router Advertisement autoconfiguration. Default: not set -.. index:: ipv6 nd other-config-flag -.. clicmd:: [no] ipv6 nd other-config-flag +.. clicmd:: ipv6 nd other-config-flag Set/unset flag in IPv6 router advertisements which indicates to hosts that they should use administered (stateful) protocol to obtain autoconfiguration information other than addresses. Default: not set -.. index:: ipv6 nd home-agent-config-flag -.. clicmd:: [no] ipv6 nd home-agent-config-flag +.. clicmd:: ipv6 nd home-agent-config-flag Set/unset flag in IPv6 router advertisements which indicates to hosts that the router acts as a Home Agent and includes a Home Agent Option. Default: not set -.. index:: ipv6 nd home-agent-preference (0-65535) -.. index:: ipv6 nd home-agent-preference (0-65535) -.. clicmd:: [no] ipv6 nd home-agent-preference [(0-65535)] +.. clicmd:: ipv6 nd home-agent-preference [(0-65535)] The value to be placed in Home Agent Option, when Home Agent config flag is set, which indicates to hosts Home Agent preference. The default value of 0 stands for the lowest preference possible. Default: ``0`` -.. index:: ipv6 nd home-agent-lifetime (0-65520) -.. clicmd:: [no] ipv6 nd home-agent-lifetime [(0-65520)] +.. clicmd:: ipv6 nd home-agent-lifetime [(0-65520)] The value to be placed in Home Agent Option, when Home Agent config flag is set, which indicates to hosts Home Agent Lifetime. The default value of 0 means to @@ -165,21 +146,18 @@ Router Advertisement Default: ``0`` -.. index:: ipv6 nd adv-interval-option -.. clicmd:: [no] ipv6 nd adv-interval-option +.. clicmd:: ipv6 nd adv-interval-option Include an Advertisement Interval option which indicates to hosts the maximum time, in milliseconds, between successive unsolicited Router Advertisements. Default: not set -.. index:: ipv6 nd router-preference (high|medium|low) -.. clicmd:: [no] ipv6 nd router-preference [(high|medium|low)] +.. clicmd:: ipv6 nd router-preference [(high|medium|low)] Set default router preference in IPv6 router advertisements per RFC4191. Default: medium -.. index:: ipv6 nd mtu (1-65535) -.. clicmd:: [no] ipv6 nd mtu [(1-65535)] +.. clicmd:: ipv6 nd mtu [(1-65535)] Include an MTU (type 5) option in each RA packet to assist the attached hosts in proper interface configuration. The announced value is not verified @@ -187,8 +165,7 @@ Router Advertisement Default: don't advertise any MTU option. -.. index:: ipv6 nd rdnss ipv6address [lifetime] -.. clicmd:: [no] ipv6 nd rdnss ipv6address [lifetime] +.. clicmd:: ipv6 nd rdnss ipv6address [lifetime] Recursive DNS server address to advertise using the RDNSS (type 25) option described in RFC8106. Can be specified more than once to advertise multiple @@ -205,8 +182,7 @@ Router Advertisement Default: do not emit RDNSS option -.. index:: ipv6 nd dnssl domain-name-suffix [lifetime] -.. clicmd:: [no] ipv6 nd dnssl domain-name-suffix [lifetime] +.. clicmd:: ipv6 nd dnssl domain-name-suffix [lifetime] Advertise DNS search list using the DNSSL (type 31) option described in RFC8106. Specify more than once to advertise multiple domain name suffixes. diff --git a/doc/user/isisd.rst b/doc/user/isisd.rst index 352701728d..ef2bf16166 100644 --- a/doc/user/isisd.rst +++ b/doc/user/isisd.rst @@ -33,51 +33,30 @@ ISIS router To start the ISIS process you have to specify the ISIS router. As of this writing, *isisd* does not support multiple ISIS processes. -.. index:: router isis WORD [vrf NAME] -.. clicmd:: [no] router isis WORD [vrf NAME] +.. clicmd:: router isis WORD [vrf NAME] Enable or disable the ISIS process by specifying the ISIS domain with 'WORD'. *isisd* does not yet support multiple ISIS processes but you must specify the name of ISIS process. The ISIS process name 'WORD' is then used for interface (see command :clicmd:`ip router isis WORD`). -.. index:: net XX.XXXX. ... .XXX.XX .. clicmd:: net XX.XXXX. ... .XXX.XX -.. index:: net XX.XXXX. ... .XXX.XX -.. clicmd:: no net XX.XXXX. ... .XXX.XX - Set/Unset network entity title (NET) provided in ISO format. -.. index:: hostname dynamic .. clicmd:: hostname dynamic -.. index:: hostname dynamic -.. clicmd:: no hostname dynamic - Enable support for dynamic hostname. -.. index:: area-password [clear | md5] <password> .. clicmd:: area-password [clear | md5] <password> -.. index:: domain-password [clear | md5] <password> .. clicmd:: domain-password [clear | md5] <password> -.. index:: area-password -.. clicmd:: no area-password - -.. index:: domain-password -.. clicmd:: no domain-password - Configure the authentication password for an area, respectively a domain, as clear text or md5 one. -.. index:: attached-bit [receive ignore | send] .. clicmd:: attached-bit [receive ignore | send] -.. index:: attached-bit -.. clicmd:: no attached-bit - Set attached bit for inter-area traffic: - receive @@ -85,20 +64,12 @@ writing, *isisd* does not support multiple ISIS processes. - send If L1|L2 router, set attached bit in LSP sent to L1 router -.. index:: log-adjacency-changes .. clicmd:: log-adjacency-changes -.. index:: log-adjacency-changes -.. clicmd:: no log-adjacency-changes - Log changes in adjacency state. -.. index:: metric-style [narrow | transition | wide] .. clicmd:: metric-style [narrow | transition | wide] -.. index:: metric-style -.. clicmd:: no metric-style - Set old-style (ISO 10589) or new-style packet formats: - narrow @@ -108,24 +79,15 @@ writing, *isisd* does not support multiple ISIS processes. - wide Use new style of TLVs to carry wider metric -.. index:: set-overload-bit .. clicmd:: set-overload-bit -.. index:: set-overload-bit -.. clicmd:: no set-overload-bit - Set overload bit to avoid any transit traffic. -.. index:: purge-originator .. clicmd:: purge-originator -.. index:: purge-originator -.. clicmd:: no purge-originator - Enable or disable :rfc:`6232` purge originator identification. -.. index:: lsp-mtu (128-4352) -.. clicmd:: [no] lsp-mtu (128-4352) +.. clicmd:: lsp-mtu (128-4352) Configure the maximum size of generated LSPs, in bytes. @@ -135,57 +97,23 @@ writing, *isisd* does not support multiple ISIS processes. ISIS Timer ========== -.. index:: lsp-gen-interval (1-120) -.. clicmd:: lsp-gen-interval (1-120) - -.. index:: lsp-gen-interval [level-1 | level-2] (1-120) .. clicmd:: lsp-gen-interval [level-1 | level-2] (1-120) -.. index:: lsp-gen-interval -.. clicmd:: no lsp-gen-interval - -.. index:: lsp-gen-interval [level-1 | level-2] -.. clicmd:: no lsp-gen-interval [level-1 | level-2] - Set minimum interval in seconds between regenerating same LSP, globally, for an area (level-1) or a domain (level-2). -.. index:: lsp-refresh-interval [level-1 | level-2] (1-65235) .. clicmd:: lsp-refresh-interval [level-1 | level-2] (1-65235) -.. index:: lsp-refresh-interval [level-1 | level-2] -.. clicmd:: no lsp-refresh-interval [level-1 | level-2] - Set LSP refresh interval in seconds, globally, for an area (level-1) or a domain (level-2). -.. index:: max-lsp-lifetime (360-65535) -.. clicmd:: max-lsp-lifetime (360-65535) - -.. index:: max-lsp-lifetime [level-1 | level-2] (360-65535) .. clicmd:: max-lsp-lifetime [level-1 | level-2] (360-65535) -.. index:: max-lsp-lifetime -.. clicmd:: no max-lsp-lifetime - -.. index:: max-lsp-lifetime [level-1 | level-2] -.. clicmd:: no max-lsp-lifetime [level-1 | level-2] - Set LSP maximum LSP lifetime in seconds, globally, for an area (level-1) or a domain (level-2). -.. index:: spf-interval (1-120) -.. clicmd:: spf-interval (1-120) - -.. index:: spf-interval [level-1 | level-2] (1-120) .. clicmd:: spf-interval [level-1 | level-2] (1-120) -.. index:: spf-interval -.. clicmd:: no spf-interval - -.. index:: spf-interval [level-1 | level-2] -.. clicmd:: no spf-interval [level-1 | level-2] - Set minimum interval between consecutive SPF calculations in seconds. .. _isis-fast-reroute: @@ -193,47 +121,41 @@ ISIS Timer ISIS Fast-Reroute ================= -.. index:: spf prefix-priority [critical | high | medium] WORD -.. clicmd:: spf prefix-priority [critical | high | medium] WORD +Unless stated otherwise, commands in this section apply to all LFA +flavors (local LFA, Remote LFA and TI-LFA). -.. index:: spf prefix-priority [critical | high | medium] WORD -.. clicmd:: no spf prefix-priority [critical | high | medium] [WORD] +.. clicmd:: spf prefix-priority [critical | high | medium] WORD Assign a priority to the prefixes that match the specified access-list. -.. index:: fast-reroute priority-limit [critical | high | medium] [level-1 | level-2] -.. clicmd:: [no] fast-reroute priority-limit [critical | high | medium] [level-1 | level-2] + By default loopback prefixes have medium priority and non-loopback prefixes + have low priority. + +.. clicmd:: fast-reroute priority-limit [critical | high | medium] [level-1 | level-2] Limit LFA backup computation up to the specified prefix priority. -.. index:: fast-reroute lfa tiebreaker [downstream | lowest-backup-metric | node-protecting] index (1-255) [level-1 | level-2] -.. clicmd:: [no] fast-reroute lfa tiebreaker [downstream | lowest-backup-metric | node-protecting] index (1-255) [level-1 | level-2] +.. clicmd:: fast-reroute lfa tiebreaker [downstream | lowest-backup-metric | node-protecting] index (1-255) [level-1 | level-2] - Configure a tie-breaker for multiple LFA backups. Lower indexes are processed - first. + Configure a tie-breaker for multiple local LFA backups. Lower indexes are + processed first. -.. index:: fast-reroute load-sharing disable [level-1 | level-2] -.. clicmd:: [no] fast-reroute load-sharing disable [level-1 | level-2] +.. clicmd:: fast-reroute load-sharing disable [level-1 | level-2] Disable load sharing across multiple LFA backups. -.. index:: fast-reroute remote-lfa prefix-list WORD [level-1 | level-2] -.. clicmd:: [no] fast-reroute remote-lfa prefix-list [WORD] [level-1 | level-2] +.. clicmd:: fast-reroute remote-lfa prefix-list [WORD] [level-1 | level-2] - Configure a prefix-list to select eligible PQ nodes (valid for all protected - interfaces). + Configure a prefix-list to select eligible PQ nodes for remote LFA + backups (valid for all protected interfaces). .. _isis-region: ISIS region =========== -.. index:: is-type [level-1 | level-1-2 | level-2-only] .. clicmd:: is-type [level-1 | level-1-2 | level-2-only] -.. index:: is-type -.. clicmd:: no is-type - Define the ISIS router behavior: - level-1 @@ -250,21 +172,15 @@ ISIS interface .. _ip-router-isis-word: -.. index:: ip router isis WORD [vrf NAME] -.. index:: ipv6 router isis WORD [vrf NAME] -.. clicmd:: [no] <ip|ipv6> router isis WORD [vrf NAME] +.. clicmd:: <ip|ipv6> router isis WORD [vrf NAME] Activate ISIS adjacency on this interface. Note that the name of ISIS instance must be the same as the one used to configure the ISIS process (see command :clicmd:`router isis WORD`). To enable IPv4, issue ``ip router isis WORD``; to enable IPv6, issue ``ipv6 router isis WORD``. -.. index:: isis circuit-type [level-1 | level-1-2 | level-2] .. clicmd:: isis circuit-type [level-1 | level-1-2 | level-2] -.. index:: isis circuit-type -.. clicmd:: no isis circuit-type - Configure circuit type for interface: - level-1 @@ -274,238 +190,126 @@ ISIS interface - level-2-only Level-2 only adjacencies are formed -.. index:: isis csnp-interval (1-600) -.. clicmd:: isis csnp-interval (1-600) - -.. index:: isis csnp-interval (1-600) [level-1 | level-2] .. clicmd:: isis csnp-interval (1-600) [level-1 | level-2] -.. index:: isis csnp-interval -.. clicmd:: no isis csnp-interval - -.. index:: isis csnp-interval [level-1 | level-2] -.. clicmd:: no isis csnp-interval [level-1 | level-2] - Set CSNP interval in seconds globally, for an area (level-1) or a domain (level-2). -.. index:: isis hello padding .. clicmd:: isis hello padding Add padding to IS-IS hello packets. -.. index:: isis hello-interval (1-600) -.. clicmd:: isis hello-interval (1-600) - -.. index:: isis hello-interval (1-600) [level-1 | level-2] .. clicmd:: isis hello-interval (1-600) [level-1 | level-2] -.. index:: isis hello-interval -.. clicmd:: no isis hello-interval - -.. index:: isis hello-interval [level-1 | level-2] -.. clicmd:: no isis hello-interval [level-1 | level-2] - Set Hello interval in seconds globally, for an area (level-1) or a domain (level-2). -.. index:: isis hello-multiplier (2-100) -.. clicmd:: isis hello-multiplier (2-100) - -.. index:: isis hello-multiplier (2-100) [level-1 | level-2] .. clicmd:: isis hello-multiplier (2-100) [level-1 | level-2] -.. index:: isis hello-multiplier -.. clicmd:: no isis hello-multiplier - -.. index:: isis hello-multiplier [level-1 | level-2] -.. clicmd:: no isis hello-multiplier [level-1 | level-2] - Set multiplier for Hello holding time globally, for an area (level-1) or a domain (level-2). -.. index:: isis metric [(0-255) | (0-16777215)] -.. clicmd:: isis metric [(0-255) | (0-16777215)] - -.. index:: isis metric [(0-255) | (0-16777215)] [level-1 | level-2] .. clicmd:: isis metric [(0-255) | (0-16777215)] [level-1 | level-2] -.. index:: isis metric -.. clicmd:: no isis metric - -.. index:: isis metric [level-1 | level-2] -.. clicmd:: no isis metric [level-1 | level-2] - Set default metric value globally, for an area (level-1) or a domain (level-2). Max value depend if metric support narrow or wide value (see command :clicmd:`metric-style [narrow | transition | wide]`). -.. index:: isis network point-to-point .. clicmd:: isis network point-to-point -.. index:: isis network point-to-point -.. clicmd:: no isis network point-to-point - Set network type to 'Point-to-Point' (broadcast by default). -.. index:: isis passive .. clicmd:: isis passive -.. index:: isis passive -.. clicmd:: no isis passive - Configure the passive mode for this interface. -.. index:: isis password [clear | md5] <password> .. clicmd:: isis password [clear | md5] <password> -.. index:: isis password -.. clicmd:: no isis password - Configure the authentication password (clear or encoded text) for the interface. -.. index:: isis priority (0-127) -.. clicmd:: isis priority (0-127) - -.. index:: isis priority (0-127) [level-1 | level-2] .. clicmd:: isis priority (0-127) [level-1 | level-2] -.. index:: isis priority -.. clicmd:: no isis priority - -.. index:: isis priority [level-1 | level-2] -.. clicmd:: no isis priority [level-1 | level-2] - Set priority for Designated Router election, globally, for the area (level-1) or the domain (level-2). -.. index:: isis psnp-interval (1-120) -.. clicmd:: isis psnp-interval (1-120) - -.. index:: isis psnp-interval (1-120) [level-1 | level-2] .. clicmd:: isis psnp-interval (1-120) [level-1 | level-2] -.. index:: isis psnp-interval -.. clicmd:: no isis psnp-interval - -.. index:: isis psnp-interval [level-1 | level-2] -.. clicmd:: no isis psnp-interval [level-1 | level-2] - Set PSNP interval in seconds globally, for an area (level-1) or a domain (level-2). -.. index:: isis three-way-handshake .. clicmd:: isis three-way-handshake -.. index:: isis three-way-handshake -.. clicmd:: no isis three-way-handshake - Enable or disable :rfc:`5303` Three-Way Handshake for P2P adjacencies. Three-Way Handshake is enabled by default. -.. index:: isis fast-reroute lfa [level-1 | level-2] -.. clicmd:: [no] isis fast-reroute lfa [level-1 | level-2] - - Enable per-prefix LFA fast reroute link protection. +.. clicmd:: isis fast-reroute lfa [level-1 | level-2] -.. index:: isis fast-reroute lfa [level-1 | level-2] exclude interface IFNAME -.. clicmd:: [no] isis fast-reroute lfa [level-1 | level-2] exclude interface IFNAME + Enable per-prefix local LFA fast reroute link protection. - Exclude an interface from the LFA backup nexthop computation. +.. clicmd:: isis fast-reroute lfa [level-1 | level-2] exclude interface IFNAME -.. index:: isis fast-reroute ti-lfa [level-1|level-2] [node-protection] -.. clicmd:: [no] isis fast-reroute ti-lfa [level-1|level-2] [node-protection] + Exclude an interface from the local LFA backup nexthop computation. - Enable per-prefix TI-LFA fast reroute link or node protection. - -.. index:: isis fast-reroute remote-lfa tunnel mpls-ldp [level-1 | level-2] -.. clicmd:: [no] isis fast-reroute remote-lfa tunnel mpls-ldp [level-1 | level-2] +.. clicmd:: isis fast-reroute remote-lfa tunnel mpls-ldp [level-1 | level-2] Enable per-prefix Remote LFA fast reroute link protection. Note that other routers in the network need to be configured to accept LDP targeted hello messages in order for RLFA to work. -.. index:: isis fast-reroute remote-lfa maximum-metric (1-16777215) [level-1 | level-2] -.. clicmd:: [no] isis fast-reroute remote-lfa maximum-metric (1-16777215) [level-1 | level-2] +.. clicmd:: isis fast-reroute remote-lfa maximum-metric (1-16777215) [level-1 | level-2] Limit Remote LFA PQ node selection within the specified metric. +.. clicmd:: isis fast-reroute ti-lfa [level-1|level-2] [node-protection] + + Enable per-prefix TI-LFA fast reroute link or node protection. + + .. _showing-isis-information: Showing ISIS information ======================== -.. index:: show isis summary .. clicmd:: show isis summary Show summary information about ISIS. -.. index:: show isis hostname .. clicmd:: show isis hostname Show information about ISIS node. -.. index:: show isis interface -.. clicmd:: show isis interface - -.. index:: show isis interface detail -.. clicmd:: show isis interface detail - -.. index:: show isis interface <interface name> -.. clicmd:: show isis interface <interface name> +.. clicmd:: show isis interface [detail] [IFNAME] Show state and configuration of ISIS specified interface, or all interfaces if no interface is given with or without details. -.. index:: show isis neighbor -.. clicmd:: show isis neighbor - -.. index:: show isis neighbor <System Id> -.. clicmd:: show isis neighbor <System Id> - -.. index:: show isis neighbor detail -.. clicmd:: show isis neighbor detail +.. clicmd:: show isis neighbor [detail] [SYSTEMID] Show state and information of ISIS specified neighbor, or all neighbors if no system id is given with or without details. -.. index:: show isis database -.. clicmd:: show isis database - -.. index:: show isis database [detail] -.. clicmd:: show isis database [detail] - -.. index:: show isis database <LSP id> [detail] -.. clicmd:: show isis database <LSP id> [detail] - -.. index:: show isis database detail <LSP id> -.. clicmd:: show isis database detail <LSP id> +.. clicmd:: show isis database [detail] [LSPID] Show the ISIS database globally, for a specific LSP id without or with details. -.. index:: show isis topology -.. clicmd:: show isis topology - -.. index:: show isis topology [level-1|level-2] .. clicmd:: show isis topology [level-1|level-2] Show topology IS-IS paths to Intermediate Systems, globally, in area (level-1) or domain (level-2). -.. index:: show isis route [level-1|level-2] [prefix-sid|backup] .. clicmd:: show isis route [level-1|level-2] [prefix-sid|backup] Show the ISIS routing table, as determined by the most recent SPF calculation. -.. index:: show isis fast-reroute summary [level-1|level-2] .. clicmd:: show isis fast-reroute summary [level-1|level-2] Show information about the number of prefixes having LFA protection, and network-wide LFA coverage. + .. _isis-traffic-engineering: Traffic Engineering @@ -513,35 +317,24 @@ Traffic Engineering .. note:: - At this time, FRR offers partial support for some of the routing - protocol extensions that can be used with MPLS-TE. FRR does not - support a complete RSVP-TE solution currently. + At this time, FRR offers partial support for some of the routing protocol + extensions that can be used with MPLS-TE. FRR does not currently support a + complete RSVP-TE solution. -.. index:: mpls-te on .. clicmd:: mpls-te on -.. index:: mpls-te -.. clicmd:: no mpls-te - Enable Traffic Engineering LSP flooding. -.. index:: mpls-te router-address <A.B.C.D> .. clicmd:: mpls-te router-address <A.B.C.D> -.. index:: mpls-te router-address -.. clicmd:: no mpls-te router-address - Configure stable IP address for MPLS-TE. -.. index:: show isis mpls-te interface .. clicmd:: show isis mpls-te interface -.. index:: show isis mpls-te interface INTERFACE .. clicmd:: show isis mpls-te interface INTERFACE Show MPLS Traffic Engineering parameters for all or specified interface. -.. index:: show isis mpls-te router .. clicmd:: show isis mpls-te router Show Traffic Engineering router parameters. @@ -550,6 +343,7 @@ Traffic Engineering :ref:`ospf-traffic-engineering` + .. _debugging-isis: Segment Routing @@ -566,36 +360,32 @@ Known limitations: - No support for SRLB - Only one SRGB and default SPF Algorithm is supported -.. index:: segment-routing on -.. clicmd:: [no] segment-routing on +.. clicmd:: segment-routing on Enable Segment Routing. -.. index:: segment-routing global-block (0-1048575) (0-1048575) -.. clicmd:: [no] segment-routing global-block (0-1048575) (0-1048575) +.. clicmd:: segment-routing global-block (16-1048575) (16-1048575) [local-block (16-1048575) (16-1048575)] Set the Segment Routing Global Block i.e. the label range used by MPLS to store label in the MPLS FIB for Prefix SID. Note that the block size - may not exceed 65535. + may not exceed 65535. Optionally sets also the Segment Routing Local Block. + The negative command always unsets both. -.. index:: segment-routing local-block (0-1048575) (0-1048575) -.. clicmd:: [no] segment-routing local-block (0-1048575) (0-1048575) +.. clicmd:: segment-routing local-block (16-1048575) (16-1048575) Set the Segment Routing Local Block i.e. the label range used by MPLS to store label in the MPLS FIB for Adjacency SID. Note that the block size - may not exceed 65535. + may not exceed 65535. This command is deprecated in favor of the combined + 'segment-routing global-block A B local-block C D' command. -.. index:: segment-routing node-msd (1-16) -.. clicmd:: [no] segment-routing node-msd (1-16) +.. clicmd:: segment-routing node-msd (1-16) Set the Maximum Stack Depth supported by the router. The value depend of the MPLS dataplane. E.g. for Linux kernel, since version 4.13 the maximum value is 32. -.. index:: segment-routing prefix <A.B.C.D/M|X:X::X:X/M> <absolute (16-1048575)|index (0-65535)> [no-php-flag|explicit-null] [n-flag-clear] -.. clicmd:: [no] segment-routing prefix <A.B.C.D/M|X:X::X:X/M> <absolute (16-1048575)|index (0-65535) [no-php-flag|explicit-null] [n-flag-clear] +.. clicmd:: segment-routing prefix <A.B.C.D/M|X:X::X:X/M> <absolute (16-1048575)|index (0-65535) [no-php-flag|explicit-null] [n-flag-clear] - Set the Segment Routing index or absolute label value for the specified prefix. The 'no-php-flag' means NO Penultimate Hop Popping that allows SR node to request to its neighbor to not pop the label. The 'explicit-null' flag allows SR node to request to its neighbor to send IP packet with the @@ -603,12 +393,10 @@ Known limitations: clear the Node flag that is set by default for Prefix-SIDs associated to loopback addresses. This option is necessary to configure Anycast-SIDs. -.. index:: show isis segment-routing prefix-sids .. clicmd:: show isis segment-routing prefix-sids Show detailed information about all learned Segment Routing Prefix-SIDs. -.. index:: show isis segment-routing nodes .. clicmd:: show isis segment-routing nodes Show detailed information about all learned Segment Routing Nodes. @@ -616,120 +404,66 @@ Known limitations: Debugging ISIS ============== -.. index:: debug isis adj-packets .. clicmd:: debug isis adj-packets -.. index:: debug isis adj-packets -.. clicmd:: no debug isis adj-packets - IS-IS Adjacency related packets. -.. index:: debug isis checksum-errors .. clicmd:: debug isis checksum-errors -.. index:: debug isis checksum-errors -.. clicmd:: no debug isis checksum-errors - IS-IS LSP checksum errors. -.. index:: debug isis events .. clicmd:: debug isis events -.. index:: debug isis events -.. clicmd:: no debug isis events - IS-IS Events. -.. index:: debug isis local-updates .. clicmd:: debug isis local-updates -.. index:: debug isis local-updates -.. clicmd:: no debug isis local-updates - IS-IS local update packets. -.. index:: debug isis packet-dump .. clicmd:: debug isis packet-dump -.. index:: debug isis packet-dump -.. clicmd:: no debug isis packet-dump - IS-IS packet dump. -.. index:: debug isis protocol-errors .. clicmd:: debug isis protocol-errors -.. index:: debug isis protocol-errors -.. clicmd:: no debug isis protocol-errors - IS-IS LSP protocol errors. -.. index:: debug isis route-events .. clicmd:: debug isis route-events -.. index:: debug isis route-events -.. clicmd:: no debug isis route-events - IS-IS Route related events. -.. index:: debug isis snp-packets .. clicmd:: debug isis snp-packets -.. index:: debug isis snp-packets -.. clicmd:: no debug isis snp-packets - IS-IS CSNP/PSNP packets. -.. index:: debug isis spf-events .. clicmd:: debug isis spf-events - -.. index:: debug isis spf-statistics .. clicmd:: debug isis spf-statistics - -.. index:: debug isis spf-triggers .. clicmd:: debug isis spf-triggers -.. index:: debug isis spf-events -.. clicmd:: no debug isis spf-events - -.. index:: debug isis spf-statistics -.. clicmd:: no debug isis spf-statistics - -.. index:: debug isis spf-triggers -.. clicmd:: no debug isis spf-triggers - IS-IS Shortest Path First Events, Timing and Statistic Data and triggering events. -.. index:: debug isis update-packets .. clicmd:: debug isis update-packets -.. index:: debug isis update-packets -.. clicmd:: no debug isis update-packets Update related packets. -.. index:: debug isis sr-events .. clicmd:: debug isis sr-events -.. index:: debug isis sr-events -.. clicmd:: no debug isis sr-events IS-IS Segment Routing events. -.. index:: debug isis lfa .. clicmd:: debug isis lfa -.. index:: debug isis lfa -.. clicmd:: no debug isis lfa IS-IS LFA events. -.. index:: show debugging isis .. clicmd:: show debugging isis Print which ISIS debug level is activate. +.. _isis-config-examples: + ISIS Configuration Examples =========================== @@ -843,6 +577,9 @@ A Segment Routing configuration, with IPv4, IPv6, SRGB and MSD configuration. segment-routing prefix 2001:db8:1000::1/128 index 101 explicit-null ! + +.. _isis-vrf-config-examples: + ISIS Vrf Configuration Examples =============================== @@ -860,5 +597,3 @@ A simple vrf example: net 47.0023.0000.0000.0000.0000.0000.0000.1900.0004.00 metric-style wide is-type level-2-only - - diff --git a/doc/user/ldpd.rst b/doc/user/ldpd.rst index 375842f2ba..3e662b14d8 100644 --- a/doc/user/ldpd.rst +++ b/doc/user/ldpd.rst @@ -97,53 +97,45 @@ implementation. LDP Configuration =================== -.. index:: mpls ldp -.. clicmd:: [no] mpls ldp +.. clicmd:: mpls ldp Enable or disable LDP daemon -.. index:: router-id A.B.C.D -.. clicmd:: [no] router-id A.B.C.D +.. clicmd:: router-id A.B.C.D The following command located under MPLS router node configures the MPLS router-id of the local device. -.. index:: ordered-control -.. clicmd:: [no] ordered-control +.. clicmd:: ordered-control Configure LDP Ordered Label Distribution Control. -.. index:: address-family [ipv4 | ipv6] -.. clicmd:: [no] address-family [ipv4 | ipv6] +.. clicmd:: address-family [ipv4 | ipv6] Configure LDP for IPv4 or IPv6 address-family. Located under MPLS route node, this subnode permits configuring the LDP neighbors. -.. index:: interface IFACE -.. clicmd:: [no] interface IFACE +.. clicmd:: interface IFACE Located under MPLS address-family node, use this command to enable or disable LDP discovery per interface. IFACE stands for the interface name where LDP is enabled. By default it is disabled. Once this command executed, the address-family interface node is configured. -.. index:: discovery transport-address A.B.C.D | A:B::C:D -.. clicmd:: [no] discovery transport-address A.B.C.D | A:B::C:D +.. clicmd:: discovery transport-address A.B.C.D | A:B::C:D Located under mpls address-family interface node, use this command to set the IPv4 or IPv6 transport-address used by the LDP protocol to talk on this interface. -.. index:: neighbor A.B.C.D password PASSWORD -.. clicmd:: [no] neighbor A.B.C.D password PASSWORD +.. clicmd:: neighbor A.B.C.D password PASSWORD The following command located under MPLS router node configures the router of a LDP device. This device, if found, will have to comply with the configured password. PASSWORD is a clear text password wit its digest sent through the network. -.. index:: neighbor A.B.C.D holdtime HOLDTIME -.. clicmd:: [no] neighbor A.B.C.D holdtime HOLDTIME +.. clicmd:: neighbor A.B.C.D holdtime HOLDTIME The following command located under MPLS router node configures the holdtime value in seconds of the LDP neighbor ID. Configuring it triggers a keepalive @@ -151,19 +143,16 @@ LDP Configuration this time of non response, the LDP established session will be considered as set to down. By default, no holdtime is configured for the LDP devices. -.. index:: discovery hello holdtime HOLDTIME -.. clicmd:: [no] discovery hello holdtime HOLDTIME +.. clicmd:: discovery hello holdtime HOLDTIME -.. index:: discovery hello interval INTERVAL -.. clicmd:: [no] discovery hello interval INTERVAL +.. clicmd:: discovery hello interval INTERVAL INTERVAL value ranges from 1 to 65535 seconds. Default value is 5 seconds. This is the value between each hello timer message sent. HOLDTIME value ranges from 1 to 65535 seconds. Default value is 15 seconds. That value is added as a TLV in the LDP messages. -.. index:: dual-stack transport-connection prefer ipv4 -.. clicmd:: [no] dual-stack transport-connection prefer ipv4 +.. clicmd:: dual-stack transport-connection prefer ipv4 When *ldpd* is configured for dual-stack operation, the transport connection preference is IPv6 by default (as specified by :rfc:`7552`). On such @@ -179,7 +168,6 @@ Show LDP Information These commands dump various parts of *ldpd*. -.. index:: show mpls ldp neighbor [A.B.C.D] .. clicmd:: show mpls ldp neighbor [A.B.C.D] This command dumps the various neighbors discovered. Below example shows that @@ -192,29 +180,22 @@ These commands dump various parts of *ldpd*. ipv4 1.1.1.1 OPERATIONAL 1.1.1.1 00:01:37 west-vm# -.. index:: show mpls ldp neighbor [A.B.C.D] capabilities .. clicmd:: show mpls ldp neighbor [A.B.C.D] capabilities -.. index:: show mpls ldp neighbor [A.B.C.D] detail .. clicmd:: show mpls ldp neighbor [A.B.C.D] detail Above commands dump other neighbor information. -.. index:: show mpls ldp discovery [detail] .. clicmd:: show mpls ldp discovery [detail] -.. index:: show mpls ldp ipv4 discovery [detail] .. clicmd:: show mpls ldp ipv4 discovery [detail] -.. index:: show mpls ldp ipv6 discovery [detail] .. clicmd:: show mpls ldp ipv6 discovery [detail] Above commands dump discovery information. -.. index:: show mpls ldp ipv4 interface .. clicmd:: show mpls ldp ipv4 interface -.. index:: show mpls ldp ipv6 interface .. clicmd:: show mpls ldp ipv6 interface Above command dumps the IPv4 or IPv6 interface per where LDP is enabled. @@ -228,7 +209,6 @@ These commands dump various parts of *ldpd*. ipv4 eth3 ACTIVE 00:08:35 5/15 1 -.. index:: show mpls ldp ipv4|ipv6 binding .. clicmd:: show mpls ldp ipv4|ipv6 binding Above command dumps the binding obtained through MPLS exchanges with LDP. @@ -245,14 +225,12 @@ These commands dump various parts of *ldpd*. ipv4 10.200.0.0/24 1.1.1.1 17 imp-null yes west-vm# + LDP debugging commands ======================== -.. index:: - simple: debug mpls ldp KIND - simple: no debug mpls ldp KIND -.. clicmd:: [no] debug mpls ldp KIND +.. clicmd:: debug mpls ldp KIND Enable or disable debugging messages of a given kind. ``KIND`` can be one of: diff --git a/doc/user/nhrpd.rst b/doc/user/nhrpd.rst index 65645c519d..b02e761acc 100644 --- a/doc/user/nhrpd.rst +++ b/doc/user/nhrpd.rst @@ -77,7 +77,6 @@ command defines the GRE subnet): Configuring NHRP ================ -.. index:: ip nhrp holdtime (1-65000) .. clicmd:: ip nhrp holdtime (1-65000) Holdtime is the number of seconds that have to pass before stopping to @@ -85,12 +84,10 @@ Configuring NHRP registration requests are sent. By default registrations are sent every one third of the holdtime. -.. index:: ip nhrp map A.B.C.D|X:X::X:X A.B.C.D|local .. clicmd:: ip nhrp map A.B.C.D|X:X::X:X A.B.C.D|local Map an IP address of a station to the station's NBMA address. -.. index:: ip nhrp network-id (1-4294967295) .. clicmd:: ip nhrp network-id (1-4294967295) Enable NHRP on this interface and set the interface's network ID. The @@ -101,30 +98,25 @@ Configuring NHRP different nodes do not need to match. When NHRP packets are received on an interface they are assigned to the local NHRP domain for that interface. -.. index:: ip nhrp nhs A.B.C.D nbma A.B.C.D|FQDN .. clicmd:: ip nhrp nhs A.B.C.D nbma A.B.C.D|FQDN Configure the Next Hop Server address and its NBMA address. -.. index:: ip nhrp nhs dynamic nbma A.B.C.D .. clicmd:: ip nhrp nhs dynamic nbma A.B.C.D Configure the Next Hop Server to have a dynamic address and set its NBMA address. -.. index:: ip nhrp registration no-unique .. clicmd:: ip nhrp registration no-unique Allow the client to not set the unique flag in the NHRP packets. This is useful when a station has a dynamic IP address that could change over time. -.. index:: ip nhrp shortcut .. clicmd:: ip nhrp shortcut Enable shortcut (spoke-to-spoke) tunnels to allow NHC to talk to each others directly after establishing a connection without going through the hub. -.. index:: ip nhrp mtu .. clicmd:: ip nhrp mtu Configure NHRP advertised MTU. @@ -159,13 +151,11 @@ However, the above should be good in most cases. This kernel NFLOG target's nflog-group is configured in global nhrp config with: -.. index:: nhrp nflog-group (1-65535) .. clicmd:: nhrp nflog-group (1-65535) To start sending these traffic notices out from hubs, use the nhrp per-interface directive: -.. index:: ip nhrp redirect .. clicmd:: ip nhrp redirect This enable redirect replies on the NHS similar to ICMP redirects except this @@ -195,7 +185,6 @@ https://gitlab.alpinelinux.org/alpine/aports/-/tree/master/main/strongswan NHRP Events =========== -.. index:: nhrp event socket SOCKET .. clicmd:: nhrp event socket SOCKET Configure the Unix path for the event socket. @@ -205,22 +194,18 @@ NHRP Events Show NHRP ========== -.. index:: show [ip|ipv6] nhrp cache [json] .. clicmd:: show [ip|ipv6] nhrp cache [json] Dump the cache entries. -.. index:: show [ip|ipv6] nhrp opennhrp [json] .. clicmd:: show [ip|ipv6] nhrp opennhrp [json] Dump the cache entries with opennhrp format. -.. index:: show [ip|ipv6] nhrp nhs [json] .. clicmd:: show [ip|ipv6] nhrp nhs [json] Dump the hub context. -.. index:: show dmvpn [json] .. clicmd:: show dmvpn [json] Dump the security contexts. diff --git a/doc/user/ospf6d.rst b/doc/user/ospf6d.rst index 99119bb7e5..607acd3706 100644 --- a/doc/user/ospf6d.rst +++ b/doc/user/ospf6d.rst @@ -12,28 +12,20 @@ described in :rfc:`2740`. OSPF6 router ============ -.. index:: router ospf6 .. clicmd:: router ospf6 -.. index:: ospf6 router-id A.B.C.D .. clicmd:: ospf6 router-id A.B.C.D Set router's Router-ID. -.. index:: interface IFNAME area (0-4294967295) .. clicmd:: interface IFNAME area (0-4294967295) -.. index:: interface IFNAME area A.B.C.D .. clicmd:: interface IFNAME area A.B.C.D Bind interface to specified area, and start sending OSPF packets. `area` can be specified as 0. -.. index:: timers throttle spf DELAY INITIAL-HOLDTIME MAX-HOLDTIME -.. clicmd:: timers throttle spf DELAY INITIAL-HOLDTIME MAX-HOLDTIME - -.. index:: timers throttle spf -.. clicmd:: no timers throttle spf +.. clicmd:: timers throttle spf (0-600000) (0-600000) (0-600000) This command sets the initial `delay`, the `initial-holdtime` and the `maximum-holdtime` between when SPF is calculated and the @@ -68,11 +60,8 @@ OSPF6 router time an SPF-triggering event occurs within the hold-time of the previous SPF calculation. -.. index:: auto-cost reference-bandwidth COST .. clicmd:: auto-cost reference-bandwidth COST -.. index:: auto-cost reference-bandwidth -.. clicmd:: no auto-cost reference-bandwidth This sets the reference bandwidth for cost calculations, where this bandwidth is considered equivalent to an OSPF cost of 1, specified in @@ -83,12 +72,12 @@ OSPF6 router This configuration setting MUST be consistent across all routers within the OSPF domain. -.. index:: maximum-paths (1-64) -.. clicmd::[no] maximum-paths (1-64) +.. clicmd:: maximum-paths (1-64) Use this command to control the maximum number of parallel routes that OSPFv3 can support. The default is 64. + .. _ospf6-area: OSPF6 area @@ -101,38 +90,31 @@ Area support for OSPFv3 is not yet implemented. OSPF6 interface =============== -.. index:: ipv6 ospf6 cost COST .. clicmd:: ipv6 ospf6 cost COST Sets interface's output cost. Default value depends on the interface bandwidth and on the auto-cost reference bandwidth. -.. index:: ipv6 ospf6 hello-interval HELLOINTERVAL .. clicmd:: ipv6 ospf6 hello-interval HELLOINTERVAL Sets interface's Hello Interval. Default 10 -.. index:: ipv6 ospf6 dead-interval DEADINTERVAL .. clicmd:: ipv6 ospf6 dead-interval DEADINTERVAL Sets interface's Router Dead Interval. Default value is 40. -.. index:: ipv6 ospf6 retransmit-interval RETRANSMITINTERVAL .. clicmd:: ipv6 ospf6 retransmit-interval RETRANSMITINTERVAL Sets interface's Rxmt Interval. Default value is 5. -.. index:: ipv6 ospf6 priority PRIORITY .. clicmd:: ipv6 ospf6 priority PRIORITY Sets interface's Router Priority. Default value is 1. -.. index:: ipv6 ospf6 transmit-delay TRANSMITDELAY .. clicmd:: ipv6 ospf6 transmit-delay TRANSMITDELAY Sets interface's Inf-Trans-Delay. Default value is 1. -.. index:: ipv6 ospf6 network (broadcast|point-to-point) .. clicmd:: ipv6 ospf6 network (broadcast|point-to-point) Set explicitly network type for specified interface. @@ -142,7 +124,6 @@ OSPF6 route-map Usage of *ospfd6*'s route-map support. -.. index:: set metric [+|-](0-4294967295) .. clicmd:: set metric [+|-](0-4294967295) Set a metric for matched route when sending announcement. Use plus (+) sign @@ -154,14 +135,9 @@ Usage of *ospfd6*'s route-map support. Redistribute routes to OSPF6 ============================ -.. index:: redistribute static -.. clicmd:: redistribute static - -.. index:: redistribute connected -.. clicmd:: redistribute connected +.. clicmd:: redistribute <babel|bgp|connected|isis|kernel|openfabric|ripng|sharp|static|table> [route-map WORD] -.. index:: redistribute ripng -.. clicmd:: redistribute ripng + Redistribute routes from other protocols into OSPFv3. .. _showing-ospf6-information: @@ -169,14 +145,12 @@ Redistribute routes to OSPF6 Showing OSPF6 information ========================= -.. index:: show ipv6 ospf6 [INSTANCE_ID] [json] .. clicmd:: show ipv6 ospf6 [INSTANCE_ID] [json] INSTANCE_ID is an optional OSPF instance ID. To see router ID and OSPF instance ID, simply type "show ipv6 ospf6 <cr>". JSON output can be obtained by appending 'json' to the end of command. -.. index:: show ipv6 ospf6 database [<detail|dump|internal>] [json] .. clicmd:: show ipv6 ospf6 database [<detail|dump|internal>] [json] This command shows LSAs present in the LSDB. There are three view options. @@ -184,14 +158,12 @@ Showing OSPF6 information can be obtained by appending 'json' to the end of command. JSON option is not applicable with 'dump' option. -.. index:: show ipv6 ospf6 database <router|network|inter-prefix|inter-router|as-external|group-membership|type-7|link|intra-prefix> [json] .. clicmd:: show ipv6 ospf6 database <router|network|inter-prefix|inter-router|as-external|group-membership|type-7|link|intra-prefix> [json] These options filters out the LSA based on its type. The three views options works here as well. JSON output can be obtained by appending 'json' to the end of command. -.. index:: show ipv6 ospf6 database adv-router A.B.C.D linkstate-id A.B.C.D [json] .. clicmd:: show ipv6 ospf6 database adv-router A.B.C.D linkstate-id A.B.C.D [json] The LSAs additinally can also be filtered with the linkstate-id and @@ -199,54 +171,45 @@ Showing OSPF6 information this command as well and visa-versa. JSON output can be obtained by appending 'json' to the end of command. -.. index:: show ipv6 ospf6 database self-originated [json] .. clicmd:: show ipv6 ospf6 database self-originated [json] This command is used to filter the LSAs which are originated by the present router. All the other filters are applicable here as well. -.. index:: show ipv6 ospf6 interface [json] .. clicmd:: show ipv6 ospf6 interface [json] To see OSPF interface configuration like costs. JSON output can be obtained by appending "json" in the end. -.. index:: show ipv6 ospf6 neighbor [json] .. clicmd:: show ipv6 ospf6 neighbor [json] Shows state and chosen (Backup) DR of neighbor. JSON output can be obtained by appending 'json' at the end. -.. index:: show ipv6 ospf6 interface traffic [json] .. clicmd:: show ipv6 ospf6 interface traffic [json] Shows counts of different packets that have been recieved and transmitted by the interfaces. JSON output can be obtained by appending "json" at the end. -.. index:: show ipv6 ospf6 request-list A.B.C.D .. clicmd:: show ipv6 ospf6 request-list A.B.C.D Shows requestlist of neighbor. -.. index:: show ipv6 route ospf6 .. clicmd:: show ipv6 route ospf6 This command shows internal routing table. -.. index:: show ipv6 ospf6 zebra [json] .. clicmd:: show ipv6 ospf6 zebra [json] Shows state about what is being redistributed between zebra and OSPF6. JSON output can be obtained by appending "json" at the end. -.. index:: show ipv6 ospf6 redistribute [json] .. clicmd:: show ipv6 ospf6 redistribute [json] Shows the routes which are redistributed by the router. JSON output can be obtained by appending 'json' at the end. -.. index:: show ipv6 ospf6 route [<intra-area|inter-area|external-1|external-2|X:X::X:X|X:X::X:X/M|detail|summary>] [json] .. clicmd:: show ipv6 ospf6 route [<intra-area|inter-area|external-1|external-2|X:X::X:X|X:X::X:X/M|detail|summary>] [json] This command displays the ospfv3 routing table as determined by the most @@ -255,19 +218,25 @@ Showing OSPF6 information and summary. JSON output can be obtained by appending 'json' to the end of command. -.. index:: show ipv6 ospf6 route X:X::X:X/M match [detail] [json] .. clicmd:: show ipv6 ospf6 route X:X::X:X/M match [detail] [json] The additional match option will match the given address to the destination of the routes, and return the result accordingly. -.. index:: show ipv6 ospf6 interface [IFNAME] prefix [detail|<X:X::X:X|X:X::X:X/M> [<match|detail>]] [json] .. clicmd:: show ipv6 ospf6 interface [IFNAME] prefix [detail|<X:X::X:X|X:X::X:X/M> [<match|detail>]] [json] This command shows the prefixes present in the interface routing table. Interface name can also be given. JSON output can be obtained by appending 'json' to the end of command. +.. clicmd:: show ipv6 ospf6 spf tree [json] + + This commands shows the spf tree from the recent spf calculation with the + calling router as the root. If json is appended in the end, we can get the + 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/ospf_fundamentals.rst b/doc/user/ospf_fundamentals.rst index b0eb018107..38c18e5526 100644 --- a/doc/user/ospf_fundamentals.rst +++ b/doc/user/ospf_fundamentals.rst @@ -3,8 +3,10 @@ OSPF Fundamentals ================= -.. index:: Link-state routing protocol -.. index:: Distance-vector routing protocol +.. index:: + pair: Link-state routing protocol; OSPF + pair: Distance-vector routing protocol; OSPF + :abbr:`OSPF` is, mostly, a link-state routing protocol. In contrast to :term:`distance-vector` protocols, such as :abbr:`RIP` or :abbr:`BGP`, where @@ -12,10 +14,12 @@ routers describe available `paths` (i.e. routes) to each other, in :term:`link-state` protocols routers instead describe the state of their links to their immediate neighbouring routers. -.. index:: Link State Announcement -.. index:: Link State Advertisement -.. index:: LSA flooding -.. index:: Link State Database +.. index:: + single: Link State Announcement + single: Link State Advertisement + single: LSA flooding + single: Link State Database + Each router describes their link-state information in a message known as an :abbr:`LSA (Link State Advertisement)`, which is then propagated through to all @@ -27,7 +31,8 @@ metric, by using an algorithm such as `Edsger Dijkstra's <http://www.cs.utexas.edu/users/EWD/>`_ :abbr:`SPF (Shortest Path First)` algorithm. -.. index:: Link-state routing protocol advantages +.. index:: + pair: Link-state routing protocol; advantages By describing connectivity of a network in this way, in terms of routers and links rather than in terms of the paths through a network, @@ -39,7 +44,8 @@ reconverge on the best paths through the network. In contrast, distance vector protocols can require a progression of different path update messages from a series of different routers in order to converge. -.. index:: Link-state routing protocol disadvantages +.. index:: + pair: Link-state routing protocol; disadvantages The disadvantage to a link-state protocol is that the process of computing the best paths can be relatively intensive when compared to @@ -64,7 +70,8 @@ will nearly all be covered in greater detail further on. They may be broadly classed as: -.. index:: OSPF Hello Protocol +.. index:: + pair: Hello protocol; OSPF The Hello Protocol ^^^^^^^^^^^^^^^^^^ @@ -86,7 +93,10 @@ sharing a link, for example: The Hello protocol is comparatively trivial and will not be explored in more detail. -.. index:: OSPF LSA overview + +.. index:: + pair: LSA; OSPF + .. _ospf-lsas: LSAs @@ -120,7 +130,9 @@ OSPF defines several related mechanisms, used to manage synchronisation of :abbr:`LSDB` s between neighbours as neighbours form adjacencies and the propagation, or `flooding` of new or updated :abbr:`LSA` s. -.. index:: OSPF Areas overview + +.. index:: + pair: Area; OSPF .. _ospf-areas: diff --git a/doc/user/ospfd.rst b/doc/user/ospfd.rst index ee02a9dae5..64ce85503e 100644 --- a/doc/user/ospfd.rst +++ b/doc/user/ospfd.rst @@ -80,19 +80,13 @@ Routers To start OSPF process you have to specify the OSPF router. -.. index:: router ospf [(1-65535)] vrf NAME .. clicmd:: router ospf [(1-65535)] vrf NAME -.. index:: router ospf [(1-65535)] vrf NAME -.. clicmd:: no router ospf [(1-65535)] vrf NAME Enable or disable the OSPF process. -.. index:: ospf router-id A.B.C.D .. clicmd:: ospf router-id A.B.C.D -.. index:: ospf router-id [A.B.C.D] -.. clicmd:: no ospf router-id [A.B.C.D] This sets the router-ID of the OSPF process. The router-ID may be an IP address of the router, but need not be - it can be any arbitrary 32bit @@ -101,11 +95,8 @@ To start OSPF process you have to specify the OSPF router. with the same router-ID! If one is not specified then *ospfd* will obtain a router-ID automatically from *zebra*. -.. index:: ospf abr-type TYPE .. clicmd:: ospf abr-type TYPE -.. index:: ospf abr-type TYPE -.. clicmd:: no ospf abr-type TYPE `type` can be cisco|ibm|shortcut|standard. The "Cisco" and "IBM" types are equivalent. @@ -137,11 +128,8 @@ To start OSPF process you have to specify the OSPF router. OSPF domain, is dropped. This document describes alternative ABR behaviors implemented in Cisco and IBM routers." -.. index:: ospf rfc1583compatibility .. clicmd:: ospf rfc1583compatibility -.. index:: ospf rfc1583compatibility -.. clicmd:: no ospf rfc1583compatibility :rfc:`2328`, the successor to :rfc:`1583`, suggests according to section G.2 (changes) in section 16.4 a change to the path @@ -152,21 +140,15 @@ To start OSPF process you have to specify the OSPF router. This command should NOT be set normally. -.. index:: log-adjacency-changes [detail] .. clicmd:: log-adjacency-changes [detail] -.. index:: log-adjacency-changes [detail] -.. clicmd:: no log-adjacency-changes [detail] Configures ospfd to log changes in adjacency. With the optional detail argument, all changes in adjacency status are shown. Without detail, only changes to full or regressions are shown. -.. index:: passive-interface INTERFACE .. clicmd:: passive-interface INTERFACE -.. index:: passive-interface INTERFACE -.. clicmd:: no passive-interface INTERFACE Do not speak OSPF interface on the given interface, but do advertise the interface as a stub link in the @@ -177,12 +159,8 @@ To start OSPF process you have to specify the OSPF router. OSPF (:ref:`redistribute-routes-to-ospf`). This is the only way to advertise non-OSPF links into stub areas. -.. index:: timers throttle spf (0-600000) (0-600000) (0-600000) .. clicmd:: timers throttle spf (0-600000) (0-600000) (0-600000) -.. index:: timers throttle spf -.. clicmd:: no timers throttle spf - This command sets the initial `delay`, the `initial-holdtime` and the `maximum-holdtime` between when SPF is calculated and the event which triggered the calculation. The times are specified in @@ -221,14 +199,10 @@ To start OSPF process you have to specify the OSPF router. This command supersedes the *timers spf* command in previous FRR releases. -.. index:: max-metric router-lsa [on-startup|on-shutdown] (5-86400) .. clicmd:: max-metric router-lsa [on-startup|on-shutdown] (5-86400) -.. index:: max-metric router-lsa administrative .. clicmd:: max-metric router-lsa administrative -.. index:: max-metric router-lsa [on-startup|on-shutdown|administrative] -.. clicmd:: no max-metric router-lsa [on-startup|on-shutdown|administrative] This enables :rfc:`3137` support, where the OSPF process describes its transit links in its router-LSA as having infinite distance so that other @@ -257,11 +231,8 @@ To start OSPF process you have to specify the OSPF router. number of second remaining till on-startup or on-shutdown ends, can be viewed with the :clicmd:`show ip ospf` command. -.. index:: auto-cost reference-bandwidth (1-4294967) .. clicmd:: auto-cost reference-bandwidth (1-4294967) -.. index:: auto-cost reference-bandwidth -.. clicmd:: no auto-cost reference-bandwidth This sets the reference bandwidth for cost calculations, where this bandwidth is considered @@ -273,17 +244,11 @@ To start OSPF process you have to specify the OSPF router. This configuration setting MUST be consistent across all routers within the OSPF domain. -.. index:: network A.B.C.D/M area A.B.C.D .. clicmd:: network A.B.C.D/M area A.B.C.D -.. index:: network A.B.C.D/M area (0-4294967295) .. clicmd:: network A.B.C.D/M area (0-4294967295) -.. index:: network A.B.C.D/M area A.B.C.D -.. clicmd:: no network A.B.C.D/M area A.B.C.D -.. index:: network A.B.C.D/M area (0-4294967295) -.. clicmd:: no network A.B.C.D/M area (0-4294967295) This command specifies the OSPF enabled interface(s). If the interface has an address from range 192.168.1.0/24 then the command below enables ospf @@ -310,11 +275,8 @@ To start OSPF process you have to specify the OSPF router. In some cases it may be more convenient to enable OSPF on a per interface/subnet basis (:clicmd:`ip ospf area AREA [ADDR]`). -.. index:: proactive-arp .. clicmd:: proactive-arp -.. index:: proactive-arp -.. clicmd:: no proactive-arp This command enables or disables sending ARP requests to update neighbor table entries. It speeds up convergence for /32 networks on a P2P @@ -322,7 +284,6 @@ To start OSPF process you have to specify the OSPF router. This feature is enabled by default. -.. index:: clear ip ospf [(1-65535)] process .. clicmd:: clear ip ospf [(1-65535)] process This command can be used to clear the ospf process data structures. This @@ -331,7 +292,6 @@ To start OSPF process you have to specify the OSPF router. in router-id and if user wants the router-id change to take effect, user can use this cli instead of restarting the ospfd daemon. -.. index:: clear ip ospf [(1-65535)] neighbor .. clicmd:: clear ip ospf [(1-65535)] neighbor This command can be used to clear the ospf neighbor data structures. This @@ -344,17 +304,11 @@ To start OSPF process you have to specify the OSPF router. Areas ----- -.. index:: area A.B.C.D range A.B.C.D/M .. clicmd:: area A.B.C.D range A.B.C.D/M -.. index:: area (0-4294967295) range A.B.C.D/M .. clicmd:: area (0-4294967295) range A.B.C.D/M -.. index:: area A.B.C.D range A.B.C.D/M -.. clicmd:: no area A.B.C.D range A.B.C.D/M -.. index:: area (0-4294967295) range A.B.C.D/M -.. clicmd:: no area (0-4294967295) range A.B.C.D/M Summarize intra area paths from specified area into one Type-3 summary-LSA announced to other areas. This command can be used only in ABR and ONLY @@ -374,21 +328,15 @@ Areas announced into backbone area if area 0.0.0.10 contains at least one intra-area network (i.e. described with router or network LSA) from this range. -.. index:: area A.B.C.D range IPV4_PREFIX not-advertise .. clicmd:: area A.B.C.D range IPV4_PREFIX not-advertise -.. index:: area A.B.C.D range IPV4_PREFIX not-advertise -.. clicmd:: no area A.B.C.D range IPV4_PREFIX not-advertise Instead of summarizing intra area paths filter them - i.e. intra area paths from this range are not advertised into other areas. This command makes sense in ABR only. -.. index:: area A.B.C.D range IPV4_PREFIX substitute IPV4_PREFIX .. clicmd:: area A.B.C.D range IPV4_PREFIX substitute IPV4_PREFIX -.. index:: area A.B.C.D range IPV4_PREFIX substitute IPV4_PREFIX -.. clicmd:: no area A.B.C.D range IPV4_PREFIX substitute IPV4_PREFIX Substitute summarized prefix with another prefix. @@ -405,44 +353,26 @@ Areas network-LSA) from range 10.0.0.0/8. This command makes sense in ABR only. -.. index:: area A.B.C.D virtual-link A.B.C.D .. clicmd:: area A.B.C.D virtual-link A.B.C.D -.. index:: area (0-4294967295) virtual-link A.B.C.D .. clicmd:: area (0-4294967295) virtual-link A.B.C.D -.. index:: area A.B.C.D virtual-link A.B.C.D -.. clicmd:: no area A.B.C.D virtual-link A.B.C.D -.. index:: area (0-4294967295) virtual-link A.B.C.D -.. clicmd:: no area (0-4294967295) virtual-link A.B.C.D -.. index:: area A.B.C.D shortcut .. clicmd:: area A.B.C.D shortcut -.. index:: area (0-4294967295) shortcut .. clicmd:: area (0-4294967295) shortcut -.. index:: area A.B.C.D shortcut -.. clicmd:: no area A.B.C.D shortcut -.. index:: area (0-4294967295) shortcut -.. clicmd:: no area (0-4294967295) shortcut Configure the area as Shortcut capable. See :rfc:`3509`. This requires that the 'abr-type' be set to 'shortcut'. -.. index:: area A.B.C.D stub .. clicmd:: area A.B.C.D stub -.. index:: area (0-4294967295) stub .. clicmd:: area (0-4294967295) stub -.. index:: area A.B.C.D stub -.. clicmd:: no area A.B.C.D stub -.. index:: area (0-4294967295) stub -.. clicmd:: no area (0-4294967295) stub Configure the area to be a stub area. That is, an area where no router originates routes external to OSPF and hence an area where all external @@ -451,40 +381,25 @@ Areas area. They need only pass Network-Summary (type-3) LSAs into such an area, along with a default-route summary. -.. index:: area A.B.C.D stub no-summary .. clicmd:: area A.B.C.D stub no-summary -.. index:: area (0-4294967295) stub no-summary .. clicmd:: area (0-4294967295) stub no-summary -.. index:: area A.B.C.D stub no-summary -.. clicmd:: no area A.B.C.D stub no-summary -.. index:: area (0-4294967295) stub no-summary -.. clicmd:: no area (0-4294967295) stub no-summary Prevents an *ospfd* ABR from injecting inter-area summaries into the specified stub area. -.. index:: area A.B.C.D default-cost (0-16777215) .. clicmd:: area A.B.C.D default-cost (0-16777215) -.. index:: area A.B.C.D default-cost (0-16777215) -.. clicmd:: no area A.B.C.D default-cost (0-16777215) Set the cost of default-summary LSAs announced to stubby areas. -.. index:: area A.B.C.D export-list NAME .. clicmd:: area A.B.C.D export-list NAME -.. index:: area (0-4294967295) export-list NAME .. clicmd:: area (0-4294967295) export-list NAME -.. index:: area A.B.C.D export-list NAME -.. clicmd:: no area A.B.C.D export-list NAME -.. index:: area (0-4294967295) export-list NAME -.. clicmd:: no area (0-4294967295) export-list NAME Filter Type-3 summary-LSAs announced to other areas originated from intra- area paths from specified area. @@ -507,67 +422,41 @@ Areas This command is only relevant if the router is an ABR for the specified area. -.. index:: area A.B.C.D import-list NAME .. clicmd:: area A.B.C.D import-list NAME -.. index:: area (0-4294967295) import-list NAME .. clicmd:: area (0-4294967295) import-list NAME -.. index:: area A.B.C.D import-list NAME -.. clicmd:: no area A.B.C.D import-list NAME -.. index:: area (0-4294967295) import-list NAME -.. clicmd:: no area (0-4294967295) import-list NAME Same as export-list, but it applies to paths announced into specified area as Type-3 summary-LSAs. -.. index:: area A.B.C.D filter-list prefix NAME in .. clicmd:: area A.B.C.D filter-list prefix NAME in -.. index:: area A.B.C.D filter-list prefix NAME out .. clicmd:: area A.B.C.D filter-list prefix NAME out -.. index:: area (0-4294967295) filter-list prefix NAME in .. clicmd:: area (0-4294967295) filter-list prefix NAME in -.. index:: area (0-4294967295) filter-list prefix NAME out .. clicmd:: area (0-4294967295) filter-list prefix NAME out -.. index:: area A.B.C.D filter-list prefix NAME in -.. clicmd:: no area A.B.C.D filter-list prefix NAME in -.. index:: area A.B.C.D filter-list prefix NAME out -.. clicmd:: no area A.B.C.D filter-list prefix NAME out -.. index:: area (0-4294967295) filter-list prefix NAME in -.. clicmd:: no area (0-4294967295) filter-list prefix NAME in -.. index:: area (0-4294967295) filter-list prefix NAME out -.. clicmd:: no area (0-4294967295) filter-list prefix NAME out Filtering Type-3 summary-LSAs to/from area using prefix lists. This command makes sense in ABR only. -.. index:: area A.B.C.D authentication .. clicmd:: area A.B.C.D authentication -.. index:: area (0-4294967295) authentication .. clicmd:: area (0-4294967295) authentication -.. index:: area A.B.C.D authentication -.. clicmd:: no area A.B.C.D authentication -.. index:: area (0-4294967295) authentication -.. clicmd:: no area (0-4294967295) authentication Specify that simple password authentication should be used for the given area. -.. index:: area A.B.C.D authentication message-digest .. clicmd:: area A.B.C.D authentication message-digest -.. index:: area (0-4294967295) authentication message-digest .. clicmd:: area (0-4294967295) authentication message-digest Specify that OSPF packets must be authenticated with MD5 HMACs within the @@ -583,11 +472,8 @@ Areas Interfaces ---------- -.. index:: ip ospf area AREA [ADDR] .. clicmd:: ip ospf area AREA [ADDR] -.. index:: ip ospf area [ADDR] -.. clicmd:: no ip ospf area [ADDR] Enable OSPF on the interface, optionally restricted to just the IP address given by `ADDR`, putting it in the `AREA` area. Per interface area settings @@ -597,11 +483,8 @@ Interfaces If you have a lot of interfaces, and/or a lot of subnets, then enabling OSPF via this command may result in a slight performance improvement. -.. index:: ip ospf authentication-key AUTH_KEY .. clicmd:: ip ospf authentication-key AUTH_KEY -.. index:: ip ospf authentication-key -.. clicmd:: no ip ospf authentication-key Set OSPF authentication key to a simple password. After setting `AUTH_KEY`, all OSPF packets are authenticated. `AUTH_KEY` has length up to 8 chars. @@ -609,7 +492,6 @@ Interfaces Simple text password authentication is insecure and deprecated in favour of MD5 HMAC authentication. -.. index:: ip ospf authentication message-digest .. clicmd:: ip ospf authentication message-digest Specify that MD5 HMAC authentication must be used on this interface. MD5 @@ -626,11 +508,8 @@ Interfaces non-volatile storage and restored at boot if MD5 authentication is to be expected to work reliably. -.. index:: ip ospf message-digest-key KEYID md5 KEY .. clicmd:: ip ospf message-digest-key KEYID md5 KEY -.. index:: ip ospf message-digest-key -.. clicmd:: no ip ospf message-digest-key Set OSPF authentication key to a cryptographic password. The cryptographic algorithm is MD5. @@ -641,23 +520,16 @@ Interfaces KEY is the actual message digest key, of up to 16 chars (larger strings will be truncated), and is associated with the given KEYID. -.. index:: ip ospf cost (1-65535) .. clicmd:: ip ospf cost (1-65535) -.. index:: ip ospf cost -.. clicmd:: no ip ospf cost Set link cost for the specified interface. The cost value is set to router-LSA's metric field and used for SPF calculation. -.. index:: ip ospf dead-interval (1-65535) .. clicmd:: ip ospf dead-interval (1-65535) -.. index:: ip ospf dead-interval minimal hello-multiplier (2-20) .. clicmd:: ip ospf dead-interval minimal hello-multiplier (2-20) -.. index:: ip ospf dead-interval -.. clicmd:: no ip ospf dead-interval Set number of seconds for RouterDeadInterval timer value used for Wait Timer and Inactivity Timer. This value must be the same for all routers attached @@ -672,11 +544,8 @@ Interfaces hello-multiplier need NOT be the same across multiple routers on a common link. -.. index:: ip ospf hello-interval (1-65535) .. clicmd:: ip ospf hello-interval (1-65535) -.. index:: ip ospf hello-interval -.. clicmd:: no ip ospf hello-interval Set number of seconds for HelloInterval timer value. Setting this value, Hello packet will be sent every timer value seconds on the specified interface. @@ -687,7 +556,6 @@ Interfaces :clicmd:`ip ospf dead-interval minimal hello-multiplier (2-20)` is also specified for the interface. -.. index:: ip ospf network (broadcast|non-broadcast|point-to-multipoint|point-to-point) .. clicmd:: ip ospf network (broadcast|non-broadcast|point-to-multipoint|point-to-point) When configuring a point-to-point network on an interface and the interface @@ -696,45 +564,31 @@ Interfaces net.ipv4.conf.<interface name>.rp_filter value to 0. In order for the ospf multicast packets to be delivered by the kernel. -.. index:: ip ospf network -.. clicmd:: no ip ospf network Set explicitly network type for specified interface. -.. index:: ip ospf priority (0-255) .. clicmd:: ip ospf priority (0-255) -.. index:: ip ospf priority -.. clicmd:: no ip ospf priority Set RouterPriority integer value. The router with the highest priority will be more eligible to become Designated Router. Setting the value to 0, makes the router ineligible to become Designated Router. The default value is 1. -.. index:: ip ospf retransmit-interval (1-65535) .. clicmd:: ip ospf retransmit-interval (1-65535) -.. index:: ip ospf retransmit interval -.. clicmd:: no ip ospf retransmit interval Set number of seconds for RxmtInterval timer value. This value is used when retransmitting Database Description and Link State Request packets. The default value is 5 seconds. -.. index:: ip ospf transmit-delay (1-65535) [A.B.C.D] .. clicmd:: ip ospf transmit-delay (1-65535) [A.B.C.D] -.. index:: ip ospf transmit-delay [(1-65535)] [A.B.C.D] -.. clicmd:: no ip ospf transmit-delay [(1-65535)] [A.B.C.D] Set number of seconds for InfTransDelay value. LSAs' age should be incremented by this value when transmitting. The default value is 1 second. -.. index:: ip ospf area (A.B.C.D|(0-4294967295)) .. clicmd:: ip ospf area (A.B.C.D|(0-4294967295)) -.. index:: ip ospf area -.. clicmd:: no ip ospf area Enable ospf on an interface and set associated area. @@ -743,7 +597,6 @@ OSPF route-map Usage of *ospfd*'s route-map support. -.. index:: set metric [+|-](0-4294967295) .. clicmd:: set metric [+|-](0-4294967295) Set a metric for matched route when sending announcement. Use plus (+) sign @@ -755,35 +608,10 @@ Usage of *ospfd*'s route-map support. Redistribution -------------- -.. index:: redistribute (kernel|connected|static|rip|bgp) -.. clicmd:: redistribute (kernel|connected|static|rip|bgp) - -.. index:: redistribute (kernel|connected|static|rip|bgp) ROUTE-MAP -.. clicmd:: redistribute (kernel|connected|static|rip|bgp) ROUTE-MAP - -.. index:: redistribute (kernel|connected|static|rip|bgp) metric-type (1|2) -.. clicmd:: redistribute (kernel|connected|static|rip|bgp) metric-type (1|2) - -.. index:: redistribute (kernel|connected|static|rip|bgp) metric-type (1|2) route-map WORD -.. clicmd:: redistribute (kernel|connected|static|rip|bgp) metric-type (1|2) route-map WORD - -.. index:: redistribute (kernel|connected|static|rip|bgp) metric (0-16777214) -.. clicmd:: redistribute (kernel|connected|static|rip|bgp) metric (0-16777214) - -.. index:: redistribute (kernel|connected|static|rip|bgp) metric (0-16777214) route-map WORD -.. clicmd:: redistribute (kernel|connected|static|rip|bgp) metric (0-16777214) route-map WORD - -.. index:: redistribute (kernel|connected|static|rip|bgp) metric-type (1|2) metric (0-16777214) -.. clicmd:: redistribute (kernel|connected|static|rip|bgp) metric-type (1|2) metric (0-16777214) - -.. index:: redistribute (kernel|connected|static|rip|bgp) metric-type (1|2) metric (0-16777214) route-map WORD -.. clicmd:: redistribute (kernel|connected|static|rip|bgp) metric-type (1|2) metric (0-16777214) route-map WORD - -.. index:: redistribute (kernel|connected|static|rip|bgp) -.. clicmd:: no redistribute (kernel|connected|static|rip|bgp) - .. _ospf-redistribute: +.. clicmd:: redistribute <babel|bgp|connected|eigrp|isis|kernel|openfabric|ospf|rip|sharp|static|table> [metric-type (1-2)] [metric (0-16777214)] [route-map WORD] + Redistribute routes of the specified protocol or kind into OSPF, with the metric type and metric set if specified, filtering the routes using the given route-map if specified. Redistributed routes may also be filtered @@ -802,43 +630,30 @@ Redistribution clicmd:`passive-interface INTERFACE`. -.. index:: default-information originate .. clicmd:: default-information originate -.. index:: default-information originate metric (0-16777214) .. clicmd:: default-information originate metric (0-16777214) -.. index:: default-information originate metric (0-16777214) metric-type (1|2) .. clicmd:: default-information originate metric (0-16777214) metric-type (1|2) -.. index:: default-information originate metric (0-16777214) metric-type (1|2) route-map WORD .. clicmd:: default-information originate metric (0-16777214) metric-type (1|2) route-map WORD -.. index:: default-information originate always .. clicmd:: default-information originate always -.. index:: default-information originate always metric (0-16777214) .. clicmd:: default-information originate always metric (0-16777214) -.. index:: default-information originate always metric (0-16777214) metric-type (1|2) .. clicmd:: default-information originate always metric (0-16777214) metric-type (1|2) -.. 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 -.. index:: default-information originate -.. clicmd:: no default-information originate Originate an AS-External (type-5) LSA describing a default route into all external-routing capable areas, of the specified metric and metric type. If the 'always' keyword is given then the default is always advertised, even when there is no default present in the routing table. -.. index:: distribute-list NAME out (kernel|connected|static|rip|ospf .. clicmd:: distribute-list NAME out (kernel|connected|static|rip|ospf -.. index:: distribute-list NAME out (kernel|connected|static|rip|ospf -.. clicmd:: no distribute-list NAME out (kernel|connected|static|rip|ospf .. _ospf-distribute-list: @@ -846,38 +661,21 @@ Redistribution type before allowing the routes to redistributed into OSPF (:ref:`ospf redistribution <ospf-redistribute>`). -.. index:: default-metric (0-16777214) .. clicmd:: default-metric (0-16777214) -.. index:: default-metric -.. clicmd:: no default-metric -.. index:: distance (1-255) .. clicmd:: distance (1-255) -.. index:: distance (1-255) -.. clicmd:: no distance (1-255) -.. index:: distance ospf (intra-area|inter-area|external) (1-255) .. clicmd:: distance ospf (intra-area|inter-area|external) (1-255) -.. index:: distance ospf -.. clicmd:: no distance ospf - -.. index:: router zebra -.. clicmd:: router zebra -.. index:: router zebra -.. clicmd:: no router zebra Graceful Restart Helper ======================= -.. index:: graceful-restart helper-only [A.B.C.D] .. clicmd:: graceful-restart helper-only [A.B.C.D] -.. index:: graceful-restart helper-only [A.B.C.D] -.. clicmd:: no graceful-restart helper-only [A.B.C.D] Configure Graceful Restart (RFC 3623) helper support. By default, helper support is disabled for all neighbours. @@ -886,30 +684,21 @@ Graceful Restart Helper To enable/disable helper support for a specific neighbour, the router-id (A.B.C.D) has to be specified. -.. index:: graceful-restart helper strict-lsa-checking .. clicmd:: graceful-restart helper strict-lsa-checking -.. index:: graceful-restart helper strict-lsa-checking -.. clicmd:: no graceful-restart helper strict-lsa-checking If 'strict-lsa-checking' is configured then the helper will abort the Graceful Restart when a LSA change occurs which affects the restarting router. By default 'strict-lsa-checking' is enabled" -.. index:: graceful-restart helper supported-grace-time .. clicmd:: graceful-restart helper supported-grace-time -.. index:: graceful-restart helper supported-grace-time -.. clicmd:: no graceful-restart helper supported-grace-time Supports as HELPER for configured grace period. -.. index:: graceful-restart helper planned-only .. clicmd:: graceful-restart helper planned-only -.. index:: graceful-restart helper planned-only -.. clicmd:: no graceful-restart helper planned-only It helps to support as HELPER only for planned restarts. By default, it supports both planned and @@ -922,68 +711,53 @@ Showing Information .. _show-ip-ospf: -.. index:: show ip ospf [json] .. clicmd:: show ip ospf [json] Show information on a variety of general OSPF and area state and configuration information. -.. index:: show ip ospf interface [INTERFACE] [json] .. clicmd:: show ip ospf interface [INTERFACE] [json] Show state and configuration of OSPF the specified interface, or all interfaces if no interface is given. -.. index:: show ip ospf neighbor [json] .. clicmd:: show ip ospf neighbor [json] -.. index:: show ip ospf neighbor INTERFACE [json] .. clicmd:: show ip ospf neighbor INTERFACE [json] -.. index:: show ip ospf neighbor detail [json] .. clicmd:: show ip ospf neighbor detail [json] -.. index:: show ip ospf neighbor INTERFACE detail [json] .. clicmd:: show ip ospf neighbor INTERFACE detail [json] Display lsa information of LSDB. Json o/p of this command covers base route information i.e all LSAs except opaque lsa info. -.. index:: show ip ospf database [json] -.. clicmd:: show ip ospf database [json] +.. clicmd:: show ip ospf [vrf <NAME|all>] database [json] -.. index:: show ip ospf 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) [json] -.. index:: show ip ospf 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 [json] -.. index:: show ip ospf 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) LINK-STATE-ID adv-router ADV-ROUTER [json] -.. index:: show ip ospf 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) adv-router ADV-ROUTER [json] -.. index:: show ip ospf 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) LINK-STATE-ID self-originate [json] -.. index:: show ip ospf 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 (asbr-summary|external|network|router|summary) self-originate [json] -.. index:: show ip ospf database max-age [json] -.. clicmd:: show ip ospf database max-age [json] +.. clicmd:: show ip ospf [vrf <NAME|all>] database max-age [json] -.. index:: show ip ospf database self-originate [json] -.. clicmd:: show ip ospf database self-originate [json] +.. clicmd:: show ip ospf [vrf <NAME|all>] database self-originate [json] + + Show the OSPF database summary. -.. index:: show ip ospf route [json] .. clicmd:: show ip ospf route [json] Show the OSPF routing table, as determined by the most recent SPF calculation. -.. index:: show ip ospf graceful-restart helper [detail] [json] .. clicmd:: show ip ospf graceful-restart helper [detail] [json] Displays the Grcaeful Restart Helper details including helper @@ -994,17 +768,11 @@ Showing Information Opaque LSA ========== -.. index:: ospf opaque-lsa .. clicmd:: ospf opaque-lsa -.. index:: capability opaque .. clicmd:: capability opaque -.. index:: ospf opaque-lsa -.. clicmd:: no ospf opaque-lsa -.. index:: capability opaque -.. clicmd:: no capability opaque *ospfd* supports Opaque LSA (:rfc:`2370`) as partial support for MPLS Traffic Engineering LSAs. The opaque-lsa capability must be @@ -1014,23 +782,17 @@ Opaque LSA extensions that are used with MPLS-TE; it does not support a complete RSVP-TE solution. -.. index:: show ip ospf database (opaque-link|opaque-area|opaque-external) -.. 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) -.. index:: show ip ospf database (opaque-link|opaque-area|opaque-external) LINK-STATE-ID -.. 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 -.. index:: show ip ospf 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) 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 -.. index:: show ip ospf database (opaque-link|opaque-area|opaque-external) 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 -.. index:: show ip ospf database (opaque-link|opaque-area|opaque-external) LINK-STATE-ID self-originate -.. 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 -.. index:: show ip ospf database (opaque-link|opaque-area|opaque-external) 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. @@ -1045,40 +807,30 @@ Traffic Engineering protocol extensions that can be used with MPLS-TE. FRR does not support a complete RSVP-TE solution currently. -.. index:: mpls-te on .. clicmd:: mpls-te on -.. index:: mpls-te -.. clicmd:: no mpls-te Enable Traffic Engineering LSA flooding. -.. index:: mpls-te router-address <A.B.C.D> .. clicmd:: mpls-te router-address <A.B.C.D> Configure stable IP address for MPLS-TE. This IP address is then advertise in Opaque LSA Type-10 TLV=1 (TE) option 1 (Router-Address). -.. index:: mpls-te inter-as area <area-id>|as .. clicmd:: mpls-te inter-as area <area-id>|as -.. index:: mpls-te inter-as -.. clicmd:: no mpls-te inter-as Enable :rfc:`5392` support - Inter-AS TE v2 - to flood Traffic Engineering parameters of Inter-AS link. 2 modes are supported: AREA and AS; LSA are flood in AREA <area-id> with Opaque Type-10, respectively in AS with Opaque Type-11. In all case, Opaque-LSA TLV=6. -.. index:: show ip ospf mpls-te interface .. clicmd:: show ip ospf mpls-te interface -.. index:: show ip ospf mpls-te interface INTERFACE .. clicmd:: show ip ospf mpls-te interface INTERFACE Show MPLS Traffic Engineering parameters for all or specified interface. -.. index:: show ip ospf mpls-te router .. clicmd:: show ip ospf mpls-te router Show Traffic Engineering router parameters. @@ -1088,11 +840,8 @@ Traffic Engineering Router Information ================== -.. index:: router-info [as | area] .. clicmd:: router-info [as | area] -.. index:: router-info -.. clicmd:: no router-info Enable Router Information (:rfc:`4970`) LSA advertisement with AS scope (default) or Area scope flooding when area is specified. Old syntax @@ -1100,35 +849,20 @@ Router Information as the area ID is no more necessary. Indeed, router information support multi-area and detect automatically the areas. -.. index:: pce address <A.B.C.D> .. clicmd:: pce address <A.B.C.D> -.. index:: pce address -.. clicmd:: no pce address -.. index:: pce domain as (0-65535) .. clicmd:: pce domain as (0-65535) -.. index:: pce domain as (0-65535) -.. clicmd:: no pce domain as (0-65535) -.. index:: pce neighbor as (0-65535) .. clicmd:: pce neighbor as (0-65535) -.. index:: pce neighbor as (0-65535) -.. clicmd:: no pce neighbor as (0-65535) -.. index:: pce flag BITPATTERN .. clicmd:: pce flag BITPATTERN -.. index:: pce flag -.. clicmd:: no pce flag -.. index:: pce scope BITPATTERN .. clicmd:: pce scope BITPATTERN -.. index:: pce scope -.. clicmd:: no pce scope The commands are conform to :rfc:`5088` and allow OSPF router announce Path Computation Element (PCE) capabilities through the Router Information (RI) @@ -1138,12 +872,10 @@ Router Information refer to :rfc`5088` for the BITPATTERN recognition. Multiple 'pce neighbor' command could be specified in order to specify all PCE neighbours. -.. index:: show ip ospf router-info .. clicmd:: show ip ospf router-info Show Router Capabilities flag. -.. index:: show ip ospf router-info pce .. clicmd:: show ip ospf router-info pce Show Router Capabilities PCE parameters. @@ -1156,42 +888,35 @@ Segment Routing This is an EXPERIMENTAL support of Segment Routing as per `RFC 8665` for MPLS dataplane. -.. index:: segment-routing on -.. clicmd:: [no] segment-routing on +.. clicmd:: segment-routing on Enable Segment Routing. Even if this also activate routing information support, it is preferable to also activate routing information, and set accordingly the Area or AS flooding. -.. index:: segment-routing global-block (0-1048575) (0-1048575) -.. clicmd:: [no] segment-routing global-block (0-1048575) (0-1048575) +.. clicmd:: segment-routing global-block (0-1048575) (0-1048575) Fix the Segment Routing Global Block i.e. the label range used by MPLS to store label in the MPLS FIB for Prefix SID. -.. index:: segment-routing local-block (0-1048575) (0-1048575) -.. clicmd:: [no] segment-routing local-block (0-1048575) (0-1048575) +.. clicmd:: segment-routing local-block (0-1048575) (0-1048575) Fix the Segment Routing Local Block i.e. the label range used by MPLS to store label in the MPLS FIB for Adjacency SID. -.. index:: segment-routing node-msd (1-16) -.. clicmd:: [no] segment-routing node-msd (1-16) +.. clicmd:: segment-routing node-msd (1-16) Fix the Maximum Stack Depth supported by the router. The value depend of the MPLS dataplane. E.g. for Linux kernel, since version 4.13 it is 32. -.. index:: segment-routing prefix A.B.C.D/M index (0-65535) [no-php-flag|explicit-null] -.. clicmd:: [no] segment-routing prefix A.B.C.D/M [index (0-65535)|no-php-flag|explicit-null] +.. clicmd:: segment-routing prefix A.B.C.D/M [index (0-65535)|no-php-flag|explicit-null] - Set the Segment Routing index for the specified prefix. Note that, only prefix with /32 corresponding to a loopback interface are currently supported. The 'no-php-flag' means NO Penultimate Hop Popping that allows SR node to request to its neighbor to not pop the label. The 'explicit-null' means that neighbor nodes must swap the incoming label by the MPLS Explicit Null label before delivering the packet. -.. index:: show ip ospf database segment-routing <adv-router ADVROUTER|self-originate> [json] .. clicmd:: show ip ospf database segment-routing <adv-router ADVROUTER|self-originate> [json] Show Segment Routing Data Base, all SR nodes, specific advertised router or @@ -1203,31 +928,25 @@ External Route Summarisation This feature summarises originated external LSAs(Type-5 and Type-7). Summary Route will be originated on-behalf of all matched external LSAs. -.. index:: summary-address A.B.C.D/M [tag (1-4294967295)] -.. clicmd:: [no] summary-address A.B.C.D/M [tag (1-4294967295)] +.. clicmd:: summary-address A.B.C.D/M [tag (1-4294967295)] This command enable/disables summarisation for the configured address range. Tag is the optional parameter. If tag configured Summary route will be originated with the configured tag. -.. index:: summary-address A.B.C.D/M no-advertise -.. clicmd:: [no] summary-address A.B.C.D/M no-advertise +.. clicmd:: summary-address A.B.C.D/M no-advertise This command to ensure not advertise the summary lsa for the matched external LSAs. -.. index:: aggregation timer (5-1800) .. clicmd:: aggregation timer (5-1800) Configure aggregation delay timer interval. Summarisation starts only after this delay timer expiry. By default, delay interval is 5 secs. -.. index:: aggregation timer -.. clicmd:: no aggregation timer Resetting the aggregation delay interval to default value. -.. index:: show ip ospf [vrf <NAME|all>] summary-address [detail] [json] .. clicmd:: show ip ospf [vrf <NAME|all>] summary-address [detail] [json] Show configuration for display all configured summary routes with @@ -1240,7 +959,6 @@ Experimental support for Topology Independent LFA (Loop-Free Alternate), see for example 'draft-bashandy-rtgwg-segment-routing-ti-lfa-05'. Note that TI-LFA requires a proper Segment Routing configuration. -.. index:: fast-reroute ti-lfa [node-protection] .. clicmd:: fast-reroute ti-lfa [node-protection] Configured on the router level. Activates TI-LFA for all interfaces. @@ -1250,107 +968,72 @@ TI-LFA requires a proper Segment Routing configuration. Debugging OSPF ============== -.. index:: debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv) [detail] +.. 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] -.. index:: debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv) [detail] -.. clicmd:: no debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv) [detail] Dump Packet for debugging -.. index:: debug ospf ism .. clicmd:: debug ospf ism -.. index:: debug ospf ism (status|events|timers) .. clicmd:: debug ospf ism (status|events|timers) -.. index:: debug ospf ism -.. clicmd:: no debug ospf ism -.. index:: debug ospf ism (status|events|timers) -.. clicmd:: no debug ospf ism (status|events|timers) Show debug information of Interface State Machine -.. index:: debug ospf nsm .. clicmd:: debug ospf nsm -.. index:: debug ospf nsm (status|events|timers) .. clicmd:: debug ospf nsm (status|events|timers) -.. index:: debug ospf nsm -.. clicmd:: no debug ospf nsm -.. index:: debug ospf nsm (status|events|timers) -.. clicmd:: no debug ospf nsm (status|events|timers) Show debug information of Network State Machine -.. index:: debug ospf event .. clicmd:: debug ospf event -.. index:: debug ospf event -.. clicmd:: no debug ospf event Show debug information of OSPF event -.. index:: debug ospf nssa .. clicmd:: debug ospf nssa -.. index:: debug ospf nssa -.. clicmd:: no debug ospf nssa Show debug information about Not So Stub Area -.. index:: debug ospf lsa .. clicmd:: debug ospf lsa -.. index:: debug ospf lsa (generate|flooding|refresh) .. clicmd:: debug ospf lsa (generate|flooding|refresh) -.. index:: debug ospf lsa -.. clicmd:: no debug ospf lsa -.. index:: debug ospf lsa (generate|flooding|refresh) -.. clicmd:: no debug ospf lsa (generate|flooding|refresh) Show debug detail of Link State messages -.. index:: debug ospf te .. clicmd:: debug ospf te -.. index:: debug ospf te -.. clicmd:: no debug ospf te Show debug information about Traffic Engineering LSA -.. index:: debug ospf zebra .. clicmd:: debug ospf zebra -.. index:: debug ospf zebra (interface|redistribute) .. clicmd:: debug ospf zebra (interface|redistribute) -.. index:: debug ospf zebra -.. clicmd:: no debug ospf zebra -.. index:: debug ospf zebra (interface|redistribute) -.. clicmd:: no debug ospf zebra (interface|redistribute) Show debug information of ZEBRA API -.. index:: debug ospf graceful-restart helper .. clicmd:: debug ospf graceful-restart helper -.. index:: debug ospf graceful-restart helper -.. clicmd:: no debug ospf graceful-restart helper Enable/disable debug information for OSPF Graceful Restart Helper -.. index:: show debugging ospf .. clicmd:: show debugging ospf -.. index:: debug ospf lsa aggregate -.. clicmd:: [no] debug ospf lsa aggregate +.. clicmd:: debug ospf lsa aggregate Debug commnd to enable/disable external route summarisation specific debugs. diff --git a/doc/user/overview.rst b/doc/user/overview.rst index f67698e404..b4f56260c9 100644 --- a/doc/user/overview.rst +++ b/doc/user/overview.rst @@ -62,9 +62,8 @@ Feature support varies by platform; see the :ref:`feature-matrix`. System Architecture ------------------- -.. index:: System architecture -.. index:: Software architecture -.. index:: Software internals +.. index:: + pair: architecture; FRR Traditional routing software is made as a one process program which provides all of the routing protocol functionalities. FRR takes a different approach. @@ -114,15 +113,15 @@ data models. When this work is completed, FRR will be a fully programmable routing stack. +.. index:: + pair: platforms; FRR + pair: operating systems; FRR + .. _supported-platforms: Supported Platforms ------------------- -.. index:: Supported platforms -.. index:: FRR on other systems -.. index:: Compatibility with other systems -.. index:: Operating systems that support FRR Currently FRR supports GNU/Linux and BSD. Porting FRR to other platforms is not too difficult as platform dependent code should be mostly limited to the @@ -149,11 +148,9 @@ Recent versions of the following compilers are well tested: .. _unsupported-platforms: -UnSupported Platforms +Unsupported Platforms --------------------- -.. index:: UnSupported platforms - In General if the platform you are attempting to use is not listed above then FRR does not support being run on that platform. The only caveat here is that version 7.5 and before Solaris was supported in a limited fashion. @@ -264,6 +261,10 @@ Known Kernel Issues especially becomes apparent if the route is being transformed from one ECMP path to another. + +.. index:: + pair: rfcs; FRR + .. _supported-rfcs: Supported RFCs @@ -341,6 +342,8 @@ BGP :t:`Default External BGP (EBGP) Route Propagation Behavior without Policies. J. Mauch, J. Snijders, G. Hankins. July 2017` - :rfc:`8277` :t:`Using BGP to Bind MPLS Labels to Address Prefixes. E. Rosen. October 2017` +- :rfc:`8654` + :t:`Extended Message Support for BGP. R. Bush, K. Patel, D. Ward. October 2019` OSPF @@ -439,13 +442,14 @@ SNMP - :rfc:`2741` :t:`Agent Extensibility (AgentX) Protocol. M. Daniele, B. Wijnen. January 2000.` -Mailing Lists -============= -.. index:: How to get in touch with FRR -.. index:: Contact information -.. index:: Mailing lists +.. index:: + pair: mailing lists; contact +.. _mailing-lists: + +Mailing Lists +============= Italicized lists are private. @@ -471,6 +475,7 @@ results of such discussions are reflected in updates, as appropriate, to code changes, updates to the Development list and either this file or information posted at `FRR`_. + Bug Reports =========== diff --git a/doc/user/pathd.rst b/doc/user/pathd.rst index 0815a6c414..fe50a5e7eb 100644 --- a/doc/user/pathd.rst +++ b/doc/user/pathd.rst @@ -105,72 +105,59 @@ Example: Configuration Commands ---------------------- -.. index:: segment-routing .. clicmd:: segment-routing Configure segment routing. -.. index:: traffic-eng .. clicmd:: traffic-eng Configure segment routing traffic engineering. -.. index:: segment-list NAME -.. clicmd:: [no] segment-list NAME +.. clicmd:: segment-list NAME Delete or start a segment list definition. - -.. index:: index INDEX mpls label LABEL [nai node ADDRESS] -.. clicmd:: [no] index INDEX mpls label LABEL [nai node ADDRESS] +.. clicmd:: index INDEX mpls label LABEL [nai node ADDRESS] Delete or specify a segment in a segment list definition. -.. index:: policy color COLOR endpoint ENDPOINT -.. clicmd:: [no] policy color COLOR endpoint ENDPOINT +.. clicmd:: policy color COLOR endpoint ENDPOINT Delete or start a policy definition. -.. index:: name NAME .. clicmd:: name NAME Specify the policy name. -.. index:: binding-sid LABEL .. clicmd:: binding-sid LABEL Specify the policy SID. -.. index:: candidate-path preference PREFERENCE name NAME explicit segment-list SEGMENT-LIST-NAME -.. clicmd:: [no] candidate-path preference PREFERENCE name NAME explicit segment-list SEGMENT-LIST-NAME +.. clicmd:: candidate-path preference PREFERENCE name NAME explicit segment-list SEGMENT-LIST-NAME Delete or define an explicit candidate path. -.. index:: candidate-path preference PREFERENCE name NAME dynamic -.. clicmd:: [no] candidate-path preference PREFERENCE name NAME dynamic +.. clicmd:: candidate-path preference PREFERENCE name NAME dynamic Delete or start a dynamic candidate path definition. -.. index:: affinity {exclude-any|include-any|include-all} BITPATTERN -.. clicmd:: [no] affinity {exclude-any|include-any|include-all} BITPATTERN +.. clicmd:: affinity {exclude-any|include-any|include-all} BITPATTERN Delete or specify an affinity constraint for a dynamic candidate path. -.. index:: bandwidth BANDWIDTH [required] -.. clicmd:: [no] bandwidth BANDWIDTH [required] +.. clicmd:: bandwidth BANDWIDTH [required] Delete or specify a bandwidth constraint for a dynamic candidate path. -.. index:: metric [bound] METRIC VALUE [required] -.. clicmd:: [no] metric [bound] METRIC VALUE [required] +.. clicmd:: metric [bound] METRIC VALUE [required] Delete or specify a metric constraint for a dynamic candidate path. @@ -198,8 +185,7 @@ Configuration Commands - bnc: Border Node Count metric -.. index:: objective-function OBJFUN1 [required] -.. clicmd:: [no] objective-function OBJFUN1 [required] +.. clicmd:: objective-function OBJFUN1 [required] Delete or specify a PCEP objective function constraint for a dynamic candidate path. @@ -224,8 +210,7 @@ Configuration Commands - msn: Minimize the number of Shared Nodes [RFC8800] -.. index:: debug pathd pcep [basic|path|message|pceplib] -.. clicmd:: [no] debug pathd pcep [basic|path|message|pceplib] +.. clicmd:: debug pathd pcep [basic|path|message|pceplib] Enable or disable debugging for the pcep module: @@ -235,33 +220,28 @@ Configuration Commands - pceplib: Enable pceplib logging -.. index:: pcep .. clicmd:: pcep Configure PCEP support. -.. index:: cep-config NAME -.. clicmd:: [no] pce-config NAME +.. clicmd:: pce-config NAME Define a shared PCE configuration that can be used in multiple PCE declarations. -.. index:: pce NAME -.. clicmd:: [no] pce NAME +.. clicmd:: pce NAME Define or delete a PCE definition. -.. index:: config WORD .. clicmd:: config WORD Select a shared configuration. If not defined, the default configuration will be used. -.. index:: address <ip A.B.C.D | ipv6 X:X::X:X> [port (1024-65535)] .. clicmd:: address <ip A.B.C.D | ipv6 X:X::X:X> [port (1024-65535)] Define the address and port of the PCE. @@ -271,7 +251,6 @@ Configuration Commands This should be specified in the PCC peer definition. -.. index:: source-address [ip A.B.C.D | ipv6 X:X::X:X] [port PORT] .. clicmd:: source-address [ip A.B.C.D | ipv6 X:X::X:X] [port PORT] Define the address and/or port of the PCC as seen by the PCE. @@ -284,7 +263,6 @@ Configuration Commands configuration group. -.. index:: tcp-md5-auth WORD .. clicmd:: tcp-md5-auth WORD Enable TCP MD5 security with the given secret. @@ -293,7 +271,6 @@ Configuration Commands configuration group. -.. index:: sr-draft07 .. clicmd:: sr-draft07 Specify if a PCE only support segment routing draft 7, this flag will limit @@ -303,7 +280,6 @@ Configuration Commands configuration group. -.. index:: pce-initiated .. clicmd:: pce-initiated Specify if PCE-initiated LSP should be allowed for this PCE. @@ -312,7 +288,6 @@ Configuration Commands configuration group. -.. index:: timer [keep-alive (1-63)] [min-peer-keep-alive (1-255)] [max-peer-keep-alive (1-255)] [dead-timer (4-255)] [min-peer-dead-timer (4-255)] [max-peer-dead-timer (4-255)] [pcep-request (1-120)] [session-timeout-interval (1-120)] [delegation-timeout (1-60)] .. clicmd:: timer [keep-alive (1-63)] [min-peer-keep-alive (1-255)] [max-peer-keep-alive (1-255)] [dead-timer (4-255)] [min-peer-dead-timer (4-255)] [max-peer-dead-timer (4-255)] [pcep-request (1-120)] [session-timeout-interval (1-120)] [delegation-timeout (1-60)] Specify the PCEP timers. @@ -321,20 +296,17 @@ Configuration Commands configuration group. -.. index:: pcc -.. clicmd:: [no] pcc +.. clicmd:: pcc Disable or start the definition of a PCC. -.. index:: msd (1-32) .. clicmd:: msd (1-32) Specify the maximum SID depth in a PCC definition. -.. index:: peer WORD [precedence (1-255)] -.. clicmd:: [no] peer WORD [precedence (1-255)] +.. clicmd:: peer WORD [precedence (1-255)] Specify a peer and its precedence in a PCC definition. @@ -342,7 +314,6 @@ Configuration Commands Introspection Commands ---------------------- -.. index:: show sr-te policy [detail] .. clicmd:: show sr-te policy [detail] Display the segment routing policies. @@ -368,38 +339,22 @@ The asterisk (*) marks the best, e.g. active, candidate path. Note that for segm retrieved via PCEP a random number based name is generated. -.. index:: show debugging pathd -.. clicmd:: show debugging pathd - - Display the current status of the pathd debugging. - - -.. index:: show debugging pathd-pcep -.. clicmd:: show debugging pathd-pcep - - Display the current status of the pcep module debugging. - - -.. index:: show sr-te pcep counters .. clicmd:: show sr-te pcep counters Display the counters from pceplib. -.. index:: show sr-te pcep pce-config [NAME] .. clicmd:: show sr-te pcep pce-config [NAME] Display a shared configuration. if no name is specified, the default configuration will be displayed. -.. index:: show sr-te pcep pcc .. clicmd:: show sr-te pcep pcc Display PCC information. -.. index:: show sr-te pcep session [NAME] .. clicmd:: show sr-te pcep session [NAME] Display the information of a PCEP session, if not name is specified all the @@ -409,7 +364,6 @@ retrieved via PCEP a random number based name is generated. Utility Commands ---------------- -.. index:: clear sr-te pcep session [NAME] .. clicmd:: clear sr-te pcep session [NAME] Reset the pcep session by disconnecting from the PCE and performing the diff --git a/doc/user/pbr.rst b/doc/user/pbr.rst index 5cec7cbe62..14a05a69d7 100644 --- a/doc/user/pbr.rst +++ b/doc/user/pbr.rst @@ -45,7 +45,7 @@ listing of ECMP nexthops used to forward packets for when a pbr-map is matched. are used to are allowed here. The syntax was intentionally kept the same as creating nexthops as you would for static routes. -.. clicmd:: [no] pbr table range (10000-4294966272) (10000-4294966272) +.. clicmd:: pbr table range (10000-4294966272) (10000-4294966272) Set or unset the range used to assign numeric table ID's to new nexthop-group tables. Existing tables will not be modified to fit in this @@ -220,6 +220,10 @@ end destination. | installedInternally | Do we think this group is installed? | Integer | +---------------------+--------------------------------------+---------+ + +.. index:: + pair: policy; PBR + .. _pbr-policy: PBR Policy @@ -229,7 +233,6 @@ After you have specified a PBR map, in order for it to be turned on, you must apply the PBR map to an interface. This policy application to an interface causes the policy to be installed into the kernel. -.. index:: pbr-policy .. clicmd:: pbr-policy NAME This command is available under interface sub-mode. This turns @@ -263,12 +266,10 @@ causes the policy to be installed into the kernel. PBR Debugs =========== -.. index:: debug pbr .. clicmd:: debug pbr events|map|nht|zebra Debug pbr in pbrd daemon. You specify what types of debugs to turn on. -.. index:: debug zebra pbr .. clicmd:: debug zebra pbr Debug pbr in zebra daemon. @@ -281,12 +282,10 @@ PBR Details Under the covers a PBR map is translated into two separate constructs in the Linux kernel. -.. index:: PBR Rules The PBR map specified creates a `ip rule ...` that is inserted into the Linux kernel that points to a table to use for forwarding once the rule matches. -.. index:: PBR Tables The creation of a nexthop or nexthop-group is translated to a default route in a table with the nexthops specified as the nexthops for the default route. diff --git a/doc/user/pim.rst b/doc/user/pim.rst index 201fe2f9ed..86716b49a4 100644 --- a/doc/user/pim.rst +++ b/doc/user/pim.rst @@ -56,7 +56,6 @@ Certain signals have special meanings to *pimd*. *pimd* invocation options. Common options that can be specified (:ref:`common-invocation-options`). -.. index:: ip pim rp A.B.C.D A.B.C.D/M .. clicmd:: ip pim rp A.B.C.D A.B.C.D/M In order to use pim, it is necessary to configure a RP for join messages to @@ -66,7 +65,6 @@ Certain signals have special meanings to *pimd*. prefix of group ranges covered. This command is vrf aware, to configure for a vrf, enter the vrf submode. -.. index:: ip pim register-accept-list PLIST .. clicmd:: ip pim register-accept-list PLIST When pim receives a register packet the source of the packet will be compared @@ -74,14 +72,12 @@ Certain signals have special meanings to *pimd*. processing continues. If a deny is returned for the source address of the register packet a register stop message is sent to the source. -.. index:: ip pim spt-switchover infinity-and-beyond .. clicmd:: ip pim spt-switchover infinity-and-beyond On the last hop router if it is desired to not switch over to the SPT tree. Configure this command. This command is vrf aware, to configure for a vrf, enter the vrf submode. -.. index:: ip pim ecmp .. clicmd:: ip pim ecmp If pim has the a choice of ECMP nexthops for a particular RPF, pim will @@ -89,7 +85,6 @@ Certain signals have special meanings to *pimd*. not specified then the first nexthop found will be used. This command is vrf aware, to configure for a vrf, enter the vrf submode. -.. index:: ip pim ecmp rebalance .. clicmd:: ip pim ecmp rebalance If pim is using ECMP and an interface goes down, cause pim to rebalance all @@ -98,14 +93,12 @@ Certain signals have special meanings to *pimd*. down. This command is vrf aware, to configure for a vrf, enter the vrf submode. -.. index:: ip pim join-prune-interval (60-600) .. clicmd:: ip pim join-prune-interval (60-600) Modify the join/prune interval that pim uses to the new value. Time is specified in seconds. This command is vrf aware, to configure for a vrf, enter the vrf submode. -.. index:: ip pim keep-alive-timer (31-60000) .. clicmd:: ip pim keep-alive-timer (31-60000) Modify the time out value for a S,G flow from 31-60000 seconds. 31 seconds @@ -113,7 +106,6 @@ Certain signals have special meanings to *pimd*. flowing in better than 30 second chunks. This command is vrf aware, to configure for a vrf, enter the vrf submode. -.. index:: ip pim packets (1-100) .. clicmd:: ip pim packets (1-100) When processing packets from a neighbor process the number of packets @@ -122,14 +114,12 @@ Certain signals have special meanings to *pimd*. a large number of pim control packets flowing. This command is vrf aware, to configure for a vrf, enter the vrf submode. -.. index:: ip pim register-suppress-time (5-60000) .. clicmd:: ip pim register-suppress-time (5-60000) Modify the time that pim will register suppress a FHR will send register notifications to the kernel. This command is vrf aware, to configure for a vrf, enter the vrf submode. -.. index:: ip pim send-v6-secondary .. clicmd:: ip pim send-v6-secondary When sending pim hello packets tell pim to send any v6 secondary addresses @@ -137,14 +127,12 @@ Certain signals have special meanings to *pimd*. in it's decision for RPF lookup. This command is vrf aware, to configure for a vrf, enter the vrf submode. -.. index:: ip pim ssm prefix-list WORD .. clicmd:: ip pim ssm prefix-list WORD Specify a range of group addresses via a prefix-list that forces pim to never do SM over. This command is vrf aware, to configure for a vrf, enter the vrf submode. -.. index:: ip multicast rpf-lookup-mode WORD .. clicmd:: ip multicast rpf-lookup-mode WORD Modify how PIM does RPF lookups in the zebra routing table. You can use @@ -166,32 +154,27 @@ Certain signals have special meanings to *pimd*. urib-only Lookup in the Unicast Rib only. -.. index:: ip msdp mesh-group [WORD] -.. clicmd:: [no] ip msdp mesh-group [WORD] +.. clicmd:: ip msdp mesh-group [WORD] Create or Delete a multicast source discovery protocol mesh-group using [WORD] as the group name. -.. index:: ip msdp mesh-group WORD member A.B.C.D -.. clicmd:: [no] ip msdp mesh-group WORD member A.B.C.D +.. clicmd:: ip msdp mesh-group WORD member A.B.C.D Attach or Delete A.B.C.D to the MSDP mesh group WORD specified. -.. index:: ip msdp mesh-group WORD source A.B.C.D -.. clicmd:: [no] ip msdp mesh-group WORD source A.B.C.D +.. clicmd:: ip msdp mesh-group WORD source A.B.C.D For the address specified A.B.C.D use that as the source address for mesh group packets being sent. -.. index:: ip igmp generate-query-once [version (2-3)] .. clicmd:: ip igmp generate-query-once [version (2-3)] Generate IGMP query (v2/v3) on user requirement. This will not depend on the existing IGMP general query timer.If no version is provided in the cli, it will be considered as default v2 query.This is a hidden command. -.. index:: ip igmp watermark-warn (10-60000) -.. clicmd:: [no] ip igmp watermark-warn (10-60000) +.. clicmd:: ip igmp watermark-warn (10-60000) Configure watermark warning generation for an igmp group limit. Generates warning once the configured group limit is reached while adding new groups. @@ -207,44 +190,33 @@ PIM interface commands allow you to configure an interface as either a Receiver or a interface that you would like to form pim neighbors on. If the interface is in a vrf, enter the interface command with the vrf keyword at the end. -.. index:: ip pim active-active .. clicmd:: ip pim active-active Turn on pim active-active configuration for a Vxlan interface. This command will not do anything if you do not have the underlying ability of a mlag implementation. -.. index:: ip pim bfd -.. clicmd:: ip pim bfd - - Turns on BFD support for PIM for this interface. - -.. index:: ip pim bsm .. clicmd:: ip pim bsm Tell pim that we would like to use this interface to process bootstrap messages. This is enabled by default. 'no' form of this command is used to restrict bsm messages on this interface. -.. index:: ip pim unicast-bsm .. clicmd:: ip pim unicast-bsm Tell pim that we would like to allow interface to process unicast bootstrap messages. This is enabled by default. 'no' form of this command is used to restrict processing of unicast bsm messages on this interface. -.. index:: ip pim drpriority (1-4294967295) .. clicmd:: ip pim drpriority (1-4294967295) Set the DR Priority for the interface. This command is useful to allow the user to influence what node becomes the DR for a lan segment. -.. index:: ip pim hello (1-180) (1-180) .. clicmd:: ip pim hello (1-180) (1-180) Set the pim hello and hold interval for a interface. -.. index:: ip pim .. clicmd:: ip pim Tell pim that we would like to use this interface to form pim neighbors @@ -252,67 +224,63 @@ is in a vrf, enter the interface command with the vrf keyword at the end. reports on the interface. Refer to the next `ip igmp` command for IGMP management. -.. index:: ip pim use-source A.B.C.D -.. clicmd:: [no] ip pim use-source A.B.C.D +.. clicmd:: ip pim use-source A.B.C.D If you have multiple addresses configured on a particular interface and would like pim to use a specific source address associated with that interface. -.. index:: ip igmp .. clicmd:: ip igmp Tell pim to receive IGMP reports and Query on this interface. The default version is v3. This command is useful on a LHR. -.. index:: ip igmp join A.B.C.D [A.B.C.D] .. clicmd:: ip igmp join A.B.C.D [A.B.C.D] Join multicast group or source-group on an interface. -.. index:: ip igmp query-interval (1-1800) .. clicmd:: ip igmp query-interval (1-1800) Set the IGMP query interval that PIM will use. -.. index:: ip igmp query-max-response-time (10-250) .. clicmd:: ip igmp query-max-response-time (10-250) Set the IGMP query response timeout value. If an report is not returned in the specified time we will assume the S,G or \*,G has timed out. -.. index:: ip igmp version (2-3) .. clicmd:: ip igmp version (2-3) Set the IGMP version used on this interface. The default value is 3. -.. index:: ip multicast boundary oil WORD .. clicmd:: ip multicast boundary oil WORD Set a pim multicast boundary, based upon the WORD prefix-list. If a pim join or IGMP report is received on this interface and the Group is denied by the prefix-list, PIM will ignore the join or report. -.. index:: ip igmp last-member-query-count (1-7) .. clicmd:: ip igmp last-member-query-count (1-7) Set the IGMP last member query count. The default value is 2. 'no' form of this command is used to to configure back to the default value. -.. index:: ip igmp last-member-query-interval (1-255) .. clicmd:: ip igmp last-member-query-interval (1-255) Set the IGMP last member query interval in deciseconds. The default value is 10 deciseconds. 'no' form of this command is used to to configure back to the default value. -.. index:: ip mroute INTERFACE A.B.C.D [A.B.C.D] .. clicmd:: ip mroute INTERFACE A.B.C.D [A.B.C.D] Set a static multicast route for a traffic coming on the current interface to be forwarded on the given interface if the traffic matches the group address and optionally the source address. + +.. seealso:: + + :ref:`bfd-pim-peer-config` + + .. _pim-multicast-rib-insertion: PIM Multicast RIB insertion: @@ -325,13 +293,11 @@ into the kernel *or* for normal rib processing. As such it is possible to create weird states with these commands. Use with caution. Most of the time this will not be necessary. -.. index:: ip mroute A.B.C.D/M A.B.C.D (1-255) .. clicmd:: ip mroute A.B.C.D/M A.B.C.D (1-255) Insert into the Multicast Rib Route A.B.C.D/M with specified nexthop. The distance can be specified as well if desired. -.. index:: ip mroute A.B.C.D/M INTERFACE (1-255) .. clicmd:: ip mroute A.B.C.D/M INTERFACE (1-255) Insert into the Multicast Rib Route A.B.C.D/M using the specified INTERFACE. @@ -342,34 +308,25 @@ caution. Most of the time this will not be necessary. Multicast Source Discovery Protocol (MSDP) Configuration ======================================================== -.. index:: ip msdp mesh-group [WORD] member A.B.C.D .. clicmd:: ip msdp mesh-group [WORD] member A.B.C.D Include a MSDP peer as a member of a MSDP mesh-group. -.. index:: ip msdp mesh-group [WORD] source A.B.C.D .. clicmd:: ip msdp mesh-group [WORD] source A.B.C.D Create a MSDP mesh-group, defining a name for it and an associated local source address. -.. index:: ip msdp peer A.B.C.D source A.B.C.D .. clicmd:: ip msdp peer A.B.C.D source A.B.C.D Establish a MSDP connection with a peer. -.. index:: ip msdp mesh-group [WORD] member A.B.C.D -.. clicmd:: no ip msdp mesh-group [WORD] member A.B.C.D Remove a MSDP peer member from a MSDP mesh-group. -.. index:: ip msdp mesh-group [WORD] source A.B.C.D -.. clicmd:: no ip msdp mesh-group [WORD] source A.B.C.D Delete a MSDP mesh-group. -.. index:: ip msdp peer A.B.C.D -.. clicmd:: no ip msdp peer A.B.C.D Delete a MSDP peer connection. @@ -384,48 +341,39 @@ vrf is specified then the default vrf is assumed. Finally the special keyword 'all' allows you to look at all vrfs for the command. Naming a vrf 'all' will cause great confusion. -.. index:: show ip igmp interface .. clicmd:: show ip igmp interface Display IGMP interface information. -.. index:: show ip igmp [vrf NAME] join [json] .. clicmd:: show ip igmp [vrf NAME] join [json] Display IGMP static join information for a specific vrf. If "vrf all" is provided, it displays information for all the vrfs present. -.. index:: show ip igmp groups .. clicmd:: show ip igmp groups Display IGMP groups information. -.. index:: show ip igmp groups retransmissions .. clicmd:: show ip igmp groups retransmissions Display IGMP group retransmission information. -.. index:: show ip igmp sources .. clicmd:: show ip igmp sources Display IGMP sources information. -.. index:: show ip igmp sources retransmissions .. clicmd:: show ip igmp sources retransmissions Display IGMP source retransmission information. -.. index:: show ip igmp statistics .. clicmd:: show ip igmp statistics Display IGMP statistics information. -.. index:: show ip multicast .. clicmd:: show ip multicast Display various information about the interfaces used in this pim instance. -.. index:: show ip mroute [vrf NAME] [A.B.C.D [A.B.C.D]] [fill] [json] .. clicmd:: show ip mroute [vrf NAME] [A.B.C.D [A.B.C.D]] [fill] [json] Display information about installed into the kernel S,G mroutes. If @@ -434,200 +382,167 @@ cause great confusion. Source Group. The keyword `fill` says to fill in all assumed data for test/data gathering purposes. -.. index:: show ip mroute [vrf NAME] count [json] .. clicmd:: show ip mroute [vrf NAME] count [json] Display information about installed into the kernel S,G mroutes and in addition display data about packet flow for the mroutes for a specific vrf. -.. index:: show ip mroute vrf all count [json] .. clicmd:: show ip mroute vrf all count [json] Display information about installed into the kernel S,G mroutes and in addition display data about packet flow for the mroutes for all vrfs. -.. index:: show ip mroute [vrf NAME] summary [json] .. clicmd:: show ip mroute [vrf NAME] summary [json] Display total number of S,G mroutes and number of S,G mroutes installed into the kernel for a specific vrf. -.. index:: show ip mroute vrf all summary [json] .. clicmd:: show ip mroute vrf all summary [json] Display total number of S,G mroutes and number of S,G mroutes installed into the kernel for all vrfs. -.. index:: show ip msdp mesh-group .. clicmd:: show ip msdp mesh-group Display the configured mesh-groups, the local address associated with each mesh-group, the peer members included in each mesh-group, and their status. -.. index:: show ip msdp peer .. clicmd:: show ip msdp peer Display information about the MSDP peers. That includes the peer address, the local address used to establish the connection to the peer, the connection status, and the number of active sources. -.. index:: show ip pim assert .. clicmd:: show ip pim assert Display information about asserts in the PIM system for S,G mroutes. -.. index:: show ip pim assert-internal .. clicmd:: show ip pim assert-internal Display internal assert state for S,G mroutes -.. index:: show ip pim assert-metric .. clicmd:: show ip pim assert-metric Display metric information about assert state for S,G mroutes -.. index:: show ip pim assert-winner-metric .. clicmd:: show ip pim assert-winner-metric Display winner metric for assert state for S,G mroutes -.. index:: show ip pim group-type .. clicmd:: show ip pim group-type Display SSM group ranges. -.. index:: show ip pim interface .. clicmd:: show ip pim interface Display information about interfaces PIM is using. -.. index:: show ip pim mlag [vrf NAME] interface [detail|WORD] [json] .. clicmd:: show ip pim mlag [vrf NAME|all] interface [detail|WORD] [json] Display mlag interface information. -.. index:: show ip pim [vrf NAME] join [A.B.C.D [A.B.C.D]] [json] .. clicmd:: show ip pim join Display information about PIM joins received. If one address is specified then we assume it is the Group we are interested in displaying data on. If the second address is specified then it is Source Group. -.. index:: show ip pim local-membership .. clicmd:: show ip pim local-membership Display information about PIM interface local-membership. -.. index:: show ip pim mlag summary [json] .. clicmd:: show ip pim mlag summary [json] Display mlag information state that PIM is keeping track of. -.. index:: show ip pim neighbor .. clicmd:: show ip pim neighbor Display information about PIM neighbors. -.. index:: show ip pim nexthop .. clicmd:: show ip pim nexthop Display information about pim nexthops that are being used. -.. index:: show ip pim nexthop-lookup .. clicmd:: show ip pim nexthop-lookup Display information about a S,G pair and how the RPF would be chosen. This is especially useful if there are ECMP's available from the RPF lookup. -.. index:: show ip pim rp-info .. clicmd:: show ip pim rp-info Display information about RP's that are configured on this router. -.. index:: show ip pim rpf .. clicmd:: show ip pim rpf Display information about currently being used S,G's and their RPF lookup information. Additionally display some statistics about what has been happening on the router. -.. index:: show ip pim secondary .. clicmd:: show ip pim secondary Display information about an interface and all the secondary addresses associated with it. -.. index:: show ip pim state .. clicmd:: show ip pim state Display information about known S,G's and incoming interface as well as the OIL and how they were chosen. -.. index:: show ip pim [vrf NAME] upstream [A.B.C.D [A.B.C.D]] [json] -.. clicmd:: show ip pim upstream +.. clicmd:: show ip pim [vrf NAME] upstream [A.B.C.D [A.B.C.D]] [json] Display upstream information about a S,G mroute. Allow the user to specify sub Source and Groups that we are only interested in. -.. index:: show ip pim upstream-join-desired .. clicmd:: show ip pim upstream-join-desired Display upstream information for S,G's and if we desire to join the multicast tree -.. index:: show ip pim upstream-rpf .. clicmd:: show ip pim upstream-rpf Display upstream information for S,G's and the RPF data associated with them. -.. index:: show ip pim [vrf NAME] mlag upstream [A.B.C.D [A.B.C.D]] [json] -.. clicmd:: show ip pim mlag upstream +.. clicmd:: show ip pim [vrf NAME] mlag upstream [A.B.C.D [A.B.C.D]] [json] Display upstream entries that are synced across MLAG switches. Allow the user to specify sub Source and Groups address filters. -.. index:: show ip pim mlag summary .. clicmd:: show ip pim mlag summary Display PIM MLAG (multi-chassis link aggregation) session status and control message statistics. -.. index:: show ip pim bsr .. clicmd:: show ip pim bsr Display current bsr, its uptime and last received bsm age. -.. index:: show ip pim bsrp-info .. clicmd:: show ip pim bsrp-info Display group-to-rp mappings received from E-BSR. -.. index:: show ip pim bsm-database .. clicmd:: show ip pim bsm-database Display all fragments ofstored bootstrap message in user readable format. -.. index:: show ip rpf -.. clicmd:: show ip rpf - - Display the multicast RIB created in zebra. - -.. index:: mtrace A.B.C.D [A.B.C.D] .. clicmd:: mtrace A.B.C.D [A.B.C.D] Display multicast traceroute towards source, optionally for particular group. -.. index:: show ip multicast count [vrf NAME] [json] .. clicmd:: show ip multicast count [vrf NAME] [json] Display multicast data packets count per interface for a vrf. -.. index:: show ip multicast count vrf all [json] .. clicmd:: show ip multicast count vrf all [json] Display multicast data packets count per interface for all vrf. + +.. seealso:: + + :ref:`multicast-rib-commands` + + PIM Debug Commands ================== @@ -637,56 +552,46 @@ configure CLI mode. If you specify debug commands in the configuration cli mode, the debug commands can be persistent across restarts of the FRR pimd if the config was written out. -.. index:: debug igmp .. clicmd:: debug igmp This turns on debugging for IGMP protocol activity. -.. index:: debug mtrace .. clicmd:: debug mtrace This turns on debugging for mtrace protocol activity. -.. index:: debug mroute .. clicmd:: debug mroute This turns on debugging for PIM interaction with kernel MFC cache. -.. index:: debug pim events .. clicmd:: debug pim events This turns on debugging for PIM system events. Especially timers. -.. index:: debug pim nht .. clicmd:: debug pim nht This turns on debugging for PIM nexthop tracking. It will display information about RPF lookups and information about when a nexthop changes. -.. index:: debug pim packet-dump .. clicmd:: debug pim packet-dump This turns on an extraordinary amount of data. Each pim packet sent and received is dumped for debugging purposes. This should be considered a developer only command. -.. index:: debug pim packets .. clicmd:: debug pim packets This turns on information about packet generation for sending and about packet handling from a received packet. -.. index:: debug pim trace .. clicmd:: debug pim trace This traces pim code and how it is running. -.. index:: debug pim bsm .. clicmd:: debug pim bsm This turns on debugging for BSR message processing. -.. index:: debug pim zebra .. clicmd:: debug pim zebra This gathers data about events from zebra that come up through the ZAPI. @@ -695,39 +600,32 @@ PIM Clear Commands ================== Clear commands reset various variables. -.. index:: clear ip interfaces .. clicmd:: clear ip interfaces Reset interfaces. -.. index:: clear ip igmp interfaces .. clicmd:: clear ip igmp interfaces Reset IGMP interfaces. -.. index:: clear ip mroute .. clicmd:: clear ip mroute Reset multicast routes. -.. index:: clear ip mroute [vrf NAME] count .. clicmd:: clear ip mroute [vrf NAME] count When this command is issued, reset the counts of data shown for packet count, byte count and wrong interface to 0 and start count up from this spot. -.. index:: clear ip pim interfaces .. clicmd:: clear ip pim interfaces Reset PIM interfaces. -.. index:: clear ip pim oil .. clicmd:: clear ip pim oil Rescan PIM OIL (output interface list). -.. index:: clear ip pim [vrf NAME] bsr-data .. clicmd:: clear ip pim [vrf NAME] bsr-data This command will clear the BSM scope data struct. This command also diff --git a/doc/user/ripd.rst b/doc/user/ripd.rst index e83b505a19..cba93e0d84 100644 --- a/doc/user/ripd.rst +++ b/doc/user/ripd.rst @@ -87,23 +87,17 @@ multipath routing. RIP Configuration ================= -.. index:: router rip .. clicmd:: router rip The `router rip` command is necessary to enable RIP. To disable RIP, use the `no router rip` command. RIP must be enabled before carrying out any of the RIP commands. -.. index:: router rip -.. clicmd:: no router rip Disable RIP. -.. index:: network NETWORK .. clicmd:: network NETWORK -.. index:: network NETWORK -.. clicmd:: no network NETWORK Set the RIP enable interface by NETWORK. The interfaces which have addresses matching with NETWORK are enabled. @@ -114,22 +108,16 @@ RIP Configuration 10.0.0.0 to 10.0.0.255 being enabled for RIP. The `no network` command will disable RIP for the specified network. -.. index:: network IFNAME .. clicmd:: network IFNAME -.. index:: network IFNAME -.. clicmd:: no network IFNAME Set a RIP enabled interface by IFNAME. Both the sending and receiving of RIP packets will be enabled on the port specified in the `network ifname` command. The `no network ifname` command will disable RIP on the specified interface. -.. index:: neighbor A.B.C.D .. clicmd:: neighbor A.B.C.D -.. index:: neighbor A.B.C.D -.. clicmd:: no neighbor A.B.C.D Specify RIP neighbor. When a neighbor doesn't understand multicast, this command is used to specify neighbors. In some cases, not all routers will be @@ -152,11 +140,8 @@ RIP Configuration ! -.. index:: passive-interface (IFNAME|default) .. clicmd:: passive-interface (IFNAME|default) -.. index:: passive-interface IFNAME -.. clicmd:: no passive-interface IFNAME This command sets the specified interface to passive mode. On passive mode interface, all receiving packets are processed as normal and ripd does not @@ -166,11 +151,8 @@ RIP Configuration The default is to be passive on all interfaces. -.. index:: ip split-horizon .. clicmd:: ip split-horizon -.. index:: ip split-horizon -.. clicmd:: no ip split-horizon Control split-horizon on the interface. Default is `ip split-horizon`. If you don't perform split-horizon on the interface, please specify `no ip @@ -192,7 +174,6 @@ is enabled then RIP will reply to REQUEST packets, sending the state of its RIP routing table to any remote routers that ask on demand. For a more detailed discussion on the security implications of RIPv1 see :ref:`rip-authentication`. -.. index:: version VERSION .. clicmd:: version VERSION Set RIP version to accept for reads and send. ``VERSION`` can be either 1 or @@ -203,12 +184,6 @@ discussion on the security implications of RIPv1 see :ref:`rip-authentication`. Default: Send Version 2, and accept either version. -.. index:: version -.. clicmd:: no version - - Reset the global version setting back to the default. - -.. index:: ip rip send version VERSION .. clicmd:: ip rip send version VERSION VERSION can be ``1``, ``2``, or ``1 2``. @@ -221,7 +196,6 @@ discussion on the security implications of RIPv1 see :ref:`rip-authentication`. Default: Send packets according to the global version (version 2) -.. index:: ip rip receive version VERSION .. clicmd:: ip rip receive version VERSION VERSION can be ``1``, ``2``, or ``1 2``. @@ -232,98 +206,22 @@ discussion on the security implications of RIPv1 see :ref:`rip-authentication`. Default: Accept packets according to the global setting (both 1 and 2). + .. _how-to-announce-rip-route: How to Announce RIP route ========================= -.. index:: redistribute kernel -.. clicmd:: redistribute kernel - -.. index:: redistribute kernel metric (0-16) -.. clicmd:: redistribute kernel metric (0-16) - -.. index:: redistribute kernel route-map ROUTE-MAP -.. clicmd:: redistribute kernel route-map ROUTE-MAP - -.. index:: redistribute kernel -.. clicmd:: no redistribute kernel - - `redistribute kernel` redistributes routing information from kernel route - entries into the RIP tables. `no redistribute kernel` disables the routes. - -.. index:: redistribute static -.. clicmd:: redistribute static - -.. index:: redistribute static metric (0-16) -.. clicmd:: redistribute static metric (0-16) - -.. index:: redistribute static route-map ROUTE-MAP -.. clicmd:: redistribute static route-map ROUTE-MAP - -.. index:: redistribute static -.. clicmd:: no redistribute static - - `redistribute static` redistributes routing information from static route - entries into the RIP tables. `no redistribute static` disables the routes. - -.. index:: redistribute connected -.. clicmd:: redistribute connected - -.. index:: redistribute connected metric (0-16) -.. clicmd:: redistribute connected metric (0-16) +.. clicmd:: redistribute <babel|bgp|connected|eigrp|isis|kernel|openfabric|ospf|sharp|static|table> [metric (0-16)] [route-map WORD] -.. index:: redistribute connected route-map ROUTE-MAP -.. clicmd:: redistribute connected route-map ROUTE-MAP + Redistribute routes from other sources into RIP. -.. index:: redistribute connected -.. clicmd:: no redistribute connected +If you want to specify RIP only static routes: - Redistribute connected routes into the RIP tables. `no redistribute - connected` disables the connected routes in the RIP tables. This command - redistribute connected of the interface which RIP disabled. The connected - route on RIP enabled interface is announced by default. - -.. index:: redistribute ospf -.. clicmd:: redistribute ospf - -.. index:: redistribute ospf metric (0-16) -.. clicmd:: redistribute ospf metric (0-16) - -.. index:: redistribute ospf route-map ROUTE-MAP -.. clicmd:: redistribute ospf route-map ROUTE-MAP - -.. index:: redistribute ospf -.. clicmd:: no redistribute ospf - - `redistribute ospf` redistributes routing information from ospf route - entries into the RIP tables. `no redistribute ospf` disables the routes. - -.. index:: redistribute bgp -.. clicmd:: redistribute bgp - -.. index:: redistribute bgp metric (0-16) -.. clicmd:: redistribute bgp metric (0-16) - -.. index:: redistribute bgp route-map ROUTE-MAP -.. clicmd:: redistribute bgp route-map ROUTE-MAP - -.. index:: redistribute bgp -.. clicmd:: no redistribute bgp - - `redistribute bgp` redistributes routing information from bgp route entries - into the RIP tables. `no redistribute bgp` disables the routes. - - If you want to specify RIP only static routes: - -.. index:: default-information originate .. clicmd:: default-information originate -.. index:: route A.B.C.D/M .. clicmd:: route A.B.C.D/M -.. index:: route A.B.C.D/M -.. clicmd:: no route A.B.C.D/M This command is specific to FRR. The `route` command makes a static route only inside RIP. This command should be used only by advanced users who are @@ -338,7 +236,6 @@ Filtering RIP Routes RIP routes can be filtered by a distribute-list. -.. index:: distribute-list ACCESS_LIST DIRECT IFNAME .. clicmd:: distribute-list ACCESS_LIST DIRECT IFNAME You can apply access lists to the interface with a `distribute-list` command. @@ -364,7 +261,6 @@ RIP routes can be filtered by a distribute-list. `distribute-list` can be applied to both incoming and outgoing data. -.. index:: distribute-list prefix PREFIX_LIST (in|out) IFNAME .. clicmd:: distribute-list prefix PREFIX_LIST (in|out) IFNAME You can apply prefix lists to the interface with a `distribute-list` @@ -381,11 +277,8 @@ RIP metric is a value for distance for the network. Usually *ripd* increment the metric when the network information is received. Redistributed routes' metric is set to 1. -.. index:: default-metric (1-16) .. clicmd:: default-metric (1-16) -.. index:: default-metric (1-16) -.. clicmd:: no default-metric (1-16) This command modifies the default metric value for redistributed routes. The default value is 1. This command does not affect connected route even if @@ -393,10 +286,8 @@ received. Redistributed routes' metric is set to 1. metric value, please use ``redistribute connected metric`` or *route-map*. *offset-list* also affects connected routes. -.. index:: offset-list ACCESS-LIST (in|out) .. clicmd:: offset-list ACCESS-LIST (in|out) -.. index:: offset-list ACCESS-LIST (in|out) IFNAME .. clicmd:: offset-list ACCESS-LIST (in|out) IFNAME @@ -407,28 +298,19 @@ RIP distance Distance value is used in zebra daemon. Default RIP distance is 120. -.. index:: distance (1-255) .. clicmd:: distance (1-255) -.. index:: distance (1-255) -.. clicmd:: no distance (1-255) Set default RIP distance to specified value. -.. index:: distance (1-255) A.B.C.D/M .. clicmd:: distance (1-255) A.B.C.D/M -.. index:: distance (1-255) A.B.C.D/M -.. clicmd:: no distance (1-255) A.B.C.D/M Set default RIP distance to specified value when the route's source IP address matches the specified prefix. -.. index:: distance (1-255) A.B.C.D/M ACCESS-LIST .. clicmd:: distance (1-255) A.B.C.D/M ACCESS-LIST -.. index:: distance (1-255) A.B.C.D/M ACCESS-LIST -.. clicmd:: no distance (1-255) A.B.C.D/M ACCESS-LIST Set default RIP distance to specified value when the route's source IP address matches the specified prefix and the specified access-list. @@ -459,7 +341,6 @@ it may be changed at future. Route-map statement (:ref:`route-map`) is needed to use route-map functionality. -.. index:: match interface WORD .. clicmd:: match interface WORD This command match to incoming interface. Notation of this match is @@ -471,37 +352,30 @@ functionality. sends to different interfaces must be different. Maybe it'd be better to made new matches - say "match interface-out NAME" or something like that. -.. index:: match ip address WORD .. clicmd:: match ip address WORD -.. index:: match ip address prefix-list WORD .. clicmd:: match ip address prefix-list WORD Match if route destination is permitted by access-list. -.. index:: match ip next-hop WORD .. clicmd:: match ip next-hop WORD -.. index:: match ip next-hop prefix-list WORD .. clicmd:: match ip next-hop prefix-list WORD Match if route next-hop (meaning next-hop listed in the rip route-table as displayed by "show ip rip") is permitted by access-list. -.. index:: match metric (0-4294967295) .. clicmd:: match metric (0-4294967295) This command match to the metric value of RIP updates. For other protocol compatibility metric range is shown as (0-4294967295). But for RIP protocol only the value range (0-16) make sense. -.. index:: set ip next-hop A.B.C.D .. clicmd:: set ip next-hop A.B.C.D This command set next hop value in RIPv2 protocol. This command does not affect RIPv1 because there is no next hop field in the packet. -.. index:: set metric (0-4294967295) .. clicmd:: set metric (0-4294967295) Set a metric for matched route when sending announcement. The metric value @@ -536,36 +410,24 @@ on the internet, via RIPv1. To prevent such unauthenticated querying of routes disable RIPv1, :ref:`rip-version-control`. -.. index:: ip rip authentication mode md5 .. clicmd:: ip rip authentication mode md5 -.. index:: ip rip authentication mode md5 -.. clicmd:: no ip rip authentication mode md5 Set the interface with RIPv2 MD5 authentication. -.. index:: ip rip authentication mode text .. clicmd:: ip rip authentication mode text -.. index:: ip rip authentication mode text -.. clicmd:: no ip rip authentication mode text Set the interface with RIPv2 simple password authentication. -.. index:: ip rip authentication string STRING .. clicmd:: ip rip authentication string STRING -.. index:: ip rip authentication string STRING -.. clicmd:: no ip rip authentication string STRING RIP version 2 has simple text authentication. This command sets authentication string. The string must be shorter than 16 characters. -.. index:: ip rip authentication key-chain KEY-CHAIN .. clicmd:: ip rip authentication key-chain KEY-CHAIN -.. index:: ip rip authentication key-chain KEY-CHAIN -.. clicmd:: no ip rip authentication key-chain KEY-CHAIN Specify Keyed MD5 chain. @@ -587,7 +449,6 @@ To prevent such unauthenticated querying of routes disable RIPv1, RIP Timers ========== -.. index:: timers basic UPDATE TIMEOUT GARBAGE .. clicmd:: timers basic UPDATE TIMEOUT GARBAGE @@ -610,11 +471,6 @@ RIP Timers The ``timers basic`` command allows the the default values of the timers listed above to be changed. -.. index:: timers basic -.. clicmd:: no timers basic - - The `no timers basic` command will reset the timers to the default settings - listed above. .. _show-rip-information: @@ -623,7 +479,6 @@ Show RIP Information To display RIP routes. -.. index:: show ip rip .. clicmd:: show ip rip Show RIP routes. @@ -633,7 +488,6 @@ through RIP, this command will display the time the packet was sent and the tag information. This command will also display this information for routes redistributed into RIP. -.. index:: show ip rip status .. clicmd:: show ip rip status The command displays current RIP status. It includes RIP timer, @@ -665,26 +519,22 @@ RIP Debug Commands Debug for RIP protocol. -.. index:: debug rip events .. clicmd:: debug rip events Shows RIP events. Sending and receiving packets, timers, and changes in interfaces are events shown with *ripd*. -.. index:: debug rip packet .. clicmd:: debug rip packet Shows display detailed information about the RIP packets. The origin and port number of the packet as well as a packet dump is shown. -.. index:: debug rip zebra .. clicmd:: debug rip zebra This command will show the communication between *ripd* and *zebra*. The main information will include addition and deletion of paths to the kernel and the sending and receiving of interface information. -.. index:: show debugging rip .. clicmd:: show debugging rip Shows all information currently set for ripd debug. diff --git a/doc/user/ripngd.rst b/doc/user/ripngd.rst index ae2400f0bb..0387e36305 100644 --- a/doc/user/ripngd.rst +++ b/doc/user/ripngd.rst @@ -22,62 +22,46 @@ ripngd Configuration Currently ripngd supports the following commands: -.. index:: router ripng .. clicmd:: router ripng Enable RIPng. -.. index:: flush_timer TIME .. clicmd:: flush_timer TIME Set flush timer. -.. index:: network NETWORK .. clicmd:: network NETWORK Set RIPng enabled interface by NETWORK. -.. index:: network IFNAME .. clicmd:: network IFNAME Set RIPng enabled interface by IFNAME. -.. index:: route NETWORK .. clicmd:: route NETWORK Set RIPng static routing announcement of NETWORK. -.. index:: router zebra -.. clicmd:: router zebra - - This command is the default and does not appear in the configuration. With - this statement, RIPng routes go to the *zebra* daemon. .. _ripngd-terminal-mode-commands: ripngd Terminal Mode Commands ============================= -.. index:: show ip ripng .. clicmd:: show ip ripng -.. index:: show debugging ripng .. clicmd:: show debugging ripng -.. index:: debug ripng events .. clicmd:: debug ripng events -.. index:: debug ripng packet .. clicmd:: debug ripng packet -.. index:: debug ripng zebra .. clicmd:: debug ripng zebra ripngd Filtering Commands ========================= -.. index:: distribute-list ACCESS_LIST (in|out) IFNAME .. clicmd:: distribute-list ACCESS_LIST (in|out) IFNAME You can apply an access-list to the interface using the `distribute-list` diff --git a/doc/user/routemap.rst b/doc/user/routemap.rst index fa8eee815d..7f357b0925 100644 --- a/doc/user/routemap.rst +++ b/doc/user/routemap.rst @@ -90,7 +90,6 @@ cont .. _route-map-show-command: -.. index:: show route-map [WORD] .. clicmd:: show route-map [WORD] Display data about each daemons knowledge of individual route-maps. @@ -98,7 +97,6 @@ cont .. _route-map-clear-counter-command: -.. index:: clear route-map counter [WORD] .. clicmd:: clear route-map counter [WORD] Clear counters that are being stored about the route-map utilization @@ -110,7 +108,6 @@ cont Route Map Command ================= -.. index:: route-map ROUTE-MAP-NAME (permit|deny) ORDER .. clicmd:: route-map ROUTE-MAP-NAME (permit|deny) ORDER Configure the `order`'th entry in `route-map-name` with ``Match Policy`` of @@ -121,98 +118,80 @@ Route Map Command Route Map Match Command ======================= -.. index:: match ip address ACCESS_LIST .. clicmd:: match ip address ACCESS_LIST Matches the specified `access_list` -.. index:: match ip address prefix-list PREFIX_LIST .. clicmd:: match ip address prefix-list PREFIX_LIST Matches the specified `PREFIX_LIST` -.. index:: match ip address prefix-len 0-32 .. clicmd:: match ip address prefix-len 0-32 Matches the specified `prefix-len`. This is a Zebra specific command. -.. index:: match ipv6 address ACCESS_LIST .. clicmd:: match ipv6 address ACCESS_LIST Matches the specified `access_list` -.. index:: match ipv6 address prefix-list PREFIX_LIST .. clicmd:: match ipv6 address prefix-list PREFIX_LIST Matches the specified `PREFIX_LIST` -.. index:: match ipv6 address prefix-len 0-128 .. clicmd:: match ipv6 address prefix-len 0-128 Matches the specified `prefix-len`. This is a Zebra specific command. -.. index:: match ip next-hop address IPV4_ADDR .. clicmd:: match ip next-hop address IPV4_ADDR This is a BGP specific match command. Matches the specified `ipv4_addr`. -.. index:: match ipv6 next-hop IPV6_ADDR .. clicmd:: match ipv6 next-hop IPV6_ADDR This is a BGP specific match command. Matches the specified `ipv6_addr`. -.. index:: match as-path AS_PATH .. clicmd:: match as-path AS_PATH Matches the specified `as_path`. -.. index:: match metric METRIC .. clicmd:: match metric METRIC Matches the specified `metric`. -.. index:: match tag TAG .. clicmd:: match tag TAG Matches the specified tag value associated with the route. This tag value can be in the range of (1-4294967295). -.. index:: match local-preference METRIC .. clicmd:: match local-preference METRIC Matches the specified `local-preference`. -.. index:: match community COMMUNITY_LIST .. clicmd:: match community COMMUNITY_LIST Matches the specified `community_list` -.. index:: match peer IPV4_ADDR .. clicmd:: match peer IPV4_ADDR This is a BGP specific match command. Matches the peer ip address if the neighbor was specified in this manner. -.. index:: match peer IPV6_ADDR .. clicmd:: match peer IPV6_ADDR This is a BGP specific match command. Matches the peer ipv6 address if the neighbor was specified in this manner. -.. index:: match peer INTERFACE_NAME .. clicmd:: match peer INTERFACE_NAME This is a BGP specific match command. Matches the peer interface name specified if the neighbor was specified in this manner. -.. index:: match source-protocol PROTOCOL_NAME .. clicmd:: match source-protocol PROTOCOL_NAME This is a ZEBRA specific match command. Matches the originating protocol specified. -.. index:: match source-instance NUMBER .. clicmd:: match source-instance NUMBER This is a ZEBRA specific match command. The number is a range from (0-255). @@ -225,7 +204,6 @@ Route Map Set Command .. program:: configure -.. index:: set tag TAG .. clicmd:: set tag TAG Set a tag on the matched route. This tag value can be from (1-4294967295). @@ -233,13 +211,11 @@ Route Map Set Command configure option. Tag values from (1-255) are sent to the Linux kernel as a realm value. Then route policy can be applied. See the tc man page. -.. index:: set ip next-hop IPV4_ADDRESS .. clicmd:: set ip next-hop IPV4_ADDRESS Set the BGP nexthop address to the specified IPV4_ADDRESS. For both incoming and outgoing route-maps. -.. index:: set ip next-hop peer-address .. clicmd:: set ip next-hop peer-address Set the BGP nexthop address to the address of the peer. For an incoming @@ -247,13 +223,11 @@ Route Map Set Command route-map this means the ip address of our self is used to establish the peering with our neighbor. -.. index:: set ip next-hop unchanged .. clicmd:: set ip next-hop unchanged Set the route-map as unchanged. Pass the route-map through without changing it's value. -.. index:: set ipv6 next-hop peer-address .. clicmd:: set ipv6 next-hop peer-address Set the BGP nexthop address to the address of the peer. For an incoming @@ -261,121 +235,104 @@ Route Map Set Command route-map this means the ip address of our self is used to establish the peering with our neighbor. -.. index:: set ipv6 next-hop prefer-global .. clicmd:: set ipv6 next-hop prefer-global For Incoming and Import Route-maps if we receive a v6 global and v6 LL address for the route, then prefer to use the global address as the nexthop. -.. index:: set ipv6 next-hop global IPV6_ADDRESS .. clicmd:: set ipv6 next-hop global IPV6_ADDRESS Set the next-hop to the specified IPV6_ADDRESS for both incoming and outgoing route-maps. -.. index:: set local-preference LOCAL_PREF .. clicmd:: set local-preference LOCAL_PREF Set the BGP local preference to `local_pref`. -.. index:: set local-preference +LOCAL_PREF .. clicmd:: set local-preference +LOCAL_PREF Add the BGP local preference to an existing `local_pref`. -.. index:: set local-preference -LOCAL_PREF .. clicmd:: set local-preference -LOCAL_PREF Subtract the BGP local preference from an existing `local_pref`. -.. index:: set distance DISTANCE -.. clicmd:: [no] set distance DISTANCE +.. clicmd:: set distance DISTANCE Set the Administrative distance to DISTANCE to use for the route. This is only locally significant and will not be dispersed to peers. -.. index:: set weight WEIGHT .. clicmd:: set weight WEIGHT Set the route's weight. -.. index:: set metric <[+|-](1-4294967295)|rtt|+rtt|-rtt> -.. clicmd:: [no] set metric <[+|-](1-4294967295)|rtt|+rtt|-rtt> +.. clicmd:: set metric <[+|-](1-4294967295)|rtt|+rtt|-rtt> Set the BGP attribute MED to a specific value. Use `+`/`-` to add or subtract the specified value to/from the MED. Use `rtt` to set the MED to the round trip time or `+rtt`/`-rtt` to add/subtract the round trip time to/from the MED. -.. index:: set as-path prepend AS_PATH .. clicmd:: set as-path prepend AS_PATH Set the BGP AS path to prepend. -.. index:: set community COMMUNITY .. clicmd:: set community COMMUNITY Set the BGP community attribute. -.. index:: set ipv6 next-hop local IPV6_ADDRESS .. clicmd:: set ipv6 next-hop local IPV6_ADDRESS Set the BGP-4+ link local IPv6 nexthop address. -.. index:: set origin ORIGIN <egp|igp|incomplete> .. clicmd:: set origin ORIGIN <egp|igp|incomplete> Set BGP route origin. -.. index:: set table (1-4294967295) .. clicmd:: set table (1-4294967295) Set the BGP table to a given table identifier -.. index:: set sr-te color (1-4294967295) .. clicmd:: set sr-te color (1-4294967295) Set the color of a SR-TE Policy to be applied to a learned route. The SR-TE Policy is uniquely determined by the color and the BGP nexthop. + .. _route-map-call-command: Route Map Call Command ====================== -.. index:: call NAME .. clicmd:: call NAME Call route-map `name`. If it returns deny, deny the route and finish processing the route-map. + .. _route-map-exit-action-command: Route Map Exit Action Command ============================= -.. index:: on-match next .. clicmd:: on-match next -.. index:: continue .. clicmd:: continue Proceed on to the next entry in the route-map. -.. index:: on-match goto N .. clicmd:: on-match goto N -.. index:: continue N .. clicmd:: continue N Proceed processing the route-map at the first entry whose order is >= N + .. _route-map-optimization-command: Route Map Optimization Command ============================== -.. index:: route-map optimization .. clicmd:: route-map optimization Enable route-map processing optimization. The optimization is @@ -387,10 +344,6 @@ Route Map Optimization Command of all the prefixes in all the prefix-lists that are included in the match rule of all the sequences of a route-map. -.. index:: route-map optimization -.. clicmd:: no route-map optimization - - Disable the route-map processing optimization. Route Map Examples ================== diff --git a/doc/user/routeserver.rst b/doc/user/routeserver.rst index 474a68db25..5100d679f7 100644 --- a/doc/user/routeserver.rst +++ b/doc/user/routeserver.rst @@ -163,13 +163,10 @@ Commands for configuring a Route Server Now we will describe the commands that have been added to frr in order to support the route server features. -.. index:: neighbor PEER-GROUP route-server-client .. clicmd:: neighbor PEER-GROUP route-server-client -.. index:: neighbor A.B.C.D route-server-client .. clicmd:: neighbor A.B.C.D route-server-client -.. index:: neighbor X:X::X:X route-server-client .. clicmd:: neighbor X:X::X:X route-server-client This command configures the peer given by `peer`, `A.B.C.D` or `X:X::X:X` as @@ -186,14 +183,12 @@ in order to support the route server features. that moment, every announcement received by the route server will be also considered for the new Loc-RIB. -.. index:: neigbor A.B.C.D|X.X::X.X|peer-group route-map WORD import|export .. clicmd:: neigbor A.B.C.D|X.X::X.X|peer-group route-map WORD import|export This set of commands can be used to specify the route-map that represents the Import or Export policy of a peer which is configured as a RS-client (with the previous command). -.. index:: match peer A.B.C.D|X:X::X:X .. clicmd:: match peer A.B.C.D|X:X::X:X This is a new *match* statement for use in route-maps, enabling them to @@ -210,7 +205,6 @@ in order to support the route server features. announce is going to be inserted (how the same export policy is applied before different Loc-RIBs is shown in :ref:`fig-rs-processing`.). -.. index:: call WORD .. clicmd:: call WORD This command (also used inside a route-map) jumps into a different diff --git a/doc/user/rpki.rst b/doc/user/rpki.rst index 451df1aa4e..01705f607c 100644 --- a/doc/user/rpki.rst +++ b/doc/user/rpki.rst @@ -54,7 +54,6 @@ In a nutshell, the current implementation provides the following features Enabling RPKI ------------- -.. index:: rpki .. clicmd:: rpki This command enables the RPKI configuration mode. Most commands that start @@ -67,7 +66,6 @@ Enabling RPKI to configure at least one reachable cache server. See section :ref:`configuring-rpki-rtr-cache-servers` for configuring a cache server. -.. index:: RPKI and daemons When first installing FRR with RPKI support from the pre-packaged binaries. Remember to add ``-M rpki`` to the variable ``bgpd_options`` in @@ -101,11 +99,8 @@ Configuring RPKI/RTR Cache Servers The following commands are independent of a specific cache server. -.. index:: rpki polling_period (1-3600) .. clicmd:: rpki polling_period (1-3600) -.. index:: rpki polling_period -.. clicmd:: no rpki polling_period Set the number of seconds the router waits until the router asks the cache again for updated data. @@ -114,11 +109,8 @@ The following commands are independent of a specific cache server. The following commands configure one or multiple cache servers. -.. index:: rpki cache (A.B.C.D|WORD) PORT [SSH_USERNAME] [SSH_PRIVKEY_PATH] [SSH_PUBKEY_PATH] [KNOWN_HOSTS_PATH] PREFERENCE .. clicmd:: rpki cache (A.B.C.D|WORD) PORT [SSH_USERNAME] [SSH_PRIVKEY_PATH] [SSH_PUBKEY_PATH] [KNOWN_HOSTS_PATH] PREFERENCE -.. index:: rpki cache (A.B.C.D|WORD) [PORT] PREFERENCE -.. clicmd:: no rpki cache (A.B.C.D|WORD) [PORT] PREFERENCE Add a cache server to the socket. By default, the connection between router and cache server is based on plain TCP. Protecting the connection between @@ -154,11 +146,8 @@ The following commands are independent of a specific cache server. Validating BGP Updates ---------------------- -.. index:: match rpki notfound|invalid|valid .. clicmd:: match rpki notfound|invalid|valid -.. index:: match rpki notfound|invalid|valid -.. clicmd:: no match rpki notfound|invalid|valid Create a clause for a route map to match prefixes with the specified RPKI state. @@ -187,11 +176,8 @@ Validating BGP Updates Debugging --------- -.. index:: debug rpki .. clicmd:: debug rpki -.. index:: debug rpki -.. clicmd:: no debug rpki Enable or disable debugging output for RPKI. @@ -200,26 +186,22 @@ Debugging Displaying RPKI --------------- -.. index:: show rpki prefix <A.B.C.D/M|X:X::X:X/M> [(1-4294967295)] .. clicmd:: show rpki prefix <A.B.C.D/M|X:X::X:X/M> [(1-4294967295)] Display validated prefixes received from the cache servers filtered by the specified prefix. -.. index:: show rpki as-number ASN .. clicmd:: show rpki as-number ASN Display validated prefixes received from the cache servers filtered by ASN. -.. index:: show rpki prefix-table .. clicmd:: show rpki prefix-table Display all validated prefix to origin AS mappings/records which have been received from the cache servers and stored in the router. Based on this data, the router validates BGP Updates. -.. index:: show rpki cache-connection .. clicmd:: show rpki cache-connection Display all configured cache servers, whether active or not. diff --git a/doc/user/sharp.rst b/doc/user/sharp.rst index 90eae4d65a..9e83e44222 100644 --- a/doc/user/sharp.rst +++ b/doc/user/sharp.rst @@ -32,7 +32,6 @@ Using SHARP All sharp commands are under the enable node and preceded by the ``sharp`` keyword. At present, no sharp commands will be preserved in the config. -.. index:: sharp install .. clicmd:: sharp install routes A.B.C.D <nexthop <E.F.G.H|X:X::X:X>|nexthop-group NAME> (1-1000000) [instance (0-255)] [repeat (2-1000)] [opaque WORD] Install up to 1,000,000 (one million) /32 routes starting at ``A.B.C.D`` @@ -49,7 +48,6 @@ keyword. At present, no sharp commands will be preserved in the config. number of times specified. If the keyword opaque is specified then the next word is sent down to zebra as part of the route installation. -.. index:: sharp remove .. clicmd:: sharp remove routes A.B.C.D (1-1000000) Remove up to 1,000,000 (one million) /32 routes starting at ``A.B.C.D``. The @@ -57,7 +55,6 @@ keyword. At present, no sharp commands will be preserved in the config. log and when all routes have been successfully deleted the debug log will be updated with this information as well. -.. index:: sharp data route .. clicmd:: sharp data route Allow end user doing route install and deletion to get timing information @@ -65,14 +62,12 @@ keyword. At present, no sharp commands will be preserved in the config. is informational only and you should look at sharp_vty.c for explanation of the output as that it may change. -.. index:: sharp label .. clicmd:: sharp label <ipv4|ipv6> vrf NAME label (0-1000000) Install a label into the kernel that causes the specified vrf NAME table to be used for pop and forward operations when the specified label is seen. -.. index:: sharp watch -.. clicmd:: [no] sharp watch <nexthop <A.B.C.D|X:X::X:X>|import <A.B.C.D/M:X:X::X:X/M> [connected] +.. clicmd:: sharp watch <nexthop <A.B.C.D|X:X::X:X>|import <A.B.C.D/M:X:X::X:X/M> [connected] Instruct zebra to monitor and notify sharp when the specified nexthop is changed. The notification from zebra is written into the debug log. @@ -83,13 +78,11 @@ keyword. At present, no sharp commands will be preserved in the config. for the import keyword connected means exact match. The no form of the command obviously turns this watching off. -.. index:: sharp data nexthop .. clicmd:: sharp data nexthop Allow end user to dump associated data with the nexthop tracking that may have been turned on. -.. index:: sharp lsp .. clicmd:: sharp lsp [update] (0-100000) nexthop-group NAME [prefix A.B.C.D/M TYPE [instance (0-255)]] Install an LSP using the specified in-label, with nexthops as @@ -98,7 +91,6 @@ keyword. At present, no sharp commands will be preserved in the config. If ``prefix`` is specified, an existing route with type ``TYPE`` (and optional ``instance`` id) will be updated to use the LSP. -.. index:: sharp remove lsp .. clicmd:: sharp remove lsp (0-100000) nexthop-group NAME [prefix A.B.C.D/M TYPE [instance (0-255)]] Remove a SHARPD LSP that uses the specified in-label, where the @@ -106,13 +98,11 @@ keyword. At present, no sharp commands will be preserved in the config. specified, remove label bindings from the route of type ``TYPE`` also. -.. index:: sharp send opaque .. clicmd:: sharp send opaque type (1-255) (1-1000) Send opaque ZAPI messages with subtype ``type``. Sharpd will send a stream of messages if the count is greater than one. -.. index:: sharp send opaque unicast .. clicmd:: sharp send opaque unicast type (1-255) $proto_str [{instance (0-1000) | session (1-1000)}] (1-1000) Send unicast opaque ZAPI messages with subtype ``type``. The @@ -120,7 +110,6 @@ keyword. At present, no sharp commands will be preserved in the config. client. Sharpd will send a stream of messages if the count is greater than one. -.. index:: sharp send opaque reg unreg .. clicmd:: sharp send opaque <reg | unreg> $proto_str [{instance (0-1000) | session (1-1000)}] type (1-1000) Send opaque ZAPI registration and unregistration messages for a @@ -128,19 +117,16 @@ keyword. At present, no sharp commands will be preserved in the config. name, and can include optional zapi ``instance`` and ``session`` values. -.. index:: sharp create session .. clicmd:: sharp create session (1-1024) Create an additional zapi client session for testing, using the specified session id. -.. index:: sharp remove session .. clicmd:: sharp remove session (1-1024) Remove a test zapi client session that was created with the specified session id. -.. index:: sharp neigh discover .. clicmd:: sharp neigh discover [vrf NAME] <A.B.C.D|X:X::X:X> IFNAME Send an ARP/NDP request to trigger the addition of a neighbor in the ARP diff --git a/doc/user/snmp.rst b/doc/user/snmp.rst index ebbe178e0b..b9058cc0d3 100644 --- a/doc/user/snmp.rst +++ b/doc/user/snmp.rst @@ -130,10 +130,7 @@ need to configure FRR to use another transport, you can configure it through Here is the syntax for using AgentX: -.. index:: agentx .. clicmd:: agentx -.. index:: agentx -.. clicmd:: no agentx .. include:: snmptrap.rst diff --git a/doc/user/static.rst b/doc/user/static.rst index 6302d1b148..200d187370 100644 --- a/doc/user/static.rst +++ b/doc/user/static.rst @@ -35,10 +35,8 @@ Static Route Commands Static routing is a very fundamental feature of routing technology. It defines a static prefix and gateway. -.. index:: ip route NETWORK GATEWAY table TABLENO nexthop-vrf VRFNAME DISTANCE vrf VRFNAME .. clicmd:: ip route NETWORK GATEWAY table TABLENO nexthop-vrf VRFNAME DISTANCE vrf VRFNAME -.. index:: ipv6 route NETWORK from SRCPREFIX GATEWAY table TABLENO nexthop-vrf VRFNAME DISTANCE vrf VRFNAME .. clicmd:: ipv6 route NETWORK from SRCPREFIX GATEWAY table TABLENO nexthop-vrf VRFNAME DISTANCE vrf VRFNAME NETWORK is destination prefix with a valid v4 or v6 network based upon diff --git a/doc/user/vnc.rst b/doc/user/vnc.rst index 4f03e543ac..4ff27c6a63 100644 --- a/doc/user/vnc.rst +++ b/doc/user/vnc.rst @@ -110,7 +110,6 @@ These are the statements that can appear between ``vnc defaults`` and - :clicmd:`export bgp|zebra route-map MAP-NAME` - :clicmd:`export bgp|zebra no route-map` -.. index:: exit-vnc .. clicmd:: exit-vnc Exit VNC configuration mode. @@ -136,7 +135,6 @@ Defaults section. **At least one `nve-group` is mandatory for useful VNC operation.** -.. index:: vnc nve-group NAME .. clicmd:: vnc nve-group NAME Enter VNC configuration mode for defining the NVE group `name`. @@ -149,14 +147,8 @@ Defaults section. exit-vnc -.. index:: vnc nve-group NAME -.. clicmd:: no vnc nve-group NAME +The following statements are valid in an NVE group definition: - Delete the NVE group named `name`. - - The following statements are valid in an NVE group definition: - -.. index:: l2rd NVE-ID-VALUE .. clicmd:: l2rd NVE-ID-VALUE Set the value used to distinguish NVEs connected to the same physical @@ -166,7 +158,6 @@ Defaults section. 1-255, or it may be specified as `auto:vn`, which means to use the least-significant octet of the originating NVE's VN address. -.. index:: prefix vn|un A.B.C.D/M|X:X::X:X/M .. clicmd:: prefix vn|un A.B.C.D/M|X:X::X:X/M Specify the matching prefix for this NVE group by either virtual-network @@ -178,7 +169,6 @@ Defaults section. These prefixes are used only for determining assignments of NVEs to NVE Groups. -.. index:: rd ROUTE-DISTINGUISHER .. clicmd:: rd ROUTE-DISTINGUISHER Specify the route distinguisher for routes advertised via BGP @@ -202,7 +192,6 @@ Defaults section. `route-distinguisher` is configured, then the advertised RD is set to ``two-byte-autonomous-system-number=0:four-byte-integer=0``. -.. index:: response-lifetime LIFETIME|infinite .. clicmd:: response-lifetime LIFETIME|infinite Specify the response lifetime, in seconds, to be included in RFP response @@ -218,13 +207,10 @@ Defaults section. `response-lifetime` is configured, the value 3600 will be used. The maximum response lifetime is 2147483647. -.. index:: rt export RT-LIST .. clicmd:: rt export RT-LIST -.. index:: rt import RT-LIST .. clicmd:: rt import RT-LIST -.. index:: rt both RT-LIST .. clicmd:: rt both RT-LIST Specify route target import and export lists. `rt-list` is a @@ -258,7 +244,6 @@ Defaults section. simultaneously, and is equivalent to `rt export `rt-list`` followed by `rt import `rt-list``. -.. index:: export bgp|zebra route-map MAP-NAME .. clicmd:: export bgp|zebra route-map MAP-NAME Specify that the named route-map should be applied to routes being exported @@ -266,7 +251,6 @@ Defaults section. :ref:`configuring-export-of-routes-to-other-routing-protocols`. This item is optional. -.. index:: export bgp|zebra no route-map .. clicmd:: export bgp|zebra no route-map Specify that no route-map should be applied to routes being exported to bgp @@ -274,7 +258,6 @@ Defaults section. :ref:`configuring-export-of-routes-to-other-routing-protocols`. This item is optional. -.. index:: export bgp|zebra ipv4|ipv6 prefix-list LIST-NAME .. clicmd:: export bgp|zebra ipv4|ipv6 prefix-list LIST-NAME Specify that the named prefix-list filter should be applied to routes being @@ -283,7 +266,6 @@ Defaults section. :ref:`configuring-export-of-routes-to-other-routing-protocols`. This item is optional. -.. index:: export bgp|zebra no ipv4|ipv6 prefix-list .. clicmd:: export bgp|zebra no ipv4|ipv6 prefix-list Specify that no prefix-list filter should be applied to routes being @@ -309,7 +291,6 @@ Note that a corresponding NVE group configuration must be present, and that other NVE associated configuration information, notably RD, is not impacted by L2 Group Configuration. -.. index:: vnc l2-group NAME .. clicmd:: vnc l2-group NAME Enter VNC configuration mode for defining the L2 group `name`. @@ -322,35 +303,26 @@ L2 Group Configuration. exit-vnc -.. index:: vnc l2-group NAME -.. clicmd:: no vnc l2-group NAME Delete the L2 group named `name`. The following statements are valid in a L2 group definition: -.. index:: logical-network-id VALUE .. clicmd:: logical-network-id VALUE Define the Logical Network Identifier with a value in the range of 0-4294967295 that identifies the logical Ethernet segment. -.. index:: labels LABEL-LIST .. clicmd:: labels LABEL-LIST -.. index:: labels LABEL-LIST -.. clicmd:: no labels LABEL-LIST Add or remove labels associated with the group. `label-list` is a space separated list of label values in the range of 0-1048575. -.. index:: rt import RT-TARGET .. clicmd:: rt import RT-TARGET -.. index:: rt export RT-TARGET .. clicmd:: rt export RT-TARGET -.. index:: rt both RT-TARGET .. clicmd:: rt both RT-TARGET Specify the route target import and export value associated with the group. @@ -484,14 +456,10 @@ There is currently no policy (prefix-list or route-map) support for Redistribution Command Syntax ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -.. index:: vnc redistribute ipv4|ipv6 bgp|bgp-direct|ipv6 bgp-direct-to-nve-groups|connected|kernel|ospf|rip|static .. clicmd:: vnc redistribute ipv4|ipv6 bgp|bgp-direct|ipv6 bgp-direct-to-nve-groups|connected|kernel|ospf|rip|static -.. index:: vnc redistribute ipv4|ipv6 bgp-direct-to-nve-groups view VIEWNAME .. clicmd:: vnc redistribute ipv4|ipv6 bgp-direct-to-nve-groups view VIEWNAME -.. index:: vnc redistribute ipv4|ipv6 bgp|bgp-direct|bgp-direct-to-nve-groups|connected|kernel|ospf|rip|static -.. clicmd:: no vnc redistribute ipv4|ipv6 bgp|bgp-direct|bgp-direct-to-nve-groups|connected|kernel|ospf|rip|static Import (or do not import) prefixes from another routing protocols. Specify both the address family to import (`ipv4` or `ipv6`) and the protocol @@ -502,17 +470,13 @@ Redistribution Command Syntax Prefixes from all other protocols (including `bgp`) are imported via the `zebra` kernel routing process. -.. index:: vnc redistribute mode plain|nve-group|resolve-nve .. clicmd:: vnc redistribute mode plain|nve-group|resolve-nve Redistribute routes from other protocols into VNC using the specified mode. Not all combinations of modes and protocols are supported. -.. index:: vnc redistribute nve-group GROUP-NAME .. clicmd:: vnc redistribute nve-group GROUP-NAME -.. index:: vnc redistribute nve-group GROUP-NAME -.. clicmd:: no vnc redistribute nve-group GROUP-NAME When using `nve-group` mode, assign (or do not assign) the NVE group `group-name` to routes redistributed from another routing protocol. @@ -522,7 +486,6 @@ Redistribution Command Syntax prefix must be specified as a full-length (/32 for IPv4, /128 for IPv6) prefix. -.. index:: vnc redistribute lifetime LIFETIME|infinite .. clicmd:: vnc redistribute lifetime LIFETIME|infinite Assign a registration lifetime, either `lifetime` seconds or `infinite`, to @@ -530,7 +493,6 @@ Redistribution Command Syntax received via RFP registration messages from an NVE. `lifetime` can be any integer between 1 and 4294967295, inclusive. -.. index:: vnc redistribute resolve-nve roo-ec-local-admin 0-65536 .. clicmd:: vnc redistribute resolve-nve roo-ec-local-admin 0-65536 Assign a value to the local-administrator subfield used in the @@ -545,25 +507,21 @@ specified outside the context of an nve-group, then they apply only for redistribution modes `plain` and `resolve-nve`, and then only for routes being redistributed from `bgp-direct`. -.. index:: vnc redistribute bgp-direct (ipv4|ipv6) prefix-list LIST-NAME .. clicmd:: vnc redistribute bgp-direct (ipv4|ipv6) prefix-list LIST-NAME When redistributing `bgp-direct` routes, specifies that the named prefix-list should be applied. -.. index:: vnc redistribute bgp-direct no (ipv4|ipv6) prefix-list .. clicmd:: vnc redistribute bgp-direct no (ipv4|ipv6) prefix-list When redistributing `bgp-direct` routes, specifies that no prefix-list should be applied. -.. index:: vnc redistribute bgp-direct route-map MAP-NAME .. clicmd:: vnc redistribute bgp-direct route-map MAP-NAME When redistributing `bgp-direct` routes, specifies that the named route-map should be applied. -.. index:: vnc redistribute bgp-direct no route-map .. clicmd:: vnc redistribute bgp-direct no route-map When redistributing `bgp-direct` routes, @@ -582,7 +540,6 @@ downstream protocol must also be configured to import the routes. For example, when VNC routes are exported to unicast BGP, the BGP configuration must include a corresponding `redistribute vnc-direct` statement. -.. index:: export bgp|zebra mode none|group-nve|registering-nve|ce .. clicmd:: export bgp|zebra mode none|group-nve|registering-nve|ce Specify how routes should be exported to bgp or zebra. If the mode is @@ -600,10 +557,8 @@ a corresponding `redistribute vnc-direct` statement. The default for both bgp and zebra is mode `none`. -.. index:: vnc export bgp|zebra group-nve group GROUP-NAME .. clicmd:: vnc export bgp|zebra group-nve group GROUP-NAME -.. index:: vnc export bgp|zebra group-nve no group GROUP-NAME .. clicmd:: vnc export bgp|zebra group-nve no group GROUP-NAME When export mode is `group-nve`, export (or do not export) prefixes from the @@ -702,14 +657,12 @@ manually and dynamically added information. `local-next-hop` parameter is used to delete specific local nexthop information. -.. index:: clear vnc mac (\\*|xx:xx:xx:xx:xx:xx) virtual-network-identifier (\\*|(1-4294967295)) (\\*|[(vn|un) (A.B.C.D|X:X::X:X|\\*) [(un|vn) (A.B.C.D|X:X::X:X|\*)] [prefix (\\*|A.B.C.D/M|X:X::X:X/M)]) .. clicmd:: clear vnc mac (\*|xx:xx:xx:xx:xx:xx) virtual-network-identifier (\*|(1-4294967295)) (\*|[(vn|un) (A.B.C.D|X:X::X:X|\*) [(un|vn) (A.B.C.D|X:X::X:X|\*)] [prefix (\*|A.B.C.D/M|X:X::X:X/M)]) Delete mac forwarding information. Any or all of these parameters may be wildcarded to (potentially) match more than one registration. The default value for the `prefix` parameter is the wildcard value `*`. -.. index:: clear vnc nve (\*|((vn|un) (A.B.C.D|X:X::X:X) [(un|vn) (A.B.C.D|X:X::X:X)])) .. clicmd:: clear vnc nve (\*|((vn|un) (A.B.C.D|X:X::X:X) [(un|vn) (A.B.C.D|X:X::X:X)])) Delete prefixes associated with the NVE specified by the given VN and UN @@ -729,24 +682,20 @@ running-configuration` command when in `enable` mode. The following commands are used to clear and display Virtual Network Control related information: -.. index:: clear vnc counters .. clicmd:: clear vnc counters Reset the counter values stored by the NVA. Counter values can be seen using the `show vnc` commands listed above. This command is only available in `enable` mode. -.. index:: show vnc summary .. clicmd:: show vnc summary Print counter values and other general information about the NVA. Counter values can be reset using the `clear vnc counters` command listed below. -.. index:: show vnc nves .. clicmd:: show vnc nves -.. index:: show vnc nves vn|un ADDRESS .. clicmd:: show vnc nves vn|un ADDRESS Display the NVA's current clients. Specifying `address` limits the output to @@ -754,10 +703,8 @@ related information: communicated with the NVE, per-NVE summary counters and each NVE's addresses will be displayed. -.. index:: show vnc queries .. clicmd:: show vnc queries -.. index:: show vnc queries PREFIX .. clicmd:: show vnc queries PREFIX Display active Query information. Queries remain valid for the default @@ -768,10 +715,8 @@ related information: Query information is provided for each querying NVE, and includes the Query Target and the time remaining before the information is removed. -.. index:: show vnc registrations [all|local|remote|holddown|imported] .. clicmd:: show vnc registrations [all|local|remote|holddown|imported] -.. index:: show vnc registrations [all|local|remote|holddown|imported] PREFIX .. clicmd:: show vnc registrations [all|local|remote|holddown|imported] PREFIX Display local, remote, holddown, and/or imported registration information. @@ -791,10 +736,8 @@ related information: registrations, the amount of time remaining before the information is removed. -.. index:: show vnc responses [active|removed] .. clicmd:: show vnc responses [active|removed] -.. index:: show vnc responses [active|removed] PREFIX .. clicmd:: show vnc responses [active|removed] PREFIX Display all, active and/or removed response information which are @@ -811,7 +754,6 @@ related information: the administrative cost, the provided response lifetime and the time remaining before the information is to be removed or will become inactive. -.. index:: show memory vnc .. clicmd:: show memory vnc Print the number of memory items allocated by the NVA. diff --git a/doc/user/vrrp.rst b/doc/user/vrrp.rst index a39bd53844..44a56f2fca 100644 --- a/doc/user/vrrp.rst +++ b/doc/user/vrrp.rst @@ -358,30 +358,26 @@ using VRRPv2. All interface configuration commands are documented below. -.. index:: vrrp (1-255) [version (2-3)] -.. clicmd:: [no] vrrp (1-255) [version (2-3)] +.. clicmd:: vrrp (1-255) [version (2-3)] Create a VRRP router with the specified VRID on the interface. Optionally specify the protocol version. If the protocol version is not specified, the default is VRRPv3. -.. index:: vrrp (1-255) advertisement-interval (10-40950) -.. clicmd:: [no] vrrp (1-255) advertisement-interval (10-40950) +.. clicmd:: vrrp (1-255) advertisement-interval (10-40950) Set the advertisement interval. This is the interval at which VRRP advertisements will be sent. Values are given in milliseconds, but must be multiples of 10, as VRRP itself uses centiseconds. -.. index:: vrrp (1-255) ip A.B.C.D -.. clicmd:: [no] vrrp (1-255) ip A.B.C.D +.. clicmd:: vrrp (1-255) ip A.B.C.D Add an IPv4 address to the router. This address must already be configured on the appropriate macvlan device. Adding an IP address to the router will implicitly activate the router; see :clicmd:`[no] vrrp (1-255) shutdown` to override this behavior. -.. index:: vrrp (1-255) ipv6 X:X::X:X -.. clicmd:: [no] vrrp (1-255) ipv6 X:X::X:X +.. clicmd:: vrrp (1-255) ipv6 X:X::X:X Add an IPv6 address to the router. This address must already be configured on the appropriate macvlan device. Adding an IP address to the router will @@ -391,23 +387,20 @@ All interface configuration commands are documented below. This command will fail if the protocol version is set to VRRPv2, as VRRPv2 does not support IPv6. -.. index:: vrrp (1-255) preempt -.. clicmd:: [no] vrrp (1-255) preempt +.. clicmd:: vrrp (1-255) preempt Toggle preempt mode. When enabled, preemption allows Backup routers with higher priority to take over Master status from the existing Master. Enabled by default. -.. index:: vrrp (1-255) priority (1-254) -.. clicmd:: [no] vrrp (1-255) priority (1-254) +.. clicmd:: vrrp (1-255) priority (1-254) Set the router priority. The router with the highest priority is elected as the Master. If all routers in the VRRP virtual router are configured with the same priority, the router with the highest primary IP address is elected as the Master. Priority value 255 is reserved for the acting Master router. -.. index:: vrrp (1-255) shutdown -.. clicmd:: [no] vrrp (1-255) shutdown +.. clicmd:: vrrp (1-255) shutdown Place the router into administrative shutdown. VRRP will not activate for this router until this command is removed with the ``no`` form. @@ -419,7 +412,6 @@ Global Configuration Show commands, global defaults and debugging configuration commands. -.. index:: show vrrp [interface INTERFACE] [(1-255)] [json] .. clicmd:: show vrrp [interface INTERFACE] [(1-255)] [json] Shows VRRP status for some or all configured VRRP routers. Specifying an @@ -427,8 +419,7 @@ Show commands, global defaults and debugging configuration commands. VRID will only show routers with that VRID. Specifying ``json`` will dump each router state in a JSON array. -.. index:: debug vrrp [{protocol|autoconfigure|packets|sockets|ndisc|arp|zebra}] -.. clicmd:: [no] debug vrrp [{protocol|autoconfigure|packets|sockets|ndisc|arp|zebra}] +.. clicmd:: debug vrrp [{protocol|autoconfigure|packets|sockets|ndisc|arp|zebra}] Toggle debugging logs for VRRP components. If no component is specified, debugging for all components are turned on/off. @@ -457,8 +448,7 @@ Show commands, global defaults and debugging configuration commands. zebra Logs communications with Zebra. -.. index:: vrrp default <advertisement-interval (1-4096)|preempt|priority (1-254)|shutdown> -.. clicmd:: [no] vrrp default <advertisement-interval (1-4096)|preempt|priority (1-254)|shutdown> +.. clicmd:: vrrp default <advertisement-interval (1-4096)|preempt|priority (1-254)|shutdown> Configure defaults for new VRRP routers. These values will not affect already configured VRRP routers, but will be applied to newly configured @@ -480,8 +470,7 @@ After configuring the interfaces as described in :ref:`vrrp-system-configuration`, and configuring any defaults you may want, execute the following command: -.. index:: vrrp autoconfigure [version (2-3)] -.. clicmd:: [no] vrrp autoconfigure [version (2-3)] +.. clicmd:: vrrp autoconfigure [version (2-3)] Generates VRRP configuration based on the interface configuration on the base system. If the protocol version is not specified, the default is VRRPv3. diff --git a/doc/user/vtysh.rst b/doc/user/vtysh.rst index b1339f26e5..ec674e377c 100644 --- a/doc/user/vtysh.rst +++ b/doc/user/vtysh.rst @@ -22,7 +22,6 @@ administrator with an external editor. have effect for vtysh) need to be manually updated in :file:`vtysh.conf`. -.. index:: copy FILENAME running-config .. clicmd:: copy FILENAME running-config Process and load a configuration file manually; each line in the @@ -52,8 +51,7 @@ and the :clicmd:`terminal paginate` command: This variable should be set by the user according to their preferences, in their :file:`~/.profile` file. -.. index:: terminal paginate -.. clicmd:: [no] terminal paginate +.. clicmd:: terminal paginate Enables/disables vtysh output pagination. This command is intended to be placed in :file:`vtysh.conf` to set a system-wide default. If this @@ -100,7 +98,6 @@ could be made SGID (set group ID) to the |INSTALL_VTY_GROUP| group. No security guarantees are made for this configuration. -.. index:: username USERNAME nopassword .. clicmd:: username USERNAME nopassword If PAM support is enabled at build-time, this command allows disabling the @@ -162,11 +159,8 @@ it can lead to /all/ of your daemons being unable to start up. Per daemon files are more robust as impact of errors in configuration are limited to the daemon in whose file the error is made. -.. index:: service integrated-vtysh-config .. clicmd:: service integrated-vtysh-config -.. index:: service integrated-vtysh-config -.. clicmd:: no service integrated-vtysh-config Control whether integrated :file:`frr.conf` file is written when 'write file' is issued. @@ -195,7 +189,6 @@ in whose file the error is made. preset one of the two operating modes and ensure consistent operation across installations. -.. index:: write integrated .. clicmd:: write integrated Unconditionally (regardless of ``service integrated-vtysh-config`` setting) diff --git a/doc/user/watchfrr.rst b/doc/user/watchfrr.rst index b29e602fe5..3a19e3c4fa 100644 --- a/doc/user/watchfrr.rst +++ b/doc/user/watchfrr.rst @@ -16,14 +16,12 @@ require end users management. WATCHFRR commands ================= -.. index:: show watchfrr .. clicmd:: show watchfrr Give status information about the state of the different daemons being watched by WATCHFRR -.. index:: watchfrr ignore DAEMON -.. clicmd:: [no] watchfrr ignore DAEMON +.. clicmd:: watchfrr ignore DAEMON Tell WATCHFRR to ignore a particular DAEMON if it goes unresponsive. This is particularly useful when you are a developer and need to debug diff --git a/doc/user/wecmp_linkbw.rst b/doc/user/wecmp_linkbw.rst index 6e516bcf9f..4df6559e5c 100644 --- a/doc/user/wecmp_linkbw.rst +++ b/doc/user/wecmp_linkbw.rst @@ -173,7 +173,6 @@ ECMP as recommended in [Draft-IETF-idr-link-bandwidth]_. The operator can change these behaviors with the following configuration: -.. index:: bgp bestpath bandwidth <ignore | skip-missing | default-weight-for-missing> .. clicmd:: bgp bestpath bandwidth <ignore | skip-missing | default-weight-for-missing> The different options imply behavior as follows: diff --git a/doc/user/zebra.rst b/doc/user/zebra.rst index a9979558c3..e5cd1de201 100644 --- a/doc/user/zebra.rst +++ b/doc/user/zebra.rst @@ -115,44 +115,30 @@ Interface Commands Standard Commands ----------------- -.. index:: interface IFNAME .. clicmd:: interface IFNAME -.. index:: interface IFNAME vrf VRF .. clicmd:: interface IFNAME vrf VRF -.. index:: shutdown .. clicmd:: shutdown -.. index:: shutdown -.. clicmd:: no shutdown Up or down the current interface. -.. index:: ip address ADDRESS/PREFIX .. clicmd:: ip address ADDRESS/PREFIX -.. index:: ipv6 address ADDRESS/PREFIX .. clicmd:: ipv6 address ADDRESS/PREFIX -.. index:: ip address ADDRESS/PREFIX -.. clicmd:: no ip address ADDRESS/PREFIX -.. index:: ipv6 address ADDRESS/PREFIX -.. clicmd:: no ipv6 address ADDRESS/PREFIX Set the IPv4 or IPv6 address/prefix for the interface. -.. index:: ip address LOCAL-ADDR peer PEER-ADDR/PREFIX .. clicmd:: ip address LOCAL-ADDR peer PEER-ADDR/PREFIX -.. index:: ip address LOCAL-ADDR peer PEER-ADDR/PREFIX -.. clicmd:: no ip address LOCAL-ADDR peer PEER-ADDR/PREFIX Configure an IPv4 Point-to-Point address on the interface. (The concept of PtP addressing does not exist for IPv6.) @@ -162,38 +148,28 @@ Standard Commands behind the other end of the link (or even on the link in Point-to-Multipoint setups), though generally /32s are used. -.. index:: description DESCRIPTION ... .. clicmd:: description DESCRIPTION ... Set description for the interface. -.. index:: multicast .. clicmd:: multicast -.. index:: multicast -.. clicmd:: no multicast Enable or disables multicast flag for the interface. -.. index:: bandwidth (1-10000000) .. clicmd:: bandwidth (1-10000000) -.. index:: bandwidth (1-10000000) -.. clicmd:: no bandwidth (1-10000000) Set bandwidth value of the interface in kilobits/sec. This is for calculating OSPF cost. This command does not affect the actual device configuration. -.. index:: link-detect .. clicmd:: link-detect -.. index:: link-detect -.. clicmd:: no link-detect Enable/disable link-detect on platforms which support this. Currently only Linux, and only where network interface drivers support reporting @@ -212,11 +188,8 @@ Link Parameters Commands protocol extensions that can be used with MPLS-TE. FRR does not support a complete RSVP-TE solution currently. -.. index:: link-params .. clicmd:: link-params -.. index:: link-param -.. clicmd:: no link-param Enter into the link parameters sub node. At least 'enable' must be set to activate the link parameters, and consequently routing @@ -228,24 +201,18 @@ Link Parameters Commands Under link parameter statement, the following commands set the different TE values: -.. index:: link-params [enable] .. clicmd:: link-params [enable] Enable link parameters for this interface. -.. index:: link-params [metric (0-4294967295)] .. clicmd:: link-params [metric (0-4294967295)] -.. index:: link-params max-bw BANDWIDTH .. clicmd:: link-params max-bw BANDWIDTH -.. index:: link-params max-rsv-bw BANDWIDTH .. clicmd:: link-params max-rsv-bw BANDWIDTH -.. index:: link-params unrsv-bw (0-7) BANDWIDTH .. clicmd:: link-params unrsv-bw (0-7) BANDWIDTH -.. index:: link-params admin-grp BANDWIDTH .. clicmd:: link-params admin-grp BANDWIDTH These commands specifies the Traffic Engineering parameters of the interface @@ -258,22 +225,16 @@ Link Parameters Commands Note that BANDIWDTH is specified in IEEE floating point format and express in Bytes/second. -.. index:: link-param delay (0-16777215) [min (0-16777215) | max (0-16777215)] .. clicmd:: link-param delay (0-16777215) [min (0-16777215) | max (0-16777215)] -.. index:: link-param delay-variation (0-16777215) .. clicmd:: link-param delay-variation (0-16777215) -.. index:: link-param packet-loss PERCENTAGE .. clicmd:: link-param packet-loss PERCENTAGE -.. index:: link-param res-bw BANDWIDTH .. clicmd:: link-param res-bw BANDWIDTH -.. index:: link-param ava-bw BANDWIDTH .. clicmd:: link-param ava-bw BANDWIDTH -.. index:: link-param use-bw BANDWIDTH .. clicmd:: link-param use-bw BANDWIDTH These command specifies additional Traffic Engineering parameters of the @@ -287,17 +248,14 @@ Link Parameters Commands (µs). Loss is specified in PERCENTAGE ranging from 0 to 50.331642% by step of 0.000003. -.. index:: link-param neighbor <A.B.C.D> as (0-65535) .. clicmd:: link-param neighbor <A.B.C.D> as (0-65535) -.. index:: link-param no neighbor .. clicmd:: link-param no neighbor Specifies the remote ASBR IP address and Autonomous System (AS) number for InterASv2 link in OSPF (RFC5392). Note that this option is not yet supported for ISIS (RFC5316). -.. index:: ip nht resolve-via-default .. clicmd:: ip nht resolve-via-default Allows nexthop tracking to resolve via the default route. This is useful @@ -427,7 +385,6 @@ see https://www.kernel.org/doc/Documentation/networking/vrf.txt. Because of that difference, there are some subtle differences when running some commands in relationship to VRF. Here is an extract of some of those commands: -.. index:: vrf VRF .. clicmd:: vrf VRF This command is available on configuration mode. By default, above command @@ -436,7 +393,6 @@ commands in relationship to VRF. Here is an extract of some of those commands: The network administrator can however decide to provision this command in configuration file to provide more clarity about the intended configuration. -.. index:: netns NAMESPACE .. clicmd:: netns NAMESPACE This command is based on VRF configuration mode. This command is available @@ -447,7 +403,6 @@ commands in relationship to VRF. Here is an extract of some of those commands: decide to provision this command in configuration file to provide more clarity about the intended configuration. -.. index:: show ip route vrf VRF .. clicmd:: show ip route vrf VRF The show command permits dumping the routing table associated to the VRF. If @@ -457,20 +412,17 @@ commands in relationship to VRF. Here is an extract of some of those commands: launched with :option:`-n` option, this will be the default routing table of the *Linux network namespace* ``VRF``. -.. index:: show ip route vrf VRF table TABLENO .. clicmd:: show ip route vrf VRF table TABLENO The show command is only available with :option:`-n` option. This command will dump the routing table ``TABLENO`` of the *Linux network namespace* ``VRF``. -.. index:: show ip route vrf VRF tables .. clicmd:: show ip route vrf VRF tables This command will dump the routing tables within the vrf scope. If `vrf all` is executed, all routing tables will be dumped. -.. index:: show <ip|ipv6> route summary [vrf VRF] [table TABLENO] [prefix] .. clicmd:: show <ip|ipv6> route summary [vrf VRF] [table TABLENO] [prefix] This command will dump a summary output of the specified VRF and TABLENO @@ -537,8 +489,7 @@ The push action is generally used for LER devices, which want to encapsulate all traffic for a wished destination into an MPLS label. This action is stored in routing entry, and can be configured like a route: -.. index:: ip route NETWORK MASK GATEWAY|INTERFACE label LABEL -.. clicmd:: [no] ip route NETWORK MASK GATEWAY|INTERFACE label LABEL +.. clicmd:: ip route NETWORK MASK GATEWAY|INTERFACE label LABEL NETWORK and MASK stand for the IP prefix entry to be added as static route entry. @@ -568,8 +519,7 @@ The swap action is generally used for LSR devices, which swap a packet with a label, with an other label. The Pop action is used on LER devices, at the termination of the MPLS traffic; this is used to remove MPLS header. -.. index:: mpls lsp INCOMING_LABEL GATEWAY OUTGOING_LABEL|explicit-null|implicit-null -.. clicmd:: [no] mpls lsp INCOMING_LABEL GATEWAY OUTGOING_LABEL|explicit-null|implicit-null +.. clicmd:: mpls lsp INCOMING_LABEL GATEWAY OUTGOING_LABEL|explicit-null|implicit-null INCOMING_LABEL and OUTGOING_LABEL are MPLS labels with values ranging from 16 to 1048575. @@ -582,7 +532,6 @@ termination of the MPLS traffic; this is used to remove MPLS header. You can check that the MPLS actions are stored in the zebra MPLS table, by looking at the presence of the entry. -.. index:: show mpls table .. clicmd:: show mpls table :: @@ -616,11 +565,8 @@ WARNING: RPF lookup results are non-responsive in this version of FRR, i.e. multicast routing does not actively react to changes in underlying unicast topology! -.. index:: ip multicast rpf-lookup-mode MODE .. clicmd:: ip multicast rpf-lookup-mode MODE -.. index:: ip multicast rpf-lookup-mode [MODE] -.. clicmd:: no ip multicast rpf-lookup-mode [MODE] MODE sets the method used to perform RPF lookups. Supported modes: @@ -650,10 +596,10 @@ unicast topology! what the default behavior is. .. warning:: + Unreachable routes do not receive special treatment and do not cause fallback to a second lookup. -.. index:: show ip rpf ADDR .. clicmd:: show ip rpf ADDR Performs a Multicast RPF lookup, as configured with ``ip multicast @@ -672,18 +618,14 @@ unicast topology! Indicates that a multicast source lookup for 192.0.2.1 would use an Unicast RIB entry for 192.0.2.0/24 with a gateway of 198.51.100.1. -.. index:: show ip rpf .. clicmd:: show ip rpf Prints the entire Multicast RIB. Note that this is independent of the configured RPF lookup mode, the Multicast RIB may be printed yet not used at all. -.. index:: ip mroute PREFIX NEXTHOP [DISTANCE] .. clicmd:: ip mroute PREFIX NEXTHOP [DISTANCE] -.. index:: ip mroute PREFIX NEXTHOP [DISTANCE] -.. clicmd:: no ip mroute PREFIX NEXTHOP [DISTANCE] Adds a static route entry to the Multicast RIB. This performs exactly as the ``ip route`` command, except that it inserts the route in the Multicast RIB @@ -699,7 +641,6 @@ received from other FRR components. The permit/deny facilities provided by these commands can be used to filter which routes zebra will install in the kernel. -.. index:: ip protocol PROTOCOL route-map ROUTEMAP .. clicmd:: ip protocol PROTOCOL route-map ROUTEMAP Apply a route-map filter to routes for the specified protocol. PROTOCOL can @@ -728,7 +669,6 @@ kernel. on a per vrf basis, by entering this command under vrf mode for the vrf you want to apply the route-map against. -.. index:: set src ADDRESS .. clicmd:: set src ADDRESS Within a route-map, set the preferred source address for matching routes @@ -767,8 +707,7 @@ IPv6 example for OSPFv3. not created at startup. On Debian, FRR might start before ifupdown completes. Consider a reboot test. -.. index:: zebra route-map delay-timer (0-600) -.. clicmd:: [no] zebra route-map delay-timer (0-600) +.. clicmd:: zebra route-map delay-timer (0-600) Set the delay before any route-maps are processed in zebra. The default time for this is 5 seconds. @@ -842,21 +781,11 @@ FPM Commands ``fpm`` implementation ---------------------- -.. index:: fpm connection ip A.B.C.D port (1-65535) .. clicmd:: fpm connection ip A.B.C.D port (1-65535) - Configure ``zebra`` to connect to a different FPM server than - ``127.0.0.1`` port ``2620``. - - -.. index:: fpm connection ip A.B.C.D port (1-65535) -.. clicmd:: no fpm connection ip A.B.C.D port (1-65535) + Configure ``zebra`` to connect to a different FPM server than the default of + ``127.0.0.1:2060`` - Configure ``zebra`` to connect to the default FPM server at ``127.0.0.1`` - port ``2620``. - - -.. index:: show zebra fpm stats .. clicmd:: show zebra fpm stats Shows the FPM statistics. @@ -892,7 +821,6 @@ FPM Commands t_conn_up_finishes 1 0 -.. index:: clear zebra fpm stats .. clicmd:: clear zebra fpm stats Reset statistics related to the zebra code that interacts with the @@ -902,35 +830,22 @@ FPM Commands ``dplane_fpm_nl`` implementation -------------------------------- -.. index:: fpm address <A.B.C.D|X:X::X:X> [port (1-65535)] .. clicmd:: fpm address <A.B.C.D|X:X::X:X> [port (1-65535)] Configures the FPM server address. Once configured ``zebra`` will attempt to connect to it immediately. + The ``no`` form disables FPM entirely. ``zebra`` will close any current + connections and will not attempt to connect to it anymore. -.. index:: fpm address [<A.B.C.D|X:X::X:X> [port (1-65535)]] -.. clicmd:: no fpm address [<A.B.C.D|X:X::X:X> [port (1-65535)]] - - Disables FPM entirely. ``zebra`` will close any current connections and - will not attempt to connect to it anymore. - - -.. index:: fpm use-next-hop-groups .. clicmd:: fpm use-next-hop-groups Use the new netlink messages ``RTM_NEWNEXTHOP`` / ``RTM_DELNEXTHOP`` to group repeated route next hop information. + The ``no`` form uses the old known FPM behavior of including next hop + information in the route (e.g. ``RTM_NEWROUTE``) messages. -.. index:: fpm use-next-hop-groups -.. clicmd:: no fpm use-next-hop-groups - - Use the old known FPM behavior of including next hop information in the - route (e.g. ``RTM_NEWROUTE``) messages. - - -.. index:: show fpm counters [json] .. clicmd:: show fpm counters [json] Show the FPM statistics (plain text or JSON formatted). @@ -955,7 +870,6 @@ FPM Commands User FPM disable requests: 0 -.. index:: clear fpm counters .. clicmd:: clear fpm counters Reset statistics related to the zebra code that interacts with the @@ -974,14 +888,12 @@ interface IP addresses. The dataplane runs in its own pthread, in order to off-load work from the main zebra pthread. -.. index:: show zebra dplane [detailed] .. clicmd:: show zebra dplane [detailed] Display statistics about the updates and events passing through the dataplane subsystem. -.. index:: show zebra dplane providers .. clicmd:: show zebra dplane providers Display information about the running dataplane plugins that are @@ -989,7 +901,6 @@ order to off-load work from the main zebra pthread. present. -.. index:: zebra dplane limit [NUMBER] .. clicmd:: zebra dplane limit [NUMBER] Configure the limit on the number of pending updates that are @@ -999,7 +910,6 @@ order to off-load work from the main zebra pthread. zebra Terminal Mode Commands ============================ -.. index:: show ip route .. clicmd:: show ip route Display current routes which zebra holds in its database. @@ -1016,19 +926,15 @@ zebra Terminal Mode Commands C* 203.181.89.240/28 eth0 -.. index:: show ipv6 route .. clicmd:: show ipv6 route -.. index:: show [ip|ipv6] route [PREFIX] [nexthop-group] .. clicmd:: show [ip|ipv6] route [PREFIX] [nexthop-group] Display detailed information about a route. If [nexthop-group] is included, it will display the nexthop group ID the route is using as well. -.. index:: show interface [NAME] [{vrf VRF|brief}] [nexthop-group] .. clicmd:: show interface [NAME] [{vrf VRF|brief}] [nexthop-group] -.. index:: show interface [NAME] [{vrf all|brief}] [nexthop-group] .. clicmd:: show interface [NAME] [{vrf all|brief}] [nexthop-group] Display interface information. If no extra information is added, it will @@ -1036,34 +942,27 @@ zebra Terminal Mode Commands detailed information about that single interface. If [nexthop-group] is specified, it will display nexthop groups pointing out that interface. -.. index:: show ip prefix-list [NAME] .. clicmd:: show ip prefix-list [NAME] -.. index:: show route-map [NAME] .. clicmd:: show route-map [NAME] -.. index:: show ip protocol .. clicmd:: show ip protocol -.. index:: show ip forward .. clicmd:: show ip forward Display whether the host's IP forwarding function is enabled or not. Almost any UNIX kernel can be configured with IP forwarding disabled. If so, the box can't work as a router. -.. index:: show ipv6 forward .. clicmd:: show ipv6 forward Display whether the host's IP v6 forwarding is enabled or not. -.. index:: show zebra .. clicmd:: show zebra Display various statistics related to the installation and deletion of routes, neighbor updates, and LSP's into the kernel. -.. index:: show zebra client [summary] .. clicmd:: show zebra client [summary] Display statistics about clients that are connected to zebra. This is @@ -1071,7 +970,6 @@ zebra Terminal Mode Commands zebra and it's clients. If the summary form of the command is choosen a table is displayed with shortened information. -.. index:: show zebra router table summary .. clicmd:: show zebra router table summary Display summarized data about tables created, their afi/safi/tableid @@ -1079,7 +977,6 @@ zebra Terminal Mode Commands total number of route nodes in the table. Which will be higher than the actual number of routes that are held. -.. index:: show nexthop-group rib [ID] [vrf NAME] [singleton [ip|ip6]] [type] .. clicmd:: show nexthop-group rib [ID] [vrf NAME] [singleton [ip|ip6]] [type] Display nexthop groups created by zebra. The [vrf NAME] option @@ -1097,34 +994,29 @@ Many routing protocols require a router-id to be configured. To have a consistent router-id across all daemons, the following commands are available to configure and display the router-id: -.. index:: router-id A.B.C.D -.. clicmd:: [no] [ip] router-id A.B.C.D +.. clicmd:: [ip] router-id A.B.C.D Allow entering of the router-id. This command also works under the vrf subnode, to allow router-id's per vrf. -.. index:: router-id A.B.C.D vrf NAME -.. clicmd:: [no] [ip] router-id A.B.C.D vrf NAME +.. clicmd:: [ip] router-id A.B.C.D vrf NAME Configure the router-id of this router from the configure NODE. A show run of this command will display the router-id command under the vrf sub node. This command is deprecated and will be removed at some point in time in the future. -.. index:: show [ip] router-id [vrf NAME] .. clicmd:: show [ip] router-id [vrf NAME] Display the user configured router-id. For protocols requiring an IPv6 router-id, the following commands are available: -.. index:: ipv6 router-id X:X::X:X -.. clicmd:: [no] ipv6 router-id X:X::X:X +.. clicmd:: ipv6 router-id X:X::X:X Configure the IPv6 router-id of this router. Like its IPv4 counterpart, this command works under the vrf subnode, to allow router-id's per vrf. -.. index:: show ipv6 router-id [vrf NAME] .. clicmd:: show ipv6 router-id [vrf NAME] Display the user configured IPv6 router-id. diff --git a/eigrpd/eigrp_cli.c b/eigrpd/eigrp_cli.c index 00d8ea8867..ae15e97d4a 100644 --- a/eigrpd/eigrp_cli.c +++ b/eigrpd/eigrp_cli.c @@ -671,7 +671,7 @@ DEFPY_YANG( as_str); nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); - snprintf(xpath_auth, sizeof(xpath_auth), "%s/summarize-address", xpath); + snprintf(xpath_auth, sizeof(xpath_auth), "%s/summarize-addresses", xpath); nb_cli_enqueue_change(vty, xpath_auth, NB_OP_CREATE, prefix_str); return nb_cli_apply_changes(vty, NULL); @@ -694,7 +694,7 @@ DEFPY_YANG( as_str); nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); - snprintf(xpath_auth, sizeof(xpath_auth), "%s/summarize-address", xpath); + snprintf(xpath_auth, sizeof(xpath_auth), "%s/summarize-addresses", xpath); nb_cli_enqueue_change(vty, xpath_auth, NB_OP_DESTROY, prefix_str); return nb_cli_apply_changes(vty, NULL); @@ -703,12 +703,12 @@ DEFPY_YANG( void eigrp_cli_show_summarize_address(struct vty *vty, struct lyd_node *dnode, bool show_defaults) { - const struct eigrp_interface *eif = nb_running_get_entry(dnode, NULL, - true); + const struct lyd_node *instance = yang_dnode_get_parent(dnode, "instance"); + uint16_t asn = yang_dnode_get_uint16(instance, "./asn"); const char *summarize_address = yang_dnode_get_string(dnode, NULL); - vty_out(vty, " ip summary-address eigrp %d %s\n", - eif->eigrp->AS, summarize_address); + vty_out(vty, " ip summary-address eigrp %d %s\n", asn, + summarize_address); } /* @@ -767,12 +767,11 @@ DEFPY_YANG( void eigrp_cli_show_authentication(struct vty *vty, struct lyd_node *dnode, bool show_defaults) { - const struct eigrp_interface *eif = nb_running_get_entry(dnode, NULL, - true); + const struct lyd_node *instance = yang_dnode_get_parent(dnode, "instance"); + uint16_t asn = yang_dnode_get_uint16(instance, "./asn"); const char *crypt = yang_dnode_get_string(dnode, NULL); - vty_out(vty, " ip authentication mode eigrp %d %s\n", - eif->eigrp->AS, crypt); + vty_out(vty, " ip authentication mode eigrp %d %s\n", asn, crypt); } /* @@ -827,12 +826,12 @@ DEFPY_YANG( void eigrp_cli_show_keychain(struct vty *vty, struct lyd_node *dnode, bool show_defaults) { - const struct eigrp_interface *eif = nb_running_get_entry(dnode, NULL, - true); + const struct lyd_node *instance = yang_dnode_get_parent(dnode, "instance"); + uint16_t asn = yang_dnode_get_uint16(instance, "./asn"); const char *keychain = yang_dnode_get_string(dnode, NULL); - vty_out(vty, " ip authentication key-chain eigrp %d %s\n", - eif->eigrp->AS, keychain); + vty_out(vty, " ip authentication key-chain eigrp %d %s\n", asn, + keychain); } 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_memory.h b/eigrpd/eigrp_memory.h deleted file mode 100644 index 21ecba2aae..0000000000 --- a/eigrpd/eigrp_memory.h +++ /dev/null @@ -1,43 +0,0 @@ -/* eigrpd memory type declarations - * - * 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 - */ - -#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) - -#endif /* _FRR_EIGRP_MEMORY_H */ 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 252cd647a2..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"}, @@ -572,17 +578,11 @@ int eigrp_read(struct thread *thread) /* If incoming interface is passive one, ignore it. */ if (eigrp_if_is_passive(ei)) { - char buf[3][INET_ADDRSTRLEN]; - if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV)) zlog_debug( - "ignoring packet from router %s sent to %s, received on a passive interface, %s", - inet_ntop(AF_INET, &eigrph->vrid, buf[0], - sizeof(buf[0])), - inet_ntop(AF_INET, &iph->ip_dst, buf[1], - sizeof(buf[1])), - inet_ntop(AF_INET, &ei->address.u.prefix4, - buf[2], sizeof(buf[2]))); + "ignoring packet from router %u sent to %pI4, received on a passive interface, %pI4", + ntohs(eigrph->vrid), &iph->ip_dst, + &ei->address.u.prefix4); if (iph->ip_dst.s_addr == htonl(EIGRP_MULTICAST_ADDRESS)) { eigrp_if_set_multicast(ei); 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_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/eigrp_zebra.c b/eigrpd/eigrp_zebra.c index e79123e6b4..7c765248c6 100644 --- a/eigrpd/eigrp_zebra.c +++ b/eigrpd/eigrp_zebra.c @@ -231,9 +231,7 @@ void eigrp_zebra_route_add(struct eigrp *eigrp, struct prefix *p, api.nexthop_num = count; if (IS_DEBUG_EIGRP(zebra, ZEBRA_REDISTRIBUTE)) { - char buf[PREFIX_STRLEN]; - zlog_debug("Zebra: Route add %pFX nexthop %s", p, - inet_ntop(AF_INET, 0, buf, PREFIX_STRLEN)); + zlog_debug("Zebra: Route add %pFX", p); } zclient_route_send(ZEBRA_ROUTE_ADD, zclient, &api); 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 71d4758163..c1f5e49eca 100644 --- a/isisd/isis_adjacency.c +++ b/isisd/isis_adjacency.c @@ -49,13 +49,24 @@ #include "isisd/fabricd.h" #include "isisd/isis_nb.h" -static struct isis_adjacency *adj_alloc(const uint8_t *id) +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) { struct isis_adjacency *adj; adj = XCALLOC(MTYPE_ISIS_ADJACENCY, sizeof(struct isis_adjacency)); memcpy(adj->sysid, id, ISIS_SYS_ID_LEN); + adj->snmp_idx = ++circuit->snmp_adj_idx_gen; + + if (circuit->snmp_adj_list == NULL) + circuit->snmp_adj_list = list_new(); + + adj->snmp_list_node = listnode_add(circuit->snmp_adj_list, adj); + return adj; } @@ -65,7 +76,7 @@ struct isis_adjacency *isis_new_adj(const uint8_t *id, const uint8_t *snpa, struct isis_adjacency *adj; int i; - adj = adj_alloc(id); /* P2P kludge */ + adj = adj_alloc(circuit, id); /* P2P kludge */ if (snpa) { memcpy(adj->snpa, snpa, ETH_ALEN); @@ -138,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) { @@ -146,6 +157,8 @@ void isis_delete_adj(void *arg) if (!adj) return; + /* Remove self from snmp list without walking the list*/ + list_delete_node(adj->circuit->snmp_adj_list, adj->snmp_list_node); thread_cancel(&adj->t_expire); if (adj->adj_state != ISIS_ADJ_DOWN) @@ -250,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"); } @@ -292,7 +309,6 @@ void isis_adj_state_change(struct isis_adjacency **padj, if (circuit->area->log_adj_changes) isis_log_adj_change(adj, old_state, new_state, reason); - circuit->adj_state_changes++; #ifndef FABRICD /* send northbound notification */ isis_notif_adj_state_change(adj, new_state, reason); @@ -303,12 +319,14 @@ void isis_adj_state_change(struct isis_adjacency **padj, if ((adj->level & level) == 0) continue; if (new_state == ISIS_ADJ_UP) { + circuit->adj_state_changes++; circuit->upadjcount[level - 1]++; /* update counter & timers for debugging * purposes */ adj->last_flap = time(NULL); adj->flaps++; } else if (old_state == ISIS_ADJ_UP) { + circuit->adj_state_changes++; listnode_delete(circuit->u.bc.adjdb[level - 1], adj); @@ -451,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 2780d826f5..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, @@ -105,6 +107,8 @@ struct isis_adjacency { unsigned int mt_count; /* Number of entries in mt_set */ struct bfd_session *bfd_session; struct list *adj_sids; /* Segment Routing Adj-SIDs. */ + uint32_t snmp_idx; + struct listnode *snmp_list_node; }; struct isis_threeway_adj; @@ -121,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); @@ -140,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 4aac3f8880..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. @@ -71,6 +73,48 @@ DEFINE_HOOK(isis_if_new_hook, (struct interface *ifp), (ifp)) int isis_if_new_hook(struct interface *); int isis_if_delete_hook(struct interface *); +static int isis_circuit_smmp_id_gen(struct isis_circuit *circuit) +{ + struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT); + struct isis *isis = NULL; + uint32_t id; + uint32_t i; + + isis = isis_lookup_by_vrfid(vrf->vrf_id); + if (isis == NULL) + return 0; + + id = isis->snmp_circuit_id_last; + id++; + + /* find next unused entry */ + for (i = 0; i < SNMP_CIRCUITS_MAX; i++) { + if (id >= SNMP_CIRCUITS_MAX) { + id = 0; + continue; + } + + if (id == 0) + continue; + + if (isis->snmp_circuits[id] == NULL) + break; + + id++; + } + + if (i == SNMP_CIRCUITS_MAX) { + zlog_warn("Could not allocate a smmp-circuit-id"); + return 0; + } + + isis->snmp_circuits[id] = circuit; + isis->snmp_circuit_id_last = id; + circuit->snmp_id = id; + + return 1; +} + struct isis_circuit *isis_circuit_new(struct isis *isis) { struct isis_circuit *circuit; @@ -80,6 +124,12 @@ struct isis_circuit *isis_circuit_new(struct isis *isis) circuit->isis = isis; /* + * Note: if snmp-id generation failed circuit will fail + * up operation + */ + isis_circuit_smmp_id_gen(circuit); + + /* * Default values */ #ifndef FABRICD @@ -150,11 +200,18 @@ struct isis_circuit *isis_circuit_new(struct isis *isis) void isis_circuit_del(struct isis_circuit *circuit) { + struct isis *isis = NULL; + if (!circuit) return; QOBJ_UNREG(circuit); + if (circuit->interface) { + isis = isis_lookup_by_vrfid(circuit->interface->vrf_id); + isis->snmp_circuits[circuit->snmp_id] = NULL; + } + isis_circuit_if_unbind(circuit, circuit->interface); circuit_mt_finish(circuit); @@ -253,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) @@ -609,6 +666,7 @@ int isis_circuit_up(struct isis_circuit *circuit) return ISIS_OK; if (circuit->is_passive) { + circuit->last_uptime = time(NULL); /* make sure the union fields are initialized, else we * could end with garbage values from a previous circuit * type, which would then cause a segfault when building @@ -623,6 +681,13 @@ int isis_circuit_up(struct isis_circuit *circuit) return ISIS_OK; } + if (circuit->snmp_id == 0) { + /* We cannot bring circuit up if does not have snmp-id */ + flog_err(EC_ISIS_CONFIG, + "No snnmp-id: there are too many circuits:"); + return ISIS_ERROR; + } + if (circuit->area->lsp_mtu > isis_circuit_pdu_size(circuit)) { flog_err( EC_ISIS_CONFIG, @@ -722,6 +787,8 @@ int isis_circuit_up(struct isis_circuit *circuit) circuit->tx_queue = isis_tx_queue_new(circuit, send_lsp); + circuit->last_uptime = time(NULL); + #ifndef FABRICD /* send northbound notification */ isis_notif_if_state_change(circuit, false); @@ -828,6 +895,15 @@ void isis_circuit_down(struct isis_circuit *circuit) thread_cancel(&circuit->u.p2p.t_send_p2p_hello); } + /* + * All adjacencies have to be gone, delete snmp list + * and reset snmpd idx generator + */ + if (circuit->snmp_adj_list != NULL) + list_delete(&circuit->snmp_adj_list); + + circuit->snmp_adj_idx_gen = 0; + /* Cancel all active threads */ thread_cancel(&circuit->t_send_csnp[0]); thread_cancel(&circuit->t_send_csnp[1]); @@ -1011,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 3387232da2..cbe4040b64 100644 --- a/isisd/isis_circuit.h +++ b/isisd/isis_circuit.h @@ -79,6 +79,7 @@ struct isis_circuit_arg { struct isis_circuit { int state; uint8_t circuit_id; /* l1/l2 bcast CircuitID */ + time_t last_uptime; struct isis *isis; struct isis_area *area; /* back pointer to the area */ struct interface *interface; /* interface info from z */ @@ -115,6 +116,8 @@ struct isis_circuit { int pad_hellos; /* add padding to Hello PDUs ? */ char ext_domain; /* externalDomain (boolean) */ int lsp_regenerate_pending[ISIS_LEVELS]; + uint64_t lsp_error_counter; + /* * Configurables */ @@ -165,9 +168,15 @@ struct isis_circuit { uint32_t auth_type_failures; /*authentication-type-fails */ uint32_t auth_failures; /* authentication-fails */ - QOBJ_FIELDS + uint32_t snmp_id; /* Circuit id in snmp */ + + uint32_t snmp_adj_idx_gen; /* Create unique id for adjacency on creation + */ + struct list *snmp_adj_list; /* List in id order */ + + 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); @@ -222,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 b48da9312f..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"); } @@ -1596,93 +1596,120 @@ void cli_show_isis_sr_enabled(struct vty *vty, struct lyd_node *dnode, } /* - * XPath: /frr-isisd:isis/instance/segment-routing/srgb + * XPath: /frr-isisd:isis/instance/segment-routing/label-block */ -DEFPY_YANG (isis_sr_global_block_label_range, - isis_sr_global_block_label_range_cmd, - "segment-routing global-block (16-1048575)$lower_bound (16-1048575)$upper_bound", - SR_STR - "Segment Routing Global Block label range\n" - "The lower bound of the block\n" - "The upper bound of the block (block size may not exceed 65535)\n") + +DEFPY_YANG( + isis_sr_global_block_label_range, isis_sr_global_block_label_range_cmd, + "segment-routing global-block (16-1048575)$gb_lower_bound (16-1048575)$gb_upper_bound [local-block (16-1048575)$lb_lower_bound (16-1048575)$lb_upper_bound]", + SR_STR + "Segment Routing Global Block label range\n" + "The lower bound of the global block\n" + "The upper bound of the global block (block size may not exceed 65535)\n" + "Segment Routing Local Block label range\n" + "The lower bound of the local block\n" + "The upper bound of the local block (block size may not exceed 65535)\n") { - nb_cli_enqueue_change(vty, "./segment-routing/srgb/lower-bound", - NB_OP_MODIFY, lower_bound_str); - nb_cli_enqueue_change(vty, "./segment-routing/srgb/upper-bound", - NB_OP_MODIFY, upper_bound_str); + nb_cli_enqueue_change(vty, + "./segment-routing/label-blocks/srgb/lower-bound", + NB_OP_MODIFY, gb_lower_bound_str); + nb_cli_enqueue_change(vty, + "./segment-routing/label-blocks/srgb/upper-bound", + NB_OP_MODIFY, gb_upper_bound_str); + + nb_cli_enqueue_change( + vty, "./segment-routing/label-blocks/srlb/lower-bound", + NB_OP_MODIFY, lb_lower_bound ? lb_lower_bound_str : NULL); + nb_cli_enqueue_change( + vty, "./segment-routing/label-blocks/srlb/upper-bound", + NB_OP_MODIFY, lb_upper_bound ? lb_upper_bound_str : NULL); return nb_cli_apply_changes(vty, NULL); } -DEFPY_YANG (no_isis_sr_global_block_label_range, - no_isis_sr_global_block_label_range_cmd, - "no segment-routing global-block [(16-1048575) (16-1048575)]", - NO_STR - SR_STR - "Segment Routing Global Block label range\n" - "The lower bound of the block\n" - "The upper bound of the block (block size may not exceed 65535)\n") +DEFPY_YANG(no_isis_sr_global_block_label_range, + no_isis_sr_global_block_label_range_cmd, + "no segment-routing global-block [(16-1048575) (16-1048575) local-block (16-1048575) (16-1048575)]", + NO_STR SR_STR + "Segment Routing Global Block label range\n" + "The lower bound of the global block\n" + "The upper bound of the global block (block size may not exceed 65535)\n" + "Segment Routing Local Block label range\n" + "The lower bound of the local block\n" + "The upper bound of the local block (block size may not exceed 65535)\n") { - nb_cli_enqueue_change(vty, "./segment-routing/srgb/lower-bound", + nb_cli_enqueue_change(vty, + "./segment-routing/label-blocks/srgb/lower-bound", + NB_OP_MODIFY, NULL); + nb_cli_enqueue_change(vty, + "./segment-routing/label-blocks/srgb/upper-bound", + NB_OP_MODIFY, NULL); + nb_cli_enqueue_change(vty, + "./segment-routing/label-blocks/srlb/lower-bound", NB_OP_MODIFY, NULL); - nb_cli_enqueue_change(vty, "./segment-routing/srgb/upper-bound", + nb_cli_enqueue_change(vty, + "./segment-routing/label-blocks/srlb/upper-bound", NB_OP_MODIFY, NULL); return nb_cli_apply_changes(vty, NULL); } -void cli_show_isis_srgb(struct vty *vty, struct lyd_node *dnode, - bool show_defaults) +void cli_show_isis_label_blocks(struct vty *vty, struct lyd_node *dnode, + bool show_defaults) { - vty_out(vty, " segment-routing global-block %s %s\n", - yang_dnode_get_string(dnode, "./lower-bound"), - yang_dnode_get_string(dnode, "./upper-bound")); + vty_out(vty, " segment-routing global-block %s %s", + yang_dnode_get_string(dnode, "./srgb/lower-bound"), + yang_dnode_get_string(dnode, "./srgb/upper-bound")); + if (!yang_dnode_is_default(dnode, "./srlb/lower-bound") + || !yang_dnode_is_default(dnode, "./srlb/upper-bound")) + vty_out(vty, " local-block %s %s", + yang_dnode_get_string(dnode, "./srlb/lower-bound"), + yang_dnode_get_string(dnode, "./srlb/upper-bound")); + vty_out(vty, "\n"); } /* * XPath: /frr-isisd:isis/instance/segment-routing/srlb */ -DEFPY_YANG (isis_sr_local_block_label_range, - isis_sr_local_block_label_range_cmd, - "segment-routing local-block (16-1048575)$lower_bound (16-1048575)$upper_bound", - SR_STR - "Segment Routing Local Block label range\n" - "The lower bound of the block\n" - "The upper bound of the block (block size may not exceed 65535)\n") -{ - nb_cli_enqueue_change(vty, "./segment-routing/srlb/lower-bound", +DEFPY_HIDDEN( + isis_sr_local_block_label_range, isis_sr_local_block_label_range_cmd, + "segment-routing local-block (16-1048575)$lower_bound (16-1048575)$upper_bound", + SR_STR + "Segment Routing Local Block label range\n" + "The lower bound of the block\n" + "The upper bound of the block (block size may not exceed 65535)\n") +{ +#if CONFDATE > 20220217 +CPP_NOTICE("Use of the local-block command is deprecated") +#endif + nb_cli_enqueue_change(vty, + "./segment-routing/label-blocks/srlb/lower-bound", NB_OP_MODIFY, lower_bound_str); - nb_cli_enqueue_change(vty, "./segment-routing/srlb/upper-bound", + nb_cli_enqueue_change(vty, + "./segment-routing/label-blocks/srlb/upper-bound", NB_OP_MODIFY, upper_bound_str); return nb_cli_apply_changes(vty, NULL); } -DEFPY_YANG (no_isis_sr_local_block_label_range, - no_isis_sr_local_block_label_range_cmd, - "no segment-routing local-block [(16-1048575) (16-1048575)]", - NO_STR - SR_STR - "Segment Routing Local Block label range\n" - "The lower bound of the block\n" - "The upper bound of the block (block size may not exceed 65535)\n") +DEFPY_HIDDEN(no_isis_sr_local_block_label_range, + no_isis_sr_local_block_label_range_cmd, + "no segment-routing local-block [(16-1048575) (16-1048575)]", + NO_STR SR_STR + "Segment Routing Local Block label range\n" + "The lower bound of the block\n" + "The upper bound of the block (block size may not exceed 65535)\n") { - nb_cli_enqueue_change(vty, "./segment-routing/srlb/lower-bound", + nb_cli_enqueue_change(vty, + "./segment-routing/label-blocks/srlb/lower-bound", NB_OP_MODIFY, NULL); - nb_cli_enqueue_change(vty, "./segment-routing/srlb/upper-bound", + nb_cli_enqueue_change(vty, + "./segment-routing/label-blocks/srlb/upper-bound", NB_OP_MODIFY, NULL); return nb_cli_apply_changes(vty, NULL); } -void cli_show_isis_srlb(struct vty *vty, struct lyd_node *dnode, - bool show_defaults) -{ - vty_out(vty, " segment-routing local-block %s %s\n", - yang_dnode_get_string(dnode, "./lower-bound"), - yang_dnode_get_string(dnode, "./upper-bound")); -} - /* * XPath: /frr-isisd:isis/instance/segment-routing/msd/node-msd */ diff --git a/isisd/isis_dr.c b/isisd/isis_dr.c index f6175fe9a4..e09e23aaeb 100644 --- a/isisd/isis_dr.c +++ b/isisd/isis_dr.c @@ -97,6 +97,7 @@ static int isis_check_dr_change(struct isis_adjacency *adj, int level) /* was there a DIS state transition ? */ { adj->dischanges[level - 1]++; + adj->circuit->desig_changes[level - 1]++; /* ok rotate the history list through */ for (i = DIS_RECORDS - 1; i > 0; i--) { adj->dis_record[(i * ISIS_LEVELS) + level - 1].dis = diff --git a/isisd/isis_dynhn.c b/isisd/isis_dynhn.c index 244f388c26..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; @@ -166,3 +168,38 @@ void dynhn_print_all(struct vty *vty, struct isis *isis) cmd_hostname_get()); return; } + +struct isis_dynhn *dynhn_snmp_next(const uint8_t *id, int level) +{ + struct listnode *node = NULL; + struct isis_dynhn *dyn = NULL; + struct isis_dynhn *found_dyn = NULL; + int res; + + for (ALL_LIST_ELEMENTS_RO(dyn_cache, node, dyn)) { + res = memcmp(dyn->id, id, ISIS_SYS_ID_LEN); + + if (res < 0) + continue; + + if (res == 0 && dyn->level <= level) + continue; + + if (res == 0) { + /* + * This is the best match, we can stop + * searching + */ + + found_dyn = dyn; + break; + } + + if (found_dyn == NULL + || memcmp(dyn->id, found_dyn->id, ISIS_SYS_ID_LEN) < 0) { + found_dyn = dyn; + } + } + + return found_dyn; +} diff --git a/isisd/isis_dynhn.h b/isisd/isis_dynhn.h index 973fde8307..8d25582e49 100644 --- a/isisd/isis_dynhn.h +++ b/isisd/isis_dynhn.h @@ -38,4 +38,7 @@ struct isis_dynhn *dynhn_find_by_id(const uint8_t *id); struct isis_dynhn *dynhn_find_by_name(const char *hostname); void dynhn_print_all(struct vty *vty, struct isis *isis); +/* Snmp support */ +struct isis_dynhn *dynhn_snmp_next(const uint8_t *id, int level); + #endif /* _ZEBRA_ISIS_DYNHN_H */ diff --git a/isisd/isis_lfa.c b/isisd/isis_lfa.c index 5b3a3827a2..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) @@ -541,10 +542,16 @@ static int tilfa_repair_list_apply(struct isis_spftree *spftree, struct isis_spf_adj *sadj = vadj->sadj; struct mpls_label_stack *label_stack; + /* + * Don't try to apply the repair list if one was already applied + * before (can't have ECMP past the P-node). + */ + if (vadj->label_stack) + continue; + if (!isis_vertex_adj_exists(spftree, vertex_pnode, sadj)) continue; - assert(!vadj->label_stack); label_stack = tilfa_compute_label_stack(spftree->lspdb, sadj, repair_list); if (!label_stack) { @@ -663,6 +670,21 @@ static int tilfa_build_repair_list(struct isis_spftree *spftree_pc, if ((!is_qnode || spftree_pc->lfa.protected_resource.type == LFA_NODE_PROTECTION) && vertex_child) { + /* + * If vertex is the penultimate hop router, then pushing an + * Adj-SID towards the final hop means that the No-PHP flag of + * the original Prefix-SID must be honored. We do that by + * removing the previously added Prefix-SID from the repair list + * when those conditions are met. + */ + if (vertex->depth == (vertex_dest->depth - 2) + && VTYPE_IP(vertex_dest->type) + && vertex_dest->N.ip.sr.present + && !CHECK_FLAG(vertex_dest->N.ip.sr.sid.flags, + ISIS_PREFIX_SID_NO_PHP)) { + list_delete_all_node(repair_list); + } + label_qnode = tilfa_find_qnode_adj_sid(spftree_pc, vertex->N.id, vertex_child->N.id); if (label_qnode == MPLS_INVALID_LABEL) { 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 a17d9a6ae2..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); @@ -324,8 +326,8 @@ void lsp_inc_seqno(struct isis_lsp *lsp, uint32_t seqno) /* check for overflow */ if (newseq < lsp->hdr.seqno) { /* send northbound notification */ - isis_notif_lsp_exceed_max(lsp->area, - rawlspid_print(lsp->hdr.lsp_id)); + lsp->area->lsp_exceeded_max_counter++; + isis_notif_lsp_exceed_max(lsp->area, lsp->hdr.lsp_id); } #endif /* ifndef FABRICD */ @@ -1357,8 +1359,8 @@ int lsp_generate(struct isis_area *area, int level) #ifndef FABRICD /* send northbound notification */ - isis_notif_lsp_gen(area, rawlspid_print(newlsp->hdr.lsp_id), - newlsp->hdr.seqno, newlsp->last_generated); + isis_notif_lsp_gen(area, newlsp->hdr.lsp_id, newlsp->hdr.seqno, + newlsp->last_generated); #endif /* ifndef FABRICD */ return ISIS_OK; @@ -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.c b/isisd/isis_nb.c index 6d46e6b67e..227724934b 100644 --- a/isisd/isis_nb.c +++ b/isisd/isis_nb.c @@ -573,41 +573,44 @@ const struct frr_yang_module_info frr_isisd_info = { }, }, { - .xpath = "/frr-isisd:isis/instance/segment-routing/srgb", + .xpath = "/frr-isisd:isis/instance/segment-routing/label-blocks", + .cbs = { + .pre_validate = isis_instance_segment_routing_label_blocks_pre_validate, + .cli_show = cli_show_isis_label_blocks, + }, + }, + { + .xpath = "/frr-isisd:isis/instance/segment-routing/label-blocks/srgb", .cbs = { .apply_finish = isis_instance_segment_routing_srgb_apply_finish, - .pre_validate = isis_instance_segment_routing_srgb_pre_validate, - .cli_show = cli_show_isis_srgb, }, }, { - .xpath = "/frr-isisd:isis/instance/segment-routing/srgb/lower-bound", + .xpath = "/frr-isisd:isis/instance/segment-routing/label-blocks/srgb/lower-bound", .cbs = { .modify = isis_instance_segment_routing_srgb_lower_bound_modify, }, }, { - .xpath = "/frr-isisd:isis/instance/segment-routing/srgb/upper-bound", + .xpath = "/frr-isisd:isis/instance/segment-routing/label-blocks/srgb/upper-bound", .cbs = { .modify = isis_instance_segment_routing_srgb_upper_bound_modify, }, }, { - .xpath = "/frr-isisd:isis/instance/segment-routing/srlb", + .xpath = "/frr-isisd:isis/instance/segment-routing/label-blocks/srlb", .cbs = { .apply_finish = isis_instance_segment_routing_srlb_apply_finish, - .pre_validate = isis_instance_segment_routing_srlb_pre_validate, - .cli_show = cli_show_isis_srlb, }, }, { - .xpath = "/frr-isisd:isis/instance/segment-routing/srlb/lower-bound", + .xpath = "/frr-isisd:isis/instance/segment-routing/label-blocks/srlb/lower-bound", .cbs = { .modify = isis_instance_segment_routing_srlb_lower_bound_modify, }, }, { - .xpath = "/frr-isisd:isis/instance/segment-routing/srlb/upper-bound", + .xpath = "/frr-isisd:isis/instance/segment-routing/label-blocks/srlb/upper-bound", .cbs = { .modify = isis_instance_segment_routing_srlb_upper_bound_modify, }, diff --git a/isisd/isis_nb.h b/isisd/isis_nb.h index 8ecd8134e6..a6841b9fd4 100644 --- a/isisd/isis_nb.h +++ b/isisd/isis_nb.h @@ -387,9 +387,7 @@ lib_interface_state_isis_event_counters_authentication_fails_get_elem( /* Optional 'pre_validate' callbacks. */ int isis_instance_segment_routing_prefix_sid_map_prefix_sid_pre_validate( struct nb_cb_pre_validate_args *args); -int isis_instance_segment_routing_srgb_pre_validate( - struct nb_cb_pre_validate_args *args); -int isis_instance_segment_routing_srlb_pre_validate( +int isis_instance_segment_routing_label_blocks_pre_validate( struct nb_cb_pre_validate_args *args); /* Optional 'apply_finish' callbacks. */ @@ -476,10 +474,8 @@ void cli_show_isis_mt_ipv6_dstsrc(struct vty *vty, struct lyd_node *dnode, bool show_defaults); void cli_show_isis_sr_enabled(struct vty *vty, struct lyd_node *dnode, bool show_defaults); -void cli_show_isis_srgb(struct vty *vty, struct lyd_node *dnode, - bool show_defaults); -void cli_show_isis_srlb(struct vty *vty, struct lyd_node *dnode, - bool show_defaults); +void cli_show_isis_label_blocks(struct vty *vty, struct lyd_node *dnode, + bool show_defaults); void cli_show_isis_node_msd(struct vty *vty, struct lyd_node *dnode, bool show_defaults); void cli_show_isis_prefix_sid(struct vty *vty, struct lyd_node *dnode, @@ -553,40 +549,97 @@ void cli_show_isis_mpls_if_ldp_sync_holddown(struct vty *vty, /* Notifications. */ void isis_notif_db_overload(const struct isis_area *area, bool overload); void isis_notif_lsp_too_large(const struct isis_circuit *circuit, - uint32_t pdu_size, const char *lsp_id); + uint32_t pdu_size, const uint8_t *lsp_id); void isis_notif_if_state_change(const struct isis_circuit *circuit, bool down); void isis_notif_corrupted_lsp(const struct isis_area *area, - const char *lsp_id); /* currently unused */ + const uint8_t *lsp_id); /* currently unused */ void isis_notif_lsp_exceed_max(const struct isis_area *area, - const char *lsp_id); + const uint8_t *lsp_id); void isis_notif_max_area_addr_mismatch(const struct isis_circuit *circuit, uint8_t max_area_addrs, - const char *raw_pdu); + const char *raw_pdu, size_t raw_pdu_len); void isis_notif_authentication_type_failure(const struct isis_circuit *circuit, - const char *raw_pdu); + const char *raw_pdu, + size_t raw_pdu_len); void isis_notif_authentication_failure(const struct isis_circuit *circuit, - const char *raw_pdu); + const char *raw_pdu, size_t raw_pdu_len); void isis_notif_adj_state_change(const struct isis_adjacency *adj, int new_state, const char *reason); void isis_notif_reject_adjacency(const struct isis_circuit *circuit, - const char *reason, const char *raw_pdu); + const char *reason, const char *raw_pdu, + size_t raw_pdu_len); void isis_notif_area_mismatch(const struct isis_circuit *circuit, - const char *raw_pdu); + const char *raw_pdu, size_t raw_pdu_len); void isis_notif_lsp_received(const struct isis_circuit *circuit, - const char *lsp_id, uint32_t seqno, + const uint8_t *lsp_id, uint32_t seqno, uint32_t timestamp, const char *sys_id); -void isis_notif_lsp_gen(const struct isis_area *area, const char *lsp_id, +void isis_notif_lsp_gen(const struct isis_area *area, const uint8_t *lsp_id, uint32_t seqno, uint32_t timestamp); void isis_notif_id_len_mismatch(const struct isis_circuit *circuit, - uint8_t rcv_id_len, const char *raw_pdu); + uint8_t rcv_id_len, const char *raw_pdu, + size_t raw_pdu_len); void isis_notif_version_skew(const struct isis_circuit *circuit, - uint8_t version, const char *raw_pdu); + uint8_t version, const char *raw_pdu, + size_t raw_pdu_len); void isis_notif_lsp_error(const struct isis_circuit *circuit, - const char *lsp_id, const char *raw_pdu, - uint32_t offset, uint8_t tlv_type); + const uint8_t *lsp_id, const char *raw_pdu, + size_t raw_pdu_len, uint32_t offset, + uint8_t tlv_type); void isis_notif_seqno_skipped(const struct isis_circuit *circuit, - const char *lsp_id); + const uint8_t *lsp_id); void isis_notif_own_lsp_purge(const struct isis_circuit *circuit, - const char *lsp_id); + const uint8_t *lsp_id); + +/* We also declare hook for every notification */ + +DECLARE_HOOK(isis_hook_db_overload, (const struct isis_area *area), (area)); +DECLARE_HOOK(isis_hook_lsp_too_large, + (const struct isis_circuit *circuit, uint32_t pdu_size, + const uint8_t *lsp_id), + (circuit, pdu_size, lsp_id)); +/* Note: no isis_hook_corrupted_lsp - because this notificaiton is not used */ +DECLARE_HOOK(isis_hook_lsp_exceed_max, + (const struct isis_area *area, const uint8_t *lsp_id), + (area, lsp_id)); +DECLARE_HOOK(isis_hook_max_area_addr_mismatch, + (const struct isis_circuit *circuit, uint8_t max_addrs, + const char *raw_pdu, size_t raw_pdu_len), + (circuit, max_addrs, raw_pdu, raw_pdu_len)); +DECLARE_HOOK(isis_hook_authentication_type_failure, + (const struct isis_circuit *circuit, const char *raw_pdu, + size_t raw_pdu_len), + (circuit, raw_pdu, raw_pdu_len)); +DECLARE_HOOK(isis_hook_authentication_failure, + (const struct isis_circuit *circuit, const char *raw_pdu, + size_t raw_pdu_len), + (circuit, raw_pdu, raw_pdu_len)); +DECLARE_HOOK(isis_hook_adj_state_change, (const struct isis_adjacency *adj), + (adj)); +DECLARE_HOOK(isis_hook_reject_adjacency, + (const struct isis_circuit *circuit, const char *pdu, + size_t pdu_len), + (circuit, pdu, pdu_len)); +DECLARE_HOOK(isis_hook_area_mismatch, + (const struct isis_circuit *circuit, const char *raw_pdu, + size_t raw_pdu_len), + (circuit)); +DECLARE_HOOK(isis_hook_id_len_mismatch, + (const struct isis_circuit *circuit, uint8_t rcv_id_len, + const char *raw_pdu, size_t raw_pdu_len), + (circuit, rcv_id_len, raw_pdu, raw_pdu_len)); +DECLARE_HOOK(isis_hook_version_skew, + (const struct isis_circuit *circuit, uint8_t version, + const char *raw_pdu, size_t raw_pdu_len), + (circuit)); +DECLARE_HOOK(isis_hook_lsp_error, + (const struct isis_circuit *circuit, const uint8_t *lsp_id, + const char *raw_pdu, size_t raw_pdu_len), + (circuit)); +DECLARE_HOOK(isis_hook_seqno_skipped, + (const struct isis_circuit *circuit, const uint8_t *lsp_id), + (circuit, lsp_id)); +DECLARE_HOOK(isis_hook_own_lsp_purge, + (const struct isis_circuit *circuit, const uint8_t *lsp_id), + (circuit, lsp_id)); #endif /* ISISD_ISIS_NB_H_ */ diff --git a/isisd/isis_nb_config.c b/isisd/isis_nb_config.c index 45bbc9737b..d47d966f71 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; /* @@ -1943,9 +1945,9 @@ int isis_instance_segment_routing_enabled_modify( } /* - * XPath: /frr-isisd:isis/instance/segment-routing/srgb + * XPath: /frr-isisd:isis/instance/segment-routing/label-blocks */ -int isis_instance_segment_routing_srgb_pre_validate( +int isis_instance_segment_routing_label_blocks_pre_validate( struct nb_cb_pre_validate_args *args) { uint32_t srgb_lbound; @@ -1953,10 +1955,10 @@ int isis_instance_segment_routing_srgb_pre_validate( uint32_t srlb_lbound; uint32_t srlb_ubound; - srgb_lbound = yang_dnode_get_uint32(args->dnode, "./lower-bound"); - srgb_ubound = yang_dnode_get_uint32(args->dnode, "./upper-bound"); - srlb_lbound = yang_dnode_get_uint32(args->dnode, "../srlb/lower-bound"); - srlb_ubound = yang_dnode_get_uint32(args->dnode, "../srlb/upper-bound"); + srgb_lbound = yang_dnode_get_uint32(args->dnode, "./srgb/lower-bound"); + srgb_ubound = yang_dnode_get_uint32(args->dnode, "./srgb/upper-bound"); + srlb_lbound = yang_dnode_get_uint32(args->dnode, "./srlb/lower-bound"); + srlb_ubound = yang_dnode_get_uint32(args->dnode, "./srlb/upper-bound"); /* Check that the block size does not exceed 65535 */ if ((srgb_ubound - srgb_lbound + 1) > 65535) { @@ -1966,12 +1968,18 @@ int isis_instance_segment_routing_srgb_pre_validate( srgb_lbound, srgb_ubound); return NB_ERR_VALIDATION; } + if ((srlb_ubound - srlb_lbound + 1) > 65535) { + snprintf(args->errmsg, args->errmsg_len, + "New SR Local Block (%u/%u) exceed the limit of 65535", + srlb_lbound, srlb_ubound); + return NB_ERR_VALIDATION; + } /* Validate SRGB against SRLB */ if (!((srgb_ubound < srlb_lbound) || (srgb_lbound > srlb_ubound))) { snprintf( args->errmsg, args->errmsg_len, - "New SR Global Block (%u/%u) conflict with Local Block (%u/%u)", + "SR Global Block (%u/%u) conflicts with Local Block (%u/%u)", srgb_lbound, srgb_ubound, srlb_lbound, srlb_ubound); return NB_ERR_VALIDATION; } @@ -1979,6 +1987,10 @@ int isis_instance_segment_routing_srgb_pre_validate( return NB_OK; } +/* + * XPath: /frr-isisd:isis/instance/segment-routing/label-blocks/srgb + */ + void isis_instance_segment_routing_srgb_apply_finish( struct nb_cb_apply_finish_args *args) { @@ -1993,7 +2005,7 @@ void isis_instance_segment_routing_srgb_apply_finish( } /* - * XPath: /frr-isisd:isis/instance/segment-routing/srgb/lower-bound + * XPath: /frr-isisd:isis/instance/segment-routing/label-blocks/srgb/lower-bound */ int isis_instance_segment_routing_srgb_lower_bound_modify( struct nb_cb_modify_args *args) @@ -2018,7 +2030,7 @@ int isis_instance_segment_routing_srgb_lower_bound_modify( } /* - * XPath: /frr-isisd:isis/instance/segment-routing/srgb/upper-bound + * XPath: /frr-isisd:isis/instance/segment-routing/label-blocks/srgb/upper-bound */ int isis_instance_segment_routing_srgb_upper_bound_modify( struct nb_cb_modify_args *args) @@ -2043,41 +2055,8 @@ int isis_instance_segment_routing_srgb_upper_bound_modify( } /* - * XPath: /frr-isisd:isis/instance/segment-routing/srlb + * XPath: /frr-isisd:isis/instance/segment-routing/label-blocks/srlb */ -int isis_instance_segment_routing_srlb_pre_validate( - struct nb_cb_pre_validate_args *args) -{ - uint32_t srgb_lbound; - uint32_t srgb_ubound; - uint32_t srlb_lbound; - uint32_t srlb_ubound; - - srgb_lbound = yang_dnode_get_uint32(args->dnode, "../srgb/lower-bound"); - srgb_ubound = yang_dnode_get_uint32(args->dnode, "../srgb/upper-bound"); - srlb_lbound = yang_dnode_get_uint32(args->dnode, "./lower-bound"); - srlb_ubound = yang_dnode_get_uint32(args->dnode, "./upper-bound"); - - /* Check that the block size does not exceed 65535 */ - if ((srlb_ubound - srlb_lbound + 1) > 65535) { - snprintf(args->errmsg, args->errmsg_len, - "New SR Local Block (%u/%u) exceed the limit of 65535", - srlb_lbound, srlb_ubound); - return NB_ERR_VALIDATION; - } - - /* Validate SRLB against SRGB */ - if (!((srlb_ubound < srgb_lbound) || (srlb_lbound > srgb_ubound))) { - snprintf( - args->errmsg, args->errmsg_len, - "New SR Local Block (%u/%u) conflict with Global Block (%u/%u)", - srlb_lbound, srlb_ubound, srgb_lbound, srgb_ubound); - return NB_ERR_VALIDATION; - } - - return NB_OK; -} - void isis_instance_segment_routing_srlb_apply_finish( struct nb_cb_apply_finish_args *args) { @@ -2092,7 +2071,7 @@ void isis_instance_segment_routing_srlb_apply_finish( } /* - * XPath: /frr-isisd:isis/instance/segment-routing/srlb/lower-bound + * XPath: /frr-isisd:isis/instance/segment-routing/label-blocks/srlb/lower-bound */ int isis_instance_segment_routing_srlb_lower_bound_modify( struct nb_cb_modify_args *args) @@ -2117,7 +2096,7 @@ int isis_instance_segment_routing_srlb_lower_bound_modify( } /* - * XPath: /frr-isisd:isis/instance/segment-routing/srlb/upper-bound + * XPath: /frr-isisd:isis/instance/segment-routing/label-blocks/srlb/upper-bound */ int isis_instance_segment_routing_srlb_upper_bound_modify( struct nb_cb_modify_args *args) @@ -2231,10 +2210,10 @@ int isis_instance_segment_routing_prefix_sid_map_prefix_sid_pre_validate( struct isis_prefix_sid psid = {}; yang_dnode_get_prefix(&prefix, args->dnode, "./prefix"); - srgb_lbound = yang_dnode_get_uint32(args->dnode, - "../../srgb/lower-bound"); - srgb_ubound = yang_dnode_get_uint32(args->dnode, - "../../srgb/upper-bound"); + srgb_lbound = yang_dnode_get_uint32( + args->dnode, "../../label-blocks/srgb/lower-bound"); + srgb_ubound = yang_dnode_get_uint32( + args->dnode, "../../label-blocks/srgb/upper-bound"); sid = yang_dnode_get_uint32(args->dnode, "./sid-value"); sid_type = yang_dnode_get_enum(args->dnode, "./sid-value-type"); diff --git a/isisd/isis_nb_notifications.c b/isisd/isis_nb_notifications.c index ea33ec10ec..755378a9b7 100644 --- a/isisd/isis_nb_notifications.c +++ b/isisd/isis_nb_notifications.c @@ -28,6 +28,56 @@ #include "isisd/isis_dynhn.h" #include "isisd/isis_misc.h" +DEFINE_HOOK(isis_hook_lsp_too_large, + (const struct isis_circuit *circuit, uint32_t pdu_size, + const uint8_t *lsp_id), + (circuit, pdu_size, lsp_id)); +DEFINE_HOOK(isis_hook_corrupted_lsp, (const struct isis_area *area), (area)); +DEFINE_HOOK(isis_hook_lsp_exceed_max, + (const struct isis_area *area, const uint8_t *lsp_id), + (area, lsp_id)); +DEFINE_HOOK(isis_hook_max_area_addr_mismatch, + (const struct isis_circuit *circuit, uint8_t max_addrs, + const char *raw_pdu, size_t raw_pdu_len), + (circuit, max_addrs, raw_pdu, raw_pdu_len)); +DEFINE_HOOK(isis_hook_authentication_type_failure, + (const struct isis_circuit *circuit, const char *raw_pdu, + size_t raw_pdu_len), + (circuit, raw_pdu, raw_pdu_len)); +DEFINE_HOOK(isis_hook_authentication_failure, + (const struct isis_circuit *circuit, const char *raw_pdu, + size_t raw_pdu_len), + (circuit, raw_pdu, raw_pdu_len)); +DEFINE_HOOK(isis_hook_adj_state_change, (const struct isis_adjacency *adj), + (adj)); +DEFINE_HOOK(isis_hook_reject_adjacency, + (const struct isis_circuit *circuit, const char *raw_pdu, + size_t raw_pdu_len), + (circuit, raw_pdu, raw_pdu_len)); +DEFINE_HOOK(isis_hook_area_mismatch, + (const struct isis_circuit *circuit, const char *raw_pdu, + size_t raw_pdu_len), + (circuit, raw_pdu, raw_pdu_len)); +DEFINE_HOOK(isis_hook_id_len_mismatch, + (const struct isis_circuit *circuit, uint8_t rcv_id_len, + const char *raw_pdu, size_t raw_pdu_len), + (circuit, rcv_id_len, raw_pdu, raw_pdu_len)); +DEFINE_HOOK(isis_hook_version_skew, + (const struct isis_circuit *circuit, uint8_t version, + const char *raw_pdu, size_t raw_pdu_len), + (circuit, version, raw_pdu, raw_pdu_len)); +DEFINE_HOOK(isis_hook_lsp_error, + (const struct isis_circuit *circuit, const uint8_t *lsp_id, + const char *raw_pdu, size_t raw_pdu_len), + (circuit, lsp_id, raw_pdu, raw_pdu_len)); +DEFINE_HOOK(isis_hook_seqno_skipped, + (const struct isis_circuit *circuit, const uint8_t *lsp_id), + (circuit, lsp_id)); +DEFINE_HOOK(isis_hook_own_lsp_purge, + (const struct isis_circuit *circuit, const uint8_t *lsp_id), + (circuit, lsp_id)); + + /* * Helper functions. */ @@ -92,7 +142,7 @@ void isis_notif_db_overload(const struct isis_area *area, bool overload) * XPath: /frr-isisd:lsp-too-large */ void isis_notif_lsp_too_large(const struct isis_circuit *circuit, - uint32_t pdu_size, const char *lsp_id) + uint32_t pdu_size, const uint8_t *lsp_id) { const char *xpath = "/frr-isisd:lsp-too-large"; struct list *arguments = yang_data_list_new(); @@ -106,9 +156,11 @@ void isis_notif_lsp_too_large(const struct isis_circuit *circuit, data = yang_data_new_uint32(xpath_arg, pdu_size); listnode_add(arguments, data); snprintf(xpath_arg, sizeof(xpath_arg), "%s/lsp-id", xpath); - data = yang_data_new_string(xpath_arg, lsp_id); + data = yang_data_new_string(xpath_arg, rawlspid_print(lsp_id)); listnode_add(arguments, data); + hook_call(isis_hook_lsp_too_large, circuit, pdu_size, lsp_id); + nb_notification_send(xpath, arguments); } @@ -135,7 +187,8 @@ void isis_notif_if_state_change(const struct isis_circuit *circuit, bool down) /* * XPath: /frr-isisd:corrupted-lsp-detected */ -void isis_notif_corrupted_lsp(const struct isis_area *area, const char *lsp_id) +void isis_notif_corrupted_lsp(const struct isis_area *area, + const uint8_t *lsp_id) { const char *xpath = "/frr-isisd:corrupted-lsp-detected"; struct list *arguments = yang_data_list_new(); @@ -144,16 +197,19 @@ void isis_notif_corrupted_lsp(const struct isis_area *area, const char *lsp_id) notif_prep_instance_hdr(xpath, area, "default", arguments); snprintf(xpath_arg, sizeof(xpath_arg), "%s/lsp-id", xpath); - data = yang_data_new_string(xpath_arg, lsp_id); + data = yang_data_new_string(xpath_arg, rawlspid_print(lsp_id)); listnode_add(arguments, data); + hook_call(isis_hook_corrupted_lsp, area); + nb_notification_send(xpath, arguments); } /* * XPath: /frr-isisd:attempt-to-exceed-max-sequence */ -void isis_notif_lsp_exceed_max(const struct isis_area *area, const char *lsp_id) +void isis_notif_lsp_exceed_max(const struct isis_area *area, + const uint8_t *lsp_id) { const char *xpath = "/frr-isisd:attempt-to-exceed-max-sequence"; struct list *arguments = yang_data_list_new(); @@ -162,9 +218,11 @@ void isis_notif_lsp_exceed_max(const struct isis_area *area, const char *lsp_id) notif_prep_instance_hdr(xpath, area, "default", arguments); snprintf(xpath_arg, sizeof(xpath_arg), "%s/lsp-id", xpath); - data = yang_data_new_string(xpath_arg, lsp_id); + data = yang_data_new_string(xpath_arg, rawlspid_print(lsp_id)); listnode_add(arguments, data); + hook_call(isis_hook_lsp_exceed_max, area, lsp_id); + nb_notification_send(xpath, arguments); } @@ -173,7 +231,7 @@ void isis_notif_lsp_exceed_max(const struct isis_area *area, const char *lsp_id) */ void isis_notif_max_area_addr_mismatch(const struct isis_circuit *circuit, uint8_t max_area_addrs, - const char *raw_pdu) + const char *raw_pdu, size_t raw_pdu_len) { const char *xpath = "/frr-isisd:max-area-addresses-mismatch"; struct list *arguments = yang_data_list_new(); @@ -190,6 +248,9 @@ void isis_notif_max_area_addr_mismatch(const struct isis_circuit *circuit, data = yang_data_new(xpath_arg, raw_pdu); listnode_add(arguments, data); + hook_call(isis_hook_max_area_addr_mismatch, circuit, max_area_addrs, + raw_pdu, raw_pdu_len); + nb_notification_send(xpath, arguments); } @@ -197,7 +258,8 @@ void isis_notif_max_area_addr_mismatch(const struct isis_circuit *circuit, * XPath: /frr-isisd:authentication-type-failure */ void isis_notif_authentication_type_failure(const struct isis_circuit *circuit, - const char *raw_pdu) + const char *raw_pdu, + size_t raw_pdu_len) { const char *xpath = "/frr-isisd:authentication-type-failure"; struct list *arguments = yang_data_list_new(); @@ -211,6 +273,9 @@ void isis_notif_authentication_type_failure(const struct isis_circuit *circuit, data = yang_data_new(xpath_arg, raw_pdu); listnode_add(arguments, data); + hook_call(isis_hook_authentication_type_failure, circuit, raw_pdu, + raw_pdu_len); + nb_notification_send(xpath, arguments); } @@ -218,7 +283,7 @@ void isis_notif_authentication_type_failure(const struct isis_circuit *circuit, * XPath: /frr-isisd:authentication-failure */ void isis_notif_authentication_failure(const struct isis_circuit *circuit, - const char *raw_pdu) + const char *raw_pdu, size_t raw_pdu_len) { const char *xpath = "/frr-isisd:authentication-failure"; struct list *arguments = yang_data_list_new(); @@ -232,6 +297,9 @@ void isis_notif_authentication_failure(const struct isis_circuit *circuit, data = yang_data_new(xpath_arg, raw_pdu); listnode_add(arguments, data); + hook_call(isis_hook_authentication_failure, circuit, raw_pdu, + raw_pdu_len); + nb_notification_send(xpath, arguments); } @@ -269,6 +337,8 @@ void isis_notif_adj_state_change(const struct isis_adjacency *adj, listnode_add(arguments, data); } + hook_call(isis_hook_adj_state_change, adj); + nb_notification_send(xpath, arguments); } @@ -276,7 +346,8 @@ void isis_notif_adj_state_change(const struct isis_adjacency *adj, * XPath: /frr-isisd:rejected-adjacency */ void isis_notif_reject_adjacency(const struct isis_circuit *circuit, - const char *reason, const char *raw_pdu) + const char *reason, const char *raw_pdu, + size_t raw_pdu_len) { const char *xpath = "/frr-isisd:rejected-adjacency"; struct list *arguments = yang_data_list_new(); @@ -293,6 +364,8 @@ void isis_notif_reject_adjacency(const struct isis_circuit *circuit, data = yang_data_new(xpath_arg, raw_pdu); listnode_add(arguments, data); + hook_call(isis_hook_reject_adjacency, circuit, raw_pdu, raw_pdu_len); + nb_notification_send(xpath, arguments); } @@ -300,7 +373,7 @@ void isis_notif_reject_adjacency(const struct isis_circuit *circuit, * XPath: /frr-isisd:area-mismatch */ void isis_notif_area_mismatch(const struct isis_circuit *circuit, - const char *raw_pdu) + const char *raw_pdu, size_t raw_pdu_len) { const char *xpath = "/frr-isisd:area-mismatch"; struct list *arguments = yang_data_list_new(); @@ -314,6 +387,8 @@ void isis_notif_area_mismatch(const struct isis_circuit *circuit, data = yang_data_new(xpath_arg, raw_pdu); listnode_add(arguments, data); + hook_call(isis_hook_area_mismatch, circuit, raw_pdu, raw_pdu_len); + nb_notification_send(xpath, arguments); } @@ -321,7 +396,7 @@ void isis_notif_area_mismatch(const struct isis_circuit *circuit, * XPath: /frr-isisd:lsp-received */ void isis_notif_lsp_received(const struct isis_circuit *circuit, - const char *lsp_id, uint32_t seqno, + const uint8_t *lsp_id, uint32_t seqno, uint32_t timestamp, const char *sys_id) { const char *xpath = "/frr-isisd:lsp-received"; @@ -333,7 +408,7 @@ void isis_notif_lsp_received(const struct isis_circuit *circuit, notif_prep_instance_hdr(xpath, area, "default", arguments); notif_prepr_iface_hdr(xpath, circuit, arguments); snprintf(xpath_arg, sizeof(xpath_arg), "%s/lsp-id", xpath); - data = yang_data_new_string(xpath_arg, lsp_id); + data = yang_data_new_string(xpath_arg, rawlspid_print(lsp_id)); listnode_add(arguments, data); snprintf(xpath_arg, sizeof(xpath_arg), "%s/sequence", xpath); data = yang_data_new_uint32(xpath_arg, seqno); @@ -351,7 +426,7 @@ void isis_notif_lsp_received(const struct isis_circuit *circuit, /* * XPath: /frr-isisd:lsp-generation */ -void isis_notif_lsp_gen(const struct isis_area *area, const char *lsp_id, +void isis_notif_lsp_gen(const struct isis_area *area, const uint8_t *lsp_id, uint32_t seqno, uint32_t timestamp) { const char *xpath = "/frr-isisd:lsp-generation"; @@ -361,7 +436,7 @@ void isis_notif_lsp_gen(const struct isis_area *area, const char *lsp_id, notif_prep_instance_hdr(xpath, area, "default", arguments); snprintf(xpath_arg, sizeof(xpath_arg), "%s/lsp-id", xpath); - data = yang_data_new_string(xpath_arg, lsp_id); + data = yang_data_new_string(xpath_arg, rawlspid_print(lsp_id)); listnode_add(arguments, data); snprintf(xpath_arg, sizeof(xpath_arg), "%s/sequence", xpath); data = yang_data_new_uint32(xpath_arg, seqno); @@ -377,7 +452,8 @@ void isis_notif_lsp_gen(const struct isis_area *area, const char *lsp_id, * XPath: /frr-isisd:id-len-mismatch */ void isis_notif_id_len_mismatch(const struct isis_circuit *circuit, - uint8_t rcv_id_len, const char *raw_pdu) + uint8_t rcv_id_len, const char *raw_pdu, + size_t raw_pdu_len) { const char *xpath = "/frr-isisd:id-len-mismatch"; struct list *arguments = yang_data_list_new(); @@ -394,6 +470,9 @@ void isis_notif_id_len_mismatch(const struct isis_circuit *circuit, data = yang_data_new(xpath_arg, raw_pdu); listnode_add(arguments, data); + hook_call(isis_hook_id_len_mismatch, circuit, rcv_id_len, raw_pdu, + raw_pdu_len); + nb_notification_send(xpath, arguments); } @@ -401,7 +480,8 @@ void isis_notif_id_len_mismatch(const struct isis_circuit *circuit, * XPath: /frr-isisd:version-skew */ void isis_notif_version_skew(const struct isis_circuit *circuit, - uint8_t version, const char *raw_pdu) + uint8_t version, const char *raw_pdu, + size_t raw_pdu_len) { const char *xpath = "/frr-isisd:version-skew"; struct list *arguments = yang_data_list_new(); @@ -418,6 +498,9 @@ void isis_notif_version_skew(const struct isis_circuit *circuit, data = yang_data_new(xpath_arg, raw_pdu); listnode_add(arguments, data); + hook_call(isis_hook_version_skew, circuit, version, raw_pdu, + raw_pdu_len); + nb_notification_send(xpath, arguments); } @@ -425,7 +508,8 @@ void isis_notif_version_skew(const struct isis_circuit *circuit, * XPath: /frr-isisd:lsp-error-detected */ void isis_notif_lsp_error(const struct isis_circuit *circuit, - const char *lsp_id, const char *raw_pdu, + const uint8_t *lsp_id, const char *raw_pdu, + size_t raw_pdu_len, __attribute__((unused)) uint32_t offset, __attribute__((unused)) uint8_t tlv_type) { @@ -438,13 +522,15 @@ void isis_notif_lsp_error(const struct isis_circuit *circuit, notif_prep_instance_hdr(xpath, area, "default", arguments); notif_prepr_iface_hdr(xpath, circuit, arguments); snprintf(xpath_arg, sizeof(xpath_arg), "%s/lsp-id", xpath); - data = yang_data_new_string(xpath_arg, lsp_id); + data = yang_data_new_string(xpath_arg, rawlspid_print(lsp_id)); listnode_add(arguments, data); snprintf(xpath_arg, sizeof(xpath_arg), "%s/raw-pdu", xpath); data = yang_data_new(xpath_arg, raw_pdu); listnode_add(arguments, data); /* ignore offset and tlv_type which cannot be set properly */ + hook_call(isis_hook_lsp_error, circuit, lsp_id, raw_pdu, raw_pdu_len); + nb_notification_send(xpath, arguments); } @@ -452,7 +538,7 @@ void isis_notif_lsp_error(const struct isis_circuit *circuit, * XPath: /frr-isisd:sequence-number-skipped */ void isis_notif_seqno_skipped(const struct isis_circuit *circuit, - const char *lsp_id) + const uint8_t *lsp_id) { const char *xpath = "/frr-isisd:sequence-number-skipped"; struct list *arguments = yang_data_list_new(); @@ -463,9 +549,11 @@ void isis_notif_seqno_skipped(const struct isis_circuit *circuit, notif_prep_instance_hdr(xpath, area, "default", arguments); notif_prepr_iface_hdr(xpath, circuit, arguments); snprintf(xpath_arg, sizeof(xpath_arg), "%s/lsp-id", xpath); - data = yang_data_new_string(xpath_arg, lsp_id); + data = yang_data_new_string(xpath_arg, rawlspid_print(lsp_id)); listnode_add(arguments, data); + hook_call(isis_hook_seqno_skipped, circuit, lsp_id); + nb_notification_send(xpath, arguments); } @@ -473,7 +561,7 @@ void isis_notif_seqno_skipped(const struct isis_circuit *circuit, * XPath: /frr-isisd:own-lsp-purge */ void isis_notif_own_lsp_purge(const struct isis_circuit *circuit, - const char *lsp_id) + const uint8_t *lsp_id) { const char *xpath = "/frr-isisd:own-lsp-purge"; struct list *arguments = yang_data_list_new(); @@ -484,8 +572,10 @@ void isis_notif_own_lsp_purge(const struct isis_circuit *circuit, notif_prep_instance_hdr(xpath, area, "default", arguments); notif_prepr_iface_hdr(xpath, circuit, arguments); snprintf(xpath_arg, sizeof(xpath_arg), "%s/lsp-id", xpath); - data = yang_data_new_string(xpath_arg, lsp_id); + data = yang_data_new_string(xpath_arg, rawlspid_print(lsp_id)); listnode_add(arguments, data); + hook_call(isis_hook_own_lsp_purge, circuit, lsp_id); + nb_notification_send(xpath, arguments); } diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c index a02b48157f..7256fcbbc7 100644 --- a/isisd/isis_pdu.c +++ b/isisd/isis_pdu.c @@ -549,6 +549,19 @@ static int pdu_len_validate(uint16_t pdu_len, struct isis_circuit *circuit) return 0; } +static void update_rej_adj_count(struct isis_circuit *circuit) +{ + circuit->rej_adjacencies++; + if (circuit->is_type == IS_LEVEL_1) + circuit->area->rej_adjacencies[0]++; + else if (circuit->is_type == IS_LEVEL_2) + circuit->area->rej_adjacencies[1]++; + else { + circuit->area->rej_adjacencies[0]++; + circuit->area->rej_adjacencies[1]++; + } +} + static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit, uint8_t *ssnpa) { @@ -581,22 +594,22 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit, if (p2p_hello) { if (circuit->circ_type != CIRCUIT_T_P2P) { zlog_warn("p2p hello on non p2p circuit"); - circuit->rej_adjacencies++; + update_rej_adj_count(circuit); #ifndef FABRICD isis_notif_reject_adjacency( circuit, "p2p hello on non p2p circuit", - raw_pdu); + raw_pdu, sizeof(raw_pdu)); #endif /* ifndef FABRICD */ return ISIS_WARNING; } } else { if (circuit->circ_type != CIRCUIT_T_BROADCAST) { zlog_warn("lan hello on non broadcast circuit"); - circuit->rej_adjacencies++; + update_rej_adj_count(circuit); #ifndef FABRICD isis_notif_reject_adjacency( circuit, "lan hello on non broadcast circuit", - raw_pdu); + raw_pdu, sizeof(raw_pdu)); #endif /* ifndef FABRICD */ return ISIS_WARNING; } @@ -605,12 +618,12 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit, zlog_debug( "level %d LAN Hello received over circuit with externalDomain = true", level); - circuit->rej_adjacencies++; + update_rej_adj_count(circuit); #ifndef FABRICD isis_notif_reject_adjacency( circuit, "LAN Hello received over circuit with externalDomain = true", - raw_pdu); + raw_pdu, sizeof(raw_pdu)); #endif /* ifndef FABRICD */ return ISIS_WARNING; } @@ -622,10 +635,11 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit, circuit->area->area_tag, circuit->interface->name); } - circuit->rej_adjacencies++; + update_rej_adj_count(circuit); #ifndef FABRICD - isis_notif_reject_adjacency( - circuit, "Interface level mismatch", raw_pdu); + isis_notif_reject_adjacency(circuit, + "Interface level mismatch", + raw_pdu, sizeof(raw_pdu)); #endif /* ifndef FABRICD */ return ISIS_WARNING; } @@ -652,10 +666,10 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit, "ISIS-Adj (%s): Rcvd %s from (%s) with invalid pdu length %hu", circuit->area->area_tag, pdu_name, circuit->interface->name, iih.pdu_len); - circuit->rej_adjacencies++; + update_rej_adj_count(circuit); #ifndef FABRICD isis_notif_reject_adjacency(circuit, "Invalid PDU length", - raw_pdu); + raw_pdu, sizeof(raw_pdu)); #endif /* ifndef FABRICD */ return ISIS_WARNING; } @@ -664,10 +678,11 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit, flog_err(EC_ISIS_PACKET, "Level %d LAN Hello with Circuit Type %d", level, iih.circ_type); - circuit->rej_adjacencies++; + update_rej_adj_count(circuit); #ifndef FABRICD - isis_notif_reject_adjacency( - circuit, "LAN Hello with wrong IS-level", raw_pdu); + isis_notif_reject_adjacency(circuit, + "LAN Hello with wrong IS-level", + raw_pdu, sizeof(raw_pdu)); #endif /* ifndef FABRICD */ return ISIS_ERROR; } @@ -678,10 +693,10 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit, if (isis_unpack_tlvs(STREAM_READABLE(circuit->rcv_stream), circuit->rcv_stream, &iih.tlvs, &error_log)) { zlog_warn("isis_unpack_tlvs() failed: %s", error_log); - circuit->rej_adjacencies++; + update_rej_adj_count(circuit); #ifndef FABRICD isis_notif_reject_adjacency(circuit, "Failed to unpack TLVs", - raw_pdu); + raw_pdu, sizeof(raw_pdu)); #endif /* ifndef FABRICD */ goto out; } @@ -690,17 +705,18 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit, zlog_warn("No Area addresses TLV in %s", pdu_name); #ifndef FABRICD /* send northbound notification */ - isis_notif_area_mismatch(circuit, raw_pdu); + isis_notif_area_mismatch(circuit, raw_pdu, sizeof(raw_pdu)); #endif /* ifndef FABRICD */ goto out; } if (!iih.tlvs->protocols_supported.count) { zlog_warn("No supported protocols TLV in %s", pdu_name); - circuit->rej_adjacencies++; + update_rej_adj_count(circuit); #ifndef FABRICD - isis_notif_reject_adjacency( - circuit, "No supported protocols TLV", raw_pdu); + isis_notif_reject_adjacency(circuit, + "No supported protocols TLV", + raw_pdu, sizeof(raw_pdu)); #endif /* ifndef FABRICD */ goto out; } @@ -716,12 +732,13 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit, stream_get_from(raw_pdu, circuit->rcv_stream, pdu_start, pdu_end - pdu_start); if (auth_code == ISIS_AUTH_FAILURE) { - circuit->auth_failures++; - isis_notif_authentication_failure(circuit, raw_pdu); + update_rej_adj_count(circuit); + isis_notif_authentication_failure(circuit, raw_pdu, + sizeof(raw_pdu)); } else { /* AUTH_TYPE_FAILURE or NO_VALIDATOR */ - circuit->auth_type_failures++; - isis_notif_authentication_type_failure(circuit, - raw_pdu); + update_rej_adj_count(circuit); + isis_notif_authentication_type_failure(circuit, raw_pdu, + sizeof(raw_pdu)); } #endif /* ifndef FABRICD */ goto out; @@ -731,10 +748,11 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit, zlog_warn( "ISIS-Adj (%s): Received IIH with own sysid on %s - discard", circuit->area->area_tag, circuit->interface->name); - circuit->rej_adjacencies++; + update_rej_adj_count(circuit); #ifndef FABRICD - isis_notif_reject_adjacency( - circuit, "Received IIH with our own sysid", raw_pdu); + isis_notif_reject_adjacency(circuit, + "Received IIH with our own sysid", + raw_pdu, sizeof(raw_pdu)); #endif /* ifndef FABRICD */ goto out; } @@ -752,7 +770,7 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit, } #ifndef FABRICD /* send northbound notification */ - isis_notif_area_mismatch(circuit, raw_pdu); + isis_notif_area_mismatch(circuit, raw_pdu, sizeof(raw_pdu)); #endif /* ifndef FABRICD */ goto out; } @@ -769,11 +787,11 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit, "ISIS-Adj (%s): Neither IPv4 nor IPv6 considered usable. Ignoring IIH", circuit->area->area_tag); } - circuit->rej_adjacencies++; + update_rej_adj_count(circuit); #ifndef FABRICD isis_notif_reject_adjacency( circuit, "Neither IPv4 not IPv6 considered usable", - raw_pdu); + raw_pdu, sizeof(raw_pdu)); #endif /* ifndef FABRICD */ goto out; } @@ -857,8 +875,8 @@ static int process_lsp(uint8_t pdu_type, struct isis_circuit *circuit, #ifndef FABRICD /* send northbound notification */ - isis_notif_lsp_received(circuit, rawlspid_print(hdr.lsp_id), hdr.seqno, - time(NULL), sysid_print(hdr.lsp_id)); + isis_notif_lsp_received(circuit, hdr.lsp_id, hdr.seqno, time(NULL), + sysid_print(hdr.lsp_id)); #endif /* ifndef FABRICD */ if (pdu_len_validate(hdr.pdu_len, circuit)) { @@ -931,8 +949,18 @@ static int process_lsp(uint8_t pdu_type, struct isis_circuit *circuit, * we change the code above to return those extra fields, we * will send dummy values which are ignored in the callback */ - isis_notif_lsp_error(circuit, rawlspid_print(hdr.lsp_id), - raw_pdu, 0, 0); + circuit->lsp_error_counter++; + if (circuit->is_type == IS_LEVEL_1) { + circuit->area->lsp_error_counter[0]++; + } else if (circuit->is_type == IS_LEVEL_2) { + circuit->area->lsp_error_counter[1]++; + } else { + circuit->area->lsp_error_counter[0]++; + circuit->area->lsp_error_counter[1]++; + } + + isis_notif_lsp_error(circuit, hdr.lsp_id, raw_pdu, + sizeof(raw_pdu), 0, 0); #endif /* ifndef FABRICD */ goto out; } @@ -956,11 +984,28 @@ static int process_lsp(uint8_t pdu_type, struct isis_circuit *circuit, /* send northbound notification */ if (auth_code == ISIS_AUTH_FAILURE) { circuit->auth_failures++; - isis_notif_authentication_failure(circuit, raw_pdu); + if (circuit->is_type == IS_LEVEL_1) { + circuit->area->auth_failures[0]++; + } else if (circuit->is_type == IS_LEVEL_2) { + circuit->area->auth_failures[1]++; + } else { + circuit->area->auth_failures[0]++; + circuit->area->auth_failures[1]++; + } + isis_notif_authentication_failure(circuit, raw_pdu, + sizeof(raw_pdu)); } else { /* AUTH_TYPE_FAILURE or NO_VALIDATOR */ circuit->auth_type_failures++; - isis_notif_authentication_type_failure(circuit, - raw_pdu); + if (circuit->is_type == IS_LEVEL_1) { + circuit->area->auth_type_failures[0]++; + } else if (circuit->is_type == IS_LEVEL_2) { + circuit->area->auth_type_failures[1]++; + } else { + circuit->area->auth_type_failures[0]++; + circuit->area->auth_type_failures[1]++; + } + isis_notif_authentication_type_failure(circuit, raw_pdu, + sizeof(raw_pdu)); } #endif /* ifndef FABRICD */ goto out; @@ -1105,10 +1150,10 @@ dontcheckadj: if (lsp->hdr.seqno < hdr.seqno) { /* send northbound * notification */ + circuit->area + ->lsp_seqno_skipped_counter++; isis_notif_seqno_skipped( - circuit, - rawlspid_print( - hdr.lsp_id)); + circuit, hdr.lsp_id); } #endif /* ifndef FABRICD */ lsp_inc_seqno(lsp, hdr.seqno); @@ -1129,8 +1174,7 @@ dontcheckadj: /* our own LSP with 0 remaining life time */ #ifndef FABRICD /* send northbound notification */ - isis_notif_own_lsp_purge( - circuit, rawlspid_print(hdr.lsp_id)); + isis_notif_own_lsp_purge(circuit, hdr.lsp_id); #endif /* ifndef FABRICD */ } } @@ -1158,8 +1202,8 @@ dontcheckadj: lsp_inc_seqno(lsp, hdr.seqno); #ifndef FABRICD /* send northbound notification */ - isis_notif_seqno_skipped(circuit, - rawlspid_print(hdr.lsp_id)); + circuit->area->lsp_seqno_skipped_counter++; + isis_notif_seqno_skipped(circuit, hdr.lsp_id); #endif /* ifndef FABRICD */ if (IS_DEBUG_UPDATE_PACKETS) { zlog_debug( @@ -1388,12 +1432,28 @@ static int process_snp(uint8_t pdu_type, struct isis_circuit *circuit, pdu_end - pdu_start); if (auth_code == ISIS_AUTH_FAILURE) { circuit->auth_failures++; - isis_notif_authentication_failure(circuit, - raw_pdu); + if (circuit->is_type == IS_LEVEL_1) { + circuit->area->auth_failures[0]++; + } else if (circuit->is_type == IS_LEVEL_2) { + circuit->area->auth_failures[1]++; + } else { + circuit->area->auth_failures[0]++; + circuit->area->auth_failures[1]++; + } + isis_notif_authentication_failure( + circuit, raw_pdu, sizeof(raw_pdu)); } else { /* AUTH_TYPE_FAILURE or NO_VALIDATOR */ circuit->auth_type_failures++; - isis_notif_authentication_type_failure(circuit, - raw_pdu); + if (circuit->is_type == IS_LEVEL_1) { + circuit->area->auth_type_failures[0]++; + } else if (circuit->is_type == IS_LEVEL_2) { + circuit->area->auth_type_failures[1]++; + } else { + circuit->area->auth_type_failures[0]++; + circuit->area->auth_type_failures[1]++; + } + isis_notif_authentication_type_failure( + circuit, raw_pdu, sizeof(raw_pdu)); } #endif /* ifndef FABRICD */ goto out; @@ -1620,7 +1680,8 @@ int isis_handle_pdu(struct isis_circuit *circuit, uint8_t *ssnpa) zlog_warn("Unsupported ISIS version %hhu", version1); #ifndef FABRICD /* send northbound notification */ - isis_notif_version_skew(circuit, version1, raw_pdu); + isis_notif_version_skew(circuit, version1, raw_pdu, + sizeof(raw_pdu)); #endif /* ifndef FABRICD */ return ISIS_WARNING; } @@ -1631,9 +1692,19 @@ int isis_handle_pdu(struct isis_circuit *circuit, uint8_t *ssnpa) "IDFieldLengthMismatch: ID Length field in a received PDU %hhu, while the parameter for this IS is %u", id_len, ISIS_SYS_ID_LEN); circuit->id_len_mismatches++; + if (circuit->is_type == IS_LEVEL_1) { + circuit->area->id_len_mismatches[0]++; + } else if (circuit->is_type == IS_LEVEL_2) { + circuit->area->id_len_mismatches[1]++; + } else { + circuit->area->id_len_mismatches[0]++; + circuit->area->id_len_mismatches[1]++; + } + #ifndef FABRICD /* send northbound notification */ - isis_notif_id_len_mismatch(circuit, id_len, raw_pdu); + isis_notif_id_len_mismatch(circuit, id_len, raw_pdu, + sizeof(raw_pdu)); #endif /* ifndef FABRICD */ return ISIS_ERROR; } @@ -1662,7 +1733,8 @@ int isis_handle_pdu(struct isis_circuit *circuit, uint8_t *ssnpa) zlog_warn("Unsupported ISIS PDU version %hhu", version2); #ifndef FABRICD /* send northbound notification */ - isis_notif_version_skew(circuit, version2, raw_pdu); + isis_notif_version_skew(circuit, version2, raw_pdu, + sizeof(raw_pdu)); #endif /* ifndef FABRICD */ return ISIS_WARNING; } @@ -1686,7 +1758,7 @@ int isis_handle_pdu(struct isis_circuit *circuit, uint8_t *ssnpa) #ifndef FABRICD /* send northbound notification */ isis_notif_max_area_addr_mismatch(circuit, max_area_addrs, - raw_pdu); + raw_pdu, sizeof(raw_pdu)); #endif /* ifndef FABRICD */ return ISIS_ERROR; } @@ -2409,7 +2481,7 @@ void send_lsp(struct isis_circuit *circuit, struct isis_lsp *lsp, #ifndef FABRICD /* send a northbound notification */ isis_notif_lsp_too_large(circuit, stream_get_endp(lsp->pdu), - rawlspid_print(lsp->hdr.lsp_id)); + lsp->hdr.lsp_id); #endif /* ifndef FABRICD */ if (IS_DEBUG_PACKET_DUMP) zlog_dump_data(STREAM_DATA(lsp->pdu), diff --git a/isisd/isis_redist.c b/isisd/isis_redist.c index 240be27cf3..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) @@ -219,7 +222,7 @@ static void isis_redist_ensure_default(struct isis *isis, int family) /* Handle notification about route being added */ void isis_redist_add(struct isis *isis, int type, struct prefix *p, struct prefix_ipv6 *src_p, uint8_t distance, - uint32_t metric) + uint32_t metric, const route_tag_t tag) { int family = p->family; struct route_table *ei_table = get_ext_info(isis, family); @@ -250,6 +253,7 @@ void isis_redist_add(struct isis *isis, int type, struct prefix *p, info->origin = type; info->distance = distance; info->metric = metric; + info->tag = tag; if (is_default_prefix(p) && (!src_p || !src_p->prefixlen)) { @@ -288,7 +292,7 @@ void isis_redist_delete(struct isis *isis, int type, struct prefix *p, * "always" setting will ignore routes with origin * DEFAULT_ROUTE. */ isis_redist_add(isis, DEFAULT_ROUTE, p, NULL, 254, - MAX_WIDE_PATH_METRIC); + MAX_WIDE_PATH_METRIC, 0); return; } @@ -326,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); } @@ -506,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_redist.h b/isisd/isis_redist.h index afce922240..fcc4ceadf4 100644 --- a/isisd/isis_redist.h +++ b/isisd/isis_redist.h @@ -31,6 +31,7 @@ struct isis_ext_info { int origin; uint32_t metric; uint8_t distance; + route_tag_t tag; }; struct isis_redist { @@ -50,7 +51,7 @@ struct route_table *get_ext_reach(struct isis_area *area, int family, int level); void isis_redist_add(struct isis *isis, int type, struct prefix *p, struct prefix_ipv6 *src_p, uint8_t distance, - uint32_t metric); + uint32_t metric, route_tag_t tag); void isis_redist_delete(struct isis *isis, int type, struct prefix *p, struct prefix_ipv6 *src_p); int isis_redist_config_write(struct vty *vty, struct isis_area *area, 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_routemap.c b/isisd/isis_routemap.c index db0f2fd8be..626e399e15 100644 --- a/isisd/isis_routemap.c +++ b/isisd/isis_routemap.c @@ -112,6 +112,35 @@ static const struct route_map_rule_cmd /* ------------------------------------------------------------*/ +/* `match tag TAG' */ +/* Match function return 1 if match is success else return zero. */ +static enum route_map_cmd_result_t +route_match_tag(void *rule, const struct prefix *p, void *object) +{ + route_tag_t *tag; + struct isis_ext_info *info; + route_tag_t info_tag; + + tag = rule; + info = object; + + info_tag = info->tag; + if (info_tag == *tag) + return RMAP_MATCH; + else + return RMAP_NOMATCH; +} + +/* Route map commands for tag matching. */ +static const struct route_map_rule_cmd route_match_tag_cmd = { + "tag", + route_match_tag, + route_map_rule_tag_compile, + route_map_rule_tag_free, +}; + +/* ------------------------------------------------------------*/ + static enum route_map_cmd_result_t route_match_ipv6_address(void *rule, const struct prefix *prefix, void *object) { @@ -234,6 +263,9 @@ void isis_route_map_init(void) route_map_match_ipv6_address_prefix_list_hook(generic_match_add); route_map_no_match_ipv6_address_prefix_list_hook(generic_match_delete); + route_map_match_tag_hook(generic_match_add); + route_map_no_match_tag_hook(generic_match_delete); + route_map_set_metric_hook(generic_set_add); route_map_no_set_metric_hook(generic_set_delete); @@ -241,5 +273,6 @@ void isis_route_map_init(void) route_map_install_match(&route_match_ip_address_prefix_list_cmd); route_map_install_match(&route_match_ipv6_address_cmd); route_map_install_match(&route_match_ipv6_address_prefix_list_cmd); + route_map_install_match(&route_match_tag_cmd); route_map_install_set(&route_set_metric_cmd); } diff --git a/isisd/isis_snmp.c b/isisd/isis_snmp.c new file mode 100644 index 0000000000..522026dde4 --- /dev/null +++ b/isisd/isis_snmp.c @@ -0,0 +1,3460 @@ +/* + * ISIS SNMP support + * Copyright (C) 2020 Volta Networks, Inc. + * Aleksey Romanov + * + * 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 + */ + +/* + * This is minimal read-only implementations providing isisReadOnlyCompliance + */ + +#include <zebra.h> + +#include <net-snmp/net-snmp-config.h> +#include <net-snmp/net-snmp-includes.h> + +#include "vrf.h" +#include "if.h" +#include "log.h" +#include "prefix.h" +#include "table.h" +#include "command.h" +#include "memory.h" +#include "smux.h" +#include "libfrr.h" +#include "version.h" + +#include "isisd/isis_constants.h" +#include "isisd/isis_common.h" +#include "isisd/isis_flags.h" +#include "isisd/isis_circuit.h" +#include "isisd/isis_lsp.h" +#include "isisd/isis_pdu.h" +#include "isisd/isis_network.h" +#include "isisd/isis_misc.h" +#include "isisd/isis_constants.h" +#include "isisd/isis_adjacency.h" +#include "isisd/isis_dynhn.h" +#include "isisd/isis_te.h" +#include "isisd/isis_dr.h" +#include "isisd/isis_nb.h" +#include "isisd/isisd.h" + +/* ISIS-MIB. */ +#define ISIS_MIB 1, 3, 6, 1, 2, 1, 138 + +#define ISIS_OBJECTS 1 +#define ISIS_SYSTEM 1, 1 +#define ISIS_SYSLEVEL 1, 2 +#define ISIS_CIRC 1, 3 +#define ISIS_CIRC_LEVEL_VALUES 1, 4 +#define ISIS_COUNTERS 1, 5 +#define ISIS_ISADJ 1, 6 + +/************************ isisSystemGroup ************************/ + +/* isisSysObject */ +#define ISIS_SYS_OBJECT 1, 1, 1 +#define ISIS_SYS_VERSION 1 +#define ISIS_SYS_LEVELTYPE 2 +#define ISIS_SYS_ID 3 +#define ISIS_SYS_MAXPATHSPLITS 4 +#define ISIS_SYS_MAXLSPGENINT 5 +#define ISIS_SYS_POLLESHELLORATE 6 +#define ISIS_SYS_WAITTIME 7 +#define ISIS_SYS_ADMINSTATE 8 +#define ISIS_SYS_L2TOL1LEAKING 9 +#define ISIS_SYS_MAXAGE 10 +#define ISIS_SYS_RECEIVELSPBUFFERSIZE 11 +#define ISIS_SYS_PROTSUPPORTED 12 +#define ISIS_SYS_NOTIFICATIONENABLE 13 + +/* isisManAreaAddrEntry */ +#define ISIS_MANAREA_ADDRENTRY 1, 1, 2, 1 +#define ISIS_MANAREA_ADDREXISTSTATE 2 + +/* isisAreaAddrEntry */ +#define ISIS_AREA_ADDRENTRY 1, 1, 3, 1 +#define ISIS_AREA_ADDR 1 + +/* isisSummAddrEntry */ +#define ISIS_SUMM_ADDRENTRY 1, 1, 4, 1 +#define ISIS_SUMM_ADDREXISTSTATE 4 +#define ISIS_SUMM_ADDRMETRIC 5 +#define ISIS_SUMM_ADDRFULLMETRIC 6 + +/* isisRedistributeAddrEntry */ +#define ISIS_REDISTRIBUTE_ADDRENTRY 1, 1, 5, 1 +#define ISIS_REDISTRIBUTE_ADDREXISTSTATE 3 + +/* isisRouterEntry */ +#define ISIS_ROUTER_ENTRY 1, 1, 6, 1 +#define ISIS_ROUTER_HOSTNAME 3 +#define ISIS_ROUTER_ID 4 + +/* isisSysLevelTable */ +#define ISIS_SYSLEVEL_ENTRY 1, 2, 1, 1 +#define ISIS_SYSLEVEL_ORIGLSPBUFFSIZE 2 +#define ISIS_SYSLEVEL_MINLSPGENINT 3 +#define ISIS_SYSLEVEL_STATE 4 +#define ISIS_SYSLEVEL_SETOVERLOAD 5 +#define ISIS_SYSLEVEL_SETOVERLOADUNTIL 6 +#define ISIS_SYSLEVEL_METRICSTYLE 7 +#define ISIS_SYSLEVEL_SPFCONSIDERS 8 +#define ISIS_SYSLEVEL_TEENABLED 9 + + +/* isisSystemCounterEntry */ +#define ISIS_SYSTEM_COUNTER_ENTRY 1, 5, 1, 1 +#define ISIS_SYSSTAT_CORRLSPS 2 +#define ISIS_SYSSTAT_AUTHTYPEFAILS 3 +#define ISIS_SYSSTAT_AUTHFAILS 4 +#define ISIS_SYSSTAT_LSPDBASEOLOADS 5 +#define ISIS_SYSSTAT_MANADDRDROPFROMAREAS 6 +#define ISIS_SYSSTAT_ATTMPTTOEXMAXSEQNUMS 7 +#define ISIS_SYSSTAT_SEQNUMSKIPS 8 +#define ISIS_SYSSTAT_OWNLSPPURGES 9 +#define ISIS_SYSSTAT_IDFIELDLENMISMATCHES 10 +#define ISIS_SYSSTAT_PARTCHANGES 11 +#define ISIS_SYSSTAT_SPFRUNS 12 +#define ISIS_SYSSTAT_LSPERRORS 13 + + +/************************ isisCircuitGroup ************************/ + +/* Scalar directly under isisCirc */ +#define ISIS_NEXTCIRC_INDEX 1 + +/* isisCircEntry */ +#define ISIS_CIRC_ENTRY 1, 3, 2, 1 +#define ISIS_CIRC_IFINDEX 2 +#define ISIS_CIRC_ADMINSTATE 3 +#define ISIS_CIRC_EXISTSTATE 4 +#define ISIS_CIRC_TYPE 5 +#define ISIS_CIRC_EXTDOMAIN 6 +#define ISIS_CIRC_LEVELTYPE 7 +#define ISIS_CIRC_PASSIVECIRCUIT 8 +#define ISIS_CIRC_MESHGROUPENABLED 9 +#define ISIS_CIRC_MESHGROUP 10 +#define ISIS_CIRC_SMALLHELLOS 11 +#define ISIS_CIRC_LASTUPTIME 12 +#define ISIS_CIRC_3WAYENABLED 13 +#define ISIS_CIRC_EXTENDEDCIRCID 14 + +/* isisCircLevelEntry */ +#define ISIS_CIRCLEVEL_ENTRY 1, 4, 1, 1 +#define ISIS_CIRCLEVEL_METRIC 2 +#define ISIS_CIRCLEVEL_WIDEMETRIC 3 +#define ISIS_CIRCLEVEL_ISPRIORITY 4 +#define ISIS_CIRCLEVEL_IDOCTET 5 +#define ISIS_CIRCLEVEL_ID 6 +#define ISIS_CIRCLEVEL_DESIS 7 +#define ISIS_CIRCLEVEL_HELLOMULTIPLIER 8 +#define ISIS_CIRCLEVEL_HELLOTIMER 9 +#define ISIS_CIRCLEVEL_DRHELLOTIMER 10 +#define ISIS_CIRCLEVEL_LSPTHROTTLE 11 +#define ISIS_CIRCLEVEL_MINLSPRETRANSINT 12 +#define ISIS_CIRCLEVEL_CSNPINTERVAL 13 +#define ISIS_CIRCLEVEL_PARTSNPINTERVAL 14 + +/* isisCircuitCounterEntry */ +#define ISIS_CIRC_COUNTER_ENTRY 1, 5, 2, 1 +#define ISIS_CIRC_ADJCHANGES 2 +#define ISIS_CIRC_NUMADJ 3 +#define ISIS_CIRC_INITFAILS 4 +#define ISIS_CIRC_REJADJS 5 +#define ISIS_CIRC_IDFIELDLENMISMATCHES 6 +#define ISIS_CIRC_MAXAREAADDRMISMATCHES 7 +#define ISIS_CIRC_AUTHTYPEFAILS 8 +#define ISIS_CIRC_AUTHFAILS 9 +#define ISIS_CIRC_LANDESISCHANGES 10 + + +/************************ isisISAdjGroup ************************/ + +/* isisISAdjEntry */ +#define ISIS_ISADJ_ENTRY 1, 6, 1, 1 +#define ISIS_ISADJ_STATE 2 +#define ISIS_ISADJ_3WAYSTATE 3 +#define ISIS_ISADJ_NEIGHSNPAADDRESS 4 +#define ISIS_ISADJ_NEIGHSYSTYPE 5 +#define ISIS_ISADJ_NEIGHSYSID 6 +#define ISIS_ISADJ_NBREXTENDEDCIRCID 7 +#define ISIS_ISADJ_USAGE 8 +#define ISIS_ISADJ_HOLDTIMER 9 +#define ISIS_ISADJ_NEIGHPRIORITY 10 +#define ISIS_ISADJ_LASTUPTIME 11 + +/* isisISAdjAreadAddrEntry */ +#define ISIS_ISADJAREA_ADDRENTRY 1, 6, 2, 1 +#define ISIS_ISADJAREA_ADDRESS 2 + +/* isisISAdjIPAddrEntry*/ +#define ISIS_ISADJIPADDR_ENTRY 1, 6, 3, 1 +#define ISIS_ISADJIPADDR_TYPE 2 +#define ISIS_ISADJIPADDR_ADDRESS 3 + + +/* isisISAdjProtSuppEntty */ + +#define ISIS_ISADJPROTSUPP_ENTRY 1, 6, 4, 1 +#define ISIS_ISADJPROTSUPP_PROTOCOL 1 + + +/************************ Trap data variables ************************/ +#define ISIS_NOTIFICATION_ENTRY 1, 10, 1 +#define ISIS_NOTIF_SYLELVELINDEX 1 +#define ISIS_NOTIF_CIRCIFINDEX 2 +#define ISIS_PDU_LSPID 3 +#define ISIS_PDU_FRAGMENT 4 +#define ISIS_PDU_FIELDLEN 5 +#define ISIS_PDU_MAXAREAADDR 6 +#define ISIS_PDU_PROTOVER 7 +#define ISIS_PDU_LSPSIZE 8 +#define ISIS_PDU_ORIGBUFFERSIZE 9 +#define ISIS_PDU_BUFFERSIZE 10 +#define ISIS_PDU_PROTSUPP 11 +#define ISIS_ADJ_STATE 12 +#define ISIS_ERROR_OFFSET 13 +#define ISIS_ERROR_TLVTYPE 14 +#define ISIS_NOTIF_AREAADDR 15 + +/************************ Traps ************************/ +#define ISIS_NOTIFICATIONS ISIS_MIB, 0 +#define ISIS_TRAP_DB_OVERLOAD 1 +#define ISIS_TRAP_MAN_ADDR_DROP 2 +#define ISIS_TRAP_CORRUPTED_LSP 3 +#define ISIS_TRAP_LSP_EXCEED_MAX 4 +#define ISIS_TRAP_ID_LEN_MISMATCH 5 +#define ISIS_TRAP_MAX_AREA_ADDR_MISMATCH 6 +#define ISIS_TRAP_OWN_LSP_PURGE 7 +#define ISIS_TRAP_SEQNO_SKIPPED 8 +#define ISIS_TRAP_AUTHEN_TYPE_FAILURE 9 +#define ISIS_TRAP_AUTHEN_FAILURE 10 +#define ISIS_TRAP_VERSION_SKEW 11 +#define ISIS_TRAP_AREA_MISMATCH 12 +#define ISIS_TRAP_REJ_ADJACENCY 13 +#define ISIS_TRAP_LSP_TOO_LARGE 14 +#define ISIS_TRAP_LSP_BUFFSIZE_MISMATCH 15 +#define ISIS_TRAP_PROTSUPP_MISMATCH 16 +#define ISIS_TRAP_ADJ_STATE_CHANGE 17 +#define ISIS_TRAP_LSP_ERROR 18 + +/* Change this definition if number of traps changes */ +#define ISIS_TRAP_LAST_TRAP ISIS_TRAP_LSP_ERROR + 1 + +#define ISIS_SNMP_TRAP_VAR 1, 3, 6, 1, 6, 3, 1, 1, 4, 1, 0 + + +/* SNMP value hack. */ +#define COUNTER32 ASN_COUNTER +#define INTEGER ASN_INTEGER +#define UNSIGNED32 ASN_GAUGE +#define TIMESTAMP ASN_TIMETICKS +#define TIMETICKS ASN_TIMETICKS +#define STRING ASN_OCTET_STR + +/* Declare static local variables for convenience. */ +SNMP_LOCAL_VARIABLES + +/* If ARRAY_SIZE is not available use a primitive substitution */ +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) +#endif + +/* + * Define time function, it serves two purposes + * 1. Uses unint32_t for unix time and encapsulates + * sing extension issues in conversion from time_t + * + * 2. I could be replaced in unit test environment + */ +#ifndef ISIS_SNMP_HAVE_TIME_FUNC +static uint32_t isis_snmp_time(void) +{ + return (uint32_t)time(NULL); +} + +#endif + +/* ISIS-MIB instances. */ +static oid isis_oid[] = {ISIS_MIB}; + +/* SNMP trap variable */ +static oid isis_snmp_trap_var[] = {ISIS_SNMP_TRAP_VAR}; + +/* SNMP trap values (others are calculated on the fly */ +static oid isis_snmp_notifications[] = {ISIS_NOTIFICATIONS}; +static oid isis_snmp_trap_val_db_overload[] = {ISIS_NOTIFICATIONS, + ISIS_TRAP_DB_OVERLOAD}; +static oid isis_snmp_trap_val_lsp_exceed_max[] = {ISIS_NOTIFICATIONS, + ISIS_TRAP_LSP_EXCEED_MAX}; +static oid isis_snmp_trap_val_area_mismatch[] = {ISIS_NOTIFICATIONS, + ISIS_TRAP_AREA_MISMATCH}; +static oid isis_snmp_trap_val_lsp_error[] = {ISIS_NOTIFICATIONS, + ISIS_TRAP_LSP_ERROR}; + +/* + * Trap vars under 'isisNotifications': note: we use full names of variables + * scalar index + */ +static oid isis_snmp_trap_data_var_sys_level_index[] = { + ISIS_MIB, ISIS_NOTIFICATION_ENTRY, ISIS_NOTIF_SYLELVELINDEX, 0}; +static oid isis_snmp_trap_data_var_circ_if_index[] = { + ISIS_MIB, ISIS_NOTIFICATION_ENTRY, ISIS_NOTIF_CIRCIFINDEX, 0}; +static oid isis_snmp_trap_data_var_pdu_lsp_id[] = { + ISIS_MIB, ISIS_NOTIFICATION_ENTRY, ISIS_PDU_LSPID, 0}; +static oid isis_snmp_trap_data_var_pdu_fragment[] = { + ISIS_MIB, ISIS_NOTIFICATION_ENTRY, ISIS_PDU_FRAGMENT, 0}; +static oid isis_snmp_trap_data_var_pdu_field_len[] = { + ISIS_MIB, ISIS_NOTIFICATION_ENTRY, ISIS_PDU_FIELDLEN, 0}; +static oid isis_snmp_trap_data_var_pdu_max_area_addr[] = { + ISIS_MIB, ISIS_NOTIFICATION_ENTRY, ISIS_PDU_MAXAREAADDR, 0}; +static oid isis_snmp_trap_data_var_pdu_proto_ver[] = { + ISIS_MIB, ISIS_NOTIFICATION_ENTRY, ISIS_PDU_PROTOVER, 0}; +static oid isis_snmp_trap_data_var_pdu_lsp_size[] = { + ISIS_MIB, ISIS_NOTIFICATION_ENTRY, ISIS_PDU_LSPSIZE, 0}; +static oid isis_snmp_trap_data_var_adj_state[] = { + ISIS_MIB, ISIS_NOTIFICATION_ENTRY, ISIS_ADJ_STATE, 0}; +static oid isis_snmp_trap_data_var_error_offset[] = { + ISIS_MIB, ISIS_NOTIFICATION_ENTRY, ISIS_ERROR_OFFSET, 0}; +static oid isis_snmp_trap_data_var_error_tlv_type[] = { + ISIS_MIB, ISIS_NOTIFICATION_ENTRY, ISIS_ERROR_TLVTYPE, 0}; + +/* + * Other variables used by traps: note we use full names of variables and + * reserve space for index + */ +static oid isis_snmp_trap_data_var_sys_level_state[] = { + ISIS_MIB, ISIS_SYSLEVEL_ENTRY, ISIS_SYSLEVEL_STATE, 0}; + +/* Throttle time values for traps */ +static time_t isis_snmp_trap_timestamp[ISIS_TRAP_LAST_TRAP]; /* ?? 1 */ + +/* Max len of raw-pdu in traps */ +#define ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN (64) + +/* + * Just to save on typing we have a shortcut structure + * to specify mib layout as prefix/leaf combination + */ +#define ISIS_SNMP_PREF_LEN_MAX 10 +struct isis_var_prefix { + FindVarMethod *findVar; + uint8_t ivd_pref_len; + oid ivd_pref[ISIS_SNMP_PREF_LEN_MAX]; +}; + + +/* Find-val functions */ +static uint8_t *isis_snmp_find_sys_object(struct variable *, oid *, size_t *, + int, size_t *, WriteMethod **); + +static uint8_t *isis_snmp_find_man_area(struct variable *, oid *, size_t *, int, + size_t *, WriteMethod **); + +static uint8_t *isis_snmp_find_area_addr(struct variable *, oid *, size_t *, + int, size_t *, WriteMethod **); + +static uint8_t *isis_snmp_find_summ_addr(struct variable *, oid *, size_t *, + int, size_t *, WriteMethod **); + +static uint8_t *isis_snmp_find_redistribute_addr(struct variable *, oid *, + size_t *, int, size_t *, + WriteMethod **); + +static uint8_t *isis_snmp_find_router(struct variable *, oid *, size_t *, int, + size_t *, WriteMethod **); + +static uint8_t *isis_snmp_find_sys_level(struct variable *, oid *, size_t *, + int, size_t *, WriteMethod **); + +static uint8_t *isis_snmp_find_system_counter(struct variable *, oid *, + size_t *, int, size_t *, + WriteMethod **); + +static uint8_t *isis_snmp_find_next_circ_index(struct variable *, oid *, + size_t *, int, size_t *, + WriteMethod **); + +static uint8_t *isis_snmp_find_circ(struct variable *, oid *, size_t *, int, + size_t *, WriteMethod **); + +static uint8_t *isis_snmp_find_circ_level(struct variable *, oid *, size_t *, + int, size_t *, WriteMethod **); + +static uint8_t *isis_snmp_find_circ_counter(struct variable *, oid *, size_t *, + int, size_t *, WriteMethod **); + +static uint8_t *isis_snmp_find_isadj(struct variable *, oid *, size_t *, int, + size_t *, WriteMethod **); + +static uint8_t *isis_snmp_find_isadj_area(struct variable *, oid *, size_t *, + int, size_t *, WriteMethod **); + +static uint8_t *isis_snmp_find_isadj_ipaddr(struct variable *, oid *, size_t *, + int, size_t *, WriteMethod **); + +static uint8_t *isis_snmp_find_isadj_prot_supp(struct variable *, oid *, + size_t *, int, size_t *, + WriteMethod **); + +/* + * Just to save on typing we have a shortcut structure + * to specify mib layout, we populate the rest of the data + * during initialization + */ +#define ISIS_PREF_LEN_MAX (6) + +struct isis_func_to_prefix { + FindVarMethod *ihtp_func; + oid ihtp_pref_oid[ISIS_PREF_LEN_MAX]; + uint8_t ihtp_pref_len; +}; + +static struct isis_func_to_prefix isis_func_to_prefix_arr[] = { + {isis_snmp_find_sys_object, {ISIS_SYS_OBJECT}, 3}, + {isis_snmp_find_man_area, {ISIS_MANAREA_ADDRENTRY}, 4}, + {isis_snmp_find_area_addr, {ISIS_AREA_ADDRENTRY}, 4}, + {isis_snmp_find_summ_addr, {ISIS_SUMM_ADDRENTRY}, 4}, + {isis_snmp_find_redistribute_addr, {ISIS_REDISTRIBUTE_ADDRENTRY}, 4}, + {isis_snmp_find_router, {ISIS_ROUTER_ENTRY}, 4}, + {isis_snmp_find_sys_level, {ISIS_SYSLEVEL_ENTRY}, 4}, + {isis_snmp_find_system_counter, {ISIS_SYSTEM_COUNTER_ENTRY}, 4}, + {isis_snmp_find_next_circ_index, {ISIS_CIRC}, 2}, + {isis_snmp_find_circ, {ISIS_CIRC_ENTRY}, 4}, + {isis_snmp_find_circ_level, {ISIS_CIRCLEVEL_ENTRY}, 4}, + {isis_snmp_find_circ_counter, {ISIS_CIRC_COUNTER_ENTRY}, 4}, + {isis_snmp_find_isadj, {ISIS_ISADJ_ENTRY}, 4}, + {isis_snmp_find_isadj_area, {ISIS_ISADJAREA_ADDRENTRY}, 4}, + {isis_snmp_find_isadj_ipaddr, {ISIS_ISADJIPADDR_ENTRY}, 4}, + {isis_snmp_find_isadj_prot_supp, {ISIS_ISADJPROTSUPP_ENTRY}, 4}, +}; +static size_t isis_func_to_prefix_count = ARRAY_SIZE(isis_func_to_prefix_arr); + +static struct variable isis_var_arr[] = { + {ISIS_SYS_VERSION, INTEGER, RONLY, isis_snmp_find_sys_object}, + {ISIS_SYS_LEVELTYPE, INTEGER, RONLY, isis_snmp_find_sys_object}, + {ISIS_SYS_ID, STRING, RONLY, isis_snmp_find_sys_object}, + {ISIS_SYS_MAXPATHSPLITS, UNSIGNED32, RONLY, isis_snmp_find_sys_object}, + {ISIS_SYS_MAXLSPGENINT, UNSIGNED32, RONLY, isis_snmp_find_sys_object}, + {ISIS_SYS_POLLESHELLORATE, UNSIGNED32, RONLY, + isis_snmp_find_sys_object}, + {ISIS_SYS_WAITTIME, UNSIGNED32, RONLY, isis_snmp_find_sys_object}, + {ISIS_SYS_ADMINSTATE, INTEGER, RONLY, isis_snmp_find_sys_object}, + {ISIS_SYS_L2TOL1LEAKING, INTEGER, RONLY, isis_snmp_find_sys_object}, + {ISIS_SYS_MAXAGE, UNSIGNED32, RONLY, isis_snmp_find_sys_object}, + {ISIS_SYS_RECEIVELSPBUFFERSIZE, UNSIGNED32, RONLY, + isis_snmp_find_sys_object}, + {ISIS_SYS_PROTSUPPORTED, STRING, RONLY, isis_snmp_find_sys_object}, + {ISIS_SYS_NOTIFICATIONENABLE, INTEGER, RONLY, + isis_snmp_find_sys_object}, + {ISIS_MANAREA_ADDREXISTSTATE, INTEGER, RONLY, isis_snmp_find_man_area}, + {ISIS_AREA_ADDR, STRING, RONLY, isis_snmp_find_area_addr}, + {ISIS_SUMM_ADDREXISTSTATE, INTEGER, RONLY, isis_snmp_find_summ_addr}, + {ISIS_SUMM_ADDRMETRIC, UNSIGNED32, RONLY, isis_snmp_find_summ_addr}, + {ISIS_SUMM_ADDRFULLMETRIC, UNSIGNED32, RONLY, isis_snmp_find_summ_addr}, + {ISIS_REDISTRIBUTE_ADDREXISTSTATE, INTEGER, RONLY, + isis_snmp_find_redistribute_addr}, + {ISIS_ROUTER_HOSTNAME, STRING, RONLY, isis_snmp_find_router}, + {ISIS_ROUTER_ID, UNSIGNED32, RONLY, isis_snmp_find_router}, + {ISIS_SYSLEVEL_ORIGLSPBUFFSIZE, UNSIGNED32, RONLY, + isis_snmp_find_sys_level}, + {ISIS_SYSLEVEL_MINLSPGENINT, UNSIGNED32, RONLY, + isis_snmp_find_sys_level}, + {ISIS_SYSLEVEL_STATE, INTEGER, RONLY, isis_snmp_find_sys_level}, + {ISIS_SYSLEVEL_SETOVERLOAD, INTEGER, RONLY, isis_snmp_find_sys_level}, + {ISIS_SYSLEVEL_SETOVERLOADUNTIL, UNSIGNED32, RONLY, + isis_snmp_find_sys_level}, + {ISIS_SYSLEVEL_METRICSTYLE, INTEGER, RONLY, isis_snmp_find_sys_level}, + {ISIS_SYSLEVEL_SPFCONSIDERS, INTEGER, RONLY, isis_snmp_find_sys_level}, + {ISIS_SYSLEVEL_TEENABLED, INTEGER, RONLY, isis_snmp_find_sys_level}, + {ISIS_SYSSTAT_CORRLSPS, COUNTER32, RONLY, + isis_snmp_find_system_counter}, + {ISIS_SYSSTAT_AUTHTYPEFAILS, COUNTER32, RONLY, + isis_snmp_find_system_counter}, + {ISIS_SYSSTAT_AUTHFAILS, COUNTER32, RONLY, + isis_snmp_find_system_counter}, + {ISIS_SYSSTAT_LSPDBASEOLOADS, COUNTER32, RONLY, + isis_snmp_find_system_counter}, + {ISIS_SYSSTAT_MANADDRDROPFROMAREAS, COUNTER32, RONLY, + isis_snmp_find_system_counter}, + {ISIS_SYSSTAT_ATTMPTTOEXMAXSEQNUMS, COUNTER32, RONLY, + isis_snmp_find_system_counter}, + {ISIS_SYSSTAT_SEQNUMSKIPS, COUNTER32, RONLY, + isis_snmp_find_system_counter}, + {ISIS_SYSSTAT_OWNLSPPURGES, COUNTER32, RONLY, + isis_snmp_find_system_counter}, + {ISIS_SYSSTAT_IDFIELDLENMISMATCHES, COUNTER32, RONLY, + isis_snmp_find_system_counter}, + {ISIS_SYSSTAT_PARTCHANGES, COUNTER32, RONLY, + isis_snmp_find_system_counter}, + {ISIS_SYSSTAT_SPFRUNS, COUNTER32, RONLY, isis_snmp_find_system_counter}, + {ISIS_SYSSTAT_LSPERRORS, COUNTER32, RONLY, + isis_snmp_find_system_counter}, + {ISIS_NEXTCIRC_INDEX, UNSIGNED32, RONLY, + isis_snmp_find_next_circ_index}, + {ISIS_CIRC_IFINDEX, INTEGER, RONLY, isis_snmp_find_circ}, + {ISIS_CIRC_ADMINSTATE, INTEGER, RONLY, isis_snmp_find_circ}, + {ISIS_CIRC_EXISTSTATE, INTEGER, RONLY, isis_snmp_find_circ}, + {ISIS_CIRC_TYPE, INTEGER, RONLY, isis_snmp_find_circ}, + {ISIS_CIRC_EXTDOMAIN, INTEGER, RONLY, isis_snmp_find_circ}, + {ISIS_CIRC_LEVELTYPE, INTEGER, RONLY, isis_snmp_find_circ}, + {ISIS_CIRC_PASSIVECIRCUIT, INTEGER, RONLY, isis_snmp_find_circ}, + {ISIS_CIRC_MESHGROUPENABLED, INTEGER, RONLY, isis_snmp_find_circ}, + {ISIS_CIRC_MESHGROUP, UNSIGNED32, RONLY, isis_snmp_find_circ}, + {ISIS_CIRC_SMALLHELLOS, INTEGER, RONLY, isis_snmp_find_circ}, + {ISIS_CIRC_LASTUPTIME, TIMESTAMP, RONLY, isis_snmp_find_circ}, + {ISIS_CIRC_3WAYENABLED, INTEGER, RONLY, isis_snmp_find_circ}, + {ISIS_CIRC_EXTENDEDCIRCID, UNSIGNED32, RONLY, isis_snmp_find_circ}, + {ISIS_CIRCLEVEL_METRIC, UNSIGNED32, RONLY, isis_snmp_find_circ_level}, + {ISIS_CIRCLEVEL_WIDEMETRIC, UNSIGNED32, RONLY, + isis_snmp_find_circ_level}, + {ISIS_CIRCLEVEL_ISPRIORITY, UNSIGNED32, RONLY, + isis_snmp_find_circ_level}, + {ISIS_CIRCLEVEL_IDOCTET, UNSIGNED32, RONLY, isis_snmp_find_circ_level}, + {ISIS_CIRCLEVEL_ID, STRING, RONLY, isis_snmp_find_circ_level}, + {ISIS_CIRCLEVEL_DESIS, STRING, RONLY, isis_snmp_find_circ_level}, + {ISIS_CIRCLEVEL_HELLOMULTIPLIER, UNSIGNED32, RONLY, + isis_snmp_find_circ_level}, + {ISIS_CIRCLEVEL_HELLOTIMER, UNSIGNED32, RONLY, + isis_snmp_find_circ_level}, + {ISIS_CIRCLEVEL_DRHELLOTIMER, UNSIGNED32, RONLY, + isis_snmp_find_circ_level}, + {ISIS_CIRCLEVEL_LSPTHROTTLE, UNSIGNED32, RONLY, + isis_snmp_find_circ_level}, + {ISIS_CIRCLEVEL_MINLSPRETRANSINT, UNSIGNED32, RONLY, + isis_snmp_find_circ_level}, + {ISIS_CIRCLEVEL_CSNPINTERVAL, UNSIGNED32, RONLY, + isis_snmp_find_circ_level}, + {ISIS_CIRCLEVEL_PARTSNPINTERVAL, UNSIGNED32, RONLY, + isis_snmp_find_circ_level}, + {ISIS_CIRC_ADJCHANGES, COUNTER32, RONLY, isis_snmp_find_circ_counter}, + {ISIS_CIRC_NUMADJ, UNSIGNED32, RONLY, isis_snmp_find_circ_counter}, + {ISIS_CIRC_INITFAILS, COUNTER32, RONLY, isis_snmp_find_circ_counter}, + {ISIS_CIRC_REJADJS, COUNTER32, RONLY, isis_snmp_find_circ_counter}, + {ISIS_CIRC_IDFIELDLENMISMATCHES, COUNTER32, RONLY, + isis_snmp_find_circ_counter}, + {ISIS_CIRC_MAXAREAADDRMISMATCHES, COUNTER32, RONLY, + isis_snmp_find_circ_counter}, + {ISIS_CIRC_AUTHTYPEFAILS, COUNTER32, RONLY, + isis_snmp_find_circ_counter}, + {ISIS_CIRC_AUTHFAILS, COUNTER32, RONLY, isis_snmp_find_circ_counter}, + {ISIS_CIRC_LANDESISCHANGES, COUNTER32, RONLY, + isis_snmp_find_circ_counter}, + {ISIS_ISADJ_STATE, INTEGER, RONLY, isis_snmp_find_isadj}, + {ISIS_ISADJ_3WAYSTATE, INTEGER, RONLY, isis_snmp_find_isadj}, + {ISIS_ISADJ_NEIGHSNPAADDRESS, STRING, RONLY, isis_snmp_find_isadj}, + {ISIS_ISADJ_NEIGHSYSTYPE, INTEGER, RONLY, isis_snmp_find_isadj}, + {ISIS_ISADJ_NEIGHSYSID, STRING, RONLY, isis_snmp_find_isadj}, + {ISIS_ISADJ_NBREXTENDEDCIRCID, UNSIGNED32, RONLY, isis_snmp_find_isadj}, + {ISIS_ISADJ_USAGE, INTEGER, RONLY, isis_snmp_find_isadj}, + {ISIS_ISADJ_HOLDTIMER, UNSIGNED32, RONLY, isis_snmp_find_isadj}, + {ISIS_ISADJ_NEIGHPRIORITY, UNSIGNED32, RONLY, isis_snmp_find_isadj}, + {ISIS_ISADJ_LASTUPTIME, TIMESTAMP, RONLY, isis_snmp_find_isadj}, + {ISIS_ISADJAREA_ADDRESS, STRING, RONLY, isis_snmp_find_isadj_area}, + {ISIS_ISADJIPADDR_TYPE, INTEGER, RONLY, isis_snmp_find_isadj_ipaddr}, + {ISIS_ISADJIPADDR_ADDRESS, STRING, RONLY, isis_snmp_find_isadj_ipaddr}, + {ISIS_ISADJPROTSUPP_PROTOCOL, INTEGER, RONLY, + isis_snmp_find_isadj_prot_supp}, +}; + +static const size_t isis_var_count = ARRAY_SIZE(isis_var_arr); + +/* Minimal set of hard-coded data */ +#define ISIS_VERSION (1) + +/* If sys-id is not set use this value */ +static uint8_t isis_null_sysid[ISIS_SYS_ID_LEN]; + +/* OSI addr-len */ +#define ISIS_SNMP_OSI_ADDR_LEN_MAX (20) + +/* + * The implementation has a fixed max-path splits value + * of 64 (see ISIS_MAX_PATH_SPLITS), the max mib value + * is 32. + * + * FIXME(aromanov): should we return 32 or 64? + */ +#define ISIS_SNMP_MAX_PATH_SPLITS (32) + +#define ISIS_SNMP_ADMIN_STATE_ON (1) + +#define ISIS_SNMP_ROW_STATUS_ACTIVE (1) + +#define ISIS_SNMP_LEVEL_STATE_OFF (1) +#define ISIS_SNMP_LEVEL_STATE_ON (2) +#define ISIS_SNMP_LEVEL_STATE_WAITING (3) +#define ISIS_SNMP_LEVEL_STATE_OVERLOADED (4) + +#define ISIS_SNMP_TRUTH_VALUE_TRUE (1) +#define ISIS_SNMP_TRUTH_VALUE_FALSE (2) + +#define ISIS_SNMP_METRIC_STYLE_NARROW (1) +#define ISIS_SNMP_METRIC_STYLE_WIDE (2) +#define ISIS_SNMP_METRIC_STYLE_BOTH (3) + +#define ISIS_SNMP_MESH_GROUP_INACTIVE (1) + +#define ISIS_SNMP_ADJ_STATE_DOWN (1) +#define ISIS_SNMP_ADJ_STATE_INITIALIZING (2) +#define ISIS_SNMP_ADJ_STATE_UP (3) +#define ISIS_SNMP_ADJ_STATE_FAILED (4) + +#define ISIS_SNMP_ADJ_NEIGHTYPE_IS_L1 (1) +#define ISIS_SNMP_ADJ_NEIGHTYPE_IS_L2 (2) +#define ISIS_SNMP_ADJ_NEIGHTYPE_IS_L1_L2 (3) +#define ISIS_SNMP_ADJ_NEIGHTYPE_UNKNOWN (4) + +#define ISIS_SNMP_INET_TYPE_V4 (1) +#define ISIS_SNMP_INET_TYPE_V6 (2) + +#define ISIS_SNMP_P2P_CIRCUIT (3) + +/* Protocols supported value */ +static uint8_t isis_snmp_protocols_supported = 0x7; /* All: iso, ipv4, ipv6 */ + +/* + * Convenience function to move to the next circuit, + */ +static struct isis_circuit *isis_snmp_circuit_next(struct isis_circuit *circuit) +{ + uint32_t start; + uint32_t off; + struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT); + + if (isis == NULL) + return NULL; + + start = 1; + + if (circuit != NULL) + start = circuit->snmp_id + 1; + + for (off = start; off < SNMP_CIRCUITS_MAX; off++) { + circuit = isis->snmp_circuits[off]; + + if (circuit != NULL) + return circuit; + } + + return NULL; +} + +/* + * Convenience function to get the first matching level + */ +static int isis_snmp_circuit_get_level_lo(struct isis_circuit *circuit) +{ + if (circuit->is_type == IS_LEVEL_2) + return IS_LEVEL_2; + + return IS_LEVEL_1; +} + +/* Check level match */ +static int isis_snmp_get_level_match(int is_type, int level) +{ + if (is_type != IS_LEVEL_1 && is_type != IS_LEVEL_2 + && is_type != IS_LEVEL_1_AND_2) + return 0; + + if (level != IS_LEVEL_1 && level != IS_LEVEL_2) + return 0; + + + if (is_type == IS_LEVEL_1) { + if (level == IS_LEVEL_1) + return 1; + + return 0; + } + + if (is_type == IS_LEVEL_2) { + if (level == IS_LEVEL_2) + return 1; + + return 0; + } + + return 1; +} +/* + * Helper function to convert oid index representing + * octet-string index (e.g. isis-sys-id) to byte string + * representing the same index. + * + * Also we do not fail if idx is longer than max_len, + * so we can use the same function to check compound + * indexes. + */ +static int isis_snmp_conv_exact(uint8_t *buf, size_t max_len, size_t *out_len, + const oid *idx, size_t idx_len) +{ + size_t off; + size_t len; + + /* Oid representation: length followed by bytes */ + if (idx == NULL || idx_len == 0) + return 0; + + len = idx[0]; + + if (len > max_len) + return 0; + + if (idx_len < len + 1) + return 0; + + for (off = 0; off < len; off++) { + if (idx[off + 1] > 0xff) + return 0; + + buf[off] = (uint8_t)(idx[off + 1] & 0xff); + } + + *out_len = len; + + return 1; +} + +static int isis_snmp_conv_next(uint8_t *buf, size_t max_len, size_t *out_len, + int *try_exact, const oid *idx, size_t idx_len) +{ + size_t off; + size_t len; + size_t cmp_len; + + if (idx == NULL || idx_len == 0) { + *out_len = 0; + *try_exact = 1; + return 1; + } + + len = idx[0]; + + if (len > max_len) + return 0; + + cmp_len = len; + + if ((idx_len - 1) < cmp_len) + cmp_len = idx_len - 1; + + for (off = 0; off < cmp_len; off++) { + if (idx[off + 1] > 0xff) { + memset(buf + off, 0xff, len - off); + *out_len = len; + *try_exact = 1; + return 1; + } + + buf[off] = (uint8_t)(idx[off + 1] & 0xff); + } + + if (cmp_len < len) + memset(buf + cmp_len, 0, len - cmp_len); + + *out_len = len; + *try_exact = cmp_len < len ? 1 : 0; + return 1; +} + +/* + * Helper functions to find area address from snmp index + */ +static int isis_snmp_area_addr_lookup_exact(oid *oid_idx, size_t oid_idx_len, + struct isis_area **ret_area, + struct area_addr **ret_addr) +{ + uint8_t cmp_buf[ISIS_SNMP_OSI_ADDR_LEN_MAX]; + size_t addr_len; + struct isis_area *area = NULL; + struct area_addr *addr = NULL; + struct listnode *addr_node; + struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT); + + if (isis == NULL) + return 0; + + if (list_isempty(isis->area_list)) { + /* Area is not configured yet */ + return 0; + } + + area = listgetdata(listhead(isis->area_list)); + + int res = isis_snmp_conv_exact(cmp_buf, sizeof(cmp_buf), &addr_len, + oid_idx, oid_idx_len); + + + if (!res || addr_len == 0 || oid_idx_len != (addr_len + 1)) { + /* Bad conversion, empty address or extra oids at the end */ + return 0; + } + + for (ALL_LIST_ELEMENTS_RO(area->area_addrs, addr_node, addr)) { + if (addr->addr_len != addr_len) + continue; + + if (memcmp(addr->area_addr, cmp_buf, addr_len) == 0) { + if (ret_area != 0) + *ret_area = area; + + if (ret_addr != 0) + *ret_addr = addr; + + return 1; + } + } + return 0; +} + +static int isis_snmp_area_addr_lookup_next(oid *oid_idx, size_t oid_idx_len, + struct isis_area **ret_area, + struct area_addr **ret_addr) +{ + uint8_t cmp_buf[ISIS_SNMP_OSI_ADDR_LEN_MAX]; + size_t addr_len; + int try_exact = 0; + struct isis_area *found_area = NULL; + struct isis_area *area = NULL; + struct area_addr *found_addr = NULL; + struct area_addr *addr = NULL; + struct listnode *addr_node; + struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT); + + if (isis == NULL) + return 0; + + if (list_isempty(isis->area_list)) { + /* Area is not configured yet */ + return 0; + } + + area = listgetdata(listhead(isis->area_list)); + + int res = isis_snmp_conv_next(cmp_buf, sizeof(cmp_buf), &addr_len, + &try_exact, oid_idx, oid_idx_len); + + if (!res) + return 0; + + for (ALL_LIST_ELEMENTS_RO(area->area_addrs, addr_node, addr)) { + if (addr->addr_len < addr_len) + continue; + + if (addr->addr_len == addr_len) { + if (addr_len == 0) + continue; + + res = memcmp(addr->area_addr, cmp_buf, addr_len); + + if (res < 0) + continue; + + if (res == 0 && addr->addr_len == addr_len) { + if (try_exact) { + /* + * This is the best match no point + * to look further + */ + found_area = area; + found_addr = addr; + break; + } + continue; + } + } + + if (found_addr == NULL || addr->addr_len < found_addr->addr_len + || (addr->addr_len == found_addr->addr_len + && memcmp(addr->area_addr, found_addr->area_addr, + addr->addr_len) + < 0)) { + found_area = area; + found_addr = addr; + } + } + + if (found_area == NULL) + return 0; + + if (ret_area != 0) + *ret_area = found_area; + + if (ret_addr != 0) + *ret_addr = found_addr; + + return 1; +} + +/* + * Helper functions to find circuit from + * snmp index + */ +static int isis_snmp_circuit_lookup_exact(oid *oid_idx, size_t oid_idx_len, + struct isis_circuit **ret_circuit) +{ + struct isis_circuit *circuit; + struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT); + + if (isis == NULL) + return 0; + + if (oid_idx == NULL || oid_idx_len < 1 + || oid_idx[0] > SNMP_CIRCUITS_MAX) + return 0; + + circuit = isis->snmp_circuits[oid_idx[0]]; + if (circuit == NULL) + return 0; + + if (ret_circuit != NULL) + *ret_circuit = circuit; + + return 1; +} + +static int isis_snmp_circuit_lookup_next(oid *oid_idx, size_t oid_idx_len, + struct isis_circuit **ret_circuit) +{ + oid off; + oid start; + struct isis_circuit *circuit; + struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT); + + if (isis == NULL) + return 0; + + start = 0; + + if (oid_idx != NULL && oid_idx_len != 0) { + if (oid_idx[0] > SNMP_CIRCUITS_MAX) + return 0; + + start = oid_idx[0]; + } + + for (off = start; off < SNMP_CIRCUITS_MAX; ++off) { + circuit = isis->snmp_circuits[off]; + + if (circuit != NULL && off > start) { + if (ret_circuit != NULL) + *ret_circuit = circuit; + + return 1; + } + } + + return 0; +} + +/* + * Helper functions to find circuit level + * combination from snmp index + */ +static int isis_snmp_circuit_level_lookup_exact( + oid *oid_idx, size_t oid_idx_len, int check_match, + struct isis_circuit **ret_circuit, int *ret_level) +{ + int level; + int res; + struct isis_circuit *circuit; + + /* Minor optimization: check level first */ + if (oid_idx == NULL || oid_idx_len < 2) + return 0; + + if (oid_idx[1] < IS_LEVEL_1 || oid_idx[1] > IS_LEVEL_2) + return 0; + + level = (int)oid_idx[1]; + + res = isis_snmp_circuit_lookup_exact(oid_idx, oid_idx_len, &circuit); + + if (!res) + return 0; + + if (check_match && !isis_snmp_get_level_match(circuit->is_type, level)) + return 0; + + if (ret_circuit != NULL) + *ret_circuit = circuit; + + if (ret_level != NULL) + *ret_level = level; + + return 1; +} + +static int isis_snmp_circuit_level_lookup_next( + oid *oid_idx, size_t oid_idx_len, int check_match, + struct isis_circuit **ret_circuit, int *ret_level) +{ + oid off; + oid start; + struct isis_circuit *circuit; + int level; + struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT); + + if (isis == NULL) + return 0; + + start = 0; + + if (oid_idx != NULL && oid_idx_len != 0) { + if (oid_idx[0] > SNMP_CIRCUITS_MAX) + return 0; + + start = oid_idx[0]; + } + + for (off = start; off < SNMP_CIRCUITS_MAX; off++) { + circuit = isis->snmp_circuits[off]; + + if (circuit == NULL) + continue; + + if (off > start || oid_idx_len < 2) { + /* Found and can use level 1 */ + level = IS_LEVEL_1; + break; + } + + /* We have to check level specified by index */ + if (oid_idx[1] < IS_LEVEL_1) { + level = IS_LEVEL_1; + break; + } + + if (oid_idx[1] < IS_LEVEL_2) { + level = IS_LEVEL_2; + break; + } + + /* Try next */ + circuit = NULL; + } + + if (circuit == NULL) + return 0; + + if (check_match + && !isis_snmp_get_level_match(circuit->is_type, level)) { + if (level == IS_LEVEL_1) { + /* + * We can simply advance level because + * at least one level should match + */ + level = IS_LEVEL_2; + } else { + /* We have to move to the next circuit */ + circuit = isis_snmp_circuit_next(circuit); + if (circuit == NULL) + return 0; + + level = isis_snmp_circuit_get_level_lo(circuit); + } + } + + if (ret_circuit != NULL) + *ret_circuit = circuit; + + if (ret_level != NULL) + *ret_level = level; + + return 1; +} + +/* + * Helper functions to find adjacency + * from snmp index. + * + * We have 4 tables related to adjacency + * looking up adjacency is quite expensive + * in case of bcast interfaces. + * + * It is pain to have 4 very similar functions + * hence we pass in and out additional data + * we are looking for. + * + * Note: we use data-len value to distinguish + * between ipv4 and ipv6 addresses + */ +#define ISIS_SNMP_ADJ_DATA_NONE (1) +#define ISIS_SNMP_ADJ_DATA_AREA_ADDR (2) +#define ISIS_SNMP_ADJ_DATA_IP_ADDR (3) +#define ISIS_SNMP_ADJ_DATA_PROTO (4) + +/* + * Helper function to process data associated + * with adjacency + */ +static int isis_snmp_adj_helper(struct isis_adjacency *adj, int data_id, + oid data_off, uint8_t **ret_data, + size_t *ret_data_len) +{ + uint8_t *data = NULL; + size_t data_len = 0; + + switch (data_id) { + case ISIS_SNMP_ADJ_DATA_NONE: + break; + + case ISIS_SNMP_ADJ_DATA_AREA_ADDR: + if (data_off >= adj->area_address_count) + return 0; + + data = adj->area_addresses[data_off].area_addr; + data_len = adj->area_addresses[data_off].addr_len; + break; + + case ISIS_SNMP_ADJ_DATA_IP_ADDR: + if (data_off + >= (adj->ipv4_address_count + adj->ipv6_address_count)) + return 0; + + if (data_off >= adj->ipv4_address_count) { + data = (uint8_t *)&adj->ipv6_addresses + [data_off - adj->ipv4_address_count]; + data_len = sizeof(adj->ipv6_addresses[0]); + } else { + data = (uint8_t *)&adj->ipv4_addresses[data_off]; + data_len = sizeof(adj->ipv4_addresses[0]); + } + + break; + + + case ISIS_SNMP_ADJ_DATA_PROTO: + if (data_off >= adj->nlpids.count) + return 0; + + data = &adj->nlpids.nlpids[data_off]; + data_len = sizeof(adj->nlpids.nlpids[0]); + break; + + default: + assert(0); + return 0; + } + + if (ret_data != NULL) + *ret_data = data; + + if (ret_data_len != NULL) + *ret_data_len = data_len; + + return 1; +} + +static int isis_snmp_adj_lookup_exact(oid *oid_idx, size_t oid_idx_len, + int data_id, + struct isis_adjacency **ret_adj, + oid *ret_data_idx, uint8_t **ret_data, + size_t *ret_data_len) +{ + int res; + struct listnode *node; + struct isis_circuit *circuit; + struct isis_adjacency *adj; + struct isis_adjacency *tmp_adj; + oid adj_idx; + oid data_off; + uint8_t *data; + size_t data_len; + + res = isis_snmp_circuit_lookup_exact(oid_idx, oid_idx_len, &circuit); + + if (!res) + return 0; + + if (oid_idx == NULL || oid_idx_len < 2 + || (data_id != ISIS_SNMP_ADJ_DATA_NONE && oid_idx_len < 3)) + return 0; + + adj_idx = oid_idx[1]; + + if (data_id != ISIS_SNMP_ADJ_DATA_NONE) { + if (oid_idx[2] == 0) + return 0; + + data_off = oid_idx[2] - 1; + } else { + /* + * Data-off is not used if data-id is none + * but we set it just for consistency + */ + data_off = 0; + } + + adj = NULL; + data = NULL; + data_len = 0; + + for (ALL_LIST_ELEMENTS_RO(circuit->snmp_adj_list, node, tmp_adj)) { + if (tmp_adj->snmp_idx > adj_idx) { + /* + * Adjacencies are ordered in the list + * no point to look further + */ + break; + } + + if (tmp_adj->snmp_idx == adj_idx) { + res = isis_snmp_adj_helper(tmp_adj, data_id, data_off, + &data, &data_len); + if (res) + adj = tmp_adj; + + break; + } + } + + if (adj == NULL) + return 0; + + if (ret_adj != NULL) + *ret_adj = adj; + + if (ret_data_idx != NULL) + *ret_data_idx = data_off + 1; + + if (ret_data) + *ret_data = data; + + if (ret_data_len) + *ret_data_len = data_len; + + return 1; +} + +static int isis_snmp_adj_lookup_next(oid *oid_idx, size_t oid_idx_len, + int data_id, + struct isis_adjacency **ret_adj, + oid *ret_data_idx, uint8_t **ret_data, + size_t *ret_data_len) +{ + struct listnode *node; + struct isis_circuit *circuit; + struct isis_adjacency *adj; + struct isis_adjacency *tmp_adj; + oid circ_idx; + oid adj_idx; + oid data_idx; + uint8_t *data; + size_t data_len; + + adj = NULL; + data = NULL; + data_len = 0; + + /* + * Note: we rely on the fact that data indexes are consequtive + * starting from 1 + */ + + if (oid_idx == 0 || oid_idx_len == 0) { + circ_idx = 0; + adj_idx = 0; + data_idx = 0; + } else if (oid_idx_len == 1) { + circ_idx = oid_idx[0]; + adj_idx = 0; + data_idx = 0; + } else if (oid_idx_len == 2) { + circ_idx = oid_idx[0]; + adj_idx = oid_idx[1]; + data_idx = 0; + } else { + circ_idx = oid_idx[0]; + adj_idx = oid_idx[1]; + + if (data_id == ISIS_SNMP_ADJ_DATA_NONE) + data_idx = 0; + else + data_idx = oid_idx[2]; + } + + if (!isis_snmp_circuit_lookup_exact(&circ_idx, 1, &circuit) + && !isis_snmp_circuit_lookup_next(&circ_idx, 1, &circuit)) + /* No circuit */ + return 0; + + if (circuit->snmp_id != circ_idx) { + /* Match is not exact */ + circ_idx = 0; + adj_idx = 0; + data_idx = 0; + } + + /* + * Note: the simple loop below will work in all cases + */ + while (circuit != NULL) { + for (ALL_LIST_ELEMENTS_RO(circuit->snmp_adj_list, node, + tmp_adj)) { + if (tmp_adj->snmp_idx < adj_idx) + continue; + + if (tmp_adj->snmp_idx == adj_idx + && data_id == ISIS_SNMP_ADJ_DATA_NONE) + continue; + + if (adj_idx != 0 && tmp_adj->snmp_idx > adj_idx) + data_idx = 0; + + if (isis_snmp_adj_helper(tmp_adj, data_id, data_idx, + &data, &data_len)) { + adj = tmp_adj; + break; + } + } + + if (adj != NULL) + break; + + circuit = isis_snmp_circuit_next(circuit); + circ_idx = 0; + adj_idx = 0; + data_idx = 0; + } + + if (adj == NULL) + return 0; + + if (ret_adj != NULL) + *ret_adj = adj; + + if (ret_data_idx != 0) { + if (data_id == ISIS_SNMP_ADJ_DATA_NONE) + /* + * Value does not matter but let us set + * it to zero for consistency + */ + *ret_data_idx = 0; + else + *ret_data_idx = data_idx + 1; + } + + if (ret_data != 0) + *ret_data = data; + + if (ret_data_len != 0) + *ret_data_len = data_len; + + return 1; +} + +static uint8_t *isis_snmp_find_sys_object(struct variable *v, oid *name, + size_t *length, int exact, + size_t *var_len, + WriteMethod **write_method) +{ + struct isis_area *area = NULL; + struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT); + + if (isis == NULL) + return NULL; + + if (!list_isempty(isis->area_list)) + area = listgetdata(listhead(isis->area_list)); + + /* Check whether the instance identifier is valid */ + if (smux_header_generic(v, name, length, exact, var_len, write_method) + == MATCH_FAILED) + return NULL; + + switch (v->magic) { + case ISIS_SYS_VERSION: + return SNMP_INTEGER(ISIS_VERSION); + + case ISIS_SYS_LEVELTYPE: + /* + * If we do not have areas use 1&2 otherwise use settings + * from the first area in the list + */ + if (area == NULL) + return SNMP_INTEGER(IS_LEVEL_1_AND_2); + + return SNMP_INTEGER(area->is_type); + + case ISIS_SYS_ID: + if (!isis->sysid_set) { + *var_len = ISIS_SYS_ID_LEN; + return isis_null_sysid; + } + + *var_len = ISIS_SYS_ID_LEN; + return isis->sysid; + + case ISIS_SYS_MAXPATHSPLITS: + return SNMP_INTEGER(ISIS_SNMP_MAX_PATH_SPLITS); + + case ISIS_SYS_MAXLSPGENINT: + return SNMP_INTEGER(DEFAULT_MAX_LSP_GEN_INTERVAL); + + case ISIS_SYS_POLLESHELLORATE: + return SNMP_INTEGER(DEFAULT_HELLO_INTERVAL); + + case ISIS_SYS_WAITTIME: + /* Note: it seems that we have same fixed delay time */ + return SNMP_INTEGER(DEFAULT_MIN_LSP_GEN_INTERVAL); + + case ISIS_SYS_ADMINSTATE: + /* If daemon is running it admin state is on */ + return SNMP_INTEGER(ISIS_SNMP_ADMIN_STATE_ON); + + + case ISIS_SYS_L2TOL1LEAKING: + /* We do not allow l2-to-l1 leaking */ + return SNMP_INTEGER(ISIS_SNMP_TRUTH_VALUE_FALSE); + + case ISIS_SYS_MAXAGE: + return SNMP_INTEGER(MAX_AGE); + + case ISIS_SYS_RECEIVELSPBUFFERSIZE: + if (area == NULL) + return SNMP_INTEGER(DEFAULT_LSP_MTU); + + return SNMP_INTEGER(area->lsp_mtu); + + case ISIS_SYS_PROTSUPPORTED: + *var_len = 1; + return &isis_snmp_protocols_supported; + + case ISIS_SYS_NOTIFICATIONENABLE: + if (isis->snmp_notifications) + return SNMP_INTEGER(ISIS_SNMP_TRUTH_VALUE_TRUE); + + return SNMP_INTEGER(ISIS_SNMP_TRUTH_VALUE_FALSE); + + default: + break; + } + + return NULL; +} + + +static uint8_t *isis_snmp_find_man_area(struct variable *v, oid *name, + size_t *length, int exact, + size_t *var_len, + WriteMethod **write_method) +{ + int res; + struct area_addr *area_addr = NULL; + oid *oid_idx; + size_t oid_idx_len; + size_t off = 0; + + *write_method = NULL; + + if (*length <= v->namelen) { + oid_idx = NULL; + oid_idx_len = 0; + } else if (memcmp(name, v->name, v->namelen * sizeof(oid)) != 0) { + oid_idx = NULL; + oid_idx_len = 0; + } else { + oid_idx = name + v->namelen; + oid_idx_len = *length - v->namelen; + } + + if (exact) { + res = isis_snmp_area_addr_lookup_exact(oid_idx, oid_idx_len, + NULL, &area_addr); + + if (!res) + return NULL; + + } else { + res = isis_snmp_area_addr_lookup_next(oid_idx, oid_idx_len, + NULL, &area_addr); + + if (!res) + return NULL; + + /* Copy the name out */ + memcpy(name, v->name, v->namelen * sizeof(oid)); + + /* Append index */ + name[v->namelen] = area_addr->addr_len; + + for (off = 0; off < area_addr->addr_len; off++) + name[v->namelen + 1 + off] = area_addr->area_addr[off]; + + *length = v->namelen + 1 + area_addr->addr_len; + } + + switch (v->magic) { + case ISIS_MANAREA_ADDREXISTSTATE: + return SNMP_INTEGER(ISIS_SNMP_ROW_STATUS_ACTIVE); + + default: + break; + } + + return NULL; +} + +static uint8_t *isis_snmp_find_area_addr(struct variable *v, oid *name, + size_t *length, int exact, + size_t *var_len, + WriteMethod **write_method) +{ + /* + * Area addresses in sense of addresses reported by L1 lsps + * are not supported yet. + */ + (void)v; + (void)name; + (void)length; + (void)exact; + (void)var_len; + + + *write_method = NULL; + + return NULL; +} + +static uint8_t *isis_snmp_find_summ_addr(struct variable *v, oid *name, + size_t *length, int exact, + size_t *var_len, + WriteMethod **write_method) +{ + /* + * So far there is no way to set summary table values through cli + * and snmp operations are read-only, hence there are no entries + */ + (void)v; + (void)name; + (void)length; + (void)exact; + (void)var_len; + *write_method = NULL; + + return NULL; +} + +static uint8_t *isis_snmp_find_redistribute_addr(struct variable *v, oid *name, + size_t *length, int exact, + size_t *var_len, + WriteMethod **write_method) +{ + /* + * It is not clear at the point whether redist code in isis is actually + * used for now we will consider that entries are not present + */ + (void)v; + (void)name; + (void)length; + (void)exact; + (void)var_len; + *write_method = NULL; + + return NULL; +} + +static uint8_t *isis_snmp_find_router(struct variable *v, oid *name, + size_t *length, int exact, + size_t *var_len, + WriteMethod **write_method) +{ + uint8_t cmp_buf[ISIS_SYS_ID_LEN]; + size_t cmp_len; + int try_exact; + int cmp_level; + int res; + struct isis_dynhn *dyn = NULL; + oid *oid_idx; + size_t oid_idx_len; + size_t off = 0; + + *write_method = NULL; + + if (*length <= v->namelen) { + oid_idx = NULL; + oid_idx_len = 0; + } else if (memcmp(name, v->name, v->namelen * sizeof(oid)) != 0) { + oid_idx = NULL; + oid_idx_len = 0; + } else { + oid_idx = name + v->namelen; + oid_idx_len = *length - v->namelen; + } + + if (exact) { + res = isis_snmp_conv_exact(cmp_buf, sizeof(cmp_buf), &cmp_len, + oid_idx, oid_idx_len); + + if (!res || cmp_len != ISIS_SYS_ID_LEN + || oid_idx_len != (cmp_len + 2)) + /* + * Bad conversion, or bad length, + * or extra oids at the end + */ + return NULL; + + if (oid_idx[ISIS_SYS_ID_LEN + 1] < IS_LEVEL_1 + || oid_idx[ISIS_SYS_ID_LEN + 1] > IS_LEVEL_2) + /* Level part of the index is out of range */ + return NULL; + + cmp_level = (int)oid_idx[ISIS_SYS_ID_LEN + 1]; + + dyn = dynhn_find_by_id(cmp_buf); + + if (dyn == NULL || dyn->level != cmp_level) + return NULL; + + switch (v->magic) { + case ISIS_ROUTER_HOSTNAME: + *var_len = strlen(dyn->hostname); + return (uint8_t *)dyn->hostname; + + case ISIS_ROUTER_ID: + /* It seems that we do no know router-id in lsps */ + return SNMP_INTEGER(0); + + default: + break; + } + + return NULL; + } + + res = isis_snmp_conv_next(cmp_buf, sizeof(cmp_buf), &cmp_len, + &try_exact, oid_idx, oid_idx_len); + + + if (!res) + /* Bad conversion */ + return NULL; + + if (cmp_len != ISIS_SYS_ID_LEN) { + /* We do not have valid index oids */ + memset(cmp_buf, 0, sizeof(cmp_buf)); + cmp_level = 0; + } else if (try_exact) + /* + * We have no valid level index. + * Let start from non-existing level 0 and + * hence not need to do exact match + */ + cmp_level = 0; + else if (oid_idx_len < (ISIS_SYS_ID_LEN + 2)) + cmp_level = 0; + else if (oid_idx[ISIS_SYS_ID_LEN + 1] <= IS_LEVEL_2) + cmp_level = (int)oid_idx[ISIS_SYS_ID_LEN + 1]; + else + /* + * Any value greater than 2 will have the same result + * but we can have integer overflows, hence 3 is a reasonable + * choice + */ + cmp_level = (int)(IS_LEVEL_2 + 1); + + dyn = dynhn_snmp_next(cmp_buf, cmp_level); + + if (dyn == NULL) + return NULL; + + /* Copy the name out */ + memcpy(name, v->name, v->namelen * sizeof(oid)); + + /* Append index */ + name[v->namelen] = ISIS_SYS_ID_LEN; + + for (off = 0; off < ISIS_SYS_ID_LEN; off++) + name[v->namelen + 1 + off] = dyn->id[off]; + + name[v->namelen + 1 + ISIS_SYS_ID_LEN] = (oid)dyn->level; + + /* Set length */ + *length = v->namelen + 1 + ISIS_SYS_ID_LEN + 1; + + switch (v->magic) { + case ISIS_ROUTER_HOSTNAME: + *var_len = strlen(dyn->hostname); + return (uint8_t *)dyn->hostname; + + case ISIS_ROUTER_ID: + /* It seems that we do no know router-id in lsps */ + return SNMP_INTEGER(0); + + default: + break; + } + + return NULL; +} + +static uint8_t *isis_snmp_find_sys_level(struct variable *v, oid *name, + size_t *length, int exact, + size_t *var_len, + WriteMethod **write_method) +{ + oid *oid_idx; + size_t oid_idx_len; + int level; + int level_match; + struct isis_area *area = NULL; + struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT); + + if (isis == NULL) + return NULL; + + *write_method = NULL; + + if (*length <= v->namelen) { + oid_idx = NULL; + oid_idx_len = 0; + } else if (memcmp(name, v->name, v->namelen * sizeof(oid)) != 0) { + oid_idx = NULL; + oid_idx_len = 0; + } else { + oid_idx = name + v->namelen; + oid_idx_len = *length - v->namelen; + } + + if (exact) { + if (oid_idx == NULL || oid_idx_len != 1) + return NULL; + + if (oid_idx[0] == IS_LEVEL_1) + level = IS_LEVEL_1; + else if (oid_idx[0] == IS_LEVEL_2) + level = IS_LEVEL_2; + else + return NULL; + + } else { + if (oid_idx == NULL) + level = IS_LEVEL_1; + else if (oid_idx_len == 0) + level = IS_LEVEL_1; + else if (oid_idx[0] < IS_LEVEL_1) + level = IS_LEVEL_1; + else if (oid_idx[0] < IS_LEVEL_2) + level = IS_LEVEL_2; + else + return NULL; + + /* Copy the name out */ + memcpy(name, v->name, v->namelen * sizeof(oid)); + + /* Append index */ + name[v->namelen] = level; + + /* Set length */ + *length = v->namelen + 1; + } + + area = NULL; + + if (!list_isempty(isis->area_list)) + area = listgetdata(listhead(isis->area_list)); + + level_match = 0; + + if (area != NULL) + level_match = isis_snmp_get_level_match(area->is_type, level); + + switch (v->magic) { + case ISIS_SYSLEVEL_ORIGLSPBUFFSIZE: + if (level_match) + return SNMP_INTEGER(area->lsp_mtu); + + return SNMP_INTEGER(DEFAULT_LSP_MTU); + + case ISIS_SYSLEVEL_MINLSPGENINT: + if (level_match) + return SNMP_INTEGER(area->lsp_gen_interval[level - 1]); + else + return SNMP_INTEGER(DEFAULT_MIN_LSP_GEN_INTERVAL); + + case ISIS_SYSLEVEL_STATE: + if (level_match) { + if (area->overload_bit) + return SNMP_INTEGER( + ISIS_SNMP_LEVEL_STATE_OVERLOADED); + + return SNMP_INTEGER(ISIS_SNMP_LEVEL_STATE_ON); + } + return SNMP_INTEGER(ISIS_SNMP_LEVEL_STATE_OFF); + + case ISIS_SYSLEVEL_SETOVERLOAD: + if (level_match && area->overload_bit) + return SNMP_INTEGER(ISIS_SNMP_TRUTH_VALUE_TRUE); + + return SNMP_INTEGER(ISIS_SNMP_TRUTH_VALUE_FALSE); + + case ISIS_SYSLEVEL_SETOVERLOADUNTIL: + /* We do not have automatic cleanup of overload bit */ + return SNMP_INTEGER(0); + + case ISIS_SYSLEVEL_METRICSTYLE: + if (level_match) { + if (area->newmetric && area->oldmetric) + return SNMP_INTEGER( + ISIS_SNMP_METRIC_STYLE_BOTH); + + if (area->newmetric) + return SNMP_INTEGER( + ISIS_SNMP_METRIC_STYLE_WIDE); + + return SNMP_INTEGER(ISIS_SNMP_METRIC_STYLE_NARROW); + } + return SNMP_INTEGER(ISIS_SNMP_METRIC_STYLE_NARROW); + + case ISIS_SYSLEVEL_SPFCONSIDERS: + return SNMP_INTEGER(ISIS_SNMP_METRIC_STYLE_BOTH); + + case ISIS_SYSLEVEL_TEENABLED: + if (level_match && IS_MPLS_TE(area->mta)) + return SNMP_INTEGER(ISIS_SNMP_TRUTH_VALUE_TRUE); + + return SNMP_INTEGER(ISIS_SNMP_TRUTH_VALUE_FALSE); + + default: + break; + } + + return NULL; +} + +static uint8_t *isis_snmp_find_system_counter(struct variable *v, oid *name, + size_t *length, int exact, + size_t *var_len, + WriteMethod **write_method) +{ + oid *oid_idx; + size_t oid_idx_len; + int level; + int level_match; + struct isis_area *area = NULL; + uint32_t val; + struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT); + + if (isis == NULL) + return NULL; + + *write_method = NULL; + + if (*length <= v->namelen) { + oid_idx = NULL; + oid_idx_len = 0; + } else if (memcmp(name, v->name, v->namelen * sizeof(oid)) != 0) { + oid_idx = NULL; + oid_idx_len = 0; + } else { + oid_idx = name + v->namelen; + oid_idx_len = *length - v->namelen; + } + + if (exact) { + if (oid_idx == NULL || oid_idx_len != 1) + return 0; + + if (oid_idx[0] == IS_LEVEL_1) + level = IS_LEVEL_1; + else if (oid_idx[0] == IS_LEVEL_2) + level = IS_LEVEL_2; + else + return NULL; + + } else { + if (oid_idx == NULL) + level = IS_LEVEL_1; + else if (oid_idx_len == 0) + level = IS_LEVEL_1; + else if (oid_idx[0] < IS_LEVEL_1) + level = IS_LEVEL_1; + else if (oid_idx[0] < IS_LEVEL_2) + level = IS_LEVEL_2; + else + return NULL; + + /* Copy the name out */ + memcpy(name, v->name, v->namelen * sizeof(oid)); + + /* Append index */ + name[v->namelen] = level; + + /* Set length */ + *length = v->namelen + 1; + } + + area = NULL; + + if (!list_isempty(isis->area_list)) + area = listgetdata(listhead(isis->area_list)); + + level_match = 0; + + if (area != NULL) + level_match = isis_snmp_get_level_match(area->is_type, level); + + if (!level_match) + /* If level does not match all counters are zeros */ + return SNMP_INTEGER(0); + + val = 0; + + switch (v->magic) { + case ISIS_SYSSTAT_CORRLSPS: + val = 0; + break; + + case ISIS_SYSSTAT_AUTHTYPEFAILS: + val = (uint32_t)area->auth_type_failures[level - 1]; + break; + + case ISIS_SYSSTAT_AUTHFAILS: + val = (uint32_t)area->auth_failures[level - 1]; + break; + + case ISIS_SYSSTAT_LSPDBASEOLOADS: + val = area->overload_counter; + break; + + case ISIS_SYSSTAT_MANADDRDROPFROMAREAS: + /* We do not support manual addresses */ + val = 0; + break; + + case ISIS_SYSSTAT_ATTMPTTOEXMAXSEQNUMS: + val = area->lsp_exceeded_max_counter; + break; + + case ISIS_SYSSTAT_SEQNUMSKIPS: + val = area->lsp_seqno_skipped_counter; + break; + + case ISIS_SYSSTAT_OWNLSPPURGES: + if (!area->purge_originator) + val = 0; + else + val = area->lsp_purge_count[level - 1]; + break; + + case ISIS_SYSSTAT_IDFIELDLENMISMATCHES: + val = (uint32_t)area->id_len_mismatches[level - 1]; + break; + + case ISIS_SYSSTAT_PARTCHANGES: + /* Not supported */ + val = 0; + break; + + case ISIS_SYSSTAT_SPFRUNS: + val = (uint32_t)area->spf_run_count[level - 1]; + break; + + case ISIS_SYSSTAT_LSPERRORS: + val = (uint32_t)area->lsp_error_counter[level - 1]; + break; + + default: + return NULL; + } + + return SNMP_INTEGER(val); +} + +static uint8_t *isis_snmp_find_next_circ_index(struct variable *v, oid *name, + size_t *length, int exact, + size_t *var_len, + WriteMethod **write_method) +{ + /* Check whether the instance identifier is valid */ + if (smux_header_generic(v, name, length, exact, var_len, write_method) + == MATCH_FAILED) + return NULL; + + switch (v->magic) { + case ISIS_NEXTCIRC_INDEX: + /* + * We do not support circuit creation through snmp + */ + return SNMP_INTEGER(0); + + default: + break; + } + + return 0; +} + +static uint8_t *isis_snmp_find_circ(struct variable *v, oid *name, + size_t *length, int exact, size_t *var_len, + WriteMethod **write_method) +{ + /* Index is circuit-id: 1-255 */ + oid *oid_idx; + size_t oid_idx_len; + struct isis_circuit *circuit; + uint32_t up_ticks; + uint32_t delta_ticks; + uint32_t now_time; + int res; + + *write_method = NULL; + + if (*length <= v->namelen) { + oid_idx = NULL; + oid_idx_len = 0; + } else if (memcmp(name, v->name, v->namelen * sizeof(oid)) != 0) { + oid_idx = NULL; + oid_idx_len = 0; + } else { + oid_idx = name + v->namelen; + oid_idx_len = *length - v->namelen; + } + if (exact) { + res = isis_snmp_circuit_lookup_exact(oid_idx, oid_idx_len, + &circuit); + + if (!res || oid_idx_len != 1) + return NULL; + + } else { + res = isis_snmp_circuit_lookup_next(oid_idx, oid_idx_len, + &circuit); + + if (!res) + return NULL; + + /* Copy the name out */ + memcpy(name, v->name, v->namelen * sizeof(oid)); + + /* Append index */ + name[v->namelen] = circuit->snmp_id; + + /* Set length */ + *length = v->namelen + 1; + } + + switch (v->magic) { + case ISIS_CIRC_IFINDEX: + if (circuit->interface == 0) + return SNMP_INTEGER(0); + + return SNMP_INTEGER(circuit->interface->ifindex); + + case ISIS_CIRC_ADMINSTATE: + return SNMP_INTEGER(ISIS_SNMP_ADMIN_STATE_ON); + + case ISIS_CIRC_EXISTSTATE: + return SNMP_INTEGER(ISIS_SNMP_ROW_STATUS_ACTIVE); + + case ISIS_CIRC_TYPE: + /* + * Note: values do not match 100%: + * + * 1. From isis_circuit.h: + * CIRCUIT_T_UNKNOWN 0 + * CIRCUIT_T_BROADCAST 1 + * CIRCUIT_T_P2P 2 + * CIRCUIT_T_LOOPBACK 3 + * + * 2. From rfc: + * broadcast(1), + * ptToPt(2), + * staticIn(3), + * staticOut(4), + */ + + return SNMP_INTEGER(circuit->circ_type); + + case ISIS_CIRC_EXTDOMAIN: + if (circuit->ext_domain) + return SNMP_INTEGER(ISIS_SNMP_TRUTH_VALUE_TRUE); + + return SNMP_INTEGER(ISIS_SNMP_TRUTH_VALUE_FALSE); + + case ISIS_CIRC_LEVELTYPE: + return SNMP_INTEGER(circuit->is_type); + + case ISIS_CIRC_PASSIVECIRCUIT: + if (circuit->is_passive) + return SNMP_INTEGER(ISIS_SNMP_TRUTH_VALUE_TRUE); + + return SNMP_INTEGER(ISIS_SNMP_TRUTH_VALUE_FALSE); + + case ISIS_CIRC_MESHGROUPENABLED: + /* Not supported */ + return SNMP_INTEGER(ISIS_SNMP_MESH_GROUP_INACTIVE); + + case ISIS_CIRC_MESHGROUP: + /* Not supported */ + return SNMP_INTEGER(0); + + case ISIS_CIRC_SMALLHELLOS: + /* + * return false if lan hellos must be padded + */ + if (circuit->pad_hellos) + return SNMP_INTEGER(ISIS_SNMP_TRUTH_VALUE_FALSE); + + return SNMP_INTEGER(ISIS_SNMP_TRUTH_VALUE_TRUE); + + case ISIS_CIRC_LASTUPTIME: + if (circuit->last_uptime == 0) + return SNMP_INTEGER(0); + + up_ticks = (uint32_t)netsnmp_get_agent_uptime(); + now_time = isis_snmp_time(); + + if (circuit->last_uptime >= now_time) + return SNMP_INTEGER(up_ticks); + + delta_ticks = (now_time - circuit->last_uptime) * 10; + + if (up_ticks < delta_ticks) + return SNMP_INTEGER(up_ticks); + + return SNMP_INTEGER(up_ticks - delta_ticks); + + case ISIS_CIRC_3WAYENABLED: + /* Not supported */ + return SNMP_INTEGER(ISIS_SNMP_TRUTH_VALUE_FALSE); + + case ISIS_CIRC_EXTENDEDCIRCID: + /* Used for 3-way hand shake only */ + return SNMP_INTEGER(0); + + default: + break; + } + + return NULL; +} + +static uint8_t *isis_snmp_find_circ_level(struct variable *v, oid *name, + size_t *length, int exact, + size_t *var_len, + WriteMethod **write_method) +{ + static uint8_t circuit_id_val[ISIS_SYS_ID_LEN + 1]; + /* Index is circuit-id: 1-255 + level: 1-2 */ + oid *oid_idx; + size_t oid_idx_len; + int res; + struct isis_circuit *circuit; + int level; + struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT); + + if (isis == NULL) + return NULL; + + *write_method = NULL; + + if (*length <= v->namelen) { + oid_idx = NULL; + oid_idx_len = 0; + } else if (memcmp(name, v->name, v->namelen * sizeof(oid)) != 0) { + oid_idx = NULL; + oid_idx_len = 0; + } else { + oid_idx = name + v->namelen; + oid_idx_len = *length - v->namelen; + } + if (exact) { + res = isis_snmp_circuit_level_lookup_exact(oid_idx, oid_idx_len, + 1, &circuit, &level); + + if (!res || oid_idx_len != 2) + return NULL; + + } else { + res = isis_snmp_circuit_level_lookup_next(oid_idx, oid_idx_len, + 1, &circuit, &level); + + if (!res) + return NULL; + + /* Copy the name out */ + memcpy(name, v->name, v->namelen * sizeof(oid)); + + /* Append index */ + name[v->namelen] = circuit->snmp_id; + name[v->namelen + 1] = level; + + /* Set length */ + *length = v->namelen + 2; + } + + switch (v->magic) { + case ISIS_CIRCLEVEL_METRIC: + return SNMP_INTEGER(circuit->metric[level - 1]); + + case ISIS_CIRCLEVEL_WIDEMETRIC: + if (circuit->area == NULL || !circuit->area->newmetric) { + /* What should we do if wide metric is not supported? */ + return SNMP_INTEGER(0); + } + return SNMP_INTEGER(circuit->te_metric[level - 1]); + + case ISIS_CIRCLEVEL_ISPRIORITY: + return SNMP_INTEGER(circuit->priority[level - 1]); + + case ISIS_CIRCLEVEL_IDOCTET: + return SNMP_INTEGER(circuit->circuit_id); + + case ISIS_CIRCLEVEL_ID: + if (circuit->circ_type != CIRCUIT_T_P2P) { + /* + * Unless it is point-to-point circuit, the value is and + * empty octet string + */ + *var_len = 0; + return circuit_id_val; + } + + /* !!!!!! Circuit-id is zero for p2p links */ + if (circuit->u.p2p.neighbor == NULL + || circuit->u.p2p.neighbor->adj_state != ISIS_ADJ_UP) { + /* No adjacency or adjacency not fully up yet */ + memcpy(circuit_id_val, isis->sysid, ISIS_SYS_ID_LEN); + circuit_id_val[ISIS_SYS_ID_LEN] = circuit->circuit_id; + *var_len = ISIS_SYS_ID_LEN + 1; + return circuit_id_val; + } + + /* Adjacency fully-up */ + memcpy(circuit_id_val, circuit->u.p2p.neighbor->sysid, + ISIS_SYS_ID_LEN); + circuit_id_val[ISIS_SYS_ID_LEN] = 0; + *var_len = ISIS_SYS_ID_LEN + 1; + return circuit_id_val; + + case ISIS_CIRCLEVEL_DESIS: + if (circuit->circ_type != CIRCUIT_T_BROADCAST + || !circuit->u.bc.is_dr[level - 1]) { + /* + * Unless it is lan circuit participating in dis process + * the value is an empty octet string + */ + *var_len = 0; + return circuit_id_val; + } + + *var_len = ISIS_SYS_ID_LEN + 1; + + if (level == IS_LEVEL_1) + return circuit->u.bc.l1_desig_is; + + return circuit->u.bc.l2_desig_is; + + case ISIS_CIRCLEVEL_HELLOMULTIPLIER: + return SNMP_INTEGER(circuit->hello_multiplier[level - 1]); + + case ISIS_CIRCLEVEL_HELLOTIMER: + return SNMP_INTEGER(circuit->hello_interval[level - 1] * 1000); + + case ISIS_CIRCLEVEL_DRHELLOTIMER: + return SNMP_INTEGER(circuit->hello_interval[level - 1] * 1000); + + case ISIS_CIRCLEVEL_LSPTHROTTLE: + if (circuit->area) + return SNMP_INTEGER( + circuit->area->min_spf_interval[level - 1] + * 1000); + else + return SNMP_INTEGER(0); + + case ISIS_CIRCLEVEL_MINLSPRETRANSINT: + if (circuit->area) + return SNMP_INTEGER( + circuit->area->min_spf_interval[level - 1]); + else + return SNMP_INTEGER(0); + + case ISIS_CIRCLEVEL_CSNPINTERVAL: + return SNMP_INTEGER(circuit->csnp_interval[level - 1]); + + case ISIS_CIRCLEVEL_PARTSNPINTERVAL: + return SNMP_INTEGER(circuit->psnp_interval[level - 1]); + + default: + break; + } + + return NULL; +} + +static uint8_t *isis_snmp_find_circ_counter(struct variable *v, oid *name, + size_t *length, int exact, + size_t *var_len, + WriteMethod **write_method) +{ + /* Index circuit-id 1-255 + level */ + oid *oid_idx; + size_t oid_idx_len; + int res; + struct isis_circuit *circuit; + int level; + uint32_t val = 0; + + *write_method = NULL; + + if (*length <= v->namelen) { + oid_idx = NULL; + oid_idx_len = 0; + } else if (memcmp(name, v->name, v->namelen * sizeof(oid)) != 0) { + oid_idx = NULL; + oid_idx_len = 0; + } else { + oid_idx = name + v->namelen; + oid_idx_len = *length - v->namelen; + } + if (exact) { + res = isis_snmp_circuit_level_lookup_exact(oid_idx, oid_idx_len, + 1, &circuit, &level); + + if (!res || oid_idx_len != 2) + return NULL; + + } else { + res = isis_snmp_circuit_level_lookup_next(oid_idx, oid_idx_len, + 1, &circuit, &level); + + if (!res) + return NULL; + + /* Copy the name out */ + memcpy(name, v->name, v->namelen * sizeof(oid)); + + /* Append index */ + name[v->namelen] = circuit->snmp_id; + if (circuit->circ_type == CIRCUIT_T_P2P) + name[v->namelen + 1] = ISIS_SNMP_P2P_CIRCUIT; + else + name[v->namelen + 1] = level; + + /* Set length */ + *length = v->namelen + 2; + } + + switch (v->magic) { + case ISIS_CIRC_ADJCHANGES: + val = circuit->adj_state_changes; + break; + + case ISIS_CIRC_NUMADJ: + if (circuit->circ_type == CIRCUIT_T_P2P) { + val = circuit->u.p2p.neighbor == NULL ? 0 : 1; + break; + } + + if (circuit->circ_type != CIRCUIT_T_BROADCAST) { + val = 0; + break; + } + + if (level == IS_LEVEL_1) { + if (circuit->u.bc.adjdb[0] == NULL) + val = 0; + else + val = listcount(circuit->u.bc.adjdb[0]); + break; + } + + if (circuit->u.bc.adjdb[1] == NULL) + val = 0; + else + val = listcount(circuit->u.bc.adjdb[1]); + + break; + + case ISIS_CIRC_INITFAILS: + val = circuit->init_failures; /* counter never incremented */ + break; + + case ISIS_CIRC_REJADJS: + val = circuit->rej_adjacencies; + break; + + case ISIS_CIRC_IDFIELDLENMISMATCHES: + val = circuit->id_len_mismatches; + break; + + case ISIS_CIRC_MAXAREAADDRMISMATCHES: + val = circuit->max_area_addr_mismatches; + break; + + case ISIS_CIRC_AUTHTYPEFAILS: + val = circuit->auth_type_failures; + break; + + case ISIS_CIRC_AUTHFAILS: + val = circuit->auth_failures; + break; + + case ISIS_CIRC_LANDESISCHANGES: + if (circuit->circ_type == CIRCUIT_T_P2P) + val = 0; + else + val = circuit->desig_changes[level - 1]; + break; + + default: + return NULL; + } + + return SNMP_INTEGER(val); +} + +static uint8_t *isis_snmp_find_isadj(struct variable *v, oid *name, + size_t *length, int exact, size_t *var_len, + WriteMethod **write_method) +{ + /* Index is circuit-id: 1-255 + adj-id: 1-... */ + oid *oid_idx; + size_t oid_idx_len; + int res; + uint32_t val; + struct isis_adjacency *adj; + uint32_t up_ticks; + uint32_t delta_ticks; + uint32_t now_time; + + *write_method = NULL; + + if (*length <= v->namelen) { + oid_idx = NULL; + oid_idx_len = 0; + } else if (memcmp(name, v->name, v->namelen * sizeof(oid)) != 0) { + oid_idx = NULL; + oid_idx_len = 0; + } else { + oid_idx = name + v->namelen; + oid_idx_len = *length - v->namelen; + } + if (exact) { + res = isis_snmp_adj_lookup_exact(oid_idx, oid_idx_len, + ISIS_SNMP_ADJ_DATA_NONE, &adj, + NULL, NULL, NULL); + + if (!res || oid_idx_len != 2) + return NULL; + + } else { + res = isis_snmp_adj_lookup_next(oid_idx, oid_idx_len, + ISIS_SNMP_ADJ_DATA_NONE, &adj, + NULL, NULL, NULL); + if (!res) + return NULL; + + /* Copy the name out */ + memcpy(name, v->name, v->namelen * sizeof(oid)); + + /* Append index */ + name[v->namelen] = adj->circuit->snmp_id; + name[v->namelen + 1] = adj->snmp_idx; + + /* Set length */ + *length = v->namelen + 2; + } + + switch (v->magic) { + case ISIS_ISADJ_STATE: + val = ISIS_SNMP_ADJ_STATE_DOWN; + + switch (adj->adj_state) { + case ISIS_ADJ_UNKNOWN: + case ISIS_ADJ_DOWN: + val = ISIS_SNMP_ADJ_STATE_DOWN; + break; + + case ISIS_ADJ_INITIALIZING: + val = ISIS_SNMP_ADJ_STATE_INITIALIZING; + break; + + case ISIS_ADJ_UP: + val = ISIS_SNMP_ADJ_STATE_UP; + break; + } + + return SNMP_INTEGER(val); + + case ISIS_ISADJ_3WAYSTATE: + return SNMP_INTEGER(adj->threeway_state); + + case ISIS_ISADJ_NEIGHSNPAADDRESS: { + const char *snpa = (char *)snpa_print(adj->snpa); + *var_len = strlen(snpa); + return (uint8_t *)snpa; + } + + case ISIS_ISADJ_NEIGHSYSTYPE: + val = ISIS_SNMP_ADJ_NEIGHTYPE_UNKNOWN; + + switch (adj->sys_type) { + case ISIS_SYSTYPE_UNKNOWN: + case ISIS_SYSTYPE_ES: + val = ISIS_SNMP_ADJ_NEIGHTYPE_UNKNOWN; + break; + + case ISIS_SYSTYPE_IS: + val = ISIS_SNMP_ADJ_NEIGHTYPE_IS_L1_L2; + break; + + case ISIS_SYSTYPE_L1_IS: + val = ISIS_SNMP_ADJ_NEIGHTYPE_IS_L1; + break; + + case ISIS_SYSTYPE_L2_IS: + val = ISIS_SNMP_ADJ_NEIGHTYPE_IS_L2; + break; + } + + return SNMP_INTEGER(val); + + case ISIS_ISADJ_NEIGHSYSID: + *var_len = sizeof(adj->sysid); + return adj->sysid; + + case ISIS_ISADJ_NBREXTENDEDCIRCID: + return SNMP_INTEGER(adj->ext_circuit_id != 0 ? 1 : 0); + + case ISIS_ISADJ_USAGE: + /* It seems that no value conversion is required */ + return SNMP_INTEGER(adj->adj_usage); + + case ISIS_ISADJ_HOLDTIMER: + /* + * It seems that we want remaining timer + */ + if (adj->last_upd != 0) { + val = isis_snmp_time(); + if (val < (adj->last_upd + adj->hold_time)) + return SNMP_INTEGER(adj->last_upd + + adj->hold_time - val); + } + /* Not running or just expired */ + return SNMP_INTEGER(0); + + case ISIS_ISADJ_NEIGHPRIORITY: + return SNMP_INTEGER(adj->prio[adj->level - 1]); + + case ISIS_ISADJ_LASTUPTIME: + if (adj->flaps == 0) + return SNMP_INTEGER(0); + + up_ticks = (uint32_t)netsnmp_get_agent_uptime(); + + now_time = isis_snmp_time(); + + if (adj->last_flap >= now_time) + return SNMP_INTEGER(up_ticks); + + delta_ticks = (now_time - adj->last_flap) * 10; + + if (up_ticks < delta_ticks) + return SNMP_INTEGER(up_ticks); + + return SNMP_INTEGER(up_ticks - delta_ticks); + + default: + break; + } + + return NULL; +} + +static uint8_t *isis_snmp_find_isadj_area(struct variable *v, oid *name, + size_t *length, int exact, + size_t *var_len, + WriteMethod **write_method) +{ + /* Index circuit-id: 1-255 + adj-id: 1-... */ + oid *oid_idx; + size_t oid_idx_len; + int res; + struct isis_adjacency *adj; + oid data_idx; + uint8_t *data; + size_t data_len; + + *write_method = NULL; + + if (*length <= v->namelen) { + oid_idx = NULL; + oid_idx_len = 0; + } else if (memcmp(name, v->name, v->namelen * sizeof(oid)) != 0) { + oid_idx = NULL; + oid_idx_len = 0; + } else { + oid_idx = name + v->namelen; + oid_idx_len = *length - v->namelen; + } + if (exact) { + res = isis_snmp_adj_lookup_exact(oid_idx, oid_idx_len, + ISIS_SNMP_ADJ_DATA_AREA_ADDR, + &adj, NULL, &data, &data_len); + + if (!res || oid_idx_len != 3) + return NULL; + + } else { + res = isis_snmp_adj_lookup_next( + oid_idx, oid_idx_len, ISIS_SNMP_ADJ_DATA_AREA_ADDR, + &adj, &data_idx, &data, &data_len); + if (!res) + return NULL; + + /* Copy the name out */ + memcpy(name, v->name, v->namelen * sizeof(oid)); + + /* Append index */ + name[v->namelen] = adj->circuit->snmp_id; + name[v->namelen + 1] = adj->snmp_idx; + name[v->namelen + 2] = data_idx; + + /* Set length */ + *length = v->namelen + 3; + } + + switch (v->magic) { + case ISIS_ISADJAREA_ADDRESS: + *var_len = data_len; + return data; + + default: + break; + } + + return NULL; +} + +static uint8_t *isis_snmp_find_isadj_ipaddr(struct variable *v, oid *name, + size_t *length, int exact, + size_t *var_len, + WriteMethod **write_method) +{ + /* Index circuit-id 1-255 + adj-id 1-... */ + oid *oid_idx; + size_t oid_idx_len; + int res; + struct isis_adjacency *adj; + oid data_idx; + uint8_t *data; + size_t data_len; + + *write_method = NULL; + + if (*length <= v->namelen) { + oid_idx = NULL; + oid_idx_len = 0; + } else if (memcmp(name, v->name, v->namelen * sizeof(oid)) != 0) { + oid_idx = NULL; + oid_idx_len = 0; + } else { + oid_idx = name + v->namelen; + oid_idx_len = *length - v->namelen; + } + if (exact) { + res = isis_snmp_adj_lookup_exact(oid_idx, oid_idx_len, + ISIS_SNMP_ADJ_DATA_IP_ADDR, + &adj, NULL, &data, &data_len); + + if (!res || oid_idx_len != 3) + return NULL; + } else { + res = isis_snmp_adj_lookup_next( + oid_idx, oid_idx_len, ISIS_SNMP_ADJ_DATA_IP_ADDR, &adj, + &data_idx, &data, &data_len); + if (!res) + return NULL; + + /* Copy the name out */ + memcpy(name, v->name, v->namelen * sizeof(oid)); + + /* Append index */ + name[v->namelen] = adj->circuit->snmp_id; + name[v->namelen + 1] = adj->snmp_idx; + name[v->namelen + 2] = data_idx; + + /* Set length */ + *length = v->namelen + 3; + } + + switch (v->magic) { + case ISIS_ISADJIPADDR_TYPE: + if (data_len == 4) + return SNMP_INTEGER(ISIS_SNMP_INET_TYPE_V4); + + return SNMP_INTEGER(ISIS_SNMP_INET_TYPE_V6); + + case ISIS_ISADJIPADDR_ADDRESS: + *var_len = data_len; + return data; + + default: + break; + } + + return NULL; +} + +static uint8_t *isis_snmp_find_isadj_prot_supp(struct variable *v, oid *name, + size_t *length, int exact, + size_t *var_len, + WriteMethod **write_method) +{ + /* Index circuit-id 1-255 + adj-id 1-... */ + oid *oid_idx; + size_t oid_idx_len; + int res; + struct isis_adjacency *adj; + oid data_idx; + uint8_t *data; + size_t data_len; + + *write_method = NULL; + + if (*length <= v->namelen) { + oid_idx = NULL; + oid_idx_len = 0; + } else if (memcmp(name, v->name, v->namelen * sizeof(oid)) != 0) { + oid_idx = NULL; + oid_idx_len = 0; + } else { + oid_idx = name + v->namelen; + oid_idx_len = *length - v->namelen; + } + if (exact) { + res = isis_snmp_adj_lookup_exact(oid_idx, oid_idx_len, + ISIS_SNMP_ADJ_DATA_PROTO, &adj, + NULL, &data, &data_len); + + if (!res || oid_idx_len != 3) + return NULL; + + } else { + res = isis_snmp_adj_lookup_next(oid_idx, oid_idx_len, + ISIS_SNMP_ADJ_DATA_PROTO, &adj, + &data_idx, &data, &data_len); + if (!res) + return NULL; + + /* Copy the name out */ + memcpy(name, v->name, v->namelen * sizeof(oid)); + + /* Append index */ + name[v->namelen] = adj->circuit->snmp_id; + name[v->namelen + 1] = adj->snmp_idx; + name[v->namelen + 2] = data_idx; + + /* Set length */ + *length = v->namelen + 3; + } + + switch (v->magic) { + case ISIS_ISADJPROTSUPP_PROTOCOL: + return SNMP_INTEGER(*data); + + default: + break; + } + + return NULL; +} + + +/* Register ISIS-MIB. */ +static int isis_snmp_init(struct thread_master *tm) +{ + struct isis_func_to_prefix *h2f = isis_func_to_prefix_arr; + struct variable *v; + + for (size_t off = 0; off < isis_var_count; off++) { + v = &isis_var_arr[off]; + + if (v->findVar != h2f->ihtp_func) { + /* Next table */ + h2f++; + assert(h2f < (isis_func_to_prefix_arr + + isis_func_to_prefix_count)); + assert(v->findVar == h2f->ihtp_func); + } + + v->namelen = h2f->ihtp_pref_len + 1; + memcpy(v->name, h2f->ihtp_pref_oid, + h2f->ihtp_pref_len * sizeof(oid)); + v->name[h2f->ihtp_pref_len] = v->magic; + } + + + smux_init(tm); + REGISTER_MIB("mibII/isis", isis_var_arr, variable, isis_oid); + return 0; +} + +/* + * ISIS notification functions: we have one function per notification + */ +static int isis_snmp_trap_throttle(oid trap_id) +{ + time_t time_now; + struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT); + + if (isis == NULL || !isis->snmp_notifications || !smux_enabled()) + return 0; + + time_now = isis_snmp_time(); + + if ((isis_snmp_trap_timestamp[trap_id] + 5) > time_now) + /* Throttle trap rate at 1 in 5 secs */ + return 0; + + isis_snmp_trap_timestamp[trap_id] = time_now; + return 1; +} + +static int isis_snmp_db_overload_update(const struct isis_area *area) +{ + netsnmp_variable_list *notification_vars; + long val; + uint32_t off; + + if (!isis_snmp_trap_throttle(ISIS_TRAP_DB_OVERLOAD)) + return 0; + + notification_vars = NULL; + + /* Put in trap value */ + snmp_varlist_add_variable(¬ification_vars, isis_snmp_trap_var, + ARRAY_SIZE(isis_snmp_trap_var), ASN_OBJECT_ID, + (uint8_t *)&isis_snmp_trap_val_db_overload, + sizeof(isis_snmp_trap_val_db_overload)); + + /* Prepare data */ + val = area->is_type; + + snmp_varlist_add_variable( + ¬ification_vars, isis_snmp_trap_data_var_sys_level_index, + ARRAY_SIZE(isis_snmp_trap_data_var_sys_level_index), INTEGER, + (uint8_t *)&val, sizeof(val)); + + /* Patch sys_level_state with proper index */ + off = ARRAY_SIZE(isis_snmp_trap_data_var_sys_level_state) - 1; + isis_snmp_trap_data_var_sys_level_state[off] = val; + + /* Prepare data */ + if (area->overload_bit) + val = ISIS_SNMP_LEVEL_STATE_OVERLOADED; + else + val = ISIS_SNMP_LEVEL_STATE_ON; + + snmp_varlist_add_variable( + ¬ification_vars, isis_snmp_trap_data_var_sys_level_state, + ARRAY_SIZE(isis_snmp_trap_data_var_sys_level_state), INTEGER, + (uint8_t *)&val, sizeof(val)); + + send_v2trap(notification_vars); + snmp_free_varbind(notification_vars); + smux_events_update(); + return 0; +} + +static int isis_snmp_lsp_exceed_max_update(const struct isis_area *area, + const uint8_t *lsp_id) +{ + netsnmp_variable_list *notification_vars; + long val; + + if (!isis_snmp_trap_throttle(ISIS_TRAP_LSP_EXCEED_MAX)) + return 0; + + notification_vars = NULL; + + /* Put in trap value */ + snmp_varlist_add_variable(¬ification_vars, isis_snmp_trap_var, + ARRAY_SIZE(isis_snmp_trap_var), ASN_OBJECT_ID, + (uint8_t *)&isis_snmp_trap_val_lsp_exceed_max, + sizeof(isis_snmp_trap_val_lsp_exceed_max)); + + /* Prepare data */ + val = area->is_type; + + snmp_varlist_add_variable( + ¬ification_vars, isis_snmp_trap_data_var_sys_level_index, + ARRAY_SIZE(isis_snmp_trap_data_var_sys_level_index), INTEGER, + (uint8_t *)&val, sizeof(val)); + + snmp_varlist_add_variable( + ¬ification_vars, isis_snmp_trap_data_var_pdu_lsp_id, + ARRAY_SIZE(isis_snmp_trap_data_var_pdu_lsp_id), STRING, lsp_id, + ISIS_SYS_ID_LEN + 2); + + send_v2trap(notification_vars); + snmp_free_varbind(notification_vars); + smux_events_update(); + return 0; +} + + +/* + * A common function to handle popular combination of trap objects + * isisNotificationSysLevelIndex, + * optional-object-a + * isisNotificationCircIfIndex, + * optional-object-b + */ +static void isis_snmp_update_worker_a(const struct isis_circuit *circuit, + oid trap_id, const oid *oid_a, + size_t oid_a_len, uint8_t type_a, + const void *data_a, size_t data_a_len, + const oid *oid_b, size_t oid_b_len, + uint8_t type_b, const void *data_b, + size_t data_b_len) +{ + netsnmp_variable_list *notification_vars = NULL; + oid var_name[MAX_OID_LEN]; + size_t var_count; + long val; + + /* Sanity */ + if (trap_id != ISIS_TRAP_ID_LEN_MISMATCH + && trap_id != ISIS_TRAP_MAX_AREA_ADDR_MISMATCH + && trap_id != ISIS_TRAP_OWN_LSP_PURGE + && trap_id != ISIS_TRAP_SEQNO_SKIPPED + && trap_id != ISIS_TRAP_AUTHEN_TYPE_FAILURE + && trap_id != ISIS_TRAP_AUTHEN_FAILURE + && trap_id != ISIS_TRAP_REJ_ADJACENCY) + return; + + /* Put in trap value */ + memcpy(var_name, isis_snmp_notifications, + sizeof(isis_snmp_notifications)); + var_count = ARRAY_SIZE(isis_snmp_notifications); + var_name[var_count++] = trap_id; + + /* Put in trap value */ + snmp_varlist_add_variable(¬ification_vars, isis_snmp_trap_var, + ARRAY_SIZE(isis_snmp_trap_var), ASN_OBJECT_ID, + (uint8_t *)var_name, var_count * sizeof(oid)); + + val = circuit->is_type; + snmp_varlist_add_variable( + ¬ification_vars, isis_snmp_trap_data_var_sys_level_index, + ARRAY_SIZE(isis_snmp_trap_data_var_sys_level_index), INTEGER, + (uint8_t *)&val, sizeof(val)); + + if (oid_a_len != 0) { + if (oid_a == NULL || data_a == NULL || data_a_len == 0) + return; + + snmp_varlist_add_variable(¬ification_vars, oid_a, oid_a_len, + type_a, (uint8_t *)data_a, + data_a_len); + } + + if (circuit->interface == NULL) + val = 0; + else + val = circuit->interface->ifindex; + + snmp_varlist_add_variable( + ¬ification_vars, isis_snmp_trap_data_var_circ_if_index, + ARRAY_SIZE(isis_snmp_trap_data_var_circ_if_index), UNSIGNED32, + (uint8_t *)&val, sizeof(val)); + + + if (oid_b_len != 0) { + if (oid_b == NULL || data_b == NULL || data_b_len == 0) + return; + + snmp_varlist_add_variable(¬ification_vars, oid_b, oid_b_len, + type_b, (uint8_t *)data_b, + data_b_len); + } + + send_v2trap(notification_vars); + snmp_free_varbind(notification_vars); + smux_events_update(); +} + +/* + * A common function to handle popular combination of trap objects + * isisNotificationSysLevelIndex, + * isisNotificationCircIfIndex, + * optional-var-a + * optional-var-b + * + * Note: the only difference with worker_a is order of circ-if-index vs + * optional-var-a + */ +static void isis_snmp_update_worker_b(const struct isis_circuit *circuit, + oid trap_id, const oid *oid_a, + size_t oid_a_len, uint8_t type_a, + const void *data_a, size_t data_a_len, + const oid *oid_b, size_t oid_b_len, + uint8_t type_b, const void *data_b, + size_t data_b_len) +{ + netsnmp_variable_list *notification_vars = NULL; + oid var_name[MAX_OID_LEN]; + size_t var_count; + long val; + + /* Sanity */ + if (trap_id != ISIS_TRAP_VERSION_SKEW + && trap_id != ISIS_TRAP_LSP_TOO_LARGE + && trap_id != ISIS_TRAP_ADJ_STATE_CHANGE) + return; + + /* Put in trap value */ + memcpy(var_name, isis_snmp_notifications, + sizeof(isis_snmp_notifications)); + var_count = ARRAY_SIZE(isis_snmp_notifications); + var_name[var_count++] = trap_id; + + /* Put in trap value */ + snmp_varlist_add_variable(¬ification_vars, isis_snmp_trap_var, + ARRAY_SIZE(isis_snmp_trap_var), ASN_OBJECT_ID, + (uint8_t *)var_name, var_count * sizeof(oid)); + + val = circuit->is_type; + snmp_varlist_add_variable( + ¬ification_vars, isis_snmp_trap_data_var_sys_level_index, + ARRAY_SIZE(isis_snmp_trap_data_var_sys_level_index), INTEGER, + (uint8_t *)&val, sizeof(val)); + + if (circuit->interface == NULL) + val = 0; + else + val = circuit->interface->ifindex; + + snmp_varlist_add_variable( + ¬ification_vars, isis_snmp_trap_data_var_circ_if_index, + ARRAY_SIZE(isis_snmp_trap_data_var_circ_if_index), UNSIGNED32, + (uint8_t *)&val, sizeof(val)); + + + if (oid_a_len != 0) { + if (oid_a == NULL || data_a == NULL || data_a_len == 0) + return; + + snmp_varlist_add_variable(¬ification_vars, oid_a, oid_a_len, + type_a, (uint8_t *)data_a, + data_a_len); + } + + if (oid_b_len != 0) { + if (oid_b == NULL || data_b == NULL || data_b_len == 0) + return; + + snmp_varlist_add_variable(¬ification_vars, oid_b, oid_b_len, + type_b, (uint8_t *)data_b, + data_b_len); + } + + send_v2trap(notification_vars); + snmp_free_varbind(notification_vars); + smux_events_update(); +} + + +static int isis_snmp_id_len_mismatch_update(const struct isis_circuit *circuit, + uint8_t rcv_id, const char *raw_pdu, + size_t raw_pdu_len) +{ + long val; + + if (!isis_snmp_trap_throttle(ISIS_TRAP_ID_LEN_MISMATCH)) + return 0; + + val = rcv_id; + + if (raw_pdu_len > ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN) + raw_pdu_len = ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN; + + isis_snmp_update_worker_a( + circuit, ISIS_TRAP_ID_LEN_MISMATCH, + isis_snmp_trap_data_var_pdu_field_len, + ARRAY_SIZE(isis_snmp_trap_data_var_pdu_field_len), UNSIGNED32, + &val, sizeof(val), isis_snmp_trap_data_var_pdu_fragment, + ARRAY_SIZE(isis_snmp_trap_data_var_pdu_fragment), STRING, + raw_pdu, raw_pdu_len); + return 0; +} + +static int +isis_snmp_max_area_addr_mismatch_update(const struct isis_circuit *circuit, + uint8_t max_addrs, const char *raw_pdu, + size_t raw_pdu_len) +{ + long val; + + if (!isis_snmp_trap_throttle(ISIS_TRAP_MAX_AREA_ADDR_MISMATCH)) + return 0; + + val = max_addrs; + + if (raw_pdu_len > ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN) + raw_pdu_len = ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN; + + isis_snmp_update_worker_a( + circuit, ISIS_TRAP_MAX_AREA_ADDR_MISMATCH, + isis_snmp_trap_data_var_pdu_max_area_addr, + ARRAY_SIZE(isis_snmp_trap_data_var_pdu_max_area_addr), + UNSIGNED32, &val, sizeof(val), + isis_snmp_trap_data_var_pdu_fragment, + ARRAY_SIZE(isis_snmp_trap_data_var_pdu_fragment), STRING, + raw_pdu, raw_pdu_len); + return 0; +} + +static int isis_snmp_own_lsp_purge_update(const struct isis_circuit *circuit, + const uint8_t *lsp_id) +{ + if (!isis_snmp_trap_throttle(ISIS_TRAP_OWN_LSP_PURGE)) + return 0; + + isis_snmp_update_worker_a( + circuit, ISIS_TRAP_OWN_LSP_PURGE, NULL, 0, STRING, NULL, 0, + isis_snmp_trap_data_var_pdu_lsp_id, + ARRAY_SIZE(isis_snmp_trap_data_var_pdu_lsp_id), STRING, lsp_id, + ISIS_SYS_ID_LEN + 2); + return 0; +} + +static int isis_snmp_seqno_skipped_update(const struct isis_circuit *circuit, + const uint8_t *lsp_id) +{ + if (!isis_snmp_trap_throttle(ISIS_TRAP_SEQNO_SKIPPED)) + return 0; + + isis_snmp_update_worker_a( + circuit, ISIS_TRAP_SEQNO_SKIPPED, NULL, 0, STRING, NULL, 0, + isis_snmp_trap_data_var_pdu_lsp_id, + ARRAY_SIZE(isis_snmp_trap_data_var_pdu_lsp_id), STRING, lsp_id, + ISIS_SYS_ID_LEN + 2); + return 0; +} + +static int +isis_snmp_authentication_type_failure_update(const struct isis_circuit *circuit, + const char *raw_pdu, + size_t raw_pdu_len) +{ + if (!isis_snmp_trap_throttle(ISIS_TRAP_AUTHEN_TYPE_FAILURE)) + return 0; + + if (raw_pdu_len > ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN) + raw_pdu_len = ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN; + + isis_snmp_update_worker_a( + circuit, ISIS_TRAP_AUTHEN_TYPE_FAILURE, NULL, 0, STRING, NULL, + 0, isis_snmp_trap_data_var_pdu_fragment, + ARRAY_SIZE(isis_snmp_trap_data_var_pdu_fragment), STRING, + raw_pdu, raw_pdu_len); + return 0; +} + +static int +isis_snmp_authentication_failure_update(const struct isis_circuit *circuit, + char const *raw_pdu, size_t raw_pdu_len) +{ + if (!isis_snmp_trap_throttle(ISIS_TRAP_AUTHEN_FAILURE)) + return 0; + + if (raw_pdu_len > ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN) + raw_pdu_len = ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN; + + isis_snmp_update_worker_a( + circuit, ISIS_TRAP_AUTHEN_FAILURE, NULL, 0, STRING, NULL, 0, + isis_snmp_trap_data_var_pdu_fragment, + ARRAY_SIZE(isis_snmp_trap_data_var_pdu_fragment), STRING, + raw_pdu, raw_pdu_len); + return 0; +} + +static int isis_snmp_version_skew_update(const struct isis_circuit *circuit, + uint8_t version, const char *raw_pdu, + size_t raw_pdu_len) +{ + long val; + + if (!isis_snmp_trap_throttle(ISIS_TRAP_VERSION_SKEW)) + return 0; + + val = version; + + if (raw_pdu_len > ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN) + raw_pdu_len = ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN; + + isis_snmp_update_worker_b( + circuit, ISIS_TRAP_VERSION_SKEW, + isis_snmp_trap_data_var_pdu_proto_ver, + ARRAY_SIZE(isis_snmp_trap_data_var_pdu_proto_ver), UNSIGNED32, + &val, sizeof(val), isis_snmp_trap_data_var_pdu_fragment, + ARRAY_SIZE(isis_snmp_trap_data_var_pdu_fragment), STRING, + raw_pdu, raw_pdu_len); + return 0; +} + +static int isis_snmp_area_mismatch_update(const struct isis_circuit *circuit, + const char *raw_pdu, + size_t raw_pdu_len) +{ + /* + * This is a special case because + * it does not include isisNotificationSysLevelIndex + */ + netsnmp_variable_list *notification_vars; + long val; + + if (!isis_snmp_trap_throttle(ISIS_TRAP_AREA_MISMATCH)) + return 0; + + notification_vars = NULL; + + /* Put in trap value */ + snmp_varlist_add_variable(¬ification_vars, isis_snmp_trap_var, + ARRAY_SIZE(isis_snmp_trap_var), ASN_OBJECT_ID, + (uint8_t *)&isis_snmp_trap_val_area_mismatch, + sizeof(isis_snmp_trap_val_area_mismatch)); + + + if (circuit->interface == NULL) + val = 0; + else + val = circuit->interface->ifindex; + + snmp_varlist_add_variable( + ¬ification_vars, isis_snmp_trap_data_var_circ_if_index, + ARRAY_SIZE(isis_snmp_trap_data_var_circ_if_index), UNSIGNED32, + (uint8_t *)&val, sizeof(val)); + + + if (raw_pdu_len > ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN) + raw_pdu_len = ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN; + + snmp_varlist_add_variable( + ¬ification_vars, isis_snmp_trap_data_var_pdu_fragment, + ARRAY_SIZE(isis_snmp_trap_data_var_pdu_fragment), STRING, + raw_pdu, raw_pdu_len); + + send_v2trap(notification_vars); + snmp_free_varbind(notification_vars); + smux_events_update(); + + return 0; +} + +static int isis_snmp_reject_adjacency_update(const struct isis_circuit *circuit, + const char *raw_pdu, + size_t raw_pdu_len) +{ + if (!isis_snmp_trap_throttle(ISIS_TRAP_REJ_ADJACENCY)) + return 0; + + if (raw_pdu_len > ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN) + raw_pdu_len = ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN; + + isis_snmp_update_worker_a( + circuit, ISIS_TRAP_REJ_ADJACENCY, NULL, 0, STRING, NULL, 0, + isis_snmp_trap_data_var_pdu_fragment, + ARRAY_SIZE(isis_snmp_trap_data_var_pdu_fragment), STRING, + raw_pdu, raw_pdu_len); + return 0; +} + +static int isis_snmp_lsp_too_large_update(const struct isis_circuit *circuit, + uint32_t pdu_size, + const uint8_t *lsp_id) +{ + if (!isis_snmp_trap_throttle(ISIS_TRAP_LSP_TOO_LARGE)) + return 0; + + isis_snmp_update_worker_b( + circuit, ISIS_TRAP_LSP_TOO_LARGE, + isis_snmp_trap_data_var_pdu_lsp_size, + ARRAY_SIZE(isis_snmp_trap_data_var_pdu_lsp_size), UNSIGNED32, + &pdu_size, sizeof(pdu_size), isis_snmp_trap_data_var_pdu_lsp_id, + ARRAY_SIZE(isis_snmp_trap_data_var_pdu_lsp_id), STRING, lsp_id, + ISIS_SYS_ID_LEN + 2); + return 0; +} + + +static int isis_snmp_adj_state_change_update(const struct isis_adjacency *adj) +{ + uint8_t lsp_id[ISIS_SYS_ID_LEN + 2]; + long val; + struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT); + + if (isis == NULL || !isis->snmp_notifications || !smux_enabled()) + return 0; + + /* Prepare data */ + memcpy(lsp_id, adj->sysid, ISIS_SYS_ID_LEN); + lsp_id[ISIS_SYS_ID_LEN] = 0; + lsp_id[ISIS_SYS_ID_LEN + 1] = 0; + + val = ISIS_SNMP_ADJ_STATE_DOWN; + + switch (adj->adj_state) { + case ISIS_ADJ_UNKNOWN: + val = ISIS_SNMP_ADJ_STATE_DOWN; + break; + + case ISIS_ADJ_INITIALIZING: + val = ISIS_SNMP_ADJ_STATE_INITIALIZING; + break; + + case ISIS_ADJ_UP: + val = ISIS_SNMP_ADJ_STATE_UP; + break; + + case ISIS_ADJ_DOWN: + val = ISIS_SNMP_ADJ_STATE_FAILED; + break; + } + + isis_snmp_update_worker_b( + adj->circuit, ISIS_TRAP_ADJ_STATE_CHANGE, + isis_snmp_trap_data_var_pdu_lsp_id, + ARRAY_SIZE(isis_snmp_trap_data_var_pdu_lsp_id), STRING, lsp_id, + ISIS_SYS_ID_LEN + 2, isis_snmp_trap_data_var_adj_state, + ARRAY_SIZE(isis_snmp_trap_data_var_adj_state), INTEGER, &val, + sizeof(val)); + return 0; +} + +static int isis_snmp_lsp_error_update(const struct isis_circuit *circuit, + const uint8_t *lsp_id, + char const *raw_pdu, size_t raw_pdu_len) +{ + /* + * This is a special case because + * it have more variables + */ + netsnmp_variable_list *notification_vars; + long val; + + if (!isis_snmp_trap_throttle(ISIS_TRAP_LSP_ERROR)) + return 0; + + notification_vars = NULL; + + /* Put in trap value */ + snmp_varlist_add_variable(¬ification_vars, isis_snmp_trap_var, + ARRAY_SIZE(isis_snmp_trap_var), ASN_OBJECT_ID, + (uint8_t *)&isis_snmp_trap_val_lsp_error, + sizeof(isis_snmp_trap_val_lsp_error)); + + /* Prepare data */ + val = circuit->is_type; + + snmp_varlist_add_variable( + ¬ification_vars, isis_snmp_trap_data_var_sys_level_index, + ARRAY_SIZE(isis_snmp_trap_data_var_sys_level_index), INTEGER, + (uint8_t *)&val, sizeof(val)); + + + snmp_varlist_add_variable( + ¬ification_vars, isis_snmp_trap_data_var_pdu_lsp_id, + ARRAY_SIZE(isis_snmp_trap_data_var_pdu_lsp_id), STRING, lsp_id, + ISIS_SYS_ID_LEN + 2); + + /* Prepare data */ + if (circuit->interface == NULL) + val = 0; + else + val = circuit->interface->ifindex; + + snmp_varlist_add_variable( + ¬ification_vars, isis_snmp_trap_data_var_circ_if_index, + ARRAY_SIZE(isis_snmp_trap_data_var_circ_if_index), UNSIGNED32, + (uint8_t *)&val, sizeof(val)); + + /* Prepare data */ + if (raw_pdu_len > ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN) + raw_pdu_len = ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN; + + snmp_varlist_add_variable( + ¬ification_vars, isis_snmp_trap_data_var_pdu_fragment, + ARRAY_SIZE(isis_snmp_trap_data_var_pdu_fragment), STRING, + raw_pdu, raw_pdu_len); + + /* Prepare data */ + val = 0; + + snmp_varlist_add_variable( + ¬ification_vars, isis_snmp_trap_data_var_error_offset, + ARRAY_SIZE(isis_snmp_trap_data_var_error_offset), UNSIGNED32, + (uint8_t *)&val, sizeof(val)); + + /* Prepare data */ + val = 0; + + snmp_varlist_add_variable( + ¬ification_vars, isis_snmp_trap_data_var_error_tlv_type, + ARRAY_SIZE(isis_snmp_trap_data_var_error_tlv_type), UNSIGNED32, + (uint8_t *)&val, sizeof(val)); + + send_v2trap(notification_vars); + snmp_free_varbind(notification_vars); + smux_events_update(); + return 0; +} + + +static int isis_snmp_module_init(void) +{ + hook_register(isis_hook_db_overload, isis_snmp_db_overload_update); + hook_register(isis_hook_lsp_exceed_max, + isis_snmp_lsp_exceed_max_update); + hook_register(isis_hook_id_len_mismatch, + isis_snmp_id_len_mismatch_update); + hook_register(isis_hook_max_area_addr_mismatch, + isis_snmp_max_area_addr_mismatch_update); + hook_register(isis_hook_own_lsp_purge, isis_snmp_own_lsp_purge_update); + hook_register(isis_hook_seqno_skipped, isis_snmp_seqno_skipped_update); + hook_register(isis_hook_authentication_type_failure, + isis_snmp_authentication_type_failure_update); + hook_register(isis_hook_authentication_failure, + isis_snmp_authentication_failure_update); + hook_register(isis_hook_version_skew, isis_snmp_version_skew_update); + hook_register(isis_hook_area_mismatch, isis_snmp_area_mismatch_update); + hook_register(isis_hook_reject_adjacency, + isis_snmp_reject_adjacency_update); + hook_register(isis_hook_lsp_too_large, isis_snmp_lsp_too_large_update); + hook_register(isis_hook_adj_state_change, + isis_snmp_adj_state_change_update); + hook_register(isis_hook_lsp_error, isis_snmp_lsp_error_update); + + hook_register(frr_late_init, isis_snmp_init); + return 0; +} + +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 22dfee994f..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, @@ -1821,6 +1837,7 @@ static int isis_run_spf_cb(struct thread *thread) struct isis_spf_run *run = THREAD_ARG(thread); struct isis_area *area = run->area; int level = run->level; + int have_run = 0; XFREE(MTYPE_ISIS_SPF_RUN, run); area->spf_timer[level - 1] = NULL; @@ -1839,15 +1856,24 @@ static int isis_run_spf_cb(struct thread *thread) zlog_debug("ISIS-SPF (%s) L%d SPF needed, periodic SPF", area->area_tag, level); - if (area->ip_circuits) + if (area->ip_circuits) { isis_run_spf_with_protection( area, area->spftree[SPFTREE_IPV4][level - 1]); - if (area->ipv6_circuits) + have_run = 1; + } + if (area->ipv6_circuits) { isis_run_spf_with_protection( area, area->spftree[SPFTREE_IPV6][level - 1]); - if (area->ipv6_circuits && isis_area_ipv6_dstsrc_enabled(area)) + have_run = 1; + } + if (area->ipv6_circuits && isis_area_ipv6_dstsrc_enabled(area)) { isis_run_spf_with_protection( area, area->spftree[SPFTREE_DSTSRC][level - 1]); + have_run = 1; + } + + if (have_run) + area->spf_run_count[level]++; isis_area_verify_routes(area); 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 89fa2018b9..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. @@ -1213,14 +1213,14 @@ void isis_sr_area_init(struct isis_area *area) /* Pull defaults from the YANG module. */ #ifndef FABRICD srdb->config.enabled = yang_get_default_bool("%s/enabled", ISIS_SR); - srdb->config.srgb_lower_bound = - yang_get_default_uint32("%s/srgb/lower-bound", ISIS_SR); - srdb->config.srgb_upper_bound = - yang_get_default_uint32("%s/srgb/upper-bound", ISIS_SR); - srdb->config.srlb_lower_bound = - yang_get_default_uint32("%s/srlb/lower-bound", ISIS_SR); - srdb->config.srlb_upper_bound = - yang_get_default_uint32("%s/srlb/upper-bound", ISIS_SR); + srdb->config.srgb_lower_bound = yang_get_default_uint32( + "%s/label-blocks/srgb/lower-bound", ISIS_SR); + srdb->config.srgb_upper_bound = yang_get_default_uint32( + "%s/label-blocks/srgb/upper-bound", ISIS_SR); + srdb->config.srlb_lower_bound = yang_get_default_uint32( + "%s/label-blocks/srlb/lower-bound", ISIS_SR); + srdb->config.srlb_upper_bound = yang_get_default_uint32( + "%s/label-blocks/srlb/upper-bound", ISIS_SR); #else srdb->config.enabled = false; srdb->config.srgb_lower_bound = SRGB_LOWER_BOUND; 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..47fd684eb3 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,9 +44,9 @@ #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, @@ -4488,9 +4487,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/isis_zebra.c b/isisd/isis_zebra.c index 703532234a..cb4dd2569d 100644 --- a/isisd/isis_zebra.c +++ b/isisd/isis_zebra.c @@ -509,7 +509,7 @@ static int isis_zebra_read(ZAPI_CALLBACK_ARGS) if (cmd == ZEBRA_REDISTRIBUTE_ROUTE_ADD) isis_redist_add(isis, api.type, &api.prefix, &api.src_prefix, - api.distance, api.metric); + api.distance, api.metric, api.tag); else isis_redist_delete(isis, api.type, &api.prefix, &api.src_prefix); diff --git a/isisd/isisd.c b/isisd/isisd.c index a802bac13b..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; @@ -89,6 +97,10 @@ static struct isis_master isis_master; /* ISIS process wide configuration pointer to export. */ struct isis_master *im; +#ifndef FABRICD +DEFINE_HOOK(isis_hook_db_overload, (const struct isis_area *area), (area)); +#endif /* ifndef FABRICD */ + /* * Prototypes. */ @@ -194,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) @@ -214,6 +226,7 @@ struct isis *isis_new(const char *vrf_name) isis->area_list = list_new(); isis->init_circ_list = list_new(); isis->uptime = time(NULL); + isis->snmp_notifications = 1; dyn_cache_init(isis); return isis; @@ -560,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; @@ -626,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) @@ -2563,6 +2576,14 @@ void isis_area_overload_bit_set(struct isis_area *area, bool overload_bit) if (new_overload_bit != area->overload_bit) { area->overload_bit = new_overload_bit; + + if (new_overload_bit) + area->overload_counter++; + +#ifndef FABRICD + hook_call(isis_hook_db_overload, area); +#endif /* ifndef FABRICD */ + lsp_regenerate_schedule(area, IS_LEVEL_1 | IS_LEVEL_2, 1); } #ifndef FABRICD diff --git a/isisd/isisd.h b/isisd/isisd.h index 22d9c6236d..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 @@ -63,6 +65,8 @@ extern void isis_cli_init(void); all_vrf = strmatch(vrf_name, "all"); \ } +#define SNMP_CIRCUITS_MAX (512) + extern struct zebra_privs_t isisd_privs; /* uncomment if you are a developer in bug hunt */ @@ -93,6 +97,9 @@ struct isis { time_t uptime; /* when did we start */ struct thread *t_dync_clean; /* dynamic hostname cache cleanup thread */ uint32_t circuit_ids_used[8]; /* 256 bits to track circuit ids 1 through 255 */ + struct isis_circuit *snmp_circuits[SNMP_CIRCUITS_MAX]; + uint32_t snmp_circuit_id_last; + int snmp_notifications; struct route_table *ext_info[REDIST_PROTOCOL_COUNT]; struct ldp_sync_info_cmd ldp_sync_cmd; /* MPLS LDP-IGP Sync */ @@ -168,6 +175,7 @@ struct isis_area { char is_type; /* level-1 level-1-2 or level-2-only */ /* are we overloaded? */ char overload_bit; + uint32_t overload_counter; /* L1/L2 router identifier for inter-area traffic */ char attached_bit_send; char attached_bit_rcv_ignore; @@ -180,6 +188,9 @@ struct isis_area { int lsp_frag_threshold; uint64_t lsp_gen_count[ISIS_LEVELS]; uint64_t lsp_purge_count[ISIS_LEVELS]; + uint32_t lsp_exceeded_max_counter; + uint32_t lsp_seqno_skipped_counter; + uint64_t spf_run_count[ISIS_LEVELS]; int ip_circuits; /* logging adjacency changes? */ uint8_t log_adj_changes; @@ -220,9 +231,21 @@ struct isis_area { pdu_counter_t pdu_rx_counters; uint64_t lsp_rxmt_count; - QOBJ_FIELDS + /* Area counters */ + uint64_t rej_adjacencies[2]; + uint64_t auth_type_failures[2]; + uint64_t auth_failures[2]; + uint64_t id_len_mismatches[2]; + uint64_t lsp_error_counter[2]; + + 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)); void isis_terminate(void); void isis_finish(struct isis *isis); diff --git a/isisd/subdir.am b/isisd/subdir.am index 4be4efc118..4cefe6e10b 100644 --- a/isisd/subdir.am +++ b/isisd/subdir.am @@ -17,6 +17,9 @@ vtysh_scan += \ isisd/isisd.c \ # end vtysh_daemons += isisd +if SNMP +module_LTLIBRARIES += isisd/isisd_snmp.la +endif man8 += $(MANBUILD)/frr-isisd.8 endif @@ -54,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 \ @@ -89,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 \ @@ -137,7 +138,12 @@ isisd_isisd_SOURCES = $(ISIS_SOURCES) nodist_isisd_isisd_SOURCES = \ yang/frr-isisd.yang.c \ # end - + +isisd_isisd_snmp_la_SOURCES = isisd/isis_snmp.c +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 + # Building fabricd FABRICD_CPPFLAGS = -DFABRICD=1 $(AM_CPPFLAGS) diff --git a/ldpd/lde.c b/ldpd/lde.c index 69338b8bad..8fa74d1c3d 100644 --- a/ldpd/lde.c +++ b/ldpd/lde.c @@ -127,15 +127,13 @@ static struct quagga_signal_t lde_signals[] = void lde(void) { - struct thread thread; - #ifdef HAVE_SETPROCTITLE setproctitle("label decision engine"); #endif ldpd_process = PROC_LDE_ENGINE; log_procname = log_procnames[PROC_LDE_ENGINE]; - master = thread_master_create(NULL); + master = frr_init(); /* setup signal handler */ signal_init(master, array_size(lde_signals), lde_signals); @@ -157,9 +155,12 @@ lde(void) /* create base configuration */ ldeconf = config_new_empty(); - /* Fetch next active thread. */ + struct thread thread; while (thread_fetch(master, &thread)) thread_call(&thread); + + /* NOTREACHED */ + return; } void @@ -566,6 +567,9 @@ lde_dispatch_parent(struct thread *thread) memcpy(&init, imsg.data, sizeof(init)); lde_init(&init); break; + case IMSG_AGENTX_ENABLED: + ldp_agentx_enabled(); + break; case IMSG_RECONF_CONF: if ((nconf = malloc(sizeof(struct ldpd_conf))) == NULL) diff --git a/ldpd/ldp_snmp.c b/ldpd/ldp_snmp.c new file mode 100644 index 0000000000..3f59d18aa8 --- /dev/null +++ b/ldpd/ldp_snmp.c @@ -0,0 +1,1247 @@ +/* + * LDP SNMP support + * Copyright (C) 2020 Volta Networks, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * This is minimal read-only implementations providing + * mplsLdpModuleReadOnlyCompliance as described in RFC 3815. + */ + +#include <zebra.h> + +#include <net-snmp/net-snmp-config.h> +#include <net-snmp/net-snmp-includes.h> + +#include "vrf.h" +#include "if.h" +#include "log.h" +#include "prefix.h" +#include "table.h" +#include "command.h" +#include "memory.h" +#include "smux.h" +#include "libfrr.h" +#include "version.h" +#include "ldpd.h" +#include "ldpe.h" + +/* SNMP value hack. */ +#define COUNTER32 ASN_COUNTER +#define INTEGER ASN_INTEGER +#define UNSIGNED32 ASN_GAUGE +#define TIMESTAMP ASN_TIMETICKS +#define TIMETICKS ASN_TIMETICKS +#define STRING ASN_OCTET_STR +#define IPADDRESS ASN_IPADDRESS + +#define LDP_LSRID_IDX_LEN 6 +#define LDP_ENTITY_IDX_LEN 1 +#define LDP_ADJACENCY_IDX_LEN 1 + +/* MPLS-LDP-STD-MIB. */ +#define MPLS_LDP_STD_MIB 1, 3, 6, 1, 2, 1, 10, 166, 4 + +#define MPLS_LDP_LSR_ID 0 +#define MPLS_LDP_LSR_LOOP_DETECTION_CAPABLE 0 +#define MPLS_LDP_ENTITY_LAST_CHANGE 0 +#define MPLS_LDP_ENTITY_INDEX_NEXT 0 + +/* Declare static local variables for convenience. */ +SNMP_LOCAL_VARIABLES + +/* LDP-MIB instances. */ +static oid ldp_oid[] = {MPLS_LDP_STD_MIB}; +static oid ldp_trap_oid[] = {MPLS_LDP_STD_MIB, 0}; + +static uint8_t snmp_ldp_rtrid[6] = {0, 0, 0, 0, 0}; + +#define LDP_DEFAULT_ENTITY_INDEX 1 + +#define MPLSLDPLSRLOOPDETECTIONCAPABLE_NONE 1 +#define MPLSLDPLSRLOOPDETECTIONCAPABLE_OTHER 2 +#define MPLSLDPLSRLOOPDETECTIONCAPABLE_HOPCOUNT 3 +#define MPLSLDPLSRLOOPDETECTIONCAPABLE_PATHVECTOR 4 +#define MPLSLDPLSRLOOPDETECTIONCAPABLE_HOPCOUNTANDPATHVECTOR 5 + +/* MPLS LDP mplsLdpHelloAdjacencyTable. */ +#define MPLSLDPHELLOADJACENCYINDEX 1 +#define MPLSLDPHELLOADJACENCYHOLDTIMEREM 2 +#define MPLSLDPHELLOADJACENCYHOLDTIME 3 +#define MPLSLDPHELLOADJACENCYTYPE 4 + +/* enums for column mplsLdpHelloAdjacencyType */ +#define MPLSLDPHELLOADJACENCYTYPE_LINK 1 +#define MPLSLDPHELLOADJACENCYTYPE_TARGETED 2 + +#define MPLSLDPPEERTRANSPORTADDRTYPE_UNKNOWN 0 +#define MPLSLDPPEERTRANSPORTADDRTYPE_IPV4 1 +#define MPLSLDPPEERTRANSPORTADDRTYPE_IPV6 2 +#define MPLSLDPPEERTRANSPORTADDRTYPE_IPV4Z 3 +#define MPLSLDPPEERTRANSPORTADDRTYPE_IPV6Z 4 +#define MPLSLDPPEERTRANSPORTADDRTYPE_DNS 16 + +#define DOWNSTREAMONDEMAND 1 +#define DOWNSTREAMUNSOLICITED 2 + +#define CONSERVATIVERETENTION 1 +#define LIBERALRETENTION 2 + +#define TRANSPORTADDRINTERFACE 1 +#define TRANSPORTADDRLOOPBACK 2 + +#define LABELTYPEGENERIC 1 + +#define STORAGETYPENONVOLATILE 3 + +#define ROWSTATUSACTIVE 4 + +#define ADMINSTATUSENABLED 1 + +#define OPERSTATUSENABLED 2 + +/* MPLS LDP mplsLdpPeerTable */ +#define MPLSLDPPEERLDPID 1 +#define MPLSLDPPEERLABELDISTMETHOD 2 +#define MPLSLDPPEERPATHVECTORLIMIT 3 +#define MPLSLDPPEERTRANSPORTADDRTYPE 4 +#define MPLSLDPPEERTRANSPORTADDR 5 + +#define MPLSLDPSESSIONROLE_UNKNOWN 1 +#define MPLSLDPSESSIONROLE_ACTIVE 2 +#define MPLSLDPSESSIONROLE_PASSIVE 3 + +#define MPLSLDPSESSIONSTATE_NONEXISTENT 1 +#define MPLSLDPSESSIONSTATE_INITIALIZED 2 +#define MPLSLDPSESSIONSTATE_OPENREC 3 +#define MPLSLDPSESSIONSTATE_OPENSENT 4 +#define MPLSLDPSESSIONSTATE_OPERATIONAL 5 + +/* MPLS LDP mplsLdpSessionTable */ +#define MPLSLDPSESSIONSTATELASTCHANGE 1 +#define MPLSLDPSESSIONSTATE 2 +#define MPLSLDPSESSIONROLE 3 +#define MPLSLDPSESSIONPROTOCOLVERSION 4 +#define MPLSLDPSESSIONKEEPALIVEHOLDTIMEREM 5 +#define MPLSLDPSESSIONKEEPALIVETIME 6 +#define MPLSLDPSESSIONMAXPDULENGTH 7 +#define MPLSLDPSESSIONDISCONTINUITYTIME 8 + +/* MPLS LDP mplsLdpEntityTable */ +#define MPLSLDPENTITYLDPID 1 +#define MPLSLDPENTITYINDEX 2 +#define MPLSLDPENTITYPROTOCOLVERSION 3 +#define MPLSLDPENTITYADMINSTATUS 4 +#define MPLSLDPENTITYOPERSTATUS 5 +#define MPLSLDPENTITYTCPPORT 6 +#define MPLSLDPENTITYUDPDSCPORT 7 +#define MPLSLDPENTITYMAXPDULENGTH 8 +#define MPLSLDPENTITYKEEPALIVEHOLDTIMER 9 +#define MPLSLDPENTITYHELLOHOLDTIMER 10 +#define MPLSLDPENTITYINITSESSIONTHRESHOLD 11 +#define MPLSLDPENTITYLABELDISTMETHOD 12 +#define MPLSLDPENTITYLABELRETENTIONMODE 13 +#define MPLSLDPENTITYPATHVECTORLIMIT 14 +#define MPLSLDPENTITYHOPCOUNTLIMIT 15 +#define MPLSLDPENTITYTRANSPORTADDRKIND 16 +#define MPLSLDPENTITYTARGETPEER 17 +#define MPLSLDPENTITYTARGETPEERADDRTYPE 18 +#define MPLSLDPENTITYTARGETPEERADDR 19 +#define MPLSLDPENTITYLABELTYPE 20 +#define MPLSLDPENTITYDISCONTINUITYTIME 21 +#define MPLSLDPENTITYSTORAGETYPE 22 +#define MPLSLDPENTITYROWSTATUS 23 + +/* MPLS LDP mplsLdpEntityStatsTable */ +#define MPLSLDPENTITYSTATSSESSIONATTEMPTS 1 +#define MPLSLDPENTITYSTATSSESSIONREJHELLO 2 +#define MPLSLDPENTITYSTATSSESSIONREJAD 3 +#define MPLSLDPENTITYSTATSSESSIONREJMAXPDU 4 +#define MPLSLDPENTITYSTATSSESSIONREJLR 5 +#define MPLSLDPENTITYSTATSBADLDPID 6 +#define MPLSLDPENTITYSTATSBADPDULENGTH 7 +#define MPLSLDPENTITYSTATSBADMSGLENGTH 8 +#define MPLSLDPENTITYSTATSBADTLVLENGTH 9 +#define MPLSLDPENTITYSTATSMALFORMEDTLV 10 +#define MPLSLDPENTITYSTATSKEEPALIVEEXP 11 +#define MPLSLDPENTITYSTATSSHUTDOWNRCVNOTIFY 12 +#define MPLSLDPENTITYSTATSSHUTDOWNSENTNOTIFY 13 + +#define MPLSLDPSESSIONSTATSUNKNOWNMESTYPEERRORS 1 +#define MPLSLDPSESSIONSTATSUNKNOWNTLVERRORS 2 + +static uint8_t *ldpLsrId(struct variable *v, oid name[], size_t *length, + int exact, size_t *var_len, + WriteMethod **write_method) +{ + if (smux_header_generic(v, name, length, exact, var_len, write_method) + == MATCH_FAILED) + return NULL; + + *var_len = 4; + return (uint8_t *)&leconf->rtr_id.s_addr; +} + +static uint8_t *ldpLoopDetectCap(struct variable *v, oid name[], size_t *length, + int exact, size_t *var_len, + WriteMethod **write_method) +{ + if (smux_header_generic(v, name, length, exact, var_len, write_method) + == MATCH_FAILED) + return NULL; + + return SNMP_INTEGER(MPLSLDPLSRLOOPDETECTIONCAPABLE_NONE); +} + +extern uint32_t ldp_start_time; +static uint8_t *ldpEntityLastChange(struct variable *v, oid name[], + size_t *length, + int exact, size_t *var_len, + WriteMethod **write_method) +{ + if (smux_header_generic(v, name, length, exact, var_len, write_method) + == MATCH_FAILED) + return NULL; + + *var_len = sizeof(time_t); + return (uint8_t *) &(leconf->config_change_time); + +} + +static uint8_t *ldpEntityIndexNext(struct variable *v, oid name[], + size_t *length,int exact, size_t *var_len, + WriteMethod **write_method) +{ + if (smux_header_generic(v, name, length, exact, var_len, write_method) + == MATCH_FAILED) + return NULL; + + return SNMP_INTEGER(0); +} + +#define LDP_ENTITY_TOTAL_LEN 21 +#define LDP_ENTITY_MAX_IDX_LEN 6 + +static struct ldpd_af_conf *ldpEntityTable_lookup(struct variable *v, oid *name, + size_t *length, int exact, + uint32_t *index) +{ + int len; + struct ldpd_af_conf *af_v4, *af_v6; + + af_v4 = &leconf->ipv4; + af_v6 = &leconf->ipv6; + + if (exact) { + if (*length != LDP_ENTITY_TOTAL_LEN) + return NULL; + + if (leconf->trans_pref == DUAL_STACK_LDPOV6 && + af_v6->flags & F_LDPD_AF_ENABLED) { + *index = 2; + return af_v6; + } else { + *index = 1; + return af_v4; + } + } else { + /* only support one router id so can just skip */ + len = *length - v->namelen - LDP_ENTITY_MAX_IDX_LEN; + if (len <= 0) { + if (leconf->trans_pref == DUAL_STACK_LDPOV6 && + af_v6->flags & F_LDPD_AF_ENABLED) { + *index = 2; + return af_v6; + } else { + *index = 1; + return af_v4; + } + } + } + return NULL; +} + +static uint8_t *ldpEntityTable(struct variable *v, oid name[], size_t *length, + int exact, size_t *var_len, + WriteMethod **write_method) +{ + struct ldpd_af_conf *af; + struct in_addr entityLdpId = {.s_addr = 0}; + uint32_t index = 0; + + *write_method = NULL; + + if (smux_header_table(v, name, length, exact, var_len, write_method) + == MATCH_FAILED) + return NULL; + + af = ldpEntityTable_lookup(v, name, length, exact, &index); + if (af == NULL) + return NULL; + + if (!exact) { + entityLdpId.s_addr = ldp_rtr_id_get(leconf); + + /* Copy the name out */ + memcpy(name, v->name, v->namelen * sizeof(oid)); + + /* Append index */ + *length = LDP_ENTITY_TOTAL_LEN; + oid_copy_addr(name + v->namelen, &entityLdpId, + IN_ADDR_SIZE); + name[v->namelen + 4] = 0; + name[v->namelen + 5] = 0; + name[v->namelen + 6] = LDP_DEFAULT_ENTITY_INDEX; + } + + /* Return the current value of the variable */ + switch (v->magic) { + case MPLSLDPENTITYLDPID: + *var_len = 6; + memcpy (snmp_ldp_rtrid, &entityLdpId, IN_ADDR_SIZE); + return (uint8_t *)snmp_ldp_rtrid; + case MPLSLDPENTITYINDEX: + return SNMP_INTEGER(LDP_DEFAULT_ENTITY_INDEX); + case MPLSLDPENTITYPROTOCOLVERSION: + return SNMP_INTEGER(LDP_VERSION); + case MPLSLDPENTITYADMINSTATUS: + return SNMP_INTEGER(ADMINSTATUSENABLED); + case MPLSLDPENTITYOPERSTATUS: + return SNMP_INTEGER(OPERSTATUSENABLED); + case MPLSLDPENTITYTCPPORT: + return SNMP_INTEGER(LDP_PORT); + case MPLSLDPENTITYUDPDSCPORT: + return SNMP_INTEGER(LDP_PORT); + case MPLSLDPENTITYMAXPDULENGTH: + return SNMP_INTEGER(LDP_MAX_LEN); + case MPLSLDPENTITYKEEPALIVEHOLDTIMER: + return SNMP_INTEGER(af->keepalive); + case MPLSLDPENTITYHELLOHOLDTIMER: + return SNMP_INTEGER(af->lhello_holdtime); + case MPLSLDPENTITYINITSESSIONTHRESHOLD: + return SNMP_INTEGER(0); /* not supported */ + case MPLSLDPENTITYLABELDISTMETHOD: + return SNMP_INTEGER(DOWNSTREAMUNSOLICITED); + case MPLSLDPENTITYLABELRETENTIONMODE: + return SNMP_INTEGER(LIBERALRETENTION); + case MPLSLDPENTITYPATHVECTORLIMIT: + return SNMP_INTEGER(0); /* not supported */ + case MPLSLDPENTITYHOPCOUNTLIMIT: + return SNMP_INTEGER(0); + case MPLSLDPENTITYTRANSPORTADDRKIND: + return SNMP_INTEGER(TRANSPORTADDRLOOPBACK); + case MPLSLDPENTITYTARGETPEER: + return SNMP_INTEGER(1); + case MPLSLDPENTITYTARGETPEERADDRTYPE: + if (index == 1) + return SNMP_INTEGER(MPLSLDPPEERTRANSPORTADDRTYPE_IPV4); + else + return SNMP_INTEGER(MPLSLDPPEERTRANSPORTADDRTYPE_IPV6); + case MPLSLDPENTITYTARGETPEERADDR: + if (index == 1) { + *var_len = sizeof(af->trans_addr.v4); + return ((uint8_t *)&af->trans_addr.v4); + }else { + *var_len = sizeof(af->trans_addr.v6); + return ((uint8_t *)&af->trans_addr.v6); + } + case MPLSLDPENTITYLABELTYPE: + return SNMP_INTEGER(LABELTYPEGENERIC); + case MPLSLDPENTITYDISCONTINUITYTIME: + return SNMP_INTEGER(0); + case MPLSLDPENTITYSTORAGETYPE: + return SNMP_INTEGER(STORAGETYPENONVOLATILE); + case MPLSLDPENTITYROWSTATUS: + return SNMP_INTEGER(ROWSTATUSACTIVE); + default: + return NULL; + } + + return NULL; +} + +static uint8_t *ldpEntityStatsTable(struct variable *v, oid name[], + size_t *length, int exact, size_t *var_len, + WriteMethod **write_method) +{ + struct in_addr entityLdpId = {.s_addr = 0}; + int len; + + *write_method = NULL; + + if (smux_header_table(v, name, length, exact, var_len, write_method) + == MATCH_FAILED) + return NULL; + + if (exact) { + if (*length != LDP_ENTITY_TOTAL_LEN) + return NULL; + } else { + len = *length - v->namelen - LDP_ENTITY_MAX_IDX_LEN; + if (len > 0) + return NULL; + + entityLdpId.s_addr = ldp_rtr_id_get(leconf); + + /* Copy the name out */ + memcpy(name, v->name, v->namelen * sizeof(oid)); + + /* Append index */ + *length = LDP_ENTITY_TOTAL_LEN; + oid_copy_addr(name + v->namelen, &entityLdpId, + IN_ADDR_SIZE); + name[v->namelen + 4] = 0; + name[v->namelen + 5] = 0; + name[v->namelen + 6] = LDP_DEFAULT_ENTITY_INDEX; + } + + /* Return the current value of the variable */ + switch (v->magic) { + case MPLSLDPENTITYSTATSSESSIONATTEMPTS: + return SNMP_INTEGER(leconf->stats.session_attempts); + case MPLSLDPENTITYSTATSSESSIONREJHELLO: + return SNMP_INTEGER(leconf->stats.session_rejects_hello); + case MPLSLDPENTITYSTATSSESSIONREJAD: + return SNMP_INTEGER(leconf->stats.session_rejects_ad); + case MPLSLDPENTITYSTATSSESSIONREJMAXPDU: + return SNMP_INTEGER(leconf->stats.session_rejects_max_pdu); + case MPLSLDPENTITYSTATSSESSIONREJLR: + return SNMP_INTEGER(leconf->stats.session_rejects_lr); + case MPLSLDPENTITYSTATSBADLDPID: + return SNMP_INTEGER(leconf->stats.bad_ldp_id); + case MPLSLDPENTITYSTATSBADPDULENGTH: + return SNMP_INTEGER(leconf->stats.bad_pdu_len); + case MPLSLDPENTITYSTATSBADMSGLENGTH: + return SNMP_INTEGER(leconf->stats.bad_msg_len); + case MPLSLDPENTITYSTATSBADTLVLENGTH: + return SNMP_INTEGER(leconf->stats.bad_tlv_len); + case MPLSLDPENTITYSTATSMALFORMEDTLV: + return SNMP_INTEGER(leconf->stats.malformed_tlv); + case MPLSLDPENTITYSTATSKEEPALIVEEXP: + return SNMP_INTEGER(leconf->stats.keepalive_timer_exp); + case MPLSLDPENTITYSTATSSHUTDOWNRCVNOTIFY: + return SNMP_INTEGER(leconf->stats.shutdown_rcv_notify); + case MPLSLDPENTITYSTATSSHUTDOWNSENTNOTIFY: + return SNMP_INTEGER(leconf->stats.shutdown_send_notify); + default: + return NULL; + } + + return NULL; +} + +#define LDP_ADJACENCY_ENTRY_MAX_IDX_LEN 14 + +static void ldpHelloAdjacencyTable_oid_to_index( + struct variable *v, oid name[], + size_t *length, + struct in_addr *entityLdpId, + uint32_t *entityIndex, + struct in_addr *peerLdpId, + uint32_t *adjacencyIndex) +{ + oid *offset = name + v->namelen; + int offsetlen = *length - v->namelen; + int len = offsetlen; + + if (len > LDP_ADJACENCY_ENTRY_MAX_IDX_LEN) + len = LDP_ADJACENCY_ENTRY_MAX_IDX_LEN; + + if (len >= LDP_LSRID_IDX_LEN) + oid2in_addr(offset, sizeof(struct in_addr), entityLdpId); + + offset += LDP_LSRID_IDX_LEN; + offsetlen -= LDP_LSRID_IDX_LEN; + len = offsetlen; + + if (len > LDP_ENTITY_IDX_LEN) + len = LDP_ENTITY_IDX_LEN; + + if (len >= LDP_ENTITY_IDX_LEN) + *entityIndex = offset[0]; + + offset += LDP_ENTITY_IDX_LEN; + offsetlen -= LDP_ENTITY_IDX_LEN; + len = offsetlen; + + if (len > LDP_LSRID_IDX_LEN) + len = LDP_LSRID_IDX_LEN; + + if (len >= LDP_LSRID_IDX_LEN) + oid2in_addr(offset, sizeof(struct in_addr), peerLdpId); + + offset += LDP_LSRID_IDX_LEN; + offsetlen -= LDP_LSRID_IDX_LEN; + len = offsetlen; + + if (len > LDP_ADJACENCY_IDX_LEN) + len = LDP_ADJACENCY_IDX_LEN; + + if (len >= LDP_ADJACENCY_IDX_LEN) + *adjacencyIndex = offset[0]; +} + +static struct adj * +nbr_get_adj_by_index(struct nbr *nbr, uint32_t adjacencyIndex) +{ + struct adj *adj; + uint32_t i = 0; + + RB_FOREACH(adj, nbr_adj_head, &nbr->adj_tree) + if (++i == adjacencyIndex) + return adj; + + return NULL; +} + +static struct ctl_adj * +ldpHelloAdjacencyTable_lookup_helper( + struct in_addr *entityLdpId, + uint32_t *entityIndex, + struct in_addr *peerLdpId, + uint32_t *adjacencyIndex) +{ + struct ctl_adj *ctl_adj = NULL; + struct adj *adj = NULL; + struct nbr *cur_nbr = nbr_find_ldpid(peerLdpId->s_addr); + + if (cur_nbr) + /* If found nbr, then look to see if the + * adjacency exists + */ + adj = nbr_get_adj_by_index(cur_nbr, *adjacencyIndex); + + if (adj) + ctl_adj = adj_to_ctl(adj); + + return ctl_adj; +} + +static struct ctl_adj * +ldpHelloAdjacencyTable_next_helper( + int first, + struct in_addr *entityLdpId, + uint32_t *entityIndex, + struct in_addr *peerLdpId, + uint32_t *adjacencyIndex) +{ + struct ctl_adj *ctl_adj = NULL; + struct nbr *nbr = NULL; + struct adj *adj = NULL; + + if (first) + nbr = nbr_get_first_ldpid(); + else { + struct nbr *cur_nbr = nbr_find_ldpid(peerLdpId->s_addr); + if (cur_nbr) + /* If found nbr, then look to see if the + * adjacency exists + */ + adj = nbr_get_adj_by_index(cur_nbr, *adjacencyIndex + 1); + if (adj) + *adjacencyIndex += 1; + else + nbr = nbr_get_next_ldpid(peerLdpId->s_addr); + } + + if (!adj && nbr) { + adj = RB_MIN(nbr_adj_head, &nbr->adj_tree); + *adjacencyIndex = 1; + } + + if (adj) + ctl_adj = adj_to_ctl(adj); + + return ctl_adj; +} + +#define HELLO_ADJ_MAX_IDX_LEN 14 + +static struct ctl_adj * +ldpHelloAdjacencyTable_lookup(struct variable *v, oid name[], + size_t *length, int exact, + struct in_addr *entityLdpId, + uint32_t *entityIndex, + struct in_addr *peerLdpId, + uint32_t *adjacencyIndex) +{ + struct ctl_adj *hello_adj = NULL; + + if (exact) { + if (*length < HELLO_ADJ_MAX_IDX_LEN) + return NULL; + + ldpHelloAdjacencyTable_oid_to_index( + v, name, length, + entityLdpId, entityIndex, peerLdpId, adjacencyIndex); + + hello_adj = ldpHelloAdjacencyTable_lookup_helper( + entityLdpId, entityIndex, peerLdpId, adjacencyIndex); + } else { + int first = 0; + int offsetlen = *length - v->namelen; + + if (offsetlen < HELLO_ADJ_MAX_IDX_LEN) + first = 1; + + ldpHelloAdjacencyTable_oid_to_index( + v, name, length, + entityLdpId, entityIndex, peerLdpId, adjacencyIndex); + + hello_adj = ldpHelloAdjacencyTable_next_helper(first, + entityLdpId, entityIndex, peerLdpId, adjacencyIndex); + + } + return hello_adj; +} + +static uint8_t *ldpHelloAdjacencyTable(struct variable *v, oid name[], size_t *length, + int exact, size_t *var_len, + WriteMethod **write_method) +{ + struct in_addr entityLdpId = {.s_addr = 0}; + uint32_t entityIndex = 0; + struct in_addr peerLdpId = {.s_addr = 0}; + uint32_t adjacencyIndex = 0; + + if (smux_header_table(v, name, length, exact, var_len, write_method) + == MATCH_FAILED) + return NULL; + + struct ctl_adj *ctl_adj = ldpHelloAdjacencyTable_lookup(v, name, + length, exact, + &entityLdpId, &entityIndex, &peerLdpId, &adjacencyIndex); + + if (!ctl_adj) + return NULL; + + if (!exact) { + + /* Copy the name out */ + memcpy(name, v->name, v->namelen * sizeof(oid)); + + /* Append index */ + struct in_addr entityLdpId = {.s_addr = 0}; + entityLdpId.s_addr = ldp_rtr_id_get(leconf); + + struct in_addr peerLdpId = ctl_adj->id; + + oid_copy_addr(name + v->namelen, &entityLdpId, + sizeof(struct in_addr)); + 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)); + name[v->namelen + 11] = 0; + name[v->namelen + 12] = 0; + name[v->namelen + 13] = adjacencyIndex; + + /* Set length */ + *length = v->namelen + HELLO_ADJ_MAX_IDX_LEN; + } + + switch (v->magic) { + case MPLSLDPHELLOADJACENCYINDEX: + return SNMP_INTEGER(adjacencyIndex); + case MPLSLDPHELLOADJACENCYHOLDTIMEREM: + return SNMP_INTEGER(ctl_adj->holdtime_remaining); + case MPLSLDPHELLOADJACENCYHOLDTIME: + return SNMP_INTEGER(ctl_adj->holdtime); + case MPLSLDPHELLOADJACENCYTYPE: + if (ctl_adj->type == HELLO_LINK) + return SNMP_INTEGER(MPLSLDPHELLOADJACENCYTYPE_LINK); + return SNMP_INTEGER(MPLSLDPHELLOADJACENCYTYPE_TARGETED); + default: + return NULL; + } + + return NULL; +} + +#define LDP_LSRID_IDX_LEN 6 +#define LDP_ENTITY_IDX_LEN 1 +#define LDP_PEER_ENTRY_MAX_IDX_LEN 13 + +static void ldpPeerTable_oid_to_index( + struct variable *v, oid name[], + size_t *length, + struct in_addr *entityLdpId, + uint32_t *entityIndex, + struct in_addr *peerLdpId) +{ + oid *offset = name + v->namelen; + int offsetlen = *length - v->namelen; + int len = offsetlen; + + if (len > LDP_PEER_ENTRY_MAX_IDX_LEN) + len = LDP_PEER_ENTRY_MAX_IDX_LEN; + + if (len >= LDP_LSRID_IDX_LEN) + oid2in_addr(offset, sizeof(struct in_addr), entityLdpId); + + offset += LDP_LSRID_IDX_LEN; + offsetlen -= LDP_LSRID_IDX_LEN; + len = offsetlen; + + if (len > LDP_ENTITY_IDX_LEN) + len = LDP_ENTITY_IDX_LEN; + + if (len >= LDP_ENTITY_IDX_LEN) + *entityIndex = offset[0]; + + offset += LDP_ENTITY_IDX_LEN; + offsetlen -= LDP_ENTITY_IDX_LEN; + len = offsetlen; + + if (len > LDP_LSRID_IDX_LEN) + len = LDP_LSRID_IDX_LEN; + + if (len >= LDP_LSRID_IDX_LEN) + oid2in_addr(offset, sizeof(struct in_addr), peerLdpId); +} + +static struct ctl_nbr * +ldpPeerTable_lookup_next(int first, + struct in_addr peerLdpId) +{ + struct nbr *nbr = NULL; + struct ctl_nbr *ctl_nbr = NULL;; + + if (first) + nbr = nbr_get_first_ldpid(); + else + nbr = nbr_get_next_ldpid(peerLdpId.s_addr); + + if (nbr) + ctl_nbr = nbr_to_ctl(nbr); + + return ctl_nbr; +} + +static struct ctl_nbr * +ldpPeerTable_lookup(struct variable *v, oid name[], + size_t *length, int exact, + struct in_addr *entityLdpId, + uint32_t *entityIndex, + struct in_addr *peerLdpId) +{ + struct ctl_nbr *ctl_nbr = NULL; + struct nbr *nbr = NULL; + int first = 0; + + if (exact) { + if (*length < (long unsigned int)v->namelen + + LDP_PEER_ENTRY_MAX_IDX_LEN) + return NULL; + + ldpPeerTable_oid_to_index( + v, name, length, + entityLdpId, entityIndex, peerLdpId); + + nbr = nbr_find_ldpid(peerLdpId->s_addr); + if (nbr) + ctl_nbr = nbr_to_ctl(nbr); + + return ctl_nbr; + } else { + + int offsetlen = *length - v->namelen; + if (offsetlen < LDP_LSRID_IDX_LEN) + first = 1; + + ldpPeerTable_oid_to_index( + v, name, length, + entityLdpId, entityIndex, peerLdpId); + + ctl_nbr = ldpPeerTable_lookup_next(first, *peerLdpId); + return ctl_nbr; + } + return NULL; +} + +static uint8_t *ldpPeerTable(struct variable *v, oid name[], size_t *length, + int exact, size_t *var_len, + WriteMethod **write_method) +{ + struct in_addr entityLdpId = {.s_addr = 0}; + uint32_t entityIndex = 0; + struct in_addr peerLdpId = {.s_addr = 0}; + struct ctl_nbr *ctl_nbr; + + + if (smux_header_table(v, name, length, exact, var_len, write_method) + == MATCH_FAILED) + return NULL; + + ctl_nbr = ldpPeerTable_lookup(v, name, length, exact, &entityLdpId, + &entityIndex, &peerLdpId); + + if (!ctl_nbr) + return NULL; + + if (!exact) { + + entityLdpId.s_addr = ldp_rtr_id_get(leconf); + entityIndex = LDP_DEFAULT_ENTITY_INDEX; + peerLdpId = ctl_nbr->id; + + /* Copy the name out */ + memcpy(name, v->name, v->namelen * sizeof(oid)); + + /* Append index */ + oid_copy_addr(name + v->namelen, &entityLdpId, + sizeof(struct in_addr)); + + 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)); + name[v->namelen + 11] = 0; + name[v->namelen + 12] = 0; + + /* Set length */ + *length = v->namelen + LDP_PEER_ENTRY_MAX_IDX_LEN; + } + + switch (v->magic) { + case MPLSLDPPEERLDPID: + *var_len = 6; + memcpy(snmp_ldp_rtrid, &ctl_nbr->id, IN_ADDR_SIZE); + return snmp_ldp_rtrid; + case MPLSLDPPEERLABELDISTMETHOD: + return SNMP_INTEGER(DOWNSTREAMUNSOLICITED); + case MPLSLDPPEERPATHVECTORLIMIT: + return SNMP_INTEGER(0); + case MPLSLDPPEERTRANSPORTADDRTYPE: + if (ctl_nbr->af == AF_INET) + return SNMP_INTEGER(MPLSLDPPEERTRANSPORTADDRTYPE_IPV4); + else + return SNMP_INTEGER(MPLSLDPPEERTRANSPORTADDRTYPE_IPV6); + case MPLSLDPPEERTRANSPORTADDR: + if (ctl_nbr->af == AF_INET) { + *var_len = sizeof(ctl_nbr->raddr.v4); + return ((uint8_t *)&ctl_nbr->raddr.v4); + } else { + *var_len = sizeof(ctl_nbr->raddr.v6); + return ((uint8_t *)&ctl_nbr->raddr.v6); + } + default: + return NULL; + } + + return NULL; +} +static uint8_t *ldpSessionTable(struct variable *v, oid name[], size_t *length, + int exact, size_t *var_len, + WriteMethod **write_method) +{ + struct in_addr entityLdpId = {.s_addr = 0}; + uint32_t entityIndex = 0; + struct in_addr peerLdpId = {.s_addr = 0}; + struct ctl_nbr *ctl_nbr; + + if (smux_header_table(v, name, length, exact, var_len, write_method) + == MATCH_FAILED) + return NULL; + + ctl_nbr = ldpPeerTable_lookup(v, name, length, exact, &entityLdpId, + &entityIndex, &peerLdpId); + + if (!ctl_nbr) + return NULL; + + if (!exact) { + entityLdpId.s_addr = ldp_rtr_id_get(leconf); + entityIndex = LDP_DEFAULT_ENTITY_INDEX; + peerLdpId = ctl_nbr->id; + + /* Copy the name out */ + memcpy(name, v->name, v->namelen * sizeof(oid)); + + /* Append index */ + oid_copy_addr(name + v->namelen, &entityLdpId, + sizeof(struct in_addr)); + + 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)); + name[v->namelen + 11] = 0; + name[v->namelen + 12] = 0; + + /* Set length */ + *length = v->namelen + LDP_PEER_ENTRY_MAX_IDX_LEN; + } + + switch (v->magic) { + case MPLSLDPSESSIONSTATELASTCHANGE: + *var_len = sizeof(time_t); + return (uint8_t *) &(ctl_nbr->uptime); + case MPLSLDPSESSIONSTATE: + switch (ctl_nbr->nbr_state) { + case NBR_STA_INITIAL: + return SNMP_INTEGER(MPLSLDPSESSIONSTATE_INITIALIZED); + case NBR_STA_OPENREC: + return SNMP_INTEGER(MPLSLDPSESSIONSTATE_OPENREC); + case NBR_STA_OPENSENT: + return SNMP_INTEGER(MPLSLDPSESSIONSTATE_OPENSENT); + case NBR_STA_OPER: + return SNMP_INTEGER(MPLSLDPSESSIONSTATE_OPERATIONAL); + default: + return SNMP_INTEGER(MPLSLDPSESSIONSTATE_NONEXISTENT); + } + case MPLSLDPSESSIONROLE: + if (ldp_addrcmp(ctl_nbr->af, &ctl_nbr->laddr, &ctl_nbr->raddr) + > 0) + return SNMP_INTEGER(MPLSLDPSESSIONROLE_ACTIVE); + else + return SNMP_INTEGER(MPLSLDPSESSIONROLE_PASSIVE); + case MPLSLDPSESSIONPROTOCOLVERSION: + return SNMP_INTEGER(LDP_VERSION); + case MPLSLDPSESSIONKEEPALIVEHOLDTIMEREM: + return SNMP_INTEGER(ctl_nbr->hold_time_remaining); + case MPLSLDPSESSIONKEEPALIVETIME: + return SNMP_INTEGER(ctl_nbr->holdtime); + case MPLSLDPSESSIONMAXPDULENGTH: + if (ctl_nbr->nbr_state == NBR_STA_OPER) + return SNMP_INTEGER(ctl_nbr->max_pdu_len); + else + return SNMP_INTEGER(LDP_MAX_LEN); + case MPLSLDPSESSIONDISCONTINUITYTIME: + return SNMP_INTEGER(0); /* not supported */ + default: + return NULL; + } + + return NULL; +} + +static uint8_t *ldpSessionStatsTable(struct variable *v, oid name[], + size_t *length, + int exact, size_t *var_len, + WriteMethod **write_method) +{ + struct in_addr entityLdpId = {.s_addr = 0}; + uint32_t entityIndex = 0; + struct in_addr peerLdpId = {.s_addr = 0}; + + if (smux_header_table(v, name, length, exact, var_len, write_method) + == MATCH_FAILED) + return NULL; + + struct ctl_nbr *ctl_nbr = ldpPeerTable_lookup(v, name, length, exact, + &entityLdpId, &entityIndex, &peerLdpId); + + if (!ctl_nbr) + return NULL; + + if (!exact) { + entityLdpId.s_addr = ldp_rtr_id_get(leconf); + entityIndex = LDP_DEFAULT_ENTITY_INDEX; + peerLdpId = ctl_nbr->id; + + /* Copy the name out */ + memcpy(name, v->name, v->namelen * sizeof(oid)); + + /* Append index */ + oid_copy_addr(name + v->namelen, &entityLdpId, + sizeof(struct in_addr)); + 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)); + name[v->namelen + 11] = 0; + name[v->namelen + 12] = 0; + + *length = v->namelen + LDP_PEER_ENTRY_MAX_IDX_LEN; + } + + switch (v->magic) { + case MPLSLDPSESSIONSTATSUNKNOWNMESTYPEERRORS: + return SNMP_INTEGER(ctl_nbr->stats.unknown_msg); + case MPLSLDPSESSIONSTATSUNKNOWNTLVERRORS: + return SNMP_INTEGER(ctl_nbr->stats.unknown_tlv); + default: + return NULL; + } + + return NULL; +} + +static struct variable ldpe_variables[] = { + {MPLS_LDP_LSR_ID, STRING, RONLY, ldpLsrId, 3, {1, 1, 1}}, + {MPLS_LDP_LSR_LOOP_DETECTION_CAPABLE, INTEGER, RONLY, + ldpLoopDetectCap, 3, {1, 1, 2}}, + {MPLS_LDP_ENTITY_LAST_CHANGE, TIMESTAMP, RONLY, ldpEntityLastChange, + 3, {1, 2, 1}}, + {MPLS_LDP_ENTITY_INDEX_NEXT, UNSIGNED32, RONLY, ldpEntityIndexNext, + 3, {1, 2, 2}}, + + /* MPLS LDP mplsLdpEntityTable. */ + {MPLSLDPENTITYLDPID, STRING, RONLY, ldpEntityTable, + 5, {1, 2, 3, 1, 1}}, + {MPLSLDPENTITYINDEX, UNSIGNED32, RONLY, ldpEntityTable, + 5, {1, 2, 3, 1, 2}}, + {MPLSLDPENTITYPROTOCOLVERSION, UNSIGNED32, RONLY, ldpEntityTable, + 5, {1, 2, 3, 1, 3}}, + {MPLSLDPENTITYADMINSTATUS, INTEGER, RONLY, ldpEntityTable, + 5, {1, 2, 3, 1, 4}}, + {MPLSLDPENTITYOPERSTATUS, INTEGER, RONLY, ldpEntityTable, + 5, {1, 2, 3, 1, 5}}, + {MPLSLDPENTITYTCPPORT, UNSIGNED32, RONLY, ldpEntityTable, + 5, {1, 2, 3, 1, 6}}, + {MPLSLDPENTITYUDPDSCPORT, UNSIGNED32, RONLY, ldpEntityTable, + 5, {1, 2, 3, 1, 7}}, + {MPLSLDPENTITYMAXPDULENGTH, UNSIGNED32, RONLY, ldpEntityTable, + 5, {1, 2, 3, 1, 8}}, + {MPLSLDPENTITYKEEPALIVEHOLDTIMER, UNSIGNED32, RONLY, ldpEntityTable, + 5, {1, 2, 3, 1, 9}}, + {MPLSLDPENTITYHELLOHOLDTIMER, UNSIGNED32, RONLY, ldpEntityTable, + 5, {1, 2, 3, 1, 10}}, + {MPLSLDPENTITYINITSESSIONTHRESHOLD, INTEGER, RONLY, ldpEntityTable, + 5, {1, 2, 3, 1, 11}}, + {MPLSLDPENTITYLABELDISTMETHOD, INTEGER, RONLY, ldpEntityTable, + 5, {1, 2, 3, 1, 12}}, + {MPLSLDPENTITYLABELRETENTIONMODE, INTEGER, RONLY, ldpEntityTable, + 5, {1, 2, 3, 1, 13}}, + {MPLSLDPENTITYPATHVECTORLIMIT, INTEGER, RONLY, ldpEntityTable, + 5, {1, 2, 3, 1, 14}}, + {MPLSLDPENTITYHOPCOUNTLIMIT, INTEGER, RONLY, ldpEntityTable, + 5, {1, 2, 3, 1, 15}}, + {MPLSLDPENTITYTRANSPORTADDRKIND, INTEGER, RONLY, ldpEntityTable, + 5, {1, 2, 3, 1, 16}}, + {MPLSLDPENTITYTARGETPEER, INTEGER, RONLY, ldpEntityTable, + 5, {1, 2, 3, 1, 17}}, + {MPLSLDPENTITYTARGETPEERADDRTYPE, INTEGER, RONLY, ldpEntityTable, + 5, {1, 2, 3, 1, 18}}, + {MPLSLDPENTITYTARGETPEERADDR, STRING, RONLY, ldpEntityTable, + 5, {1, 2, 3, 1, 19}}, + {MPLSLDPENTITYLABELTYPE, INTEGER, RONLY, ldpEntityTable, + 5, {1, 2, 3, 1, 20}}, + {MPLSLDPENTITYDISCONTINUITYTIME, TIMESTAMP, RONLY, ldpEntityTable, + 5, {1, 2, 3, 1, 21}}, + {MPLSLDPENTITYSTORAGETYPE, INTEGER, RONLY, ldpEntityTable, + 5, {1, 2, 3, 1, 22}}, + {MPLSLDPENTITYROWSTATUS, INTEGER, RONLY, ldpEntityTable, + 5, {1, 2, 3, 1, 23}}, + + /* MPLS LDP mplsLdpEntityStatsTable. */ + { MPLSLDPENTITYSTATSSESSIONATTEMPTS, COUNTER32, RONLY, + ldpEntityStatsTable, 5, {1, 2, 4, 1, 1}}, + { MPLSLDPENTITYSTATSSESSIONREJHELLO, COUNTER32, RONLY, + ldpEntityStatsTable, 5, {1, 2, 4, 1, 2}}, + { MPLSLDPENTITYSTATSSESSIONREJAD, COUNTER32, RONLY, + ldpEntityStatsTable, 5, {1, 2, 4, 1, 3}}, + { MPLSLDPENTITYSTATSSESSIONREJMAXPDU, COUNTER32, RONLY, + ldpEntityStatsTable, 5, {1, 2, 4, 1, 4}}, + { MPLSLDPENTITYSTATSSESSIONREJLR, COUNTER32, RONLY, + ldpEntityStatsTable, 5, {1, 2, 4, 1, 5}}, + { MPLSLDPENTITYSTATSBADLDPID, COUNTER32, RONLY, + ldpEntityStatsTable, 5, {1, 2, 4, 1, 6}}, + { MPLSLDPENTITYSTATSBADPDULENGTH, COUNTER32, RONLY, + ldpEntityStatsTable, 5, {1, 2, 4, 1, 7}}, + { MPLSLDPENTITYSTATSBADMSGLENGTH, COUNTER32, RONLY, + ldpEntityStatsTable, 5, {1, 2, 4, 1, 8}}, + { MPLSLDPENTITYSTATSBADTLVLENGTH, COUNTER32, RONLY, + ldpEntityStatsTable, 5, {1, 2, 4, 1, 9}}, + { MPLSLDPENTITYSTATSMALFORMEDTLV, COUNTER32, RONLY, + ldpEntityStatsTable, 5, {1, 2, 4, 1, 10}}, + { MPLSLDPENTITYSTATSKEEPALIVEEXP, COUNTER32, RONLY, + ldpEntityStatsTable, 5, {1, 2, 4, 1, 11}}, + { MPLSLDPENTITYSTATSSHUTDOWNRCVNOTIFY, COUNTER32, RONLY, + ldpEntityStatsTable, 5, {1, 2, 4, 1, 12}}, + { MPLSLDPENTITYSTATSSHUTDOWNSENTNOTIFY, COUNTER32, RONLY, + ldpEntityStatsTable, 5, {1, 2, 4, 1, 13}}, + + /* MPLS LDP mplsLdpPeerTable */ + {MPLSLDPPEERLDPID, STRING, RONLY, ldpPeerTable, 5, {1, 3, 2, 1, 1}}, + {MPLSLDPPEERLABELDISTMETHOD, INTEGER, RONLY, ldpPeerTable, + 5, {1, 3, 2, 1, 2}}, + {MPLSLDPPEERPATHVECTORLIMIT, INTEGER, RONLY, ldpPeerTable, + 5, {1, 3, 2, 1, 3}}, + {MPLSLDPPEERTRANSPORTADDRTYPE, INTEGER, RONLY, ldpPeerTable, + 5, {1, 3, 2, 1, 4}}, + {MPLSLDPPEERTRANSPORTADDR, STRING, RONLY, ldpPeerTable, + 5, {1, 3, 2, 1, 5}}, + + /* MPLS LDP mplsLdpSessionTable */ + {MPLSLDPSESSIONSTATELASTCHANGE, TIMESTAMP, RONLY, ldpSessionTable, + 5, {1, 3, 3, 1, 1}}, + {MPLSLDPSESSIONSTATE, INTEGER, RONLY, ldpSessionTable, + 5, {1, 3, 3, 1, 2}}, + {MPLSLDPSESSIONROLE, INTEGER, RONLY, ldpSessionTable, + 5, {1, 3, 3, 1, 3}}, + {MPLSLDPSESSIONPROTOCOLVERSION, UNSIGNED32, RONLY, ldpSessionTable, + 5, {1, 3, 3, 1, 4}}, + {MPLSLDPSESSIONKEEPALIVEHOLDTIMEREM, INTEGER, RONLY, ldpSessionTable, + 5, {1, 3, 3, 1, 5}}, + {MPLSLDPSESSIONKEEPALIVETIME, UNSIGNED32, RONLY, ldpSessionTable, + 5, {1, 3, 3, 1, 6}}, + {MPLSLDPSESSIONMAXPDULENGTH, UNSIGNED32, RONLY, ldpSessionTable, + 5, {1, 3, 3, 1, 7}}, + {MPLSLDPSESSIONDISCONTINUITYTIME, TIMESTAMP, RONLY, ldpSessionTable, + 5, {1, 3, 3, 1, 8}}, + + /* MPLS LDP mplsLdpSessionStatsTable */ + {MPLSLDPSESSIONSTATSUNKNOWNMESTYPEERRORS, COUNTER32, RONLY, + ldpSessionStatsTable, 5, {1, 3, 4, 1, 1}}, + {MPLSLDPSESSIONSTATSUNKNOWNTLVERRORS, COUNTER32, RONLY, + ldpSessionStatsTable, 5, {1, 3, 4, 1, 2}}, + + /* MPLS LDP mplsLdpHelloAdjacencyTable. */ + {MPLSLDPHELLOADJACENCYINDEX, UNSIGNED32, RONLY, + ldpHelloAdjacencyTable, 6, {1, 3, 5, 1, 1, 1}}, + {MPLSLDPHELLOADJACENCYHOLDTIMEREM, INTEGER, RONLY, + ldpHelloAdjacencyTable, 6, {1, 3, 5, 1, 1, 2}}, + {MPLSLDPHELLOADJACENCYHOLDTIME, UNSIGNED32, RONLY, + ldpHelloAdjacencyTable, 6, {1, 3, 5, 1, 1, 3}}, + {MPLSLDPHELLOADJACENCYTYPE, INTEGER, RONLY, + ldpHelloAdjacencyTable, 6, {1, 3, 5, 1, 1, 4}}, +}; + +static struct variable lde_variables[] = { +}; + +static struct trap_object ldpSessionTrapList[] = { + {5, {1, 3, 3, 1, MPLSLDPSESSIONSTATE}}, + {5, {1, 3, 3, 1, MPLSLDPSESSIONDISCONTINUITYTIME}}, + {5, {1, 3, 4, 1, MPLSLDPSESSIONSTATSUNKNOWNMESTYPEERRORS}}, + {5, {1, 3, 4, 1, MPLSLDPSESSIONSTATSUNKNOWNTLVERRORS}}}; + +/* LDP TRAP. */ +#define LDPINITSESSIONTHRESHOLDEXCEEDED 1 +#define LDPPATHVECTORLIMITMISMATCH 2 +#define LDPSESSIONUP 3 +#define LDPSESSIONDOWN 4 + +static void +ldpTrapSession(struct nbr * nbr, unsigned int sptrap) +{ + oid index[sizeof(oid) * (LDP_PEER_ENTRY_MAX_IDX_LEN + 1)]; + + struct in_addr entityLdpId = {.s_addr = 0}; + uint32_t entityIndex = 0; + struct in_addr peerLdpId = {.s_addr = 0}; + + struct ctl_nbr *ctl_nbr = nbr_to_ctl(nbr); + + entityLdpId.s_addr = ldp_rtr_id_get(leconf); + 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; + + 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, + sizeof(ldp_oid) / sizeof(oid), index, + LDP_PEER_ENTRY_MAX_IDX_LEN + 1, + ldpSessionTrapList, array_size(ldpSessionTrapList), sptrap); +} + +static void +ldpTrapSessionUp(struct nbr * nbr) +{ + ldpTrapSession(nbr, LDPSESSIONUP); +} + +static void +ldpTrapSessionDown(struct nbr * nbr) +{ + ldpTrapSession(nbr, LDPSESSIONDOWN); +} + +static int ldp_snmp_agentx_enabled() +{ + main_imsg_compose_both(IMSG_AGENTX_ENABLED, NULL, 0); + + return 0; +} + +static int ldp_snmp_nbr_state_change(struct nbr * nbr, int old_state) +{ + if (old_state == nbr->state) + return 0; + + if (nbr->state == NBR_STA_OPER) + ldpTrapSessionUp(nbr); + else if (old_state == NBR_STA_OPER) + ldpTrapSessionDown(nbr); + + return 0; +} + +static int ldp_snmp_init(struct thread_master *tm) +{ + hook_register(agentx_enabled, ldp_snmp_agentx_enabled); + + smux_init(tm); + + return 0; +} + +static int ldp_snmp_register_mib(struct thread_master *tm) +{ + static int registered = 0; + + if (registered) + return 0; + + registered = 1; + + smux_init(tm); + + smux_agentx_enable(); + + if (ldpd_process == PROC_LDE_ENGINE) + REGISTER_MIB("mibII/ldp", lde_variables, variable, ldp_oid); + else if (ldpd_process == PROC_LDP_ENGINE) { + REGISTER_MIB("mibII/ldp", ldpe_variables, variable, ldp_oid); + + hook_register(ldp_nbr_state_change, ldp_snmp_nbr_state_change); + } + + return 0; +} + +static int ldp_snmp_module_init(void) +{ + if (ldpd_process == PROC_MAIN) + hook_register(frr_late_init, ldp_snmp_init); + else + hook_register(ldp_register_mib, ldp_snmp_register_mib); + + return 0; +} + +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 83e93ebbbc..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; @@ -86,6 +86,30 @@ static struct imsgev *iev_lde, *iev_lde_sync; static pid_t ldpe_pid; static pid_t lde_pid; +static struct frr_daemon_info ldpd_di; + +DEFINE_HOOK(ldp_register_mib, (struct thread_master * tm), (tm)); + +static void ldp_load_module(const char *name) +{ + const char *dir; + dir = ldpd_di.module_path ? ldpd_di.module_path : frr_moduledir; + char moderr[256]; + struct frrmod_runtime *module; + + module = frrmod_load(name, dir, moderr, sizeof(moderr)); + if (!module) { + fprintf(stderr, "%s: failed to load %s", __func__, name); + log_warnx("%s: failed to load %s", __func__, name); + } +} + +void ldp_agentx_enabled(void) +{ + ldp_load_module("snmp"); + hook_call(ldp_register_mib, master); +} + enum ldpd_process ldpd_process; #define LDP_DEFAULT_CONFIG "ldpd.conf" @@ -94,8 +118,6 @@ enum ldpd_process ldpd_process; /* Master of threads. */ struct thread_master *master; -static struct frr_daemon_info ldpd_di; - /* ldpd privileges */ static zebra_capabilities_t _caps_p [] = { @@ -196,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) { @@ -1343,6 +1365,9 @@ merge_global(struct ldpd_conf *conf, struct ldpd_conf *xconf) ldpe_reset_ds_nbrs(); } + if (ldpd_process == PROC_LDP_ENGINE) + ldpe_set_config_change_time(); + conf->flags = xconf->flags; } diff --git a/ldpd/ldpd.h b/ldpd/ldpd.h index beb625d8a2..8fdc16fc7b 100644 --- a/ldpd/ldpd.h +++ b/ldpd/ldpd.h @@ -161,6 +161,7 @@ enum imsg_type { IMSG_RLFA_REG, IMSG_RLFA_UNREG_ALL, IMSG_RLFA_LABELS, + IMSG_AGENTX_ENABLED, }; struct ldpd_init { @@ -361,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 { @@ -378,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 @@ -404,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 @@ -434,6 +435,25 @@ struct ldp_stats { uint32_t labelrel_rcvd; uint32_t labelabreq_sent; uint32_t labelabreq_rcvd; + uint32_t unknown_tlv; + uint32_t unknown_msg; + +}; + +struct ldp_entity_stats { + uint32_t session_attempts; + uint32_t session_rejects_hello; + uint32_t session_rejects_ad; + uint32_t session_rejects_max_pdu; + uint32_t session_rejects_lr; + uint32_t bad_ldp_id; + uint32_t bad_pdu_len; + uint32_t bad_msg_len; + uint32_t bad_tlv_len; + uint32_t malformed_tlv; + uint32_t keepalive_timer_exp; + uint32_t shutdown_rcv_notify; + uint32_t shutdown_send_notify; }; struct l2vpn_if { @@ -443,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; @@ -465,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 */ @@ -493,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 @@ -562,9 +582,11 @@ struct ldpd_conf { uint16_t trans_pref; uint16_t wait_for_sync_interval; int flags; - QOBJ_FIELDS + time_t config_change_time; + struct ldp_entity_stats stats; + 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 @@ -683,6 +705,8 @@ struct ctl_nbr { int nbr_state; struct ldp_stats stats; int flags; + uint16_t max_pdu_len; + uint16_t hold_time_remaining; }; struct ctl_rt { @@ -891,4 +915,8 @@ 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)); + +extern void ldp_agentx_enabled(void); + #endif /* _LDPD_H_ */ diff --git a/ldpd/ldpe.c b/ldpd/ldpe.c index 6a5a0750bd..d09eb2fa33 100644 --- a/ldpd/ldpe.c +++ b/ldpd/ldpe.c @@ -33,6 +33,7 @@ #include "memory.h" #include "privs.h" #include "sigevent.h" +#include "libfrr.h" static void ldpe_shutdown(void); static int ldpe_dispatch_main(struct thread *); @@ -103,15 +104,13 @@ char *pkt_ptr; /* packet buffer */ void ldpe(void) { - struct thread thread; - #ifdef HAVE_SETPROCTITLE setproctitle("ldp engine"); #endif ldpd_process = PROC_LDP_ENGINE; log_procname = log_procnames[ldpd_process]; - master = thread_master_create(NULL); + master = frr_init(); /* setup signal handler */ signal_init(master, array_size(ldpe_signals), ldpe_signals); @@ -133,9 +132,12 @@ ldpe(void) /* create base configuration */ leconf = config_new_empty(); - /* Fetch next active thread. */ + struct thread thread; while (thread_fetch(master, &thread)) thread_call(&thread); + + /* NOTREACHED */ + return; } void @@ -387,6 +389,9 @@ ldpe_dispatch_main(struct thread *thread) memcpy(&init, imsg.data, sizeof(init)); ldpe_init(&init); break; + case IMSG_AGENTX_ENABLED: + ldp_agentx_enabled(); + break; case IMSG_CLOSE_SOCKETS: af = imsg.hdr.peerid; @@ -1073,3 +1078,10 @@ ldpe_check_filter_af(int af, struct ldpd_af_conf *af_conf, if (strcmp(af_conf->acl_thello_accept_from, filter_name) == 0) ldpe_remove_dynamic_tnbrs(af); } + +void +ldpe_set_config_change_time(void) +{ + /* SNMP update time when ever there is a config change */ + leconf->config_change_time = time(NULL); +} diff --git a/ldpd/ldpe.h b/ldpd/ldpe.h index ef4702341b..880722424e 100644 --- a/ldpd/ldpe.h +++ b/ldpd/ldpe.h @@ -216,6 +216,7 @@ void ldpe_nbr_ctl(struct ctl_conn *); void ldpe_ldp_sync_ctl(struct ctl_conn *); void mapping_list_add(struct mapping_head *, struct map *); void mapping_list_clr(struct mapping_head *); +void ldpe_set_config_change_time(void); /* interface.c */ struct iface *if_new(const char *); @@ -266,6 +267,8 @@ struct nbr *nbr_new(struct in_addr, int, int, union ldpd_addr *, uint32_t); void nbr_del(struct nbr *); struct nbr *nbr_find_ldpid(uint32_t); +struct nbr *nbr_get_first_ldpid(void); +struct nbr *nbr_get_next_ldpid(uint32_t); struct nbr *nbr_find_addr(int, union ldpd_addr *); struct nbr *nbr_find_peerid(uint32_t); int nbr_adj_count(struct nbr *, int); @@ -318,4 +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)); + #endif /* _LDPE_H_ */ diff --git a/ldpd/neighbor.c b/ldpd/neighbor.c index 75deaad2c0..e884b3ebfc 100644 --- a/ldpd/neighbor.c +++ b/ldpd/neighbor.c @@ -26,6 +26,9 @@ #include "lde.h" #include "log.h" +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 *, const struct nbr *); @@ -158,6 +161,8 @@ nbr_fsm(struct nbr *nbr, enum nbr_event event) &nbr->id, nbr_state_name(old_state), nbr_state_name(nbr->state)); + hook_call(ldp_nbr_state_change, nbr, old_state); + if (nbr->state == NBR_STA_OPER) { gettimeofday(&now, NULL); nbr->uptime = now.tv_sec; @@ -355,6 +360,23 @@ nbr_find_ldpid(uint32_t lsr_id) } struct nbr * +nbr_get_first_ldpid() +{ + return (RB_MIN(nbr_id_head, &nbrs_by_id)); +} + +struct nbr * +nbr_get_next_ldpid(uint32_t lsr_id) +{ + struct nbr *nbr; + nbr = nbr_find_ldpid(lsr_id); + if (nbr) + return (RB_NEXT(nbr_id_head, nbr)); + return NULL; +} + + +struct nbr * nbr_find_addr(int af, union ldpd_addr *addr) { struct nbr n; @@ -831,14 +853,20 @@ nbr_to_ctl(struct nbr *nbr) nctl.af = nbr->af; nctl.id = nbr->id; nctl.laddr = nbr->laddr; - nctl.lport = nbr->tcp->lport; + nctl.lport = nbr->tcp ? nbr->tcp->lport : 0; nctl.raddr = nbr->raddr; - nctl.rport = nbr->tcp->rport; + nctl.rport = nbr->tcp ? nbr->tcp->rport : 0; nctl.auth_method = nbr->auth.method; nctl.holdtime = nbr->keepalive; nctl.nbr_state = nbr->state; nctl.stats = nbr->stats; nctl.flags = nbr->flags; + nctl.max_pdu_len = nbr->max_pdu_len; + if (nbr->keepalive_timer) + nctl.hold_time_remaining = + thread_timer_remain_second(nbr->keepalive_timer); + else + nctl.hold_time_remaining = 0; gettimeofday(&now, NULL); if (nbr->state == NBR_STA_OPER) { diff --git a/ldpd/notification.c b/ldpd/notification.c index f84e0f893b..3ecf5d4ba5 100644 --- a/ldpd/notification.c +++ b/ldpd/notification.c @@ -69,6 +69,36 @@ send_notification_full(struct tcp_conn *tcp, struct notify_msg *nm) tcp->nbr->stats.notif_sent++; } + /* update SNMP session counters */ + switch (nm->status_code) { + case S_NO_HELLO: + leconf->stats.session_rejects_hello++; + break; + case S_BAD_LDP_ID: + leconf->stats.bad_ldp_id++; + break; + case S_BAD_PDU_LEN: + leconf->stats.bad_pdu_len++; + break; + case S_BAD_MSG_LEN: + leconf->stats.bad_msg_len++; + break; + case S_BAD_TLV_LEN: + leconf->stats.bad_tlv_len++; + break; + case S_BAD_TLV_VAL: + leconf->stats.malformed_tlv++; + break; + case S_KEEPALIVE_TMR: + leconf->stats.keepalive_timer_exp++; + break; + case S_SHUTDOWN: + leconf->stats.shutdown_send_notify++; + break; + default: + break; + } + evbuf_enqueue(&tcp->wbuf, buf); } @@ -122,6 +152,7 @@ recv_notification(struct nbr *nbr, char *buf, uint16_t len) if (len < STATUS_SIZE) { session_shutdown(nbr, S_BAD_MSG_LEN, msg.id, msg.type); + leconf->stats.bad_msg_len++; return (-1); } memcpy(&st, buf, sizeof(st)); @@ -129,6 +160,7 @@ recv_notification(struct nbr *nbr, char *buf, uint16_t len) if (ntohs(st.length) > STATUS_SIZE - TLV_HDR_SIZE || ntohs(st.length) > len - TLV_HDR_SIZE) { session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type); + leconf->stats.bad_tlv_len++; return (-1); } buf += STATUS_SIZE; @@ -145,6 +177,7 @@ recv_notification(struct nbr *nbr, char *buf, uint16_t len) if (len < sizeof(tlv)) { session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type); + leconf->stats.bad_tlv_len++; return (-1); } @@ -153,6 +186,7 @@ recv_notification(struct nbr *nbr, char *buf, uint16_t len) tlv_len = ntohs(tlv.length); if (tlv_len + TLV_HDR_SIZE > len) { session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type); + leconf->stats.bad_tlv_len++; return (-1); } buf += TLV_HDR_SIZE; @@ -182,14 +216,17 @@ recv_notification(struct nbr *nbr, char *buf, uint16_t len) if (tlen != tlv_len) { session_shutdown(nbr, S_BAD_TLV_VAL, msg.id, msg.type); + leconf->stats.bad_tlv_len++; return (-1); } nm.flags |= F_NOTIF_FEC; break; default: - if (!(ntohs(tlv.type) & UNKNOWN_FLAG)) + if (!(ntohs(tlv.type) & UNKNOWN_FLAG)) { + nbr->stats.unknown_tlv++; send_notification_rtlvs(nbr, S_UNKNOWN_TLV, msg.id, msg.type, tlv_type, tlv_len, buf); + } /* ignore unknown tlv */ break; } @@ -243,21 +280,57 @@ recv_notification(struct nbr *nbr, char *buf, uint16_t len) * initialization, it SHOULD transmit a Shutdown message and * then close the transport connection". */ - if (nbr->state != NBR_STA_OPER && nm.status_code == S_SHUTDOWN) + if (nbr->state != NBR_STA_OPER && + nm.status_code == S_SHUTDOWN) { + leconf->stats.session_attempts++; send_notification(nbr->tcp, S_SHUTDOWN, msg.id, msg.type); + } + leconf->stats.shutdown_rcv_notify++; nbr_fsm(nbr, NBR_EVT_CLOSE_SESSION); return (-1); } - /* lde needs to know about a few notification messages */ + /* lde needs to know about a few notification messages + * and update SNMP session counters + */ switch (nm.status_code) { case S_PW_STATUS: case S_ENDOFLIB: ldpe_imsg_compose_lde(IMSG_NOTIFICATION, nbr->peerid, 0, &nm, sizeof(nm)); break; + case S_NO_HELLO: + leconf->stats.session_rejects_hello++; + break; + case S_PARM_ADV_MODE: + leconf->stats.session_rejects_ad++; + break; + case S_MAX_PDU_LEN: + leconf->stats.session_rejects_max_pdu++; + break; + case S_PARM_L_RANGE: + leconf->stats.session_rejects_lr++; + break; + case S_BAD_LDP_ID: + leconf->stats.bad_ldp_id++; + break; + case S_BAD_PDU_LEN: + leconf->stats.bad_pdu_len++; + break; + case S_BAD_MSG_LEN: + leconf->stats.bad_msg_len++; + break; + case S_BAD_TLV_LEN: + leconf->stats.bad_tlv_len++; + break; + case S_BAD_TLV_VAL: + leconf->stats.malformed_tlv++; + break; + case S_SHUTDOWN: + leconf->stats.shutdown_rcv_notify++; + break; default: break; } diff --git a/ldpd/packet.c b/ldpd/packet.c index fdcaa79d23..8735faf3dd 100644 --- a/ldpd/packet.c +++ b/ldpd/packet.c @@ -560,9 +560,11 @@ session_read(struct thread *thread) default: log_debug("%s: unknown LDP message from nbr %pI4", __func__, &nbr->id); - if (!(ntohs(msg->type) & UNKNOWN_FLAG)) + if (!(ntohs(msg->type) & UNKNOWN_FLAG)) { + nbr->stats.unknown_msg++; send_notification(nbr->tcp, S_UNKNOWN_MSG, msg->id, msg->type); + } /* ignore the message */ ret = 0; break; @@ -667,6 +669,12 @@ session_shutdown(struct nbr *nbr, uint32_t status, uint32_t msg_id, case NBR_STA_INITIAL: case NBR_STA_OPENREC: case NBR_STA_OPENSENT: + /* update SNMP session counters during initialization */ + leconf->stats.session_attempts++; + send_notification(nbr->tcp, status, msg_id, msg_type); + + nbr_fsm(nbr, NBR_EVT_CLOSE_SESSION); + break; case NBR_STA_OPER: send_notification(nbr->tcp, status, msg_id, msg_type); diff --git a/ldpd/subdir.am b/ldpd/subdir.am index d89d18341d..aa9b751bcc 100644 --- a/ldpd/subdir.am +++ b/ldpd/subdir.am @@ -41,6 +41,10 @@ ldpd_libldp_a_SOURCES = \ ldpd/util.c \ # end +if SNMP +module_LTLIBRARIES += ldpd/ldpd_snmp.la +endif + clippy_scan += \ ldpd/ldp_vty_cmds.c \ # end @@ -59,3 +63,8 @@ noinst_HEADERS += \ 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=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 5351f8bda2..b5a035ee2b 100644 --- a/lib/agentx.c +++ b/lib/agentx.c @@ -34,7 +34,9 @@ #include "lib_errors.h" #include "xref.h" -XREF_SETUP() +XREF_SETUP(); + +DEFINE_HOOK(agentx_enabled, (), ()); static int agentx_enabled = 0; @@ -226,6 +228,7 @@ DEFUN (agentx_enable, events = list_new(); agentx_events_update(); agentx_enabled = 1; + hook_call(agentx_enabled); } return CMD_SUCCESS; @@ -243,6 +246,11 @@ DEFUN (no_agentx, return CMD_WARNING_CONFIG_FAILED; } +int smux_enabled(void) +{ + return agentx_enabled; +} + void smux_init(struct thread_master *tm) { agentx_tm = tm; @@ -259,6 +267,16 @@ void smux_init(struct thread_master *tm) install_element(CONFIG_NODE, &no_agentx_cmd); } +void smux_agentx_enable(void) +{ + if (!agentx_enabled) { + init_snmp(FRR_SMUX_NAME); + events = list_new(); + agentx_events_update(); + agentx_enabled = 1; + } +} + void smux_register_mib(const char *descr, struct variable *var, size_t width, int num, oid name[], size_t namelen) { @@ -379,4 +397,9 @@ int smux_trap_multi_index(struct variable *vp, size_t vp_len, const oid *ename, return 1; } +void smux_events_update(void) +{ + agentx_events_update(); +} + #endif /* SNMP_AGENTX */ 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/clippy.h b/lib/clippy.h index be4db6e638..95af274106 100644 --- a/lib/clippy.h +++ b/lib/clippy.h @@ -20,6 +20,7 @@ #ifndef _FRR_CLIPPY_H #define _FRR_CLIPPY_H +#include <stdbool.h> #include <Python.h> #ifdef __cplusplus @@ -28,6 +29,7 @@ extern "C" { extern PyObject *clippy_parse(PyObject *self, PyObject *args); extern PyMODINIT_FUNC command_py_init(void); +extern bool elf_py_init(PyObject *pymod); #ifdef __cplusplus } 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 09824460e6..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; @@ -99,7 +99,7 @@ struct cmd_element { const char *string; /* Command specification by string. */ const char *doc; /* Documentation of this command. */ int daemon; /* Daemon to which this command belong. */ - uint8_t attr; /* Command attributes */ + uint32_t attr; /* Command attributes */ /* handler function for command */ int (*func)(const struct cmd_element *, struct vty *, int, 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/command_py.c b/lib/command_py.c index 4ec116df33..7f19008fbf 100644 --- a/lib/command_py.c +++ b/lib/command_py.c @@ -345,5 +345,7 @@ PyMODINIT_FUNC command_py_init(void) PyModule_AddObject(pymod, "GraphNode", (PyObject *)&typeobj_graph_node); Py_INCREF(&typeobj_graph); PyModule_AddObject(pymod, "Graph", (PyObject *)&typeobj_graph); + if (!elf_py_init(pymod)) + initret(NULL); initret(pymod); } 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 new file mode 100644 index 0000000000..d26e443b82 --- /dev/null +++ b/lib/elf_py.c @@ -0,0 +1,1301 @@ +/* + * fast ELF file accessor + * Copyright (C) 2018-2020 David Lamparter for 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 + */ + +/* Note: this wrapper is intended to be used as build-time helper. While + * it should be generally correct and proper, there may be the occasional + * memory leak or SEGV for things that haven't been well-tested. + * _ + * / \ This code is NOT SUITABLE FOR UNTRUSTED ELF FILES. It's used + * / ! \ in FRR to read files created by its own build. Don't take it out + * /_____\ of FRR and use it to parse random ELF files you found somewhere. + * + * If you're working with this code (or even reading it), you really need to + * read a bunch of the ELF specs. There's no way around it, things in here + * just represent pieces of ELF pretty much 1:1. Also, readelf & objdump are + * your friends. + * + * Required reading: + * https://refspecs.linuxfoundation.org/elf/elf.pdf + * https://refspecs.linuxfoundation.org/elf/x86_64-SysV-psABI.pdf + * Recommended reading: + * https://github.com/ARM-software/abi-aa/releases/download/2020Q4/aaelf64.pdf + * + * The core ELF spec is *not* enough, you should read at least one of the + * processor specific (psABI) docs. They define what & how relocations work. + * Luckily we don't need to care about the processor specifics since this only + * does data relocations, but without looking at the psABI, some things aren't + * quite clear. + */ + +/* the API of this module roughly follows a very small subset of the one + * provided by the python elfutils package, which unfortunately is painfully + * slow. + */ + +#define PY_SSIZE_T_CLEAN + +#include <Python.h> +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "structmember.h" +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/mman.h> +#include <fcntl.h> + +#if defined(__sun__) && (__SIZEOF_POINTER__ == 4) +/* Solaris libelf bails otherwise ... */ +#undef _FILE_OFFSET_BITS +#define _FILE_OFFSET_BITS 32 +#endif + +#include <elf.h> +#include <libelf.h> +#include <gelf.h> + +#include "typesafe.h" +#include "jhash.h" +#include "clippy.h" + +static bool debug; + +#define debugf(...) \ + do { \ + if (debug) \ + fprintf(stderr, __VA_ARGS__); \ + } while (0) + +/* Exceptions */ +static PyObject *ELFFormatError; +static PyObject *ELFAccessError; + +/* most objects can only be created as return values from one of the methods */ +static PyObject *refuse_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyErr_SetString(PyExc_ValueError, + "cannot create instances of this type"); + return NULL; +} + +struct elfreloc; +struct elfsect; + +PREDECL_HASH(elfrelocs); + +/* ELFFile and ELFSection intentionally share some behaviour, particularly + * subscript[123:456] access to file data. This is because relocatables + * (.o files) do things section-based, but linked executables/libraries do + * things file-based. Having the two behave similar allows simplifying the + * Python code. + */ + +/* class ELFFile: + * + * overall entry point, instantiated by reading in an ELF file + */ +struct elffile { + PyObject_HEAD + + char *filename; + char *mmap, *mmend; + size_t len; + Elf *elf; + + /* note from here on there are several instances of + * + * GElf_Something *x, _x; + * + * this is a pattern used by libelf's generic ELF routines; the _x + * field is used to create a copy of the ELF structure from the file + * with 32/64bit and endianness adjusted. + */ + + GElf_Ehdr *ehdr, _ehdr; + Elf_Scn *symtab; + size_t nsym, symstridx; + Elf_Data *symdata; + + PyObject **sects; + size_t n_sect; + + struct elfrelocs_head dynrelocs; + + int elfclass; + bool bigendian; + bool has_symbols; +}; + +/* class ELFSection: + * + * note that executables and shared libraries can have their section headers + * removed, though in practice this is only used as an obfuscation technique. + */ +struct elfsect { + PyObject_HEAD + + const char *name; + struct elffile *ef; + + GElf_Shdr _shdr, *shdr; + Elf_Scn *scn; + unsigned long idx, len; + + struct elfrelocs_head relocs; +}; + +/* class ELFReloc: + * + * note: relocations in object files (.o) are section-based while relocations + * in executables and shared libraries are file-based. + * + * Whenever accessing something that is a pointer in the ELF file, the Python + * code needs to check for a relocation; if the pointer is pointing to some + * unresolved symbol the file will generally contain 0 bytes. The relocation + * will tell what the pointer is actually pointing to. + * + * This represents both static (.o file) and dynamic (.so/exec) relocations. + */ +struct elfreloc { + PyObject_HEAD + + struct elfrelocs_item elfrelocs_item; + + struct elfsect *es; + struct elffile *ef; + + /* there's also old-fashioned GElf_Rel; we're converting that to + * GElf_Rela in elfsect_add_relocations() + */ + GElf_Rela _rela, *rela; + GElf_Sym _sym, *sym; + size_t symidx; + const char *symname; + + /* documented below in python docstrings */ + bool symvalid, unresolved, relative; + unsigned long long st_value; +}; + +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); + +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); +static PyObject *elfreloc_getsection(PyObject *self, PyObject *args); +static PyObject *elfreloc_getaddend(PyObject *obj, void *closure); + +/* --- end of declarations -------------------------------------------------- */ + +/* + * class ELFReloc: + */ + +static const char elfreloc_doc[] = + "Represents an ELF relocation record\n" + "\n" + "(struct elfreloc * in elf_py.c)"; + +#define member(name, type, doc) \ + { \ + (char *)#name, type, offsetof(struct elfreloc, name), READONLY,\ + (char *)doc "\n\n(\"" #name "\", " #type " in elf_py.c)" \ + } +static PyMemberDef members_elfreloc[] = { + member(symname, T_STRING, + "Name of symbol this relocation refers to.\n" + "\n" + "Will frequently be `None` in executables and shared libraries." + ), + member(symvalid, T_BOOL, + "Target symbol has a valid type, i.e. not STT_NOTYPE"), + member(unresolved, T_BOOL, + "Target symbol refers to an existing section"), + member(relative, T_BOOL, + "Relocation is a REL (not RELA) record and thus relative."), + member(st_value, T_ULONGLONG, + "Target symbol's value, if known\n\n" + "Will be zero for unresolved/external symbols."), + {} +}; +#undef member + +static PyGetSetDef getset_elfreloc[] = { + { .name = (char *)"r_addend", .get = elfreloc_getaddend, .doc = + (char *)"Relocation addend value"}, + {} +}; + +static PyMethodDef methods_elfreloc[] = { + {"getsection", elfreloc_getsection, METH_VARARGS, + "Find relocation target's ELF section\n\n" + "Args: address of relocatee (TODO: fix/remove?)\n" + "Returns: ELFSection or None\n\n" + "Not possible if section headers have been stripped."}, + {} +}; + +static int elfreloc_cmp(const struct elfreloc *a, const struct elfreloc *b) +{ + if (a->rela->r_offset < b->rela->r_offset) + return -1; + if (a->rela->r_offset > b->rela->r_offset) + return 1; + return 0; +} + +static uint32_t elfreloc_hash(const struct elfreloc *reloc) +{ + return jhash(&reloc->rela->r_offset, sizeof(reloc->rela->r_offset), + 0xc9a2b7f4); +} + +static struct elfreloc *elfrelocs_get(struct elfrelocs_head *head, + GElf_Addr offset) +{ + struct elfreloc dummy; + + dummy.rela = &dummy._rela; + dummy.rela->r_offset = offset; + return elfrelocs_find(head, &dummy); +} + +static PyObject *elfreloc_getsection(PyObject *self, PyObject *args) +{ + struct elfreloc *w = (struct elfreloc *)self; + long data; + + if (!PyArg_ParseTuple(args, "k", &data)) + return NULL; + + if (!w->es) + Py_RETURN_NONE; + + if (w->symidx == 0) { + size_t idx = 0; + Elf_Scn *scn; + + data = (w->relative ? data : 0) + w->rela->r_addend; + scn = elf_find_addr(w->es->ef, data, &idx); + if (!scn) + Py_RETURN_NONE; + return elffile_secbyidx(w->es->ef, scn, idx); + } + return elffile_secbyidx(w->es->ef, NULL, w->sym->st_shndx); +} + +static PyObject *elfreloc_getaddend(PyObject *obj, void *closure) +{ + struct elfreloc *w = (struct elfreloc *)obj; + + return Py_BuildValue("K", (unsigned long long)w->rela->r_addend); +} + +static PyObject *elfreloc_repr(PyObject *arg) +{ + struct elfreloc *w = (struct elfreloc *)arg; + + return PyUnicode_FromFormat("<ELFReloc @%lu %s+%lu>", + (unsigned long)w->rela->r_offset, + (w->symname && w->symname[0]) ? w->symname + : "[0]", + (unsigned long)w->rela->r_addend); +} + +static void elfreloc_free(void *arg) +{ + struct elfreloc *w = arg; + + (void)w; +} + +static PyTypeObject typeobj_elfreloc = { + PyVarObject_HEAD_INIT(NULL, 0).tp_name = "_clippy.ELFReloc", + .tp_basicsize = sizeof(struct elfreloc), + .tp_flags = Py_TPFLAGS_DEFAULT, + .tp_doc = elfreloc_doc, + .tp_new = refuse_new, + .tp_free = elfreloc_free, + .tp_repr = elfreloc_repr, + .tp_members = members_elfreloc, + .tp_methods = methods_elfreloc, + .tp_getset = getset_elfreloc, +}; + +/* + * class ELFSection: + */ + +static const char elfsect_doc[] = + "Represents an ELF section\n" + "\n" + "To access section contents, use subscript notation, e.g.\n" + " section[123:456]\n" + "To read null terminated C strings, replace the end with str:\n" + " section[123:str]\n\n" + "(struct elfsect * in elf_py.c)"; + +static PyObject *elfsect_getaddr(PyObject *self, void *closure); + +#define member(name, type, doc) \ + { \ + (char *)#name, type, offsetof(struct elfsect, name), READONLY, \ + (char *)doc "\n\n(\"" #name "\", " #type " in elf_py.c)" \ + } +static PyMemberDef members_elfsect[] = { + member(name, T_STRING, + "Section name, e.g. \".text\""), + member(idx, T_ULONG, + "Section index in file"), + member(len, T_ULONG, + "Section length in bytes"), + {}, +}; +#undef member + +static PyGetSetDef getset_elfsect[] = { + { .name = (char *)"sh_addr", .get = elfsect_getaddr, .doc = + (char *)"Section virtual address (mapped program view)"}, + {} +}; + +static PyObject *elfsect_getaddr(PyObject *self, void *closure) +{ + struct elfsect *w = (struct elfsect *)self; + + return Py_BuildValue("K", (unsigned long long)w->shdr->sh_addr); +} + + +static PyObject *elfsect_getreloc(PyObject *self, PyObject *args) +{ + struct elfsect *w = (struct elfsect *)self; + struct elfreloc *relw; + unsigned long offs; + PyObject *ret; + + if (!PyArg_ParseTuple(args, "k", &offs)) + return NULL; + + relw = elfrelocs_get(&w->relocs, offs + w->shdr->sh_addr); + if (!relw) + Py_RETURN_NONE; + + ret = (PyObject *)relw; + Py_INCREF(ret); + return ret; +} + +static PyMethodDef methods_elfsect[] = { + {"getreloc", elfsect_getreloc, METH_VARARGS, + "Check for / get relocation at offset into section\n\n" + "Args: byte offset into section to check\n" + "Returns: ELFReloc or None"}, + {} +}; + +static PyObject *elfsect_subscript(PyObject *self, PyObject *key) +{ + Py_ssize_t start, stop, step, sllen; + struct elfsect *w = (struct elfsect *)self; + PySliceObject *slice; + unsigned long offs, len = ~0UL; + + if (!PySlice_Check(key)) { + PyErr_SetString(PyExc_IndexError, + "ELFSection subscript must be slice"); + return NULL; + } + slice = (PySliceObject *)key; + if (PyLong_Check(slice->stop)) { + if (PySlice_GetIndicesEx(key, w->shdr->sh_size, + &start, &stop, &step, &sllen)) + return NULL; + + if (step != 1) { + PyErr_SetString(PyExc_IndexError, + "ELFSection subscript slice step must be 1"); + return NULL; + } + if ((GElf_Xword)stop > w->shdr->sh_size) { + PyErr_Format(ELFAccessError, + "access (%lu) beyond end of section %lu/%s (%lu)", + stop, w->idx, w->name, w->shdr->sh_size); + return NULL; + } + + offs = start; + len = sllen; + } else { + if (slice->stop != (void *)&PyUnicode_Type + || !PyLong_Check(slice->start)) { + PyErr_SetString(PyExc_IndexError, "invalid slice"); + return NULL; + } + + offs = PyLong_AsUnsignedLongLong(slice->start); + len = ~0UL; + } + + offs += w->shdr->sh_offset; + if (offs > w->ef->len) { + PyErr_Format(ELFAccessError, + "access (%lu) beyond end of file (%lu)", + offs, w->ef->len); + return NULL; + } + if (len == ~0UL) + len = strnlen(w->ef->mmap + offs, w->ef->len - offs); + + Py_ssize_t pylen = len; + +#if PY_MAJOR_VERSION >= 3 + return Py_BuildValue("y#", w->ef->mmap + offs, pylen); +#else + return Py_BuildValue("s#", w->ef->mmap + offs, pylen); +#endif +} + +static PyMappingMethods mp_elfsect = { + .mp_subscript = elfsect_subscript, +}; + +static void elfsect_free(void *arg) +{ + struct elfsect *w = arg; + + (void)w; +} + +static PyObject *elfsect_repr(PyObject *arg) +{ + struct elfsect *w = (struct elfsect *)arg; + + return PyUnicode_FromFormat("<ELFSection %s>", w->name); +} + +static PyTypeObject typeobj_elfsect = { + PyVarObject_HEAD_INIT(NULL, 0).tp_name = "_clippy.ELFSection", + .tp_basicsize = sizeof(struct elfsect), + .tp_flags = Py_TPFLAGS_DEFAULT, + .tp_doc = elfsect_doc, + .tp_new = refuse_new, + .tp_free = elfsect_free, + .tp_repr = elfsect_repr, + .tp_as_mapping = &mp_elfsect, + .tp_members = members_elfsect, + .tp_methods = methods_elfsect, + .tp_getset = getset_elfsect, +}; + +static void elfsect_add_relocations(struct elfsect *w, Elf_Scn *rel, + GElf_Shdr *relhdr) +{ + size_t i, entries; + Elf_Scn *symtab = elf_getscn(w->ef->elf, relhdr->sh_link); + GElf_Shdr _symhdr, *symhdr = gelf_getshdr(symtab, &_symhdr); + Elf_Data *symdata = elf_getdata(symtab, NULL); + Elf_Data *reldata = elf_getdata(rel, NULL); + + entries = relhdr->sh_size / relhdr->sh_entsize; + for (i = 0; i < entries; i++) { + struct elfreloc *relw; + size_t symidx; + GElf_Rela *rela; + GElf_Sym *sym; + + relw = (struct elfreloc *)typeobj_elfreloc.tp_alloc( + &typeobj_elfreloc, 0); + relw->es = w; + + if (relhdr->sh_type == SHT_REL) { + GElf_Rel _rel, *rel; + + rel = gelf_getrel(reldata, i, &_rel); + relw->rela = &relw->_rela; + relw->rela->r_offset = rel->r_offset; + relw->rela->r_info = rel->r_info; + relw->rela->r_addend = 0; + relw->relative = true; + } else + relw->rela = gelf_getrela(reldata, i, &relw->_rela); + + rela = relw->rela; + if (rela->r_offset < w->shdr->sh_addr + || rela->r_offset >= w->shdr->sh_addr + w->shdr->sh_size) + continue; + + symidx = relw->symidx = GELF_R_SYM(rela->r_info); + sym = relw->sym = gelf_getsym(symdata, symidx, &relw->_sym); + if (sym) { + relw->symname = elf_strptr(w->ef->elf, symhdr->sh_link, + sym->st_name); + relw->symvalid = GELF_ST_TYPE(sym->st_info) + != STT_NOTYPE; + relw->unresolved = sym->st_shndx == SHN_UNDEF; + relw->st_value = sym->st_value; + } else { + relw->symname = NULL; + relw->symvalid = false; + relw->unresolved = false; + relw->st_value = 0; + } + + debugf("reloc @ %016llx sym %5llu %016llx %s\n", + (long long)rela->r_offset, (unsigned long long)symidx, + (long long)rela->r_addend, relw->symname); + + elfrelocs_add(&w->relocs, relw); + } +} + +/* + * bindings & loading code between ELFFile and ELFSection + */ + +static PyObject *elfsect_wrap(struct elffile *ef, Elf_Scn *scn, size_t idx, + const char *name) +{ + struct elfsect *w; + size_t i; + + w = (struct elfsect *)typeobj_elfsect.tp_alloc(&typeobj_elfsect, 0); + if (!w) + return NULL; + + w->name = name; + w->ef = ef; + w->scn = scn; + w->shdr = gelf_getshdr(scn, &w->_shdr); + w->len = w->shdr->sh_size; + w->idx = idx; + elfrelocs_init(&w->relocs); + + for (i = 0; i < ef->ehdr->e_shnum; i++) { + Elf_Scn *scn = elf_getscn(ef->elf, i); + GElf_Shdr _shdr, *shdr = gelf_getshdr(scn, &_shdr); + + if (shdr->sh_type != SHT_RELA && shdr->sh_type != SHT_REL) + continue; + if (shdr->sh_info && shdr->sh_info != idx) + continue; + elfsect_add_relocations(w, scn, shdr); + } + + return (PyObject *)w; +} + +static Elf_Scn *elf_find_section(struct elffile *ef, const char *name, + size_t *idx) +{ + size_t i; + const char *secname; + + for (i = 0; i < ef->ehdr->e_shnum; i++) { + Elf_Scn *scn = elf_getscn(ef->elf, i); + GElf_Shdr _shdr, *shdr = gelf_getshdr(scn, &_shdr); + + secname = elf_strptr(ef->elf, ef->ehdr->e_shstrndx, + shdr->sh_name); + if (strcmp(secname, name)) + continue; + if (idx) + *idx = i; + return scn; + } + return NULL; +} + +static Elf_Scn *elf_find_addr(struct elffile *ef, uint64_t addr, size_t *idx) +{ + size_t i; + + for (i = 0; i < ef->ehdr->e_shnum; i++) { + Elf_Scn *scn = elf_getscn(ef->elf, i); + GElf_Shdr _shdr, *shdr = gelf_getshdr(scn, &_shdr); + + if (addr < shdr->sh_addr || + addr >= shdr->sh_addr + shdr->sh_size) + continue; + + if (idx) + *idx = i; + return scn; + } + return NULL; +} + +/* + * class ELFFile: + */ + +static const char elffile_doc[] = + "Represents an ELF file\n" + "\n" + "Args: filename to load\n" + "\n" + "To access raw file contents, use subscript notation, e.g.\n" + " file[123:456]\n" + "To read null terminated C strings, replace the end with str:\n" + " file[123:str]\n\n" + "(struct elffile * in elf_py.c)"; + + +#define member(name, type, doc) \ + { \ + (char *)#name, type, offsetof(struct elffile, name), READONLY, \ + (char *)doc "\n\n(\"" #name "\", " #type " in elf_py.c)" \ + } +static PyMemberDef members_elffile[] = { + member(filename, T_STRING, + "Original file name as given when opening"), + member(elfclass, T_INT, + "ELF class (architecture bit size)\n\n" + "Either 32 or 64, straight integer."), + member(bigendian, T_BOOL, + "ELF file is big-endian\n\n" + "All internal ELF structures are automatically converted."), + member(has_symbols, T_BOOL, + "A symbol section is present\n\n" + "Note: only refers to .symtab/SHT_SYMTAB section, not DT_SYMTAB" + ), + {}, +}; +#undef member + +static PyObject *elffile_secbyidx(struct elffile *w, Elf_Scn *scn, size_t idx) +{ + const char *name; + PyObject *ret; + + if (!scn) + scn = elf_getscn(w->elf, idx); + if (!scn || idx >= w->n_sect) + Py_RETURN_NONE; + + if (!w->sects[idx]) { + GElf_Shdr _shdr, *shdr = gelf_getshdr(scn, &_shdr); + + name = elf_strptr(w->elf, w->ehdr->e_shstrndx, shdr->sh_name); + w->sects[idx] = elfsect_wrap(w, scn, idx, name); + } + + ret = w->sects[idx]; + Py_INCREF(ret); + return ret; +} + +static PyObject *elffile_get_section(PyObject *self, PyObject *args) +{ + const char *name; + struct elffile *w = (struct elffile *)self; + Elf_Scn *scn; + size_t idx = 0; + + if (!PyArg_ParseTuple(args, "s", &name)) + return NULL; + + scn = elf_find_section(w, name, &idx); + return elffile_secbyidx(w, scn, idx); +} + +static PyObject *elffile_get_section_addr(PyObject *self, PyObject *args) +{ + unsigned long long addr; + struct elffile *w = (struct elffile *)self; + Elf_Scn *scn; + size_t idx = 0; + + if (!PyArg_ParseTuple(args, "K", &addr)) + return NULL; + + scn = elf_find_addr(w, addr, &idx); + return elffile_secbyidx(w, scn, idx); +} + +static PyObject *elffile_get_section_idx(PyObject *self, PyObject *args) +{ + unsigned long long idx; + struct elffile *w = (struct elffile *)self; + + if (!PyArg_ParseTuple(args, "K", &idx)) + return NULL; + + return elffile_secbyidx(w, NULL, idx); +} + +static PyObject *elffile_get_symbol(PyObject *self, PyObject *args) +{ + const char *name, *symname; + struct elffile *w = (struct elffile *)self; + GElf_Sym _sym, *sym; + size_t i; + + if (!PyArg_ParseTuple(args, "s", &name)) + return NULL; + + for (i = 0; i < w->nsym; i++) { + sym = gelf_getsym(w->symdata, i, &_sym); + if (sym->st_name == 0) + continue; + symname = elf_strptr(w->elf, w->symstridx, sym->st_name); + if (strcmp(symname, name)) + continue; + + PyObject *pysect; + Elf_Scn *scn = elf_getscn(w->elf, sym->st_shndx); + + if (scn) + pysect = elffile_secbyidx(w, scn, sym->st_shndx); + else { + pysect = Py_None; + Py_INCREF(pysect); + } + return Py_BuildValue("sKN", symname, + (unsigned long long)sym->st_value, pysect); + } + Py_RETURN_NONE; +} + +static PyObject *elffile_getreloc(PyObject *self, PyObject *args) +{ + struct elffile *w = (struct elffile *)self; + struct elfreloc *relw; + unsigned long offs; + PyObject *ret; + + if (!PyArg_ParseTuple(args, "k", &offs)) + return NULL; + + relw = elfrelocs_get(&w->dynrelocs, offs); + if (!relw) + Py_RETURN_NONE; + + ret = (PyObject *)relw; + Py_INCREF(ret); + return ret; +} + +static PyObject *elffile_find_note(PyObject *self, PyObject *args) +{ +#if defined(HAVE_GELF_GETNOTE) && defined(HAVE_ELF_GETDATA_RAWCHUNK) + const char *owner; + const uint8_t *ids; + GElf_Word id; + struct elffile *w = (struct elffile *)self; + size_t i; + + if (!PyArg_ParseTuple(args, "ss", &owner, &ids)) + return NULL; + + if (strlen((char *)ids) != 4) { + PyErr_SetString(PyExc_ValueError, + "ELF note ID must be exactly 4-byte string"); + return NULL; + } + if (w->bigendian) + id = (ids[0] << 24) | (ids[1] << 16) | (ids[2] << 8) | ids[3]; + else + id = (ids[3] << 24) | (ids[2] << 16) | (ids[1] << 8) | ids[0]; + + for (i = 0; i < w->ehdr->e_phnum; i++) { + GElf_Phdr _phdr, *phdr = gelf_getphdr(w->elf, i, &_phdr); + Elf_Data *notedata; + size_t offset; + + if (phdr->p_type != PT_NOTE) + continue; + + notedata = elf_getdata_rawchunk(w->elf, phdr->p_offset, + phdr->p_filesz, ELF_T_NHDR); + + GElf_Nhdr nhdr[1]; + size_t nameoffs, dataoffs; + + offset = 0; + while ((offset = gelf_getnote(notedata, offset, nhdr, + &nameoffs, &dataoffs))) { + if (phdr->p_offset + nameoffs >= w->len) + continue; + + const char *name = w->mmap + phdr->p_offset + nameoffs; + + if (strcmp(name, owner)) + continue; + if (id != nhdr->n_type) + continue; + + PyObject *s, *e; + + s = PyLong_FromUnsignedLongLong( + phdr->p_vaddr + dataoffs); + e = PyLong_FromUnsignedLongLong( + phdr->p_vaddr + dataoffs + nhdr->n_descsz); + return PySlice_New(s, e, NULL); + } + } +#endif + Py_RETURN_NONE; +} + +static bool elffile_virt2file(struct elffile *w, GElf_Addr virt, + GElf_Addr *offs) +{ + *offs = 0; + + for (size_t i = 0; i < w->ehdr->e_phnum; i++) { + GElf_Phdr _phdr, *phdr = gelf_getphdr(w->elf, i, &_phdr); + + if (phdr->p_type != PT_LOAD) + continue; + + if (virt < phdr->p_vaddr + || virt >= phdr->p_vaddr + phdr->p_memsz) + continue; + + if (virt >= phdr->p_vaddr + phdr->p_filesz) + return false; + + *offs = virt - phdr->p_vaddr + phdr->p_offset; + return true; + } + + return false; +} + +static PyObject *elffile_subscript(PyObject *self, PyObject *key) +{ + Py_ssize_t start, stop, step; + PySliceObject *slice; + struct elffile *w = (struct elffile *)self; + bool str = false; + + if (!PySlice_Check(key)) { + PyErr_SetString(PyExc_IndexError, + "ELFFile subscript must be slice"); + return NULL; + } + slice = (PySliceObject *)key; + stop = -1; + step = 1; + if (PyLong_Check(slice->stop)) { + start = PyLong_AsSsize_t(slice->start); + if (PyErr_Occurred()) + return NULL; + if (slice->stop != Py_None) { + stop = PyLong_AsSsize_t(slice->stop); + if (PyErr_Occurred()) + return NULL; + } + if (slice->step != Py_None) { + step = PyLong_AsSsize_t(slice->step); + if (PyErr_Occurred()) + return NULL; + } + } else { + if (slice->stop != (void *)&PyUnicode_Type + || !PyLong_Check(slice->start)) { + PyErr_SetString(PyExc_IndexError, "invalid slice"); + return NULL; + } + + str = true; + start = PyLong_AsUnsignedLongLong(slice->start); + } + if (step != 1) { + PyErr_SetString(PyExc_IndexError, + "ELFFile subscript slice step must be 1"); + return NULL; + } + + GElf_Addr xstart = start, xstop = stop; + + for (size_t i = 0; i < w->ehdr->e_phnum; i++) { + GElf_Phdr _phdr, *phdr = gelf_getphdr(w->elf, i, &_phdr); + + if (phdr->p_type != PT_LOAD) + continue; + + if (xstart < phdr->p_vaddr + || xstart >= phdr->p_vaddr + phdr->p_memsz) + continue; + if (!str && (xstop < phdr->p_vaddr + || xstop > phdr->p_vaddr + phdr->p_memsz)) { + PyErr_Format(ELFAccessError, + "access (%llu) beyond end of program header (%llu)", + (long long)xstop, + (long long)(phdr->p_vaddr + + phdr->p_memsz)); + return NULL; + } + + xstart = xstart - phdr->p_vaddr + phdr->p_offset; + + if (str) + xstop = strlen(w->mmap + xstart); + else + xstop = xstop - phdr->p_vaddr + phdr->p_offset; + + Py_ssize_t pylen = xstop - xstart; + +#if PY_MAJOR_VERSION >= 3 + return Py_BuildValue("y#", w->mmap + xstart, pylen); +#else + return Py_BuildValue("s#", w->mmap + xstart, pylen); +#endif + }; + + return PyErr_Format(ELFAccessError, + "virtual address (%llu) not found in program headers", + (long long)start); +} + +static PyMethodDef methods_elffile[] = { + {"find_note", elffile_find_note, METH_VARARGS, + "find specific note entry"}, + {"getreloc", elffile_getreloc, METH_VARARGS, + "find relocation"}, + {"get_symbol", elffile_get_symbol, METH_VARARGS, + "find symbol by name"}, + {"get_section", elffile_get_section, METH_VARARGS, + "find section by name"}, + {"get_section_addr", elffile_get_section_addr, METH_VARARGS, + "find section by address"}, + {"get_section_idx", elffile_get_section_idx, METH_VARARGS, + "find section by index"}, + {} +}; + +static PyObject *elffile_load(PyTypeObject *type, PyObject *args, + PyObject *kwds); + +static void elffile_free(void *arg) +{ + struct elffile *w = arg; + + elf_end(w->elf); + munmap(w->mmap, w->len); + free(w->filename); +} + +static PyMappingMethods mp_elffile = { + .mp_subscript = elffile_subscript, +}; + +static PyTypeObject typeobj_elffile = { + PyVarObject_HEAD_INIT(NULL, 0).tp_name = "_clippy.ELFFile", + .tp_basicsize = sizeof(struct elffile), + .tp_flags = Py_TPFLAGS_DEFAULT, + .tp_doc = elffile_doc, + .tp_new = elffile_load, + .tp_free = elffile_free, + .tp_as_mapping = &mp_elffile, + .tp_members = members_elffile, + .tp_methods = methods_elffile, +}; + +static char *elfdata_strptr(Elf_Data *data, size_t offset) +{ + char *p; + + if (offset >= data->d_size) + return NULL; + + p = (char *)data->d_buf + offset; + if (strnlen(p, data->d_size - offset) >= data->d_size - offset) + return NULL; + + return p; +} + +static void elffile_add_dynreloc(struct elffile *w, Elf_Data *reldata, + size_t entries, Elf_Data *symdata, + Elf_Data *strdata) +{ + size_t i; + + for (i = 0; i < entries; i++) { + struct elfreloc *relw; + size_t symidx; + GElf_Rela *rela; + GElf_Sym *sym; + + relw = (struct elfreloc *)typeobj_elfreloc.tp_alloc( + &typeobj_elfreloc, 0); + relw->ef = w; + + rela = relw->rela = gelf_getrela(reldata, i, &relw->_rela); + symidx = relw->symidx = GELF_R_SYM(rela->r_info); + sym = relw->sym = gelf_getsym(symdata, symidx, &relw->_sym); + if (sym) { + relw->symname = elfdata_strptr(strdata, sym->st_name); + relw->symvalid = GELF_ST_TYPE(sym->st_info) + != STT_NOTYPE; + relw->unresolved = sym->st_shndx == SHN_UNDEF; + relw->st_value = sym->st_value; + } else { + relw->symname = NULL; + relw->symvalid = false; + relw->unresolved = false; + relw->st_value = 0; + } + + debugf("dynreloc @ %016llx sym %5llu %016llx %s\n", + (long long)rela->r_offset, (unsigned long long)symidx, + (long long)rela->r_addend, relw->symname); + + elfrelocs_add(&w->dynrelocs, relw); + } + +} + +/* primary (only, really) entry point to anything in this module */ +static PyObject *elffile_load(PyTypeObject *type, PyObject *args, + PyObject *kwds) +{ + const char *filename; + static const char * const kwnames[] = {"filename", NULL}; + struct elffile *w; + struct stat st; + int fd, err; + + w = (struct elffile *)typeobj_elffile.tp_alloc(&typeobj_elffile, 0); + if (!w) + return NULL; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", (char **)kwnames, + &filename)) + return NULL; + + w->filename = strdup(filename); + fd = open(filename, O_RDONLY | O_NOCTTY); + if (fd < 0 || fstat(fd, &st)) { + PyErr_SetFromErrnoWithFilename(PyExc_OSError, filename); + close(fd); + goto out; + } + w->len = st.st_size; + w->mmap = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0); + if (!w->mmap) { + PyErr_SetFromErrnoWithFilename(PyExc_IOError, filename); + close(fd); + goto out; + } + close(fd); + w->mmend = w->mmap + st.st_size; + + if (w->len < EI_NIDENT || memcmp(w->mmap, ELFMAG, SELFMAG)) { + PyErr_SetString(ELFFormatError, "invalid ELF signature"); + goto out; + } + + switch (w->mmap[EI_CLASS]) { + case ELFCLASS32: + w->elfclass = 32; + break; + case ELFCLASS64: + w->elfclass = 64; + break; + default: + PyErr_SetString(ELFFormatError, "invalid ELF class"); + goto out; + } + switch (w->mmap[EI_DATA]) { + case ELFDATA2LSB: + w->bigendian = false; + break; + case ELFDATA2MSB: + w->bigendian = true; + break; + default: + PyErr_SetString(ELFFormatError, "invalid ELF byte order"); + goto out; + } + + w->elf = elf_memory(w->mmap, w->len); + if (!w->elf) + goto out_elferr; + w->ehdr = gelf_getehdr(w->elf, &w->_ehdr); + if (!w->ehdr) + goto out_elferr; + + for (size_t i = 0; i < w->ehdr->e_shnum; i++) { + Elf_Scn *scn = elf_getscn(w->elf, i); + GElf_Shdr _shdr, *shdr = gelf_getshdr(scn, &_shdr); + + if (shdr->sh_type == SHT_SYMTAB) { + w->symtab = scn; + w->nsym = shdr->sh_size / shdr->sh_entsize; + w->symdata = elf_getdata(scn, NULL); + w->symstridx = shdr->sh_link; + break; + } + } + w->has_symbols = w->symtab && w->symstridx; + elfrelocs_init(&w->dynrelocs); + +#ifdef HAVE_ELF_GETDATA_RAWCHUNK + for (size_t i = 0; i < w->ehdr->e_phnum; i++) { + GElf_Phdr _phdr, *phdr = gelf_getphdr(w->elf, i, &_phdr); + + if (phdr->p_type != PT_DYNAMIC) + continue; + + Elf_Data *dyndata = elf_getdata_rawchunk(w->elf, + phdr->p_offset, phdr->p_filesz, ELF_T_DYN); + + GElf_Addr dynrela = 0, symtab = 0, strtab = 0; + size_t dynrelasz = 0, dynrelaent = 0, strsz = 0; + GElf_Dyn _dyn, *dyn; + + for (size_t j = 0;; j++) { + dyn = gelf_getdyn(dyndata, j, &_dyn); + + if (dyn->d_tag == DT_NULL) + break; + + switch (dyn->d_tag) { + case DT_SYMTAB: + symtab = dyn->d_un.d_ptr; + break; + + case DT_STRTAB: + strtab = dyn->d_un.d_ptr; + break; + case DT_STRSZ: + strsz = dyn->d_un.d_val; + break; + + case DT_RELA: + dynrela = dyn->d_un.d_ptr; + break; + case DT_RELASZ: + dynrelasz = dyn->d_un.d_val; + break; + case DT_RELAENT: + dynrelaent = dyn->d_un.d_val; + break; + + case DT_RELSZ: + if (dyn->d_un.d_val) + fprintf(stderr, + "WARNING: ignoring non-empty DT_REL!\n"); + break; + } + } + + GElf_Addr offset; + Elf_Data *symdata = NULL, *strdata = NULL, *reladata = NULL; + + if (elffile_virt2file(w, symtab, &offset)) + symdata = elf_getdata_rawchunk(w->elf, offset, + w->len - offset, + ELF_T_SYM); + if (elffile_virt2file(w, strtab, &offset)) + strdata = elf_getdata_rawchunk(w->elf, offset, + strsz, ELF_T_BYTE); + + if (!dynrela || !dynrelasz || !dynrelaent) + continue; + + if (!elffile_virt2file(w, dynrela, &offset)) + continue; + + debugf("dynrela @%llx/%llx+%llx\n", (long long)dynrela, + (long long)offset, (long long)dynrelasz); + + reladata = elf_getdata_rawchunk(w->elf, offset, dynrelasz, + ELF_T_RELA); + elffile_add_dynreloc(w, reladata, dynrelasz / dynrelaent, + symdata, strdata); + } +#endif + + w->sects = calloc(sizeof(PyObject *), w->ehdr->e_shnum); + w->n_sect = w->ehdr->e_shnum; + + return (PyObject *)w; + +out_elferr: + err = elf_errno(); + + PyErr_Format(ELFFormatError, "libelf error %d: %s", + err, elf_errmsg(err)); +out: + if (w->elf) + elf_end(w->elf); + free(w->filename); + return NULL; +} + +static PyObject *elfpy_debug(PyObject *self, PyObject *args) +{ + int arg; + + if (!PyArg_ParseTuple(args, "p", &arg)) + return NULL; + + debug = arg; + + Py_RETURN_NONE; +} + +static PyMethodDef methods_elfpy[] = { + {"elfpy_debug", elfpy_debug, METH_VARARGS, "switch debuging on/off"}, + {} +}; + +bool elf_py_init(PyObject *pymod) +{ + if (PyType_Ready(&typeobj_elffile) < 0) + return false; + if (PyType_Ready(&typeobj_elfsect) < 0) + return false; + if (PyType_Ready(&typeobj_elfreloc) < 0) + return false; + if (elf_version(EV_CURRENT) == EV_NONE) + return false; + +#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 5 + PyModule_AddFunctions(pymod, methods_elfpy); +#else + (void)methods_elfpy; +#endif + + ELFFormatError = PyErr_NewException("_clippy.ELFFormatError", + PyExc_ValueError, NULL); + PyModule_AddObject(pymod, "ELFFormatError", ELFFormatError); + ELFAccessError = PyErr_NewException("_clippy.ELFAccessError", + PyExc_IndexError, NULL); + PyModule_AddObject(pymod, "ELFAccessError", ELFAccessError); + + Py_INCREF(&typeobj_elffile); + PyModule_AddObject(pymod, "ELFFile", (PyObject *)&typeobj_elffile); + Py_INCREF(&typeobj_elfsect); + PyModule_AddObject(pymod, "ELFSection", (PyObject *)&typeobj_elfsect); + Py_INCREF(&typeobj_elfreloc); + PyModule_AddObject(pymod, "ELFReloc", (PyObject *)&typeobj_elfreloc); + return true; +} 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_nb.c b/lib/filter_nb.c index 2007b37cdf..c83738e729 100644 --- a/lib/filter_nb.c +++ b/lib/filter_nb.c @@ -120,6 +120,101 @@ static void prefix_list_entry_set_empty(struct prefix_list_entry *ple) ple->le = 0; } +static int +prefix_list_nb_validate_v4_af_type(const struct lyd_node *plist_dnode, + char *errmsg, size_t errmsg_len) +{ + int af_type; + + af_type = yang_dnode_get_enum(plist_dnode, "./type"); + if (af_type != YPLT_IPV4) { + snprintf(errmsg, errmsg_len, + "prefix-list type %u is mismatched.", af_type); + return NB_ERR_VALIDATION; + } + + return NB_OK; +} + +static int +prefix_list_nb_validate_v6_af_type(const struct lyd_node *plist_dnode, + char *errmsg, size_t errmsg_len) +{ + int af_type; + + af_type = yang_dnode_get_enum(plist_dnode, "./type"); + if (af_type != YPLT_IPV6) { + snprintf(errmsg, errmsg_len, + "prefix-list type %u is mismatched.", af_type); + return NB_ERR_VALIDATION; + } + + return NB_OK; +} + +static int lib_prefix_list_entry_prefix_length_lesser_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->le = 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_greater_or_equal_destroy( + struct nb_cb_destroy_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 = 0; + + /* 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_destroy( + struct nb_cb_destroy_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->le = 0; + + /* Finish prefix entry update procedure. */ + prefix_list_entry_update_finish(ple); + + return NB_OK; +} + /** * Unsets the cisco style rule for addresses so it becomes disabled (the * equivalent of setting: `0.0.0.0/32`). @@ -308,45 +403,6 @@ 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_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 */ @@ -1148,25 +1204,11 @@ static int lib_prefix_list_entry_action_modify(struct nb_cb_modify_args *args) return NB_OK; } -/* - * XPath: /frr-filter:lib/prefix-list/entry/ipv4-prefix - */ -static int -lib_prefix_list_entry_ipv4_prefix_modify(struct nb_cb_modify_args *args) +static int lib_prefix_list_entry_prefix_modify(struct nb_cb_modify_args *args) { struct prefix_list_entry *ple; struct prefix p; - 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; @@ -1193,8 +1235,7 @@ lib_prefix_list_entry_ipv4_prefix_modify(struct nb_cb_modify_args *args) return NB_OK; } -static int -lib_prefix_list_entry_ipv4_prefix_destroy(struct nb_cb_destroy_args *args) +static int lib_prefix_list_entry_prefix_destroy(struct nb_cb_destroy_args *args) { struct prefix_list_entry *ple; @@ -1215,6 +1256,61 @@ lib_prefix_list_entry_ipv4_prefix_destroy(struct nb_cb_destroy_args *args) } /* + * XPath: /frr-filter:lib/prefix-list/entry/ipv4-prefix + */ +static int +lib_prefix_list_entry_ipv4_prefix_modify(struct nb_cb_modify_args *args) +{ + if (args->event == NB_EV_VALIDATE) { + const struct lyd_node *plist_dnode = + yang_dnode_get_parent(args->dnode, "prefix-list"); + + return prefix_list_nb_validate_v4_af_type( + plist_dnode, args->errmsg, args->errmsg_len); + } + + return lib_prefix_list_entry_prefix_modify(args); +} + +static int +lib_prefix_list_entry_ipv4_prefix_destroy(struct nb_cb_destroy_args *args) +{ + + if (args->event != NB_EV_APPLY) + return NB_OK; + + return lib_prefix_list_entry_prefix_destroy(args); +} + +/* + * XPath: /frr-filter:lib/prefix-list/entry/ipv6-prefix + */ +static int +lib_prefix_list_entry_ipv6_prefix_modify(struct nb_cb_modify_args *args) +{ + + if (args->event == NB_EV_VALIDATE) { + const struct lyd_node *plist_dnode = + yang_dnode_get_parent(args->dnode, "prefix-list"); + + return prefix_list_nb_validate_v6_af_type( + plist_dnode, args->errmsg, args->errmsg_len); + } + + return lib_prefix_list_entry_prefix_modify(args); +} + +static int +lib_prefix_list_entry_ipv6_prefix_destroy(struct nb_cb_destroy_args *args) +{ + + if (args->event != NB_EV_APPLY) + return NB_OK; + + return lib_prefix_list_entry_prefix_destroy(args); +} + +/* * XPath: /frr-filter:lib/prefix-list/entry/ipv4-prefix-length-greater-or-equal */ static int lib_prefix_list_entry_ipv4_prefix_length_greater_or_equal_modify( @@ -1226,16 +1322,6 @@ static int lib_prefix_list_entry_ipv4_prefix_length_greater_or_equal_modify( prefix_list_length_validate(args) != NB_OK) return NB_ERR_VALIDATION; - 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; @@ -1255,44 +1341,72 @@ static int lib_prefix_list_entry_ipv4_prefix_length_greater_or_equal_modify( static int lib_prefix_list_entry_ipv4_prefix_length_greater_or_equal_destroy( struct nb_cb_destroy_args *args) { - struct prefix_list_entry *ple; + if (args->event == NB_EV_VALIDATE) { + const struct lyd_node *plist_dnode = + yang_dnode_get_parent(args->dnode, "prefix-list"); - if (args->event != NB_EV_APPLY) - return NB_OK; + return prefix_list_nb_validate_v4_af_type( + plist_dnode, args->errmsg, args->errmsg_len); + } - ple = nb_running_get_entry(args->dnode, NULL, true); + return lib_prefix_list_entry_prefix_length_greater_or_equal_destroy( + args); +} - /* Start prefix entry update procedure. */ - prefix_list_entry_update_start(ple); +/* + * XPath: /frr-filter:lib/prefix-list/entry/ipv4-prefix-length-lesser-or-equal + */ +static int lib_prefix_list_entry_ipv4_prefix_length_lesser_or_equal_modify( + struct nb_cb_modify_args *args) +{ + if (args->event == NB_EV_VALIDATE + && prefix_list_length_validate(args) != NB_OK) + return NB_ERR_VALIDATION; - ple->ge = 0; + if (args->event == NB_EV_VALIDATE) { + const struct lyd_node *plist_dnode = + yang_dnode_get_parent(args->dnode, "prefix-list"); - /* 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_lesser_or_equal_modify(args); +} + +static int lib_prefix_list_entry_ipv4_prefix_length_lesser_or_equal_destroy( + struct nb_cb_destroy_args *args) +{ + if (args->event == NB_EV_VALIDATE) { + const struct lyd_node *plist_dnode = + yang_dnode_get_parent(args->dnode, "prefix-list"); + + 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_destroy( + args); } /* - * XPath: /frr-filter:lib/prefix-list/entry/ipv4-prefix-length-lesser-or-equal + * XPath: /frr-filter:lib/prefix-list/entry/ipv6-prefix-length-greater-or-equal */ -static int lib_prefix_list_entry_ipv4_prefix_length_lesser_or_equal_modify( +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) + if (args->event == NB_EV_VALIDATE + && prefix_list_length_validate(args) != NB_OK) return NB_ERR_VALIDATION; 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; + const struct lyd_node *plist_dnode = + yang_dnode_get_parent(args->dnode, "prefix-list"); + + return prefix_list_nb_validate_v6_af_type( + plist_dnode, args->errmsg, args->errmsg_len); } if (args->event != NB_EV_APPLY) @@ -1303,7 +1417,7 @@ static int lib_prefix_list_entry_ipv4_prefix_length_lesser_or_equal_modify( /* Start prefix entry update procedure. */ prefix_list_entry_update_start(ple); - ple->le = yang_dnode_get_uint8(args->dnode, NULL); + ple->ge = yang_dnode_get_uint8(args->dnode, NULL); /* Finish prefix entry update procedure. */ prefix_list_entry_update_finish(ple); @@ -1311,45 +1425,71 @@ static int lib_prefix_list_entry_ipv4_prefix_length_lesser_or_equal_modify( return NB_OK; } -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_destroy( struct nb_cb_destroy_args *args) { - struct prefix_list_entry *ple; + if (args->event == NB_EV_VALIDATE) { + const struct lyd_node *plist_dnode = + yang_dnode_get_parent(args->dnode, "prefix-list"); - if (args->event != NB_EV_APPLY) - return NB_OK; + return prefix_list_nb_validate_v6_af_type( + plist_dnode, args->errmsg, args->errmsg_len); + } - ple = nb_running_get_entry(args->dnode, NULL, true); + return lib_prefix_list_entry_prefix_length_greater_or_equal_destroy( + args); +} - /* Start prefix entry update procedure. */ - prefix_list_entry_update_start(ple); +/* + * XPath: /frr-filter:lib/prefix-list/entry/ipv6-prefix-length-lesser-or-equal + */ +static int lib_prefix_list_entry_ipv6_prefix_length_lesser_or_equal_modify( + struct nb_cb_modify_args *args) +{ + if (args->event == NB_EV_VALIDATE + && prefix_list_length_validate(args) != NB_OK) + return NB_ERR_VALIDATION; - ple->le = 0; + if (args->event == NB_EV_VALIDATE) { + const struct lyd_node *plist_dnode = + yang_dnode_get_parent(args->dnode, "prefix-list"); - /* Finish prefix entry update procedure. */ - prefix_list_entry_update_finish(ple); + return prefix_list_nb_validate_v6_af_type( + plist_dnode, args->errmsg, args->errmsg_len); + } - return NB_OK; + return lib_prefix_list_entry_prefix_length_lesser_or_equal_modify(args); } -/* - * XPath: /frr-filter:lib/prefix-list/entry/any - */ -static int lib_prefix_list_entry_any_create(struct nb_cb_create_args *args) +static int lib_prefix_list_entry_ipv6_prefix_length_lesser_or_equal_destroy( + struct nb_cb_destroy_args *args) { - struct prefix_list_entry *ple; - int type; + int af_type; if (args->event == NB_EV_VALIDATE) { - if (plist_is_dup_nb(args->dnode)) { + 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, - "duplicated prefix list value: %s", - yang_dnode_get_string(args->dnode, NULL)); + "prefix-list type %u is mismatched.", af_type); return NB_ERR_VALIDATION; } return NB_OK; } + return lib_prefix_list_entry_prefix_length_lesser_or_equal_destroy( + args); +} + +/* + * XPath: /frr-filter:lib/prefix-list/entry/any + */ +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_APPLY) return NB_OK; @@ -1583,22 +1723,22 @@ const struct frr_yang_module_info frr_filter_info = { { .xpath = "/frr-filter:lib/prefix-list/entry/ipv6-prefix", .cbs = { - .modify = lib_prefix_list_entry_ipv4_prefix_modify, - .destroy = lib_prefix_list_entry_ipv4_prefix_destroy, + .modify = lib_prefix_list_entry_ipv6_prefix_modify, + .destroy = lib_prefix_list_entry_ipv6_prefix_destroy, } }, { .xpath = "/frr-filter:lib/prefix-list/entry/ipv6-prefix-length-greater-or-equal", .cbs = { - .modify = lib_prefix_list_entry_ipv4_prefix_length_greater_or_equal_modify, - .destroy = lib_prefix_list_entry_ipv4_prefix_length_greater_or_equal_destroy, + .modify = lib_prefix_list_entry_ipv6_prefix_length_greater_or_equal_modify, + .destroy = lib_prefix_list_entry_ipv6_prefix_length_greater_or_equal_destroy, } }, { .xpath = "/frr-filter:lib/prefix-list/entry/ipv6-prefix-length-lesser-or-equal", .cbs = { - .modify = lib_prefix_list_entry_ipv4_prefix_length_lesser_or_equal_modify, - .destroy = lib_prefix_list_entry_ipv4_prefix_length_lesser_or_equal_destroy, + .modify = lib_prefix_list_entry_ipv6_prefix_length_lesser_or_equal_modify, + .destroy = lib_prefix_list_entry_ipv6_prefix_length_lesser_or_equal_destroy, } }, { 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..7f0d2a1245 100644 --- a/lib/link_state.c +++ b/lib/link_state.c @@ -36,7 +36,7 @@ #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 diff --git a/lib/link_state.h b/lib/link_state.h index 93669f5b23..f9eb59b76a 100644 --- a/lib/link_state.h +++ b/lib/link_state.h @@ -324,7 +324,7 @@ extern int ls_attributes_same(struct ls_attributes *a1, */ /* Link State Vertex structure */ -PREDECL_RBTREE_UNIQ(vertices) +PREDECL_RBTREE_UNIQ(vertices); struct ls_vertex { struct vertices_item entry; /* Entry in RB Tree */ uint64_t key; /* Unique Key identifier */ @@ -335,7 +335,7 @@ struct ls_vertex { }; /* Link State Edge structure */ -PREDECL_RBTREE_UNIQ(edges) +PREDECL_RBTREE_UNIQ(edges); struct ls_edge { struct edges_item entry; /* Entry in RB tree */ uint64_t key; /* Unique Key identifier */ @@ -345,7 +345,7 @@ struct ls_edge { }; /* Link State Subnet structure */ -PREDECL_RBTREE_UNIQ(subnets) +PREDECL_RBTREE_UNIQ(subnets); struct ls_subnet { struct subnets_item entry; /* Entry in RB tree */ struct prefix key; /* Unique Key identifier */ @@ -359,21 +359,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 { 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) { 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 b2fa945690..17ef95c687 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) @@ -739,6 +739,16 @@ static ssize_t printfrr_nh(char *buf, size_t bsz, const char *fmt, const char *s, *v_is = "", *v_via = "", *v_viaif = "via "; ssize_t ret = 3; + /* NULL-check */ + if (nexthop == NULL) { + if (fmt[2] == 'v' && fmt[3] == 'v') + ret++; + + strlcpy(buf, "NULL", bsz); + + return ret; + } + switch (fmt[2]) { case 'v': if (fmt[3] == 'v') { 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 224951b22b..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; @@ -1817,6 +1817,16 @@ int nb_oper_data_iterate(const char *xpath, struct yang_translator *translator, /* Find the list entry pointer. */ nn = dn->schema->priv; + if (!nn->cbs.lookup_entry) { + flog_warn( + EC_LIB_NB_OPERATIONAL_DATA, + "%s: data path doesn't support iteration over operational data: %s", + __func__, xpath); + list_delete(&list_dnodes); + yang_dnode_free(dnode); + return NB_ERR; + } + list_entry = nb_callback_lookup_entry(nn, list_entry, &list_keys); if (list_entry == NULL) { diff --git a/lib/northbound.h b/lib/northbound.h index 3e1342f985..21aad64a09 100644 --- a/lib/northbound.h +++ b/lib/northbound.h @@ -677,9 +677,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 1416b758d8..a2c8bc8633 100644 --- a/lib/northbound_cli.c +++ b/lib/northbound_cli.c @@ -1906,7 +1906,6 @@ void nb_cli_init(struct thread_master *tm) if (frr_get_cli_mode() == FRR_CLI_TRANSACTIONAL) { install_element(ENABLE_NODE, &config_exclusive_cmd); install_element(ENABLE_NODE, &config_private_cmd); - install_element(ENABLE_NODE, &show_config_running_cmd); install_element(ENABLE_NODE, &show_config_compare_without_candidate_cmd); install_element(ENABLE_NODE, &show_config_transaction_cmd); @@ -1919,6 +1918,7 @@ void nb_cli_init(struct thread_master *tm) } /* Other commands. */ + install_element(ENABLE_NODE, &show_config_running_cmd); install_element(CONFIG_NODE, &yang_module_translator_load_cmd); install_element(CONFIG_NODE, &yang_module_translator_unload_cmd); install_element(ENABLE_NODE, &show_yang_operational_data_cmd); 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 4588dfe1d3..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 @@ -684,6 +684,7 @@ void prefix_list_entry_update_start(struct prefix_list_entry *ple) if (pl->head || pl->tail || pl->desc) pl->master->recent = pl; + ple->next_best = NULL; ple->installed = false; } diff --git a/lib/prefix.c b/lib/prefix.c index c98e0c1c72..afc4d3d5c2 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, @@ -1366,7 +1366,11 @@ static ssize_t printfrr_ea(char *buf, size_t bsz, const char *fmt, { const struct ethaddr *mac = ptr; - prefix_mac2str(mac, buf, bsz); + if (mac) + prefix_mac2str(mac, buf, bsz); + else + strlcpy(buf, "NULL", bsz); + return 2; } @@ -1376,7 +1380,11 @@ static ssize_t printfrr_ia(char *buf, size_t bsz, const char *fmt, { const struct ipaddr *ipa = ptr; - ipaddr2str(ipa, buf, bsz); + if (ipa) + ipaddr2str(ipa, buf, bsz); + else + strlcpy(buf, "NULL", bsz); + return 2; } @@ -1384,7 +1392,11 @@ 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) { - inet_ntop(AF_INET, ptr, buf, bsz); + if (ptr) + inet_ntop(AF_INET, ptr, buf, bsz); + else + strlcpy(buf, "NULL", bsz); + return 2; } @@ -1392,7 +1404,11 @@ 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) { - inet_ntop(AF_INET6, ptr, buf, bsz); + if (ptr) + inet_ntop(AF_INET6, ptr, buf, bsz); + else + strlcpy(buf, "NULL", bsz); + return 2; } @@ -1400,7 +1416,11 @@ 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) { - prefix2str(ptr, buf, bsz); + if (ptr) + prefix2str(ptr, buf, bsz); + else + strlcpy(buf, "NULL", bsz); + return 2; } @@ -1411,16 +1431,22 @@ static ssize_t printfrr_psg(char *buf, size_t bsz, const char *fmt, const struct prefix_sg *sg = ptr; struct fbuf fb = { .buf = buf, .pos = buf, .len = bsz - 1 }; - if (sg->src.s_addr == INADDR_ANY) - bprintfrr(&fb, "(*,"); - else - bprintfrr(&fb, "(%pI4,", &sg->src); + 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->grp.s_addr == INADDR_ANY) + bprintfrr(&fb, "*)"); + else + bprintfrr(&fb, "%pI4)", &sg->grp); + + fb.pos[0] = '\0'; + + } else { + strlcpy(buf, "NULL", bsz); + } - fb.pos[0] = '\0'; return 3; } diff --git a/lib/printfrr.h b/lib/printfrr.h index a775e1517b..418e839d97 100644 --- a/lib/printfrr.h +++ b/lib/printfrr.h @@ -160,6 +160,30 @@ void printfrr_ext_reg(const struct printfrr_ext *); } \ /* end */ +/* fbuf helper functions */ + +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; +} + #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 1c3c3e9753..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) { @@ -131,3 +131,38 @@ void ringbuf_wipe(struct ringbuf *buf) memset(buf->data, 0x00, buf->size); ringbuf_reset(buf); } + +ssize_t ringbuf_read(struct ringbuf *buf, int sock) +{ + size_t to_read = ringbuf_space(buf); + size_t bytes_to_end = buf->size - buf->end; + ssize_t bytes_read; + struct iovec iov[2] = {}; + + /* Calculate amount of read blocks. */ + if (to_read > bytes_to_end) { + iov[0].iov_base = buf->data + buf->end; + iov[0].iov_len = bytes_to_end; + iov[1].iov_base = buf->data; + iov[1].iov_len = to_read - bytes_to_end; + } else { + iov[0].iov_base = buf->data + buf->end; + iov[0].iov_len = to_read; + } + + /* Do the system call. */ + bytes_read = readv(sock, iov, 2); + if (bytes_read <= 0) + return bytes_read; + + /* Calculate the new end. */ + if ((size_t)bytes_read > bytes_to_end) + buf->end = bytes_read - bytes_to_end; + else + buf->end += bytes_read; + + /* Set emptiness state. */ + buf->empty = (buf->start == buf->end) && (buf->empty && !bytes_read); + + return bytes_read; +} diff --git a/lib/ringbuf.h b/lib/ringbuf.h index b8f4d9798d..209687512b 100644 --- a/lib/ringbuf.h +++ b/lib/ringbuf.h @@ -126,6 +126,17 @@ void ringbuf_reset(struct ringbuf *buf); */ void ringbuf_wipe(struct ringbuf *buf); +/** + * Perform a socket/file `read()` in to the ring buffer. + * + * \param buf the ring buffer pointer. + * \param sock the file descriptor. + * \returns the number of bytes read, `0` on connection close or `-1` with + * `errno` pointing the error (see `readv()` man page for more + * information.) + */ +ssize_t ringbuf_read(struct ringbuf *buf, int sock); + #ifdef __cplusplus } #endif diff --git a/lib/routemap.c b/lib/routemap.c index 7714086672..b836b55aad 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" diff --git a/lib/routemap.h b/lib/routemap.h index 3e208c8cb5..bad3ca6d3d 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,9 @@ 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); /* Prototypes. */ extern void route_map_init(void); 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 11c1becd60..c063833e41 100644 --- a/lib/smux.h +++ b/lib/smux.h @@ -25,6 +25,7 @@ #include <net-snmp/agent/snmp_vars.h> #include "thread.h" +#include "hook.h" #ifdef __cplusplus extern "C" { @@ -102,7 +103,10 @@ struct index_oid { #define SNMP_IP6ADDRESS(V) (*var_len = sizeof(struct in6_addr), (uint8_t *)&V) +extern int smux_enabled(void); + extern void smux_init(struct thread_master *tm); +extern void smux_agentx_enable(void); extern void smux_register_mib(const char *, struct variable *, size_t, int, oid[], size_t); extern int smux_header_generic(struct variable *, oid[], size_t *, int, @@ -141,6 +145,8 @@ extern int smux_trap_multi_index(struct variable *vp, size_t vp_len, struct index_oid *iname, size_t index_len, const struct trap_object *trapobj, size_t trapobjlen, uint8_t sptrap); + +extern void smux_events_update(void); extern int oid_compare(const oid *, int, const oid *, int); extern void oid2in_addr(oid[], int, struct in_addr *); extern void oid2in6_addr(oid oid[], struct in6_addr *addr); @@ -151,6 +157,8 @@ 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, (), ()); + #ifdef __cplusplus } #endif diff --git a/lib/sockunion.c b/lib/sockunion.c index 1dbf77efa4..d65235b41c 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) { @@ -673,39 +673,44 @@ static ssize_t printfrr_psu(char *buf, size_t bsz, const char *fmt, bool endflags = false; ssize_t consumed = 2; - while (!endflags) { - switch (fmt[consumed++]) { - case 'p': - include_port = true; + 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; - default: - consumed--; - endflags = true; + 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); + 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); break; + default: + bprintfrr(&fb, "(af %d)", sockunion_family(su)); } - }; - 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); - 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); - break; - default: - bprintfrr(&fb, "(af %d)", sockunion_family(su)); + fb.pos[0] = '\0'; + } else { + strlcpy(buf, "NULL", bsz); } - fb.pos[0] = '\0'; return consumed; } 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 8ffa0e9709..a115507192 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 { @@ -313,8 +313,13 @@ static ssize_t printfrr_rn(char *buf, size_t bsz, const char *fmt, const struct route_node *rn = ptr; const struct prefix *dst_p, *src_p; - srcdest_rnode_prefixes(rn, &dst_p, &src_p); - srcdest2str(dst_p, (const struct prefix_ipv6 *)src_p, buf, bsz); + 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); + } + return 2; } 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/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 d5ffa08546..bfd367b134 100644 --- a/lib/subdir.am +++ b/lib/subdir.am @@ -313,7 +313,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 = \ @@ -410,7 +410,7 @@ lib_grammar_sandbox_LDADD = \ lib_clippy_CPPFLAGS = $(AM_CPPFLAGS) -D_GNU_SOURCE -DBUILDING_CLIPPY lib_clippy_CFLAGS = $(PYTHON_CFLAGS) -lib_clippy_LDADD = $(PYTHON_LIBS) $(UST_LIBS) +lib_clippy_LDADD = $(PYTHON_LIBS) $(UST_LIBS) -lelf lib_clippy_LDFLAGS = -export-dynamic lib_clippy_SOURCES = \ lib/jhash.c \ @@ -420,9 +420,11 @@ lib_clippy_SOURCES = \ lib/command_parse.y \ lib/command_py.c \ lib/defun_lex.l \ + lib/elf_py.c \ lib/graph.c \ lib/libfrr_trace.c \ lib/memory.c \ + lib/typesafe.c \ lib/vector.c \ # end @@ -439,6 +441,32 @@ SUFFIXES += _clippy.c .c_clippy.c: $(AM_V_CLIPPY) $(CLIPPY) $(top_srcdir)/python/clidef.py -o $@ $< +# xrelfo, the ELF xref extractor + +AM_V_XRELFO = $(am__v_XRELFO_$(V)) +am__v_XRELFO_ = $(am__v_XRELFO_$(AM_DEFAULT_VERBOSITY)) +am__v_XRELFO_0 = @echo " XRELFO " $@; +am__v_XRELFO_1 = + +if DEV_BUILD +XRELFO_FLAGS = -Wlog-format -Wlog-args +else +XRELFO_FLAGS = +endif + +SUFFIXES += .xref +%.xref: % $(CLIPPY) + $(AM_V_XRELFO) $(CLIPPY) $(top_srcdir)/python/xrelfo.py $(XRELFO_FLAGS) -o $@ $< + +# dependencies added in python/makefile.py +frr.xref: + $(AM_V_XRELFO) $(CLIPPY) $(top_srcdir)/python/xrelfo.py -o $@ $^ +all-am: frr.xref + +clean-xref: + -rm -rf $(xrefs) frr.xref +clean-local: clean-xref + ## automake's "ylwrap" is a great piece of GNU software... not. .l.c: $(AM_V_LEX)$(am__skiplex) $(LEXCOMPILE) $< 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 5c06c6ddb5..866090341e 100644 --- a/lib/thread.c +++ b/lib/thread.c @@ -38,12 +38,22 @@ #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; + struct thread *thread; + void *eventobj; + struct thread **threadref; +}; + +/* Flags for task cancellation */ +#define THREAD_CANCEL_FLAG_READY 0x01 static int thread_timer_cmp(const struct thread *a, const struct thread *b) { @@ -58,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> @@ -1050,21 +1060,29 @@ struct thread *_thread_add_event(const struct xref_threadsched *xref, * - POLLIN * - POLLOUT */ -static void thread_cancel_rw(struct thread_master *master, int fd, short state) +static void thread_cancel_rw(struct thread_master *master, int fd, short state, + int idx_hint) { bool found = false; - /* Cancel POLLHUP too just in case some bozo set it */ - state |= POLLHUP; - /* find the index of corresponding pollfd */ nfds_t i; - for (i = 0; i < master->handler.pfdcount; i++) - if (master->handler.pfds[i].fd == fd) { - found = true; - break; - } + /* Cancel POLLHUP too just in case some bozo set it */ + state |= POLLHUP; + + /* Some callers know the index of the pfd already */ + if (idx_hint >= 0) { + i = idx_hint; + found = true; + } else { + /* Have to look for the fd in the pfd array */ + for (i = 0; i < master->handler.pfdcount; i++) + if (master->handler.pfds[i].fd == fd) { + found = true; + break; + } + } if (!found) { zlog_debug( @@ -1104,6 +1122,95 @@ static void thread_cancel_rw(struct thread_master *master, int fd, short state) } } +/* + * Process task cancellation given a task argument: iterate through the + * various lists of tasks, looking for any that match the argument. + */ +static void cancel_arg_helper(struct thread_master *master, + const struct cancel_req *cr) +{ + struct thread *t; + nfds_t i; + int fd; + struct pollfd *pfd; + + /* We're only processing arg-based cancellations here. */ + if (cr->eventobj == NULL) + return; + + /* First process the ready lists. */ + frr_each_safe(thread_list, &master->event, t) { + if (t->arg != cr->eventobj) + continue; + thread_list_del(&master->event, t); + if (t->ref) + *t->ref = NULL; + thread_add_unuse(master, t); + } + + frr_each_safe(thread_list, &master->ready, t) { + if (t->arg != cr->eventobj) + continue; + thread_list_del(&master->ready, t); + if (t->ref) + *t->ref = NULL; + thread_add_unuse(master, t); + } + + /* If requested, stop here and ignore io and timers */ + if (CHECK_FLAG(cr->flags, THREAD_CANCEL_FLAG_READY)) + return; + + /* Check the io tasks */ + for (i = 0; i < master->handler.pfdcount;) { + pfd = master->handler.pfds + i; + + if (pfd->events & POLLIN) + t = master->read[pfd->fd]; + else + t = master->write[pfd->fd]; + + if (t && t->arg == cr->eventobj) { + fd = pfd->fd; + + /* Found a match to cancel: clean up fd arrays */ + thread_cancel_rw(master, pfd->fd, pfd->events, i); + + /* Clean up thread arrays */ + master->read[fd] = NULL; + master->write[fd] = NULL; + + /* Clear caller's ref */ + if (t->ref) + *t->ref = NULL; + + thread_add_unuse(master, t); + + /* Don't increment 'i' since the cancellation will have + * removed the entry from the pfd array + */ + } else + i++; + } + + /* Check the timer tasks */ + t = thread_timer_list_first(&master->timer); + while (t) { + struct thread *t_next; + + t_next = thread_timer_list_next(&master->timer, t); + + if (t->arg == cr->eventobj) { + thread_timer_list_del(&master->timer, t); + if (t->ref) + *t->ref = NULL; + thread_add_unuse(master, t); + } + + t = t_next; + } +} + /** * Process cancellation requests. * @@ -1122,31 +1229,12 @@ static void do_thread_cancel(struct thread_master *master) struct listnode *ln; for (ALL_LIST_ELEMENTS_RO(master->cancel_req, ln, cr)) { /* - * If this is an event object cancellation, linear search - * through event list deleting any events which have the - * specified argument. We also need to check every thread - * in the ready queue. + * If this is an event object cancellation, search + * through task lists deleting any tasks which have the + * specified argument - use this handy helper function. */ if (cr->eventobj) { - struct thread *t; - - frr_each_safe(thread_list, &master->event, t) { - if (t->arg != cr->eventobj) - continue; - thread_list_del(&master->event, t); - if (t->ref) - *t->ref = NULL; - thread_add_unuse(master, t); - } - - frr_each_safe(thread_list, &master->ready, t) { - if (t->arg != cr->eventobj) - continue; - thread_list_del(&master->ready, t); - if (t->ref) - *t->ref = NULL; - thread_add_unuse(master, t); - } + cancel_arg_helper(master, cr); continue; } @@ -1164,11 +1252,11 @@ static void do_thread_cancel(struct thread_master *master) /* Determine the appropriate queue to cancel the thread from */ switch (thread->type) { case THREAD_READ: - thread_cancel_rw(master, thread->u.fd, POLLIN); + thread_cancel_rw(master, thread->u.fd, POLLIN, -1); thread_array = master->read; break; case THREAD_WRITE: - thread_cancel_rw(master, thread->u.fd, POLLOUT); + thread_cancel_rw(master, thread->u.fd, POLLOUT, -1); thread_array = master->write; break; case THREAD_TIMER: @@ -1206,6 +1294,30 @@ static void do_thread_cancel(struct thread_master *master) pthread_cond_broadcast(&master->cancel_cond); } +/* + * Helper function used for multiple flavors of arg-based cancellation. + */ +static void cancel_event_helper(struct thread_master *m, void *arg, int flags) +{ + struct cancel_req *cr; + + assert(m->owner == pthread_self()); + + /* Only worth anything if caller supplies an arg. */ + if (arg == NULL) + return; + + cr = XCALLOC(MTYPE_TMP, sizeof(struct cancel_req)); + + cr->flags = flags; + + frr_with_mutex(&m->mtx) { + cr->eventobj = arg; + listnode_add(m->cancel_req, cr); + do_thread_cancel(m); + } +} + /** * Cancel any events which have the specified argument. * @@ -1216,15 +1328,22 @@ static void do_thread_cancel(struct thread_master *master) */ void thread_cancel_event(struct thread_master *master, void *arg) { - assert(master->owner == pthread_self()); + cancel_event_helper(master, arg, 0); +} - frr_with_mutex(&master->mtx) { - struct cancel_req *cr = - XCALLOC(MTYPE_TMP, sizeof(struct cancel_req)); - cr->eventobj = arg; - listnode_add(master->cancel_req, cr); - do_thread_cancel(master); - } +/* + * Cancel ready tasks with an arg matching 'arg' + * + * MT-Unsafe + * + * @param m the thread_master to cancel from + * @param arg the argument passed when creating the event + */ +void thread_cancel_event_ready(struct thread_master *m, void *arg) +{ + + /* Only cancel ready/event tasks */ + cancel_event_helper(m, arg, THREAD_CANCEL_FLAG_READY); } /** diff --git a/lib/thread.h b/lib/thread.h index b23c6a9865..af68331131 100644 --- a/lib/thread.h +++ b/lib/thread.h @@ -41,13 +41,13 @@ 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 - * constant - * and is the same for both pfds and copy. */ + * constant and is the same for both pfds and copy. + */ nfds_t pfdsize; /* file descriptors to monitor for i/o */ @@ -61,12 +61,6 @@ struct fd_handler { nfds_t copycount; }; -struct cancel_req { - struct thread *thread; - void *eventobj; - struct thread **threadref; -}; - struct xref_threadsched { struct xref xref; @@ -191,7 +185,7 @@ struct cpu_thread_history { #define thread_add_timer(m,f,a,v,t) _xref_t_a(timer, TIMER, m,f,a,v,t) #define thread_add_timer_msec(m,f,a,v,t) _xref_t_a(timer_msec, TIMER, m,f,a,v,t) #define thread_add_timer_tv(m,f,a,v,t) _xref_t_a(timer_tv, TIMER, m,f,a,v,t) -#define thread_add_event(m,f,a,v,t) _xref_t_a(event, TIMER, m,f,a,v,t) +#define thread_add_event(m,f,a,v,t) _xref_t_a(event, EVENT, m,f,a,v,t) #define thread_execute(m,f,a,v) \ ({ \ @@ -240,7 +234,10 @@ extern void _thread_execute(const struct xref_threadsched *xref, extern void thread_cancel(struct thread **event); extern void thread_cancel_async(struct thread_master *, struct thread **, void *); -extern void thread_cancel_event(struct thread_master *, void *); +/* Cancel ready tasks with an arg matching 'arg' */ +extern void thread_cancel_event_ready(struct thread_master *m, void *arg); +/* Cancel all tasks with an arg matching 'arg', including timers and io */ +extern void thread_cancel_event(struct thread_master *m, void *arg); extern struct thread *thread_fetch(struct thread_master *, struct thread *); extern void thread_call(struct thread *); extern unsigned long thread_timer_remain_second(struct thread *); 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 *); @@ -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 { @@ -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 { @@ -1783,7 +1783,6 @@ static int vty_accept(struct thread *thread) int accept_sock; struct prefix p; struct access_list *acl = NULL; - char buf[SU_ADDRSTRLEN]; accept_sock = THREAD_FD(thread); @@ -1804,8 +1803,8 @@ static int vty_accept(struct thread *thread) if (!sockunion2hostprefix(&su, &p)) { close(vty_sock); - zlog_info("Vty unable to convert prefix from sockunion %s", - sockunion2str(&su, buf, SU_ADDRSTRLEN)); + zlog_info("Vty unable to convert prefix from sockunion %pSU", + &su); return -1; } @@ -1813,8 +1812,7 @@ static int vty_accept(struct thread *thread) if (p.family == AF_INET && vty_accesslist_name) { if ((acl = access_list_lookup(AFI_IP, vty_accesslist_name)) && (access_list_apply(acl, &p) == FILTER_DENY)) { - zlog_info("Vty connection refused from %s", - sockunion2str(&su, buf, SU_ADDRSTRLEN)); + zlog_info("Vty connection refused from %pSU", &su); close(vty_sock); /* continue accepting connections */ @@ -1829,8 +1827,7 @@ static int vty_accept(struct thread *thread) if ((acl = access_list_lookup(AFI_IP6, vty_ipv6_accesslist_name)) && (access_list_apply(acl, &p) == FILTER_DENY)) { - zlog_info("Vty connection refused from %s", - sockunion2str(&su, buf, SU_ADDRSTRLEN)); + zlog_info("Vty connection refused from %pSU", &su); close(vty_sock); /* continue accepting connections */ @@ -1847,8 +1844,7 @@ static int vty_accept(struct thread *thread) zlog_info("can't set sockopt to vty_sock : %s", safe_strerror(errno)); - zlog_info("Vty connection from %s", - sockunion2str(&su, buf, SU_ADDRSTRLEN)); + zlog_info("Vty connection from %pSU", &su); vty_create(vty_sock, &su); @@ -2325,7 +2321,7 @@ static void vty_read_file(struct nb_config *config, FILE *confp) nl = strchr(ve->error_buf, '\n'); if (nl) *nl = '\0'; - flog_err(EC_LIB_VTY, "ERROR: %s on config line %u: %s", + flog_err(EC_LIB_VTY, "%s on config line %u: %s", message, ve->line_num, ve->error_buf); } } @@ -2444,9 +2440,8 @@ bool vty_read_config(struct nb_config *config, const char *config_file, confp = vty_use_backup_config(fullpath); if (confp) - flog_warn( - EC_LIB_BACKUP_CONFIG, - "WARNING: using backup configuration file!"); + flog_warn(EC_LIB_BACKUP_CONFIG, + "using backup configuration file!"); else { flog_err( EC_LIB_VTY, @@ -2495,9 +2490,8 @@ bool vty_read_config(struct nb_config *config, const char *config_file, confp = vty_use_backup_config(config_default_dir); if (confp) { - flog_warn( - EC_LIB_BACKUP_CONFIG, - "WARNING: using backup configuration file!"); + flog_warn(EC_LIB_BACKUP_CONFIG, + "using backup configuration file!"); fullpath = config_default_dir; } else { flog_err(EC_LIB_VTY, @@ -2625,7 +2619,7 @@ int vty_config_node_exit(struct vty *vty) /* Check if there's a pending confirmed commit. */ if (vty->t_confirmed_commit_timeout) { vty_out(vty, - "WARNING: exiting with a pending confirmed commit. Rolling back to previous configuration.\n\n"); + "exiting with a pending confirmed commit. Rolling back to previous configuration.\n\n"); nb_cli_confirmed_commit_rollback(vty); nb_cli_confirmed_commit_clean(vty); } 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 20c285cf7f..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 }; @@ -1551,15 +1551,16 @@ bool zapi_ipset_notify_decode(struct stream *s, uint32_t *unique, enum zapi_ipset_notify_owner *note) { uint32_t uni; + uint16_t notew; - STREAM_GET(note, s, sizeof(*note)); + STREAM_GETW(s, notew); STREAM_GETL(s, uni); if (zclient_debug) zlog_debug("%s: %u", __func__, uni); *unique = uni; - + *note = (enum zapi_ipset_notify_owner)notew; return true; stream_failure: @@ -1571,8 +1572,9 @@ bool zapi_ipset_entry_notify_decode(struct stream *s, uint32_t *unique, enum zapi_ipset_entry_notify_owner *note) { uint32_t uni; + uint16_t notew; - STREAM_GET(note, s, sizeof(*note)); + STREAM_GETW(s, notew); STREAM_GETL(s, uni); @@ -1581,6 +1583,7 @@ bool zapi_ipset_entry_notify_decode(struct stream *s, uint32_t *unique, if (zclient_debug) zlog_debug("%s: %u", __func__, uni); *unique = uni; + *note = (enum zapi_ipset_entry_notify_owner)notew; return true; @@ -1593,14 +1596,16 @@ bool zapi_iptable_notify_decode(struct stream *s, enum zapi_iptable_notify_owner *note) { uint32_t uni; + uint16_t notew; - STREAM_GET(note, s, sizeof(*note)); + STREAM_GETW(s, notew); STREAM_GETL(s, uni); if (zclient_debug) zlog_debug("%s: %u", __func__, uni); *unique = uni; + *note = (enum zapi_iptable_notify_owner)notew; return true; @@ -2335,7 +2340,7 @@ struct connected *zebra_interface_address_read(int type, struct stream *s, * "peer" */ flog_err( EC_LIB_ZAPI_ENCODE, - "warning: interface %s address %pFX with peer flag set, but no peer address!", + "interface %s address %pFX with peer flag set, but no peer address!", ifp->name, ifc->address); UNSET_FLAG(ifc->flags, ZEBRA_IFA_PEER); } diff --git a/lib/zclient.h b/lib/zclient.h index cf52ea91a0..43197534a8 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -713,21 +713,21 @@ enum ipset_type { }; enum zapi_ipset_notify_owner { - ZAPI_IPSET_FAIL_INSTALL, + ZAPI_IPSET_FAIL_INSTALL = 0, ZAPI_IPSET_INSTALLED, ZAPI_IPSET_REMOVED, ZAPI_IPSET_FAIL_REMOVE, }; enum zapi_ipset_entry_notify_owner { - ZAPI_IPSET_ENTRY_FAIL_INSTALL, + ZAPI_IPSET_ENTRY_FAIL_INSTALL = 0, ZAPI_IPSET_ENTRY_INSTALLED, ZAPI_IPSET_ENTRY_REMOVED, ZAPI_IPSET_ENTRY_FAIL_REMOVE, }; enum zapi_iptable_notify_owner { - ZAPI_IPTABLE_FAIL_INSTALL, + ZAPI_IPTABLE_FAIL_INSTALL = 0, ZAPI_IPTABLE_INSTALLED, ZAPI_IPTABLE_REMOVED, ZAPI_IPTABLE_FAIL_REMOVE, 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 3e86aa1345..66d8f1e5d7 100644 --- a/lib/zlog.h +++ b/lib/zlog.h @@ -44,6 +44,7 @@ struct xref_logmsg { const char *fmtstring; uint32_t priority; uint32_t ec; + const char *args; }; struct xrefdata_logmsg { @@ -84,30 +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), \ - }; \ - 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 = { \ @@ -122,20 +99,25 @@ static inline void zlog_ref(const struct xref_logmsg *xref, .fmtstring = (msg), \ .priority = (prio), \ .ec = (ec_), \ + .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); @@ -200,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; @@ -244,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/netlink_arp.c b/nhrpd/netlink_arp.c index 309f733526..dc4697cda0 100644 --- a/nhrpd/netlink_arp.c +++ b/nhrpd/netlink_arp.c @@ -67,7 +67,6 @@ static void netlink_neigh_msg(struct nlmsghdr *msg, struct zbuf *zb) struct zbuf payload; union sockunion addr, lladdr; size_t len; - char buf[4][SU_ADDRSTRLEN]; int state; memset(&lladdr, 0, sizeof(lladdr)); @@ -99,27 +98,20 @@ static void netlink_neigh_msg(struct nlmsghdr *msg, struct zbuf *zb) return; debugf(NHRP_DEBUG_KERNEL, - "Netlink: %s %s dev %s lladdr %s nud 0x%x cache used %u type %u", + "Netlink: %s %pSU dev %s lladdr %pSU nud 0x%x cache used %u type %u", (msg->nlmsg_type == RTM_GETNEIGH) ? "who-has" : (msg->nlmsg_type == RTM_NEWNEIGH) ? "new-neigh" : "del-neigh", - sockunion2str(&addr, buf[0], sizeof(buf[0])), ifp->name, - sockunion2str(&lladdr, buf[1], sizeof(buf[1])), ndm->ndm_state, - c->used, c->cur.type); + &addr, ifp->name, &lladdr, ndm->ndm_state, c->used, c->cur.type); if (msg->nlmsg_type == RTM_GETNEIGH) { if (c->cur.type >= NHRP_CACHE_CACHED) { nhrp_cache_set_used(c, 1); debugf(NHRP_DEBUG_KERNEL, - "Netlink: update binding for %s dev %s from c %s peer.vc.nbma %s to lladdr %s", - sockunion2str(&addr, buf[0], sizeof(buf[0])), - ifp->name, - sockunion2str(&c->cur.remote_nbma_natoa, buf[1], - sizeof(buf[1])), - sockunion2str(&c->cur.peer->vc->remote.nbma, - buf[2], sizeof(buf[2])), - sockunion2str(&lladdr, buf[3], sizeof(buf[3]))); + "Netlink: update binding for %pSU dev %s from c %pSU peer.vc.nbma %pSU to lladdr %pSU", + &addr, ifp->name, &c->cur.remote_nbma_natoa, + &c->cur.peer->vc->remote.nbma, &lladdr); /* In case of shortcuts, nbma is given by lladdr, not * vc->remote.nbma. */ diff --git a/nhrpd/nhrp_cache.c b/nhrpd/nhrp_cache.c index 0b5a0427e6..4de8e220ce 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]; @@ -220,7 +220,6 @@ static void nhrp_cache_update_route(struct nhrp_cache *c) { struct prefix pfx; struct nhrp_peer *p = c->cur.peer; - char buf[3][SU_ADDRSTRLEN]; struct nhrp_interface *nifp; if (!sockunion2hostprefix(&c->remote_addr, &pfx)) @@ -233,26 +232,18 @@ static void nhrp_cache_update_route(struct nhrp_cache *c) * nbma. */ debugf(NHRP_DEBUG_COMMON, - "cache (remote_nbma_natoa set): Update binding for %s dev %s from (deleted) peer.vc.nbma %s to %s", - sockunion2str(&c->remote_addr, buf[0], - sizeof(buf[0])), - p->ifp->name, - sockunion2str(&p->vc->remote.nbma, buf[1], - sizeof(buf[1])), - sockunion2str(&c->cur.remote_nbma_natoa, buf[2], - sizeof(buf[2]))); + "cache (remote_nbma_natoa set): Update binding for %pSU dev %s from (deleted) peer.vc.nbma %pSU to %pSU", + &c->remote_addr, p->ifp->name, + &p->vc->remote.nbma, &c->cur.remote_nbma_natoa); netlink_update_binding(p->ifp, &c->remote_addr, &c->cur.remote_nbma_natoa); } else { /* update binding to peer->vc->remote->nbma */ debugf(NHRP_DEBUG_COMMON, - "cache (remote_nbma_natoa unspec): Update binding for %s dev %s from (deleted) to peer.vc.nbma %s", - sockunion2str(&c->remote_addr, buf[0], - sizeof(buf[0])), - p->ifp->name, - sockunion2str(&p->vc->remote.nbma, buf[1], - sizeof(buf[1]))); + "cache (remote_nbma_natoa unspec): Update binding for %pSU dev %s from (deleted) to peer.vc.nbma %pSU", + &c->remote_addr, p->ifp->name, + &p->vc->remote.nbma); netlink_update_binding(p->ifp, &c->remote_addr, &p->vc->remote.nbma); @@ -353,9 +344,8 @@ static void nhrp_cache_authorize_binding(struct nhrp_reqid *r, void *arg) struct nhrp_cache *c = container_of(r, struct nhrp_cache, eventid); char buf[3][SU_ADDRSTRLEN]; - debugf(NHRP_DEBUG_COMMON, "cache: %s %s: %s", c->ifp->name, - sockunion2str(&c->remote_addr, buf[0], sizeof(buf[0])), - (const char *)arg); + debugf(NHRP_DEBUG_COMMON, "cache: %s %pSU: %s", c->ifp->name, + &c->remote_addr, (const char *)arg); nhrp_reqid_free(&nhrp_event_reqid, r); @@ -377,16 +367,13 @@ static void nhrp_cache_authorize_binding(struct nhrp_reqid *r, void *arg) if (sockunion_family(&c->cur.remote_nbma_natoa) != AF_UNSPEC) { debugf(NHRP_DEBUG_COMMON, - "cache: update binding for %s dev %s from (deleted) peer.vc.nbma %s to %s", - sockunion2str(&c->remote_addr, buf[0], - sizeof(buf[0])), - c->ifp->name, + "cache: update binding for %pSU dev %s from (deleted) peer.vc.nbma %s to %pSU", + &c->remote_addr, c->ifp->name, (c->cur.peer ? sockunion2str( &c->cur.peer->vc->remote.nbma, buf[1], sizeof(buf[1])) : "(no peer)"), - sockunion2str(&c->cur.remote_nbma_natoa, buf[2], - sizeof(buf[2]))); + &c->cur.remote_nbma_natoa); if (c->cur.peer) netlink_update_binding( diff --git a/nhrpd/nhrp_event.c b/nhrpd/nhrp_event.c index 40efeb5795..f784ef22d6 100644 --- a/nhrpd/nhrp_event.c +++ b/nhrpd/nhrp_event.c @@ -63,9 +63,9 @@ static void evmgr_recv_message(struct event_manager *evmgr, struct zbuf *zb) buf[len] = 0; debugf(NHRP_DEBUG_EVENT, "evmgr: msg: %s", buf); - if (sscanf(buf, "eventid=%" SCNu32, &eventid) != 1) + if (sscanf(buf, "eventid=%" SCNu32, &eventid) == 1) continue; - if (sscanf(buf, "result=%63s", result) != 1) + if (sscanf(buf, "result=%63s", result) == 1) continue; } debugf(NHRP_DEBUG_EVENT, "evmgr: received: eventid=%d result=%s", diff --git a/nhrpd/nhrp_interface.c b/nhrpd/nhrp_interface.c index 269499cc59..a64708d88e 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, @@ -117,7 +117,6 @@ static void nhrp_interface_interface_notifier(struct notifier_block *n, container_of(n, struct nhrp_interface, nbmanifp_notifier); struct interface *nbmaifp = nifp->nbmaifp; struct nhrp_interface *nbmanifp = nbmaifp->info; - char buf[SU_ADDRSTRLEN]; switch (cmd) { case NOTIFY_INTERFACE_CHANGED: @@ -129,9 +128,8 @@ static void nhrp_interface_interface_notifier(struct notifier_block *n, nhrp_interface_update(nifp->ifp); notifier_call(&nifp->notifier_list, NOTIFY_INTERFACE_NBMA_CHANGED); - debugf(NHRP_DEBUG_IF, "%s: NBMA change: address %s", - nifp->ifp->name, - sockunion2str(&nifp->nbma, buf, sizeof(buf))); + debugf(NHRP_DEBUG_IF, "%s: NBMA change: address %pSU", + nifp->ifp->name, &nifp->nbma); break; } } @@ -466,16 +464,22 @@ void nhrp_interface_set_protection(struct interface *ifp, const char *profile, { struct nhrp_interface *nifp = ifp->info; - if (nifp->ipsec_profile) + if (nifp->ipsec_profile) { + vici_terminate_vc_by_profile_name(nifp->ipsec_profile); + nhrp_vc_reset(); free(nifp->ipsec_profile); + } nifp->ipsec_profile = profile ? strdup(profile) : NULL; - if (nifp->ipsec_fallback_profile) + if (nifp->ipsec_fallback_profile) { + vici_terminate_vc_by_profile_name(nifp->ipsec_fallback_profile); + nhrp_vc_reset(); free(nifp->ipsec_fallback_profile); + } nifp->ipsec_fallback_profile = fallback_profile ? strdup(fallback_profile) : NULL; - notifier_call(&nifp->notifier_list, NOTIFY_INTERFACE_ADDRESS_CHANGED); + notifier_call(&nifp->notifier_list, NOTIFY_INTERFACE_IPSEC_CHANGED); } void nhrp_interface_set_source(struct interface *ifp, const char *ifname) 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 540708f1ae..1689facbcf 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); @@ -33,7 +33,6 @@ static void nhrp_reg_reply(struct nhrp_reqid *reqid, void *arg) struct nhrp_cache *c; struct zbuf extpl; union sockunion cie_nbma, cie_proto, *proto; - char buf[64]; int ok = 0, holdtime; unsigned short mtu = 0; @@ -52,8 +51,8 @@ static void nhrp_reg_reply(struct nhrp_reqid *reqid, void *arg) proto = sockunion_family(&cie_proto) != AF_UNSPEC ? &cie_proto : &p->src_proto; - debugf(NHRP_DEBUG_COMMON, "NHS: CIE registration: %s: %d", - sockunion2str(proto, buf, sizeof(buf)), cie->code); + debugf(NHRP_DEBUG_COMMON, "NHS: CIE registration: %pSU: %d", + proto, cie->code); if (!((cie->code == NHRP_CODE_SUCCESS) || (cie->code == NHRP_CODE_ADMINISTRATIVELY_PROHIBITED && nhs->hub))) @@ -76,10 +75,8 @@ 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: %s", - ifp->name, - sockunion2str(&nifp->nbma, buf, - sizeof(buf))); + "%s: NAT detected, real NBMA address: %pSU", + ifp->name, &nifp->nbma); } break; } @@ -119,8 +116,20 @@ static int nhrp_reg_timeout(struct thread *t) } r->timeout <<= 1; - if (r->timeout > 64) + if (r->timeout > 64) { + /* If registration fails repeatedly, this may be because the + * IPSec connection is not working. Close the connection so it + * can be re-established correctly + */ + if (r->peer && r->peer->vc && r->peer->vc->ike_uniqueid) { + debugf(NHRP_DEBUG_COMMON, + "Terminating IPSec Connection for %d", + r->peer->vc->ike_uniqueid); + vici_terminate_vc_by_ike_id(r->peer->vc->ike_uniqueid); + r->peer->vc->ike_uniqueid = 0; + } r->timeout = 2; + } thread_add_timer_msec(master, nhrp_reg_send_req, r, 10, &r->t_register); return 0; @@ -130,16 +139,14 @@ static void nhrp_reg_peer_notify(struct notifier_block *n, unsigned long cmd) { struct nhrp_registration *r = container_of(n, struct nhrp_registration, peer_notifier); - char buf[SU_ADDRSTRLEN]; switch (cmd) { case NOTIFY_PEER_UP: case NOTIFY_PEER_DOWN: case NOTIFY_PEER_IFCONFIG_CHANGED: case NOTIFY_PEER_MTU_CHANGED: - debugf(NHRP_DEBUG_COMMON, "NHS: Flush timer for %s", - sockunion2str(&r->peer->vc->remote.nbma, buf, - sizeof(buf))); + debugf(NHRP_DEBUG_COMMON, "NHS: Flush timer for %pSU", + &r->peer->vc->remote.nbma); THREAD_OFF(r->t_register); thread_add_timer_msec(master, nhrp_reg_send_req, r, 10, &r->t_register); @@ -163,9 +170,8 @@ static int nhrp_reg_send_req(struct thread *t) r->t_register = NULL; if (!nhrp_peer_check(r->peer, 2)) { - debugf(NHRP_DEBUG_COMMON, "NHS: Waiting link for %s", - sockunion2str(&r->peer->vc->remote.nbma, buf1, - sizeof(buf1))); + debugf(NHRP_DEBUG_COMMON, "NHS: Waiting link for %pSU", + &r->peer->vc->remote.nbma); thread_add_timer(master, nhrp_reg_send_req, r, 120, &r->t_register); return 0; diff --git a/nhrpd/nhrp_peer.c b/nhrpd/nhrp_peer.c index 9aaa9dec1e..af352c68ee 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; @@ -38,16 +38,13 @@ static void nhrp_packet_debug(struct zbuf *zb, const char *dir); static void nhrp_peer_check_delete(struct nhrp_peer *p) { - char buf[2][256]; struct nhrp_interface *nifp = p->ifp->info; if (p->ref || notifier_active(&p->notifier_list)) return; - debugf(NHRP_DEBUG_COMMON, "Deleting peer ref:%d remote:%s local:%s", - p->ref, - sockunion2str(&p->vc->remote.nbma, buf[0], sizeof(buf[0])), - sockunion2str(&p->vc->local.nbma, buf[1], sizeof(buf[1]))); + debugf(NHRP_DEBUG_COMMON, "Deleting peer ref:%d remote:%pSU local:%pSU", + p->ref, &p->vc->remote.nbma, &p->vc->local.nbma); THREAD_OFF(p->t_fallback); hash_release(nifp->peer_hash, p); @@ -150,6 +147,10 @@ static void nhrp_peer_ifp_notify(struct notifier_block *n, unsigned long cmd) case NOTIFY_INTERFACE_ADDRESS_CHANGED: notifier_call(&p->notifier_list, NOTIFY_PEER_IFCONFIG_CHANGED); break; + case NOTIFY_INTERFACE_IPSEC_CHANGED: + __nhrp_peer_check(p); + notifier_call(&p->notifier_list, NOTIFY_PEER_IFCONFIG_CHANGED); + break; case NOTIFY_INTERFACE_MTU_CHANGED: notifier_call(&p->notifier_list, NOTIFY_PEER_MTU_CHANGED); break; @@ -326,16 +327,13 @@ void nhrp_peer_notify_del(struct nhrp_peer *p, struct notifier_block *n) void nhrp_peer_send(struct nhrp_peer *p, struct zbuf *zb) { - char buf[2][256]; - nhrp_packet_debug(zb, "Send"); if (!p->online) return; - debugf(NHRP_DEBUG_KERNEL, "PACKET: Send %s -> %s", - sockunion2str(&p->vc->local.nbma, buf[0], sizeof(buf[0])), - sockunion2str(&p->vc->remote.nbma, buf[1], sizeof(buf[1]))); + debugf(NHRP_DEBUG_KERNEL, "PACKET: Send %pSU -> %pSU", + &p->vc->local.nbma, &p->vc->remote.nbma); os_sendmsg(zb->head, zbuf_used(zb), p->ifp->ifindex, sockunion_get_addr(&p->vc->remote.nbma), @@ -658,7 +656,6 @@ void nhrp_peer_send_indication(struct interface *ifp, uint16_t protocol_type, struct nhrp_afi_data *if_ad; struct nhrp_packet_header *hdr; struct nhrp_peer *p; - char buf[2][SU_ADDRSTRLEN]; if (!nifp->enabled) return; @@ -673,23 +670,20 @@ void nhrp_peer_send_indication(struct interface *ifp, uint16_t protocol_type, if_ad = &nifp->afi[family2afi(sockunion_family(&dst))]; if (!(if_ad->flags & NHRP_IFF_REDIRECT)) { debugf(NHRP_DEBUG_COMMON, - "Send Traffic Indication to %s about packet to %s ignored", - sockunion2str(&p->vc->remote.nbma, buf[0], - sizeof(buf[0])), - sockunion2str(&dst, buf[1], sizeof(buf[1]))); + "Send Traffic Indication to %pSU about packet to %pSU ignored", + &p->vc->remote.nbma, &dst); return; } debugf(NHRP_DEBUG_COMMON, - "Send Traffic Indication to %s (online=%d) about packet to %s", - sockunion2str(&p->vc->remote.nbma, buf[0], sizeof(buf[0])), - p->online, sockunion2str(&dst, buf[1], sizeof(buf[1]))); + "Send Traffic Indication to %pSU (online=%d) about packet to %pSU", + &p->vc->remote.nbma, p->online, &dst); /* Create reply */ zb = zbuf_alloc(1500); hdr = nhrp_packet_push(zb, NHRP_PACKET_TRAFFIC_INDICATION, &nifp->nbma, &if_ad->addr, &dst); - hdr->hop_count = 0; + hdr->hop_count = 1; /* Payload is the packet causing indication */ zbuf_copy(zb, pkt, zbuf_used(pkt)); @@ -705,16 +699,14 @@ static void nhrp_handle_error_ind(struct nhrp_packet_parser *pp) struct nhrp_packet_header *hdr; struct nhrp_reqid *reqid; union sockunion src_nbma, src_proto, dst_proto; - char buf[2][SU_ADDRSTRLEN]; hdr = nhrp_packet_pull(&origmsg, &src_nbma, &src_proto, &dst_proto); if (!hdr) return; debugf(NHRP_DEBUG_COMMON, - "Error Indication from %s about packet to %s ignored", - sockunion2str(&pp->src_proto, buf[0], sizeof(buf[0])), - sockunion2str(&dst_proto, buf[1], sizeof(buf[1]))); + "Error Indication from %pSU about packet to %pSU ignored", + &pp->src_proto, &dst_proto); reqid = nhrp_reqid_lookup(&nhrp_packet_reqid, htonl(hdr->u.request_id)); if (reqid) @@ -724,16 +716,14 @@ static void nhrp_handle_error_ind(struct nhrp_packet_parser *pp) static void nhrp_handle_traffic_ind(struct nhrp_packet_parser *p) { union sockunion dst; - char buf[2][SU_ADDRSTRLEN]; if (!parse_ether_packet(&p->payload, htons(p->hdr->protocol_type), NULL, &dst)) return; debugf(NHRP_DEBUG_COMMON, - "Traffic Indication from %s about packet to %s: %s", - sockunion2str(&p->src_proto, buf[0], sizeof(buf[0])), - sockunion2str(&dst, buf[1], sizeof(buf[1])), + "Traffic Indication from %pSU about packet to %pSU: %s", + &p->src_proto, &dst, (p->if_ad->flags & NHRP_IFF_SHORTCUT) ? "trying shortcut" : "ignored"); @@ -929,7 +919,6 @@ struct nhrp_route_info { void nhrp_peer_recv(struct nhrp_peer *p, struct zbuf *zb) { - char buf[2][SU_ADDRSTRLEN]; struct nhrp_packet_header *hdr; struct nhrp_vc *vc = p->vc; struct interface *ifp = p->ifp; @@ -942,9 +931,8 @@ void nhrp_peer_recv(struct nhrp_peer *p, struct zbuf *zb) unsigned paylen, extoff, extlen, realsize; afi_t nbma_afi, proto_afi; - debugf(NHRP_DEBUG_KERNEL, "PACKET: Recv %s -> %s", - sockunion2str(&vc->remote.nbma, buf[0], sizeof(buf[0])), - sockunion2str(&vc->local.nbma, buf[1], sizeof(buf[1]))); + debugf(NHRP_DEBUG_KERNEL, "PACKET: Recv %pSU -> %pSU", &vc->remote.nbma, + &vc->local.nbma); if (!p->online) { info = "peer not online"; @@ -975,10 +963,9 @@ void nhrp_peer_recv(struct nhrp_peer *p, struct zbuf *zb) || packet_types[hdr->type].type == PACKET_UNKNOWN || htons(hdr->packet_size) > realsize) { zlog_info( - "From %s: error: packet type %d, version %d, AFI %d, proto %x, size %d (real size %d)", - sockunion2str(&vc->remote.nbma, buf[0], sizeof(buf[0])), - (int)hdr->type, (int)hdr->version, (int)nbma_afi, - (int)htons(hdr->protocol_type), + "From %pSU: error: packet type %d, version %d, AFI %d, proto %x, size %d (real size %d)", + &vc->remote.nbma, (int)hdr->type, (int)hdr->version, + (int)nbma_afi, (int)htons(hdr->protocol_type), (int)htons(hdr->packet_size), (int)realsize); goto drop; } @@ -1055,10 +1042,7 @@ void nhrp_peer_recv(struct nhrp_peer *p, struct zbuf *zb) drop: if (info) { - zlog_info( - "From %s: error: %s", - sockunion2str(&vc->remote.nbma, buf[0], sizeof(buf[0])), - info); + zlog_info("From %pSU: error: %s", &vc->remote.nbma, info); } if (peer) nhrp_peer_unref(peer); diff --git a/nhrpd/nhrp_route.c b/nhrpd/nhrp_route.c index 334f468c18..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]; @@ -200,7 +200,6 @@ int nhrp_route_read(ZAPI_CALLBACK_ARGS) struct zapi_nexthop *api_nh; struct interface *ifp = NULL; union sockunion nexthop_addr; - char buf[PREFIX_STRLEN]; int added; if (zapi_route_decode(zclient->ibuf, &api) < 0) @@ -233,9 +232,8 @@ int nhrp_route_read(ZAPI_CALLBACK_ARGS) } added = (cmd == ZEBRA_REDISTRIBUTE_ROUTE_ADD); - debugf(NHRP_DEBUG_ROUTE, "if-route-%s: %pFX via %s dev %s", - added ? "add" : "del", &api.prefix, - sockunion2str(&nexthop_addr, buf, sizeof(buf)), + debugf(NHRP_DEBUG_ROUTE, "if-route-%s: %pFX via %pSU dev %s", + added ? "add" : "del", &api.prefix, &nexthop_addr, ifp ? ifp->name : "(none)"); nhrp_route_update_zebra(&api.prefix, &nexthop_addr, added ? ifp : NULL); diff --git a/nhrpd/nhrp_shortcut.c b/nhrpd/nhrp_shortcut.c index fbb883185a..8ce19cd4a3 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]; @@ -94,8 +94,6 @@ static void nhrp_shortcut_update_binding(struct nhrp_shortcut *s, enum nhrp_cache_type type, struct nhrp_cache *c, int holding_time) { - char buf[2][PREFIX_STRLEN]; - s->type = type; if (c != s->cache) { if (s->cache) { @@ -111,13 +109,9 @@ static void nhrp_shortcut_update_binding(struct nhrp_shortcut *s, * change */ s->route_installed = 0; debugf(NHRP_DEBUG_ROUTE, - "Shortcut: forcing renewal of zebra announce on prefix change peer %s ht %u cur nbma %s dev %s", - sockunion2str(&s->cache->remote_addr, - buf[0], sizeof(buf[0])), - holding_time, - sockunion2str( - &s->cache->cur.remote_nbma_natoa, - buf[1], sizeof(buf[1])), + "Shortcut: forcing renewal of zebra announce on prefix change peer %pSU ht %u cur nbma %pSU dev %s", + &s->cache->remote_addr, holding_time, + &s->cache->cur.remote_nbma_natoa, s->cache->ifp->name); nhrp_shortcut_cache_notify(&s->cache_notifier, NOTIFY_CACHE_UP); @@ -255,9 +249,9 @@ static void nhrp_shortcut_recv_resolution_rep(struct nhrp_reqid *reqid, prefix2sockunion(s->p, &cie_proto); if (!sockunion_same(&cie_proto, &pp->dst_proto)) { debugf(NHRP_DEBUG_COMMON, - "Shortcut: Warning dst_proto altered from %s to %s", - sockunion2str(&cie_proto, buf[0], sizeof(buf[0])), - sockunion2str(&pp->dst_proto, buf[1], sizeof(buf[1]))); + "Shortcut: Warning dst_proto altered from %pSU to %pSU", + &cie_proto, &pp->dst_proto); + ; } /* One or more CIEs should be given as reply, we support only one */ @@ -287,11 +281,8 @@ static void nhrp_shortcut_recv_resolution_rep(struct nhrp_reqid *reqid, } debugf(NHRP_DEBUG_COMMON, - "Shortcut: %pFX is at proto %s dst_proto %s cie-nbma %s nat-nbma %s cie-holdtime %d", - &prefix, sockunion2str(proto, buf[0], sizeof(buf[0])), - sockunion2str(&pp->dst_proto, buf[1], sizeof(buf[1])), - sockunion2str(&cie_nbma, buf[2], sizeof(buf[2])), - sockunion2str(&nat_nbma, buf[3], sizeof(buf[3])), + "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)); /* Update cache entry for the protocol to nbma binding */ diff --git a/nhrpd/nhrp_vc.c b/nhrpd/nhrp_vc.c index 6567b231a9..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; @@ -100,7 +100,6 @@ static void nhrp_vc_ipsec_reset(struct nhrp_vc *vc) int nhrp_vc_ipsec_updown(uint32_t child_id, struct nhrp_vc *vc) { - char buf[2][SU_ADDRSTRLEN]; struct child_sa *sa = NULL, *lsa; uint32_t child_hash = child_id % array_size(childlist_head); int abort_migration = 0; @@ -140,10 +139,8 @@ int nhrp_vc_ipsec_updown(uint32_t child_id, struct nhrp_vc *vc) if (sa->vc && vc) { /* Notify old VC of migration */ sa->vc->abort_migration = 0; - debugf(NHRP_DEBUG_COMMON, "IPsec NBMA change of %s to %s", - sockunion2str(&sa->vc->remote.nbma, buf[0], - sizeof(buf[0])), - sockunion2str(&vc->remote.nbma, buf[1], sizeof(buf[1]))); + debugf(NHRP_DEBUG_COMMON, "IPsec NBMA change of %pSU to %pSU", + &sa->vc->remote.nbma, &vc->remote.nbma); nhrp_vc_update(sa->vc, NOTIFY_VC_IPSEC_UPDATE_NBMA); abort_migration = sa->vc->abort_migration; } diff --git a/nhrpd/nhrpd.h b/nhrpd/nhrpd.h index a36d0c445d..9c8c293b9e 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 @@ -105,6 +105,7 @@ enum nhrp_notify_type { NOTIFY_INTERFACE_ADDRESS_CHANGED, NOTIFY_INTERFACE_NBMA_CHANGED, NOTIFY_INTERFACE_MTU_CHANGED, + NOTIFY_INTERFACE_IPSEC_CHANGED, NOTIFY_VC_IPSEC_CHANGED, NOTIFY_VC_IPSEC_UPDATE_NBMA, @@ -125,6 +126,7 @@ enum nhrp_notify_type { struct nhrp_vc { struct notifier_list notifier_list; uint32_t ipsec; + uint32_t ike_uniqueid; uint8_t updating; uint8_t abort_migration; @@ -399,6 +401,8 @@ void nhrp_vc_reset(void); void vici_init(void); void vici_terminate(void); +void vici_terminate_vc_by_profile_name(char *profile_name); +void vici_terminate_vc_by_ike_id(unsigned int ike_id); void vici_request_vc(const char *profile, union sockunion *src, union sockunion *dst, int prio); diff --git a/nhrpd/vici.c b/nhrpd/vici.c index 86554f53dc..9b117ddf0d 100644 --- a/nhrpd/vici.c +++ b/nhrpd/vici.c @@ -200,6 +200,7 @@ static void parse_sa_message(struct vici_message_ctx *ctx, nhrp_vc_ipsec_updown( sactx->child_uniqueid, vc); + vc->ike_uniqueid = sactx->ike_uniqueid; } } else { nhrp_vc_ipsec_updown(sactx->child_uniqueid, 0); @@ -521,6 +522,26 @@ void vici_terminate(void) { } +void vici_terminate_vc_by_profile_name(char *profile_name) +{ + struct vici_conn *vici = &vici_connection; + + debugf(NHRP_DEBUG_VICI, "Terminate profile = %s", profile_name); + vici_submit_request(vici, "terminate", VICI_KEY_VALUE, "ike", + strlen(profile_name), profile_name, VICI_END); +} + +void vici_terminate_vc_by_ike_id(unsigned int ike_id) +{ + struct vici_conn *vici = &vici_connection; + char ike_id_str[10]; + + snprintf(ike_id_str, sizeof(ike_id_str), "%d", ike_id); + debugf(NHRP_DEBUG_VICI, "Terminate ike_id_str = %s", ike_id_str); + vici_submit_request(vici, "terminate", VICI_KEY_VALUE, "ike-id", + strlen(ike_id_str), ike_id_str, VICI_END); +} + void vici_request_vc(const char *profile, union sockunion *src, union sockunion *dst, int prio) { diff --git a/nhrpd/zbuf.c b/nhrpd/zbuf.c index 7f1475cc69..a78d827ea5 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) { diff --git a/ospf6d/ospf6_area.c b/ospf6d/ospf6_area.c index 778bcb9a45..6bf61b4804 100644 --- a/ospf6d/ospf6_area.c +++ b/ospf6d/ospf6_area.c @@ -44,8 +44,10 @@ #include "ospf6_abr.h" #include "ospf6_asbr.h" #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) { @@ -141,11 +143,12 @@ static void ospf6_area_stub_update(struct ospf6_area *area) if (IS_AREA_STUB(area)) { if (IS_OSPF6_DEBUG_ORIGINATE(ROUTER)) - zlog_debug("Stubbing out area for if %s", area->name); + zlog_debug("Stubbing out area for area %s", area->name); OSPF6_OPT_CLEAR(area->options, OSPF6_OPT_E); + ospf6_asbr_remove_externals_from_area(area); } else if (IS_AREA_ENABLED(area)) { if (IS_OSPF6_DEBUG_ORIGINATE(ROUTER)) - zlog_debug("Normal area for if %s", area->name); + zlog_debug("Normal area for area %s", area->name); OSPF6_OPT_SET(area->options, OSPF6_OPT_E); ospf6_asbr_send_externals_to_area(area); } @@ -850,12 +853,13 @@ DEFUN (no_area_export_list, DEFUN (show_ipv6_ospf6_spf_tree, show_ipv6_ospf6_spf_tree_cmd, - "show ipv6 ospf6 spf tree", + "show ipv6 ospf6 spf tree [json]", SHOW_STR IP6_STR OSPF6_STR "Shortest Path First calculation\n" - "Show SPF tree\n") + "Show SPF tree\n" + JSON_STR) { struct listnode *node; struct ospf6_area *oa; @@ -863,20 +867,52 @@ DEFUN (show_ipv6_ospf6_spf_tree, struct ospf6_route *route; struct prefix prefix; struct ospf6 *ospf6; + json_object *json = NULL; + json_object *json_area = NULL; + json_object *json_head = NULL; + bool uj = use_json(argc, argv); ospf6 = ospf6_lookup_by_vrf_name(VRF_DEFAULT_NAME); OSPF6_CMD_CHECK_RUNNING(ospf6); + + if (uj) + json = json_object_new_object(); ospf6_linkstate_prefix(ospf6->router_id, htonl(0), &prefix); for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, node, oa)) { + if (uj) { + json_area = json_object_new_object(); + json_head = json_object_new_object(); + } route = ospf6_route_lookup(&prefix, oa->spf_table); if (route == NULL) { - vty_out(vty, "LS entry for root not found in area %s\n", - oa->name); + if (uj) { + json_object_string_add( + json, oa->name, + "LS entry for not not found"); + json_object_free(json_head); + json_object_free(json_area); + } else + vty_out(vty, + "LS entry for root not found in area %s\n", + oa->name); continue; } root = (struct ospf6_vertex *)route->route_option; - ospf6_spf_display_subtree(vty, "", 0, root); + ospf6_spf_display_subtree(vty, "", 0, root, json_head, uj); + + if (uj) { + json_object_object_add(json_area, root->name, + json_head); + json_object_object_add(json, oa->name, json_area); + } + } + + 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; @@ -924,7 +960,7 @@ DEFUN (show_ipv6_ospf6_area_spf_tree, return CMD_SUCCESS; } root = (struct ospf6_vertex *)route->route_option; - ospf6_spf_display_subtree(vty, "", 0, root); + ospf6_spf_display_subtree(vty, "", 0, root, NULL, false); return CMD_SUCCESS; } @@ -985,7 +1021,7 @@ DEFUN (show_ipv6_ospf6_simulate_spf_tree_root, return CMD_SUCCESS; } root = (struct ospf6_vertex *)route->route_option; - ospf6_spf_display_subtree(vty, "", 0, root); + ospf6_spf_display_subtree(vty, "", 0, root, NULL, false); ospf6_spf_table_finish(spf_table); ospf6_route_table_delete(spf_table); diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c index d0c93dd577..3497b26656 100644 --- a/ospf6d/ospf6_asbr.c +++ b/ospf6d/ospf6_asbr.c @@ -49,6 +49,10 @@ #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); @@ -1099,6 +1103,30 @@ void ospf6_asbr_send_externals_to_area(struct ospf6_area *oa) } } +/* When an area is stubified, remove all the external LSAs in the area */ +void ospf6_asbr_remove_externals_from_area(struct ospf6_area *oa) +{ + struct ospf6_lsa *lsa, *lsanext; + struct listnode *node, *nnode; + struct ospf6_area *area; + struct ospf6 *ospf6 = oa->ospf6; + const struct route_node *iterend; + + /* skip if router is in other non-stub areas */ + for (ALL_LIST_ELEMENTS(ospf6->area_list, node, nnode, area)) + if (!IS_AREA_STUB(area)) + return; + + /* 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) { + lsanext = ospf6_lsdb_next(iterend, lsa); + if (ntohs(lsa->header->type) == OSPF6_LSTYPE_AS_EXTERNAL) + ospf6_lsdb_remove(lsa, ospf6->lsdb); + lsa = lsanext; + } +} + void ospf6_asbr_redistribute_add(int type, ifindex_t ifindex, struct prefix *prefix, unsigned int nexthop_num, diff --git a/ospf6d/ospf6_asbr.h b/ospf6d/ospf6_asbr.h index fd14610042..e4a4455a5c 100644 --- a/ospf6d/ospf6_asbr.h +++ b/ospf6d/ospf6_asbr.h @@ -95,6 +95,7 @@ extern void ospf6_asbr_init(void); extern void ospf6_asbr_redistribute_reset(struct ospf6 *ospf6); extern void ospf6_asbr_terminate(void); 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 void install_element_ospf6_debug_asbr(void); diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c index 621cc36a0c..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, @@ -1622,12 +1629,11 @@ DEFUN (ipv6_ospf6_cost, return CMD_WARNING_CONFIG_FAILED; } + SET_FLAG(oi->flag, OSPF6_INTERFACE_NOAUTOCOST); if (oi->cost == lcost) return CMD_SUCCESS; oi->cost = lcost; - SET_FLAG(oi->flag, OSPF6_INTERFACE_NOAUTOCOST); - ospf6_interface_force_recalculate_cost(oi); return CMD_SUCCESS; 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_intra.c b/ospf6d/ospf6_intra.c index 2cffc3a397..adff76ec41 100644 --- a/ospf6d/ospf6_intra.c +++ b/ospf6d/ospf6_intra.c @@ -684,11 +684,9 @@ static int ospf6_link_lsa_show(struct vty *vty, struct ospf6_lsa *lsa, int prefixnum; char buf[128], options[32]; struct ospf6_prefix *prefix; - const char *p, *mc, *la, *nu; struct in6_addr in6; json_object *json_loop; json_object *json_arr = NULL; - char str[15]; char prefix_string[133]; link_lsa = (struct ospf6_link_lsa *)((caddr_t)lsa->header @@ -720,26 +718,13 @@ static int ospf6_link_lsa_show(struct vty *vty, struct ospf6_lsa *lsa, || current + OSPF6_PREFIX_SIZE(prefix) > end) break; - p = (CHECK_FLAG(prefix->prefix_options, OSPF6_PREFIX_OPTION_P) - ? "P" - : "--"); - mc = (CHECK_FLAG(prefix->prefix_options, OSPF6_PREFIX_OPTION_MC) - ? "MC" - : "--"); - la = (CHECK_FLAG(prefix->prefix_options, OSPF6_PREFIX_OPTION_LA) - ? "LA" - : "--"); - nu = (CHECK_FLAG(prefix->prefix_options, OSPF6_PREFIX_OPTION_NU) - ? "NU" - : "--"); + ospf6_prefix_options_printbuf(prefix->prefix_options, buf, + sizeof(buf)); if (use_json) { json_loop = json_object_new_object(); - snprintf(str, sizeof(str), "%s|%s|%s|%s", p, mc, la, - nu); - json_object_string_add(json_loop, "prefixOption", str); + json_object_string_add(json_loop, "prefixOption", buf); } else - vty_out(vty, " Prefix Options: %s|%s|%s|%s\n", p, - mc, la, nu); + vty_out(vty, " Prefix Options: %s\n", buf); memset(&in6, 0, sizeof(in6)); memcpy(&in6, OSPF6_PREFIX_BODY(prefix), @@ -918,11 +903,9 @@ static int ospf6_intra_prefix_lsa_show(struct vty *vty, struct ospf6_lsa *lsa, char buf[128]; struct ospf6_prefix *prefix; char id[16], adv_router[16]; - const char *p, *mc, *la, *nu; struct in6_addr in6; json_object *json_loop; json_object *json_arr = NULL; - char str[15]; char prefix_string[133]; intra_prefix_lsa = (struct ospf6_intra_prefix_lsa @@ -961,26 +944,13 @@ static int ospf6_intra_prefix_lsa_show(struct vty *vty, struct ospf6_lsa *lsa, || current + OSPF6_PREFIX_SIZE(prefix) > end) break; - p = (CHECK_FLAG(prefix->prefix_options, OSPF6_PREFIX_OPTION_P) - ? "P" - : "--"); - mc = (CHECK_FLAG(prefix->prefix_options, OSPF6_PREFIX_OPTION_MC) - ? "MC" - : "--"); - la = (CHECK_FLAG(prefix->prefix_options, OSPF6_PREFIX_OPTION_LA) - ? "LA" - : "--"); - nu = (CHECK_FLAG(prefix->prefix_options, OSPF6_PREFIX_OPTION_NU) - ? "NU" - : "--"); + ospf6_prefix_options_printbuf(prefix->prefix_options, buf, + sizeof(buf)); if (use_json) { json_loop = json_object_new_object(); - snprintf(str, sizeof(str), "%s|%s|%s|%s", p, mc, la, - nu); - json_object_string_add(json_loop, "prefixOption", str); + json_object_string_add(json_loop, "prefixOption", buf); } else - vty_out(vty, " Prefix Options: %s|%s|%s|%s\n", p, - mc, la, nu); + vty_out(vty, " Prefix Options: %s\n", buf); memset(&in6, 0, sizeof(in6)); memcpy(&in6, OSPF6_PREFIX_BODY(prefix), diff --git a/ospf6d/ospf6_lsa.c b/ospf6d/ospf6_lsa.c index f1b04c9bec..f2a933d878 100644 --- a/ospf6d/ospf6_lsa.c +++ b/ospf6d/ospf6_lsa.c @@ -43,6 +43,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) @@ -145,7 +149,7 @@ const char *ospf6_lstype_short_name(uint16_t type) const struct ospf6_lsa_handler *handler; handler = ospf6_get_lsa_handler(type); - if (handler && handler != &unknown_handler) + if (handler) return handler->lh_short_name; snprintf(buf, sizeof(buf), "0x%04hx", ntohs(type)); @@ -420,9 +424,10 @@ void ospf6_lsa_show_summary(struct vty *vty, struct ospf6_lsa *lsa, if (use_json) json_obj = json_object_new_object(); - if ((type == OSPF6_LSTYPE_INTER_PREFIX) - || (type == OSPF6_LSTYPE_INTER_ROUTER) - || (type == OSPF6_LSTYPE_AS_EXTERNAL)) { + switch (type) { + case OSPF6_LSTYPE_INTER_PREFIX: + case OSPF6_LSTYPE_INTER_ROUTER: + case OSPF6_LSTYPE_AS_EXTERNAL: if (use_json) { json_object_string_add( json_obj, "type", @@ -447,7 +452,13 @@ void ospf6_lsa_show_summary(struct vty *vty, struct ospf6_lsa *lsa, (unsigned long)ntohl(lsa->header->seqnum), handler->lh_get_prefix_str(lsa, buf, sizeof(buf), 0)); - } else if (type != OSPF6_LSTYPE_UNKNOWN) { + break; + case OSPF6_LSTYPE_ROUTER: + case OSPF6_LSTYPE_NETWORK: + case OSPF6_LSTYPE_GROUP_MEMBERSHIP: + case OSPF6_LSTYPE_TYPE_7: + case OSPF6_LSTYPE_LINK: + case OSPF6_LSTYPE_INTRA_PREFIX: while (handler->lh_get_prefix_str(lsa, buf, sizeof(buf), cnt) != NULL) { if (use_json) { @@ -481,7 +492,8 @@ void ospf6_lsa_show_summary(struct vty *vty, struct ospf6_lsa *lsa, } if (use_json) json_object_free(json_obj); - } else { + break; + default: if (use_json) { json_object_string_add( json_obj, "type", @@ -500,6 +512,7 @@ void ospf6_lsa_show_summary(struct vty *vty, struct ospf6_lsa *lsa, ospf6_lstype_short_name(lsa->header->type), id, adv_router, ospf6_lsa_age_current(lsa), (unsigned long)ntohl(lsa->header->seqnum)); + break; } } @@ -648,27 +661,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)); @@ -682,20 +697,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)); - - /* LSA information structure */ - /* allocate memory */ - lsa = XCALLOC(MTYPE_OSPF6_LSA, sizeof(struct ospf6_lsa)); + memcpy(lsa->header, header, sizeof(struct ospf6_lsa_header)); - lsa->header = new_header; SET_FLAG(lsa->flag, OSPF6_LSA_HEADERONLY); /* dump string */ diff --git a/ospf6d/ospf6_lsa.h b/ospf6d/ospf6_lsa.h index 7fa9c5fe40..c4d0290c0c 100644 --- a/ospf6d/ospf6_lsa.h +++ b/ospf6d/ospf6_lsa.h @@ -217,6 +217,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..c601693a7e 100644 --- a/ospf6d/ospf6_main.c +++ b/ospf6d/ospf6_main.c @@ -182,7 +182,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 bd180a9f55..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"}, @@ -86,13 +88,9 @@ const uint16_t ospf6_lsa_minlen[OSPF6_LSTYPE_SIZE] = { static void ospf6_header_print(struct ospf6_header *oh) { - char router_id[16], area_id[16]; - inet_ntop(AF_INET, &oh->router_id, router_id, sizeof(router_id)); - inet_ntop(AF_INET, &oh->area_id, area_id, sizeof(area_id)); - - zlog_debug(" OSPFv%d Type:%d Len:%hu Router-ID:%s", oh->version, - oh->type, ntohs(oh->length), router_id); - zlog_debug(" Area-ID:%s Cksum:%hx Instance-ID:%d", area_id, + zlog_debug(" OSPFv%d Type:%d Len:%hu Router-ID:%pI4", oh->version, + oh->type, ntohs(oh->length), &oh->router_id); + zlog_debug(" Area-ID:%pI4 Cksum:%hx Instance-ID:%d", &oh->area_id, ntohs(oh->checksum), oh->instance_id); } @@ -100,7 +98,6 @@ void ospf6_hello_print(struct ospf6_header *oh) { struct ospf6_hello *hello; char options[16]; - char drouter[16], bdrouter[16], neighbor[16]; char *p; ospf6_header_print(oh); @@ -109,8 +106,6 @@ void ospf6_hello_print(struct ospf6_header *oh) hello = (struct ospf6_hello *)((caddr_t)oh + sizeof(struct ospf6_header)); - inet_ntop(AF_INET, &hello->drouter, drouter, sizeof(drouter)); - inet_ntop(AF_INET, &hello->bdrouter, bdrouter, sizeof(bdrouter)); ospf6_options_printbuf(hello->options, options, sizeof(options)); zlog_debug(" I/F-Id:%ld Priority:%d Option:%s", @@ -118,14 +113,12 @@ void ospf6_hello_print(struct ospf6_header *oh) options); zlog_debug(" HelloInterval:%hu DeadInterval:%hu", ntohs(hello->hello_interval), ntohs(hello->dead_interval)); - zlog_debug(" DR:%s BDR:%s", drouter, bdrouter); + zlog_debug(" DR:%pI4 BDR:%pI4", &hello->drouter, &hello->bdrouter); for (p = (char *)((caddr_t)hello + sizeof(struct ospf6_hello)); p + sizeof(uint32_t) <= OSPF6_MESSAGE_END(oh); - p += sizeof(uint32_t)) { - inet_ntop(AF_INET, (void *)p, neighbor, sizeof(neighbor)); - zlog_debug(" Neighbor: %s", neighbor); - } + p += sizeof(uint32_t)) + zlog_debug(" Neighbor: %pI4", (in_addr_t *)p); assert(p == OSPF6_MESSAGE_END(oh)); } @@ -162,7 +155,6 @@ void ospf6_dbdesc_print(struct ospf6_header *oh) void ospf6_lsreq_print(struct ospf6_header *oh) { - char id[16], adv_router[16]; char *p; ospf6_header_print(oh); @@ -172,11 +164,9 @@ void ospf6_lsreq_print(struct ospf6_header *oh) p + sizeof(struct ospf6_lsreq_entry) <= OSPF6_MESSAGE_END(oh); p += sizeof(struct ospf6_lsreq_entry)) { struct ospf6_lsreq_entry *e = (struct ospf6_lsreq_entry *)p; - inet_ntop(AF_INET, &e->adv_router, adv_router, - sizeof(adv_router)); - inet_ntop(AF_INET, &e->id, id, sizeof(id)); - zlog_debug(" [%s Id:%s Adv:%s]", ospf6_lstype_name(e->type), - id, adv_router); + + zlog_debug(" [%s Id:%pI4 Adv:%pI4]", + ospf6_lstype_name(e->type), &e->id, &e->adv_router); } assert(p == OSPF6_MESSAGE_END(oh)); @@ -856,15 +846,11 @@ static void ospf6_lsreq_recv(struct in6_addr *src, struct in6_addr *dst, /* Find database copy */ lsa = ospf6_lsdb_lookup(e->type, e->id, e->adv_router, lsdb); if (lsa == NULL) { - char id[16], adv_router[16]; if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV)) { - inet_ntop(AF_INET, &e->id, id, sizeof(id)); - inet_ntop(AF_INET, &e->adv_router, adv_router, - sizeof(adv_router)); zlog_debug( - "Can't find requested [%s Id:%s Adv:%s]", - ospf6_lstype_name(e->type), id, - adv_router); + "Can't find requested [%s Id:%pI4 Adv:%pI4]", + ospf6_lstype_name(e->type), &e->id, + &e->adv_router); } thread_add_event(master, bad_lsreq, on, 0, NULL); return; @@ -1321,7 +1307,6 @@ static int ospf6_rxpacket_examin(struct ospf6_interface *oi, struct ospf6_header *oh, const unsigned bytesonwire) { - char buf[2][INET_ADDRSTRLEN]; if (MSG_OK != ospf6_packet_examin(oh, bytesonwire)) return MSG_NG; @@ -1335,13 +1320,10 @@ static int ospf6_rxpacket_examin(struct ospf6_interface *oi, oi->interface->name); else zlog_warn( - "VRF %s: I/F %s Area-ID mismatch (my %s, rcvd %s)", + "VRF %s: I/F %s Area-ID mismatch (my %pI4, rcvd %pI4)", vrf_id_to_name(oi->interface->vrf_id), - oi->interface->name, - inet_ntop(AF_INET, &oi->area->area_id, buf[0], - INET_ADDRSTRLEN), - inet_ntop(AF_INET, &oh->area_id, buf[1], - INET_ADDRSTRLEN)); + oi->interface->name, &oi->area->area_id, + &oh->area_id); return MSG_NG; } @@ -1356,11 +1338,9 @@ static int ospf6_rxpacket_examin(struct ospf6_interface *oi, /* Router-ID check */ if (oh->router_id == oi->area->ospf6->router_id) { - zlog_warn("VRF %s: I/F %s Duplicate Router-ID (%s)", + zlog_warn("VRF %s: I/F %s Duplicate Router-ID (%pI4)", vrf_id_to_name(oi->interface->vrf_id), - oi->interface->name, - inet_ntop(AF_INET, &oh->router_id, buf[0], - INET_ADDRSTRLEN)); + oi->interface->name, &oh->router_id); return MSG_NG; } return MSG_OK; @@ -1541,7 +1521,6 @@ int ospf6_receive(struct thread *thread) { int sockfd; unsigned int len; - char srcname[64], dstname[64]; struct in6_addr src, dst; ifindex_t ifindex; struct iovec iovector[2]; @@ -1598,13 +1577,11 @@ int ospf6_receive(struct thread *thread) /* Log */ if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV)) { - inet_ntop(AF_INET6, &src, srcname, sizeof(srcname)); - inet_ntop(AF_INET6, &dst, dstname, sizeof(dstname)); zlog_debug("%s received on %s", lookup_msg(ospf6_message_type_str, oh->type, NULL), oi->interface->name); - zlog_debug(" src: %s", srcname); - zlog_debug(" dst: %s", dstname); + zlog_debug(" src: %pI6", &src); + zlog_debug(" dst: %pI6", &dst); switch (oh->type) { case OSPF6_MESSAGE_TYPE_HELLO: @@ -1659,7 +1636,7 @@ static void ospf6_send(struct in6_addr *src, struct in6_addr *dst, struct ospf6_interface *oi, struct ospf6_header *oh) { unsigned int len; - char srcname[64], dstname[64]; + char srcname[64]; struct iovec iovector[2]; /* initialize */ @@ -1680,7 +1657,6 @@ static void ospf6_send(struct in6_addr *src, struct in6_addr *dst, /* Log */ if (IS_OSPF6_DEBUG_MESSAGE(oh->type, SEND)) { - inet_ntop(AF_INET6, dst, dstname, sizeof(dstname)); if (src) inet_ntop(AF_INET6, src, srcname, sizeof(srcname)); else @@ -1689,7 +1665,7 @@ static void ospf6_send(struct in6_addr *src, struct in6_addr *dst, lookup_msg(ospf6_message_type_str, oh->type, NULL), oi->interface->name); zlog_debug(" src: %s", srcname); - zlog_debug(" dst: %s", dstname); + zlog_debug(" dst: %pI6", dst); switch (oh->type) { case OSPF6_MESSAGE_TYPE_HELLO: @@ -1855,7 +1831,9 @@ int ospf6_dbdesc_send(struct thread *thread) /* MTU check */ if (p - sendbuf + sizeof(struct ospf6_lsa_header) > ospf6_packet_max(on->ospf6_if)) { - ospf6_lsdb_lsa_unlock(lsa); + ospf6_lsa_unlock(lsa); + if (lsanext) + ospf6_lsa_unlock(lsanext); break; } memcpy(p, lsa->header, sizeof(struct ospf6_lsa_header)); @@ -1893,9 +1871,18 @@ int ospf6_dbdesc_send_newone(struct thread *thread) so that ospf6_send_dbdesc () can send those LSAs */ size = sizeof(struct ospf6_lsa_header) + sizeof(struct ospf6_dbdesc); for (ALL_LSDB(on->summary_list, lsa, lsanext)) { + /* if stub area then don't advertise AS-External LSAs */ + if (IS_AREA_STUB(on->ospf6_if->area) + && ntohs(lsa->header->type) == OSPF6_LSTYPE_AS_EXTERNAL) { + ospf6_lsdb_remove(lsa, on->summary_list); + continue; + } + if (size + sizeof(struct ospf6_lsa_header) > ospf6_packet_max(on->ospf6_if)) { - ospf6_lsdb_lsa_unlock(lsa); + ospf6_lsa_unlock(lsa); + if (lsanext) + ospf6_lsa_unlock(lsanext); break; } @@ -1954,7 +1941,9 @@ int ospf6_lsreq_send(struct thread *thread) /* MTU check */ if (p - sendbuf + sizeof(struct ospf6_lsreq_entry) > ospf6_packet_max(on->ospf6_if)) { - ospf6_lsdb_lsa_unlock(lsa); + ospf6_lsa_unlock(lsa); + if (lsanext) + ospf6_lsa_unlock(lsanext); break; } @@ -2415,7 +2404,9 @@ int ospf6_lsack_send_interface(struct thread *thread) thread_add_event(master, ospf6_lsack_send_interface, oi, 0, &oi->thread_send_lsack); - ospf6_lsdb_lsa_unlock(lsa); + ospf6_lsa_unlock(lsa); + if (lsanext) + ospf6_lsa_unlock(lsanext); break; } 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_proto.c b/ospf6d/ospf6_proto.c index 864974c9a4..e60d2c7e0e 100644 --- a/ospf6d/ospf6_proto.c +++ b/ospf6d/ospf6_proto.c @@ -60,7 +60,14 @@ void ospf6_prefix_apply_mask(struct ospf6_prefix *op) void ospf6_prefix_options_printbuf(uint8_t prefix_options, char *buf, int size) { - snprintf(buf, size, "xxx"); + const char *dn, *p, *mc, *la, *nu; + + dn = (CHECK_FLAG(prefix_options, OSPF6_PREFIX_OPTION_DN) ? "DN" : "--"); + p = (CHECK_FLAG(prefix_options, OSPF6_PREFIX_OPTION_P) ? "P" : "--"); + mc = (CHECK_FLAG(prefix_options, OSPF6_PREFIX_OPTION_MC) ? "MC" : "--"); + la = (CHECK_FLAG(prefix_options, OSPF6_PREFIX_OPTION_LA) ? "LA" : "--"); + nu = (CHECK_FLAG(prefix_options, OSPF6_PREFIX_OPTION_NU) ? "NU" : "--"); + snprintf(buf, size, "%s|%s|%s|%s|%s", dn, p, mc, la, nu); } void ospf6_capability_printbuf(char capability, char *buf, int size) diff --git a/ospf6d/ospf6_proto.h b/ospf6d/ospf6_proto.h index 3876a98c50..da6b270e01 100644 --- a/ospf6d/ospf6_proto.h +++ b/ospf6d/ospf6_proto.h @@ -69,6 +69,8 @@ struct ospf6_prefix { #define OSPF6_PREFIX_OPTION_LA (1 << 1) /* Local Address */ #define OSPF6_PREFIX_OPTION_MC (1 << 2) /* MultiCast */ #define OSPF6_PREFIX_OPTION_P (1 << 3) /* Propagate (NSSA) */ +#define OSPF6_PREFIX_OPTION_DN \ + (1 << 4) /* DN bit to prevent loops in VPN environment */ /* caddr_t OSPF6_PREFIX_BODY (struct ospf6_prefix *); */ #define OSPF6_PREFIX_BODY(x) ((caddr_t)(x) + sizeof(struct ospf6_prefix)) 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_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 f94252991c..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) { @@ -649,14 +651,10 @@ static int ospf6_spf_calculation_thread(struct thread *t) ospf6_spf_reason_string(ospf6->spf_reason, rbuf, sizeof(rbuf)); if (IS_OSPF6_DEBUG_SPF(PROCESS) || IS_OSPF6_DEBUG_SPF(TIME)) - zlog_debug("SPF runtime: %lld sec %lld usec", - (long long)runtime.tv_sec, - (long long)runtime.tv_usec); - - zlog_info( - "SPF processing: # Areas: %d, SPF runtime: %lld sec %lld usec, Reason: %s", - areas_processed, (long long)runtime.tv_sec, - (long long)runtime.tv_usec, rbuf); + zlog_debug( + "SPF processing: # Areas: %d, SPF runtime: %lld sec %lld usec, Reason: %s", + areas_processed, (long long)runtime.tv_sec, + (long long)runtime.tv_usec, rbuf); ospf6->last_spf_reason = ospf6->spf_reason; ospf6_reset_spf_reason(ospf6); @@ -718,9 +716,7 @@ void ospf6_spf_schedule(struct ospf6 *ospf6, unsigned int reason) } if (IS_OSPF6_DEBUG_SPF(PROCESS) || IS_OSPF6_DEBUG_SPF(TIME)) - zlog_debug("SPF: calculation timer delay = %ld", delay); - - zlog_info("SPF: Scheduled in %ld msec", delay); + zlog_debug("SPF: Rescheduling in %ld msec", delay); ospf6->t_spf_calc = NULL; thread_add_timer_msec(master, ospf6_spf_calculation_thread, ospf6, @@ -728,16 +724,24 @@ void ospf6_spf_schedule(struct ospf6 *ospf6, unsigned int reason) } void ospf6_spf_display_subtree(struct vty *vty, const char *prefix, int rest, - struct ospf6_vertex *v) + struct ospf6_vertex *v, json_object *json_obj, + bool use_json) { struct listnode *node, *nnode; struct ospf6_vertex *c; char *next_prefix; int len; int restnum; + json_object *json_childs = NULL; + json_object *json_child = NULL; - /* "prefix" is the space prefix of the display line */ - vty_out(vty, "%s+-%s [%d]\n", prefix, v->name, v->cost); + if (use_json) { + json_childs = json_object_new_object(); + json_object_int_add(json_obj, "cost", v->cost); + } else { + /* "prefix" is the space prefix of the display line */ + vty_out(vty, "%s+-%s [%d]\n", prefix, v->name, v->cost); + } len = strlen(prefix) + 4; next_prefix = (char *)malloc(len); @@ -749,10 +753,27 @@ void ospf6_spf_display_subtree(struct vty *vty, const char *prefix, int rest, restnum = listcount(v->child_list); for (ALL_LIST_ELEMENTS(v->child_list, node, nnode, c)) { - restnum--; - ospf6_spf_display_subtree(vty, next_prefix, restnum, c); - } + if (use_json) + json_child = json_object_new_object(); + else + restnum--; + ospf6_spf_display_subtree(vty, next_prefix, restnum, c, + json_child, use_json); + + if (use_json) + json_object_object_add(json_childs, c->name, + json_child); + } + if (use_json) { + json_object_boolean_add(json_obj, "isLeafNode", + !listcount(v->child_list)); + if (listcount(v->child_list)) + json_object_object_add(json_obj, "children", + json_childs); + else + json_object_free(json_childs); + } free(next_prefix); } @@ -1002,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 253888d8ce..523b318d5b 100644 --- a/ospf6d/ospf6_spf.h +++ b/ospf6d/ospf6_spf.h @@ -23,6 +23,7 @@ #include "typesafe.h" #include "ospf6_top.h" +#include "lib/json.h" /* Debug option */ extern unsigned char conf_debug_ospf6_spf; @@ -34,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 */ @@ -147,7 +148,8 @@ extern void ospf6_spf_calculation(uint32_t router_id, extern void ospf6_spf_schedule(struct ospf6 *ospf, unsigned int reason); extern void ospf6_spf_display_subtree(struct vty *vty, const char *prefix, - int rest, struct ospf6_vertex *v); + int rest, struct ospf6_vertex *v, + json_object *json_obj, bool use_json); extern void ospf6_spf_config_write(struct vty *vty, struct ospf6 *ospf6); extern int config_write_ospf6_debug_spf(struct vty *vty); diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c index 3f72ec828e..a38f1cbc45 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; @@ -809,7 +811,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 +833,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; } diff --git a/ospf6d/ospf6_top.h b/ospf6d/ospf6_top.h index 75dff86cd7..7980659e68 100644 --- a/ospf6d/ospf6_top.h +++ b/ospf6d/ospf6_top.h @@ -132,9 +132,9 @@ 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 diff --git a/ospf6d/ospf6_zebra.c b/ospf6d/ospf6_zebra.c index 2b7072d34f..8d5e0f0a39 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; @@ -96,13 +96,9 @@ static int ospf6_router_id_update_zebra(ZAPI_CALLBACK_ARGS) return 0; o->router_id_zebra = router_id.u.prefix4; - if (IS_OSPF6_DEBUG_ZEBRA(RECV)) { - char buf[INET_ADDRSTRLEN]; - - zlog_debug("%s: zebra router-id %s update", __func__, - inet_ntop(AF_INET, &router_id.u.prefix4, buf, - INET_ADDRSTRLEN)); - } + if (IS_OSPF6_DEBUG_ZEBRA(RECV)) + zlog_debug("%s: zebra router-id %pI4 update", __func__, + &router_id.u.prefix4); ospf6_router_id_update(o); 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..3f9461c7f0 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; diff --git a/ospf6d/subdir.am b/ospf6d/subdir.am index ec6e593533..82d880cca8 100644 --- a/ospf6d/subdir.am +++ b/ospf6d/subdir.am @@ -40,7 +40,6 @@ ospf6d_libospf6_a_SOURCES = \ 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,7 +61,6 @@ 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 \ @@ -80,6 +78,6 @@ 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 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_bfd.c b/ospfd/ospf_bfd.c index a9bc9069d2..b202cd01f1 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,155 @@ 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); + 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 +213,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 +234,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 +314,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 b98852eeee..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) { @@ -616,7 +619,7 @@ DEFUN (debug_ospf_packet, if (inst) // user passed instance ID { - if (!ospf_lookup_instance(strtoul(argv[2]->arg, NULL, 10))) + if (inst != ospf_instance) return CMD_NOT_MY_INSTANCE; } @@ -692,7 +695,7 @@ DEFUN (no_debug_ospf_packet, if (inst) // user passed instance ID { - if (!ospf_lookup_instance(strtoul(argv[3]->arg, NULL, 10))) + if (inst != ospf_instance) return CMD_NOT_MY_INSTANCE; } @@ -763,7 +766,7 @@ DEFUN (debug_ospf_ism, if (inst) // user passed instance ID { - if (!ospf_lookup_instance(strtoul(argv[2]->arg, NULL, 10))) + if (inst != ospf_instance) return CMD_NOT_MY_INSTANCE; } @@ -814,7 +817,7 @@ DEFUN (no_debug_ospf_ism, if (inst) // user passed instance ID { - if (!ospf_lookup_instance(strtoul(argv[3]->arg, NULL, 10))) + if (inst != ospf_instance) return CMD_NOT_MY_INSTANCE; } @@ -909,8 +912,8 @@ DEFUN (debug_ospf_instance_nsm, unsigned short instance = 0; instance = strtoul(argv[idx_number]->arg, NULL, 10); - if (!ospf_lookup_instance(instance)) - return CMD_SUCCESS; + if (instance != ospf_instance) + return CMD_NOT_MY_INSTANCE; return debug_ospf_nsm_common(vty, 4, argc, argv); } @@ -981,7 +984,7 @@ DEFUN (no_debug_ospf_instance_nsm, unsigned short instance = 0; instance = strtoul(argv[idx_number]->arg, NULL, 10); - if (!ospf_lookup_instance(instance)) + if (instance != ospf_instance) return CMD_NOT_MY_INSTANCE; return no_debug_ospf_nsm_common(vty, 5, argc, argv); @@ -1062,7 +1065,7 @@ DEFUN (debug_ospf_instance_lsa, unsigned short instance = 0; instance = strtoul(argv[idx_number]->arg, NULL, 10); - if (!ospf_lookup_instance(instance)) + if (instance != ospf_instance) return CMD_NOT_MY_INSTANCE; return debug_ospf_lsa_common(vty, 4, argc, argv); @@ -1145,7 +1148,7 @@ DEFUN (no_debug_ospf_instance_lsa, unsigned short instance = 0; instance = strtoul(argv[idx_number]->arg, NULL, 10); - if (!ospf_lookup_instance(instance)) + if (instance != ospf_instance) return CMD_NOT_MY_INSTANCE; return no_debug_ospf_lsa_common(vty, 5, argc, argv); @@ -1207,7 +1210,7 @@ DEFUN (debug_ospf_instance_zebra, unsigned short instance = 0; instance = strtoul(argv[idx_number]->arg, NULL, 10); - if (!ospf_lookup_instance(instance)) + if (instance != ospf_instance) return CMD_NOT_MY_INSTANCE; return debug_ospf_zebra_common(vty, 4, argc, argv); @@ -1271,8 +1274,8 @@ DEFUN (no_debug_ospf_instance_zebra, unsigned short instance = 0; instance = strtoul(argv[idx_number]->arg, NULL, 10); - if (!ospf_lookup_instance(instance)) - return CMD_SUCCESS; + if (instance != ospf_instance) + return CMD_NOT_MY_INSTANCE; return no_debug_ospf_zebra_common(vty, 5, argc, argv); } @@ -1317,8 +1320,8 @@ DEFUN (debug_ospf_instance_event, unsigned short instance = 0; instance = strtoul(argv[idx_number]->arg, NULL, 10); - if (!ospf_lookup_instance(instance)) - return CMD_SUCCESS; + if (instance != ospf_instance) + return CMD_NOT_MY_INSTANCE; if (vty->node == CONFIG_NODE) CONF_DEBUG_ON(event, EVENT); @@ -1339,8 +1342,8 @@ DEFUN (no_debug_ospf_instance_event, unsigned short instance = 0; instance = strtoul(argv[idx_number]->arg, NULL, 10); - if (!ospf_lookup_instance(instance)) - return CMD_SUCCESS; + if (instance != ospf_instance) + return CMD_NOT_MY_INSTANCE; if (vty->node == CONFIG_NODE) CONF_DEBUG_OFF(event, EVENT); @@ -1387,8 +1390,8 @@ DEFUN (debug_ospf_instance_nssa, unsigned short instance = 0; instance = strtoul(argv[idx_number]->arg, NULL, 10); - if (!ospf_lookup_instance(instance)) - return CMD_SUCCESS; + if (instance != ospf_instance) + return CMD_NOT_MY_INSTANCE; if (vty->node == CONFIG_NODE) CONF_DEBUG_ON(nssa, NSSA); @@ -1409,8 +1412,8 @@ DEFUN (no_debug_ospf_instance_nssa, unsigned short instance = 0; instance = strtoul(argv[idx_number]->arg, NULL, 10); - if (!ospf_lookup_instance(instance)) - return CMD_SUCCESS; + if (instance != ospf_instance) + return CMD_NOT_MY_INSTANCE; if (vty->node == CONFIG_NODE) CONF_DEBUG_OFF(nssa, NSSA); @@ -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,16 +1653,17 @@ 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; } -static int show_debugging_ospf_common(struct vty *vty, struct ospf *ospf) +static int show_debugging_ospf_common(struct vty *vty) { int i; - if (ospf->instance) - vty_out(vty, "\nOSPF Instance: %d\n\n", ospf->instance); + if (ospf_instance) + vty_out(vty, "\nOSPF Instance: %d\n\n", ospf_instance); vty_out(vty, "OSPF debugging status:\n"); @@ -1730,6 +1763,10 @@ static int show_debugging_ospf_common(struct vty *vty, struct ospf *ospf) 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; @@ -1742,13 +1779,7 @@ DEFUN_NOSH (show_debugging_ospf, DEBUG_STR OSPF_STR) { - struct ospf *ospf = NULL; - - ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT); - if (ospf == NULL) - return CMD_SUCCESS; - - return show_debugging_ospf_common(vty, ospf); + return show_debugging_ospf_common(vty); } DEFUN_NOSH (show_debugging_ospf_instance, @@ -1760,14 +1791,13 @@ DEFUN_NOSH (show_debugging_ospf_instance, "Instance ID\n") { int idx_number = 3; - struct ospf *ospf; unsigned short instance = 0; instance = strtoul(argv[idx_number]->arg, NULL, 10); - if ((ospf = ospf_lookup_instance(instance)) == NULL) - return CMD_SUCCESS; + if (instance != ospf_instance) + return CMD_NOT_MY_INSTANCE; - return show_debugging_ospf_common(vty, ospf); + return show_debugging_ospf_common(vty); } static int config_write_debug(struct vty *vty); @@ -1790,16 +1820,11 @@ static int config_write_debug(struct vty *vty) "", " send", " recv", "", " detail", " send detail", " recv detail", " detail"}; - struct ospf *ospf; char str[16]; memset(str, 0, 16); - ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT); - if (ospf == NULL) - return CMD_SUCCESS; - - if (ospf->instance) - snprintf(str, sizeof(str), " %u", ospf->instance); + if (ospf_instance) + snprintf(str, sizeof(str), " %u", ospf_instance); /* debug ospf ism (status|events|timers). */ if (IS_CONF_DEBUG_OSPF(ism, ISM) == OSPF_DEBUG_ISM) @@ -1929,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; } @@ -1961,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); @@ -2004,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_ext.c b/ospfd/ospf_ext.c index 4fa61221a6..754e2bcbab 100644 --- a/ospfd/ospf_ext.c +++ b/ospfd/ospf_ext.c @@ -301,6 +301,8 @@ static void set_ext_prefix(struct ext_itf *exti, uint8_t route_type, exti->prefix.af = 0; exti->prefix.pref_length = p.prefixlen; exti->prefix.address = p.prefix; + + SET_FLAG(exti->flags, EXT_LPFLG_LSA_ACTIVE); } /* Extended Link TLV - RFC7684 section 3.1 */ @@ -766,7 +768,6 @@ static void ospf_ext_ism_change(struct ospf_interface *oi, int old_status) if (OspfEXT.enabled) { osr_debug("EXT (%s): Set Prefix SID to interface %s ", __func__, oi->ifp->name); - exti->flags = EXT_LPFLG_LSA_ACTIVE; ospf_sr_update_local_prefix(oi->ifp, oi->address); } } else { diff --git a/ospfd/ospf_flood.c b/ospfd/ospf_flood.c index 5f74984c66..caba03c1b5 100644 --- a/ospfd/ospf_flood.c +++ b/ospfd/ospf_flood.c @@ -537,11 +537,9 @@ static int ospf_flood_through_interface(struct ospf_interface *oi, if (!CHECK_FLAG(onbr->options, OSPF_OPTION_O)) { if (IS_DEBUG_OSPF(lsa, LSA_FLOODING)) zlog_debug( - "%s: Skipping neighbor %s via %s -- Not Opaque-capable.", + "%s: Skipping neighbor %s via %pI4 -- Not Opaque-capable.", __func__, IF_NAME(oi), - inet_ntop(AF_INET, - &onbr->router_id, buf, - sizeof(buf))); + &onbr->router_id); continue; } } @@ -557,11 +555,9 @@ static int ospf_flood_through_interface(struct ospf_interface *oi, &onbr->router_id)) { if (IS_DEBUG_OSPF(lsa, LSA_FLOODING)) zlog_debug( - "%s: Skipping neighbor %s via %s -- inbr == onbr.", + "%s: Skipping neighbor %s via %pI4 -- inbr == onbr.", __func__, IF_NAME(oi), - inet_ntop(AF_INET, - &inbr->router_id, buf, - sizeof(buf))); + &inbr->router_id); continue; } } else { @@ -573,11 +569,9 @@ static int ospf_flood_through_interface(struct ospf_interface *oi, &onbr->router_id)) { if (IS_DEBUG_OSPF(lsa, LSA_FLOODING)) zlog_debug( - "%s: Skipping neighbor %s via %s -- lsah->adv_router == onbr.", + "%s: Skipping neighbor %s via %pI4 -- lsah->adv_router == onbr.", __func__, IF_NAME(oi), - inet_ntop(AF_INET, - &onbr->router_id, buf, - sizeof(buf))); + &onbr->router_id); continue; } } diff --git a/ospfd/ospf_interface.c b/ospfd/ospf_interface.c index 51599ccc8a..d494f0fbce 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; diff --git a/ospfd/ospf_interface.h b/ospfd/ospf_interface.h index bf59af16c2..a9534f543d 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,10 @@ 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)) +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)) +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_main.c b/ospfd/ospf_main.c index 6be5486b55..d23dea0ca1 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" @@ -98,6 +99,7 @@ static void sighup(void) static void sigint(void) { zlog_notice("Terminating on signal"); + bfd_protocol_integration_set_shutdown(true); ospf_terminate(); exit(0); } @@ -141,14 +143,12 @@ 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) { - unsigned short instance = 0; - bool created = false; - #ifdef SUPPORT_OSPF_API /* OSPF apiserver is disabled by default. */ ospf_apiserver_enable = 0; @@ -169,8 +169,8 @@ int main(int argc, char **argv) switch (opt) { case 'n': - ospfd_di.instance = instance = atoi(optarg); - if (instance < 1) + ospfd_di.instance = ospf_instance = atoi(optarg); + if (ospf_instance < 1) exit(0); break; case 0: @@ -208,7 +208,7 @@ int main(int argc, char **argv) /* OSPFd inits. */ ospf_if_init(); - ospf_zebra_init(master, instance); + ospf_zebra_init(master, ospf_instance); /* OSPF vty inits. */ ospf_vty_init(); @@ -216,7 +216,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(); @@ -227,17 +227,6 @@ int main(int argc, char **argv) /* OSPF errors init */ ospf_error_init(); - /* - * Need to initialize the default ospf structure, so the interface mode - * commands can be duly processed if they are received before 'router - * ospf', when ospfd is restarted - */ - if (instance && !ospf_get_instance(instance, &created)) { - flog_err(EC_OSPF_INIT_FAIL, "OSPF instance init failed: %s", - strerror(errno)); - exit(1); - } - frr_config_fork(); frr_run(master); 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_packet.c b/ospfd/ospf_packet.c index 343e406f28..0fd4803c79 100644 --- a/ospfd/ospf_packet.c +++ b/ospfd/ospf_packet.c @@ -1881,20 +1881,10 @@ static void ospf_ls_upd(struct ospf *ospf, struct ip *iph, struct ospf_lsa *ls_ret, *current; int ret = 1; - if (IS_DEBUG_OSPF_NSSA) { - char buf1[INET_ADDRSTRLEN]; - char buf2[INET_ADDRSTRLEN]; - char buf3[INET_ADDRSTRLEN]; - - zlog_debug("LSA Type-%d from %s, ID: %s, ADV: %s", - lsa->data->type, - inet_ntop(AF_INET, &ospfh->router_id, buf1, - INET_ADDRSTRLEN), - inet_ntop(AF_INET, &lsa->data->id, buf2, - INET_ADDRSTRLEN), - inet_ntop(AF_INET, &lsa->data->adv_router, - buf3, INET_ADDRSTRLEN)); - } + if (IS_DEBUG_OSPF_NSSA) + zlog_debug("LSA Type-%d from %pI4, ID: %pI4, ADV: %pI4", + lsa->data->type, &ospfh->router_id, + &lsa->data->id, &lsa->data->adv_router); listnode_delete(lsas, lsa); /* We don't need it in list anymore */ @@ -1940,19 +1930,11 @@ static void ospf_ls_upd(struct ospf *ospf, struct ip *iph, if (lsa->data->type == OSPF_ROUTER_LSA) if (!IPV4_ADDR_SAME(&lsa->data->id, &lsa->data->adv_router)) { - char buf1[INET_ADDRSTRLEN]; - char buf2[INET_ADDRSTRLEN]; - char buf3[INET_ADDRSTRLEN]; - - flog_err(EC_OSPF_ROUTER_LSA_MISMATCH, - "Incoming Router-LSA from %s with Adv-ID[%s] != LS-ID[%s]", - inet_ntop(AF_INET, &ospfh->router_id, - buf1, INET_ADDRSTRLEN), - inet_ntop(AF_INET, &lsa->data->id, - buf2, INET_ADDRSTRLEN), - inet_ntop(AF_INET, - &lsa->data->adv_router, buf3, - INET_ADDRSTRLEN)); + flog_err( + EC_OSPF_ROUTER_LSA_MISMATCH, + "Incoming Router-LSA from %pI4 with Adv-ID[%pI4] != LS-ID[%pI4]", + &ospfh->router_id, &lsa->data->id, + &lsa->data->adv_router); flog_err( EC_OSPF_DOMAIN_CORRUPT, "OSPF domain compromised by attack or corruption. Verify correct operation of -ALL- OSPF routers."); @@ -3045,17 +3027,11 @@ static enum ospf_read_return_enum ospf_read_helper(struct ospf *ospf) /* If incoming interface is passive one, ignore it. */ if (oi && OSPF_IF_PASSIVE_STATUS(oi) == OSPF_IF_PASSIVE) { - char buf[3][INET_ADDRSTRLEN]; - if (IS_DEBUG_OSPF_EVENT) zlog_debug( - "ignoring packet from router %s sent to %s, received on a passive interface, %s", - inet_ntop(AF_INET, &ospfh->router_id, buf[0], - sizeof(buf[0])), - inet_ntop(AF_INET, &iph->ip_dst, buf[1], - sizeof(buf[1])), - inet_ntop(AF_INET, &oi->address->u.prefix4, - buf[2], sizeof(buf[2]))); + "ignoring packet from router %pI4 sent to %pI4, received on a passive interface, %pI4", + &ospfh->router_id, &iph->ip_dst, + &oi->address->u.prefix4); if (iph->ip_dst.s_addr == htonl(OSPF_ALLSPFROUTERS)) { /* Try to fix multicast membership. @@ -3097,16 +3073,11 @@ static enum ospf_read_return_enum ospf_read_helper(struct ospf *ospf) &iph->ip_src, ifp->name); return OSPF_READ_CONTINUE; } else if (oi->state == ISM_Down) { - char buf[2][INET_ADDRSTRLEN]; - flog_warn( EC_OSPF_PACKET, - "Ignoring packet from %s to %s received on interface that is down [%s]; interface flags are %s", - inet_ntop(AF_INET, &iph->ip_src, buf[0], - sizeof(buf[0])), - inet_ntop(AF_INET, &iph->ip_dst, buf[1], - sizeof(buf[1])), - ifp->name, if_flag_dump(ifp->flags)); + "Ignoring packet from %pI4 to %pI4 received on interface that is down [%s]; interface flags are %s", + &iph->ip_src, &iph->ip_dst, ifp->name, + if_flag_dump(ifp->flags)); /* Fix multicast memberships? */ if (iph->ip_dst.s_addr == htonl(OSPF_ALLSPFROUTERS)) OI_MEMBER_JOINED(oi, MEMBER_ALLROUTERS); diff --git a/ospfd/ospf_snmp.c b/ospfd/ospf_snmp.c index 3f4ca44b05..8418bbf2b9 100644 --- a/ospfd/ospf_snmp.c +++ b/ospfd/ospf_snmp.c @@ -2565,4 +2565,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 82acd0829c..1e0814764b 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) { @@ -251,15 +251,11 @@ static void ospf_vertex_dump(const char *msg, struct vertex *v, struct vertex_parent *vp; for (ALL_LIST_ELEMENTS_RO(v->parents, node, vp)) { - char buf1[BUFSIZ]; - if (vp) { zlog_debug( - "parent %pI4 backlink %d nexthop %s lsa pos %d", - &vp->parent->lsa->id, - vp->backlink, - inet_ntop(AF_INET, &vp->nexthop->router, - buf1, BUFSIZ), + "parent %pI4 backlink %d nexthop %pI4 lsa pos %d", + &vp->parent->lsa->id, vp->backlink, + &vp->nexthop->router, vp->nexthop->lsa_pos); } } @@ -707,14 +703,9 @@ static void ospf_spf_add_parent(struct vertex *v, struct vertex *w, else w->distance = distance; - if (IS_DEBUG_OSPF_EVENT) { - char buf[2][INET_ADDRSTRLEN]; - zlog_debug( - "%s: Adding %s as parent of %s", __func__, - inet_ntop(AF_INET, &v->lsa->id, buf[0], sizeof(buf[0])), - inet_ntop(AF_INET, &w->lsa->id, buf[1], - sizeof(buf[1]))); - } + if (IS_DEBUG_OSPF_EVENT) + zlog_debug("%s: Adding %pI4 as parent of %pI4", __func__, + &v->lsa->id, &w->lsa->id); /* * Adding parent for a new, better path: flush existing parents from W. @@ -805,8 +796,6 @@ static unsigned int ospf_nexthop_calculation(struct ospf_area *area, struct vertex_nexthop *nh, *lnh; struct vertex_parent *vp; unsigned int added = 0; - char buf1[BUFSIZ]; - char buf2[BUFSIZ]; if (IS_DEBUG_OSPF_EVENT) { zlog_debug("ospf_nexthop_calculation(): Start"); @@ -828,14 +817,11 @@ static unsigned int ospf_nexthop_calculation(struct ospf_area *area, /* we *must* be supplied with the link data */ assert(l != NULL); - if (IS_DEBUG_OSPF_EVENT) { + if (IS_DEBUG_OSPF_EVENT) zlog_debug( - "%s: considering link type:%d link_id:%s link_data:%s", - __func__, l->m[0].type, - inet_ntop(AF_INET, &l->link_id, buf1, BUFSIZ), - inet_ntop(AF_INET, &l->link_data, buf2, - BUFSIZ)); - } + "%s: considering link type:%d link_id:%pI4 link_data:%pI4", + __func__, l->m[0].type, &l->link_id, + &l->link_data); if (w->type == OSPF_VERTEX_ROUTER) { /* @@ -852,15 +838,10 @@ static unsigned int ospf_nexthop_calculation(struct ospf_area *area, lsa_pos); if (!oi) { zlog_debug( - "%s: OI not found in LSA: lsa_pos: %d link_id:%s link_data:%s", + "%s: OI not found in LSA: lsa_pos: %d link_id:%pI4 link_data:%pI4", __func__, lsa_pos, - inet_ntop(AF_INET, - &l->link_id, - buf1, BUFSIZ), - inet_ntop(AF_INET, - &l->link_data, - buf2, - BUFSIZ)); + &l->link_id, + &l->link_data); return 0; } } diff --git a/ospfd/ospf_spf.h b/ospfd/ospf_spf.h index 66555be4b7..835caab288 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; diff --git a/ospfd/ospf_sr.c b/ospfd/ospf_sr.c index 7b2d794214..a7a2e03632 100644 --- a/ospfd/ospf_sr.c +++ b/ospfd/ospf_sr.c @@ -1202,16 +1202,22 @@ static void update_ext_prefix_sid(struct sr_node *srn, struct sr_prefix *srp) found ? "Update" : "Add", GET_OPAQUE_ID(srp->instance), &srn->adv_router); + /* Complete SR-Prefix */ + srp->srn = srn; + IPV4_ADDR_COPY(&srp->adv_router, &srn->adv_router); + /* if not found, add new Segment Prefix and install NHLFE */ if (!found) { - /* Complete SR-Prefix and add it to SR-Node list */ - srp->srn = srn; - IPV4_ADDR_COPY(&srp->adv_router, &srn->adv_router); + /* Add it to SR-Node list ... */ listnode_add(srn->ext_prefix, srp); - /* Try to set MPLS table */ + /* ... and try to set MPLS table */ if (compute_prefix_nhlfe(srp) == 1) ospf_zebra_update_prefix_sid(srp); } else { + /* + * An old SR prefix exist. Check if something changes or if it + * is just a refresh. + */ if (sr_prefix_cmp(pref, srp)) { if (compute_prefix_nhlfe(srp) == 1) { ospf_zebra_delete_prefix_sid(pref); @@ -2462,10 +2468,18 @@ DEFUN (sr_prefix_sid, new->type = LOCAL_SID; } + /* First, remove old NHLFE if installed */ + if (srp == new && CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_NPFLG) + && !CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_EFLG)) + ospf_zebra_delete_prefix_sid(srp); + /* Then, reset Flag & labels to handle flag update */ + new->flags = 0; + new->label_in = 0; + new->nhlfe.label_out = 0; + /* Set NO PHP flag if present and compute NHLFE */ if (argv_find(argv, argc, "no-php-flag", &idx)) { SET_FLAG(new->flags, EXT_SUBTLV_PREFIX_SID_NPFLG); - UNSET_FLAG(new->flags, EXT_SUBTLV_PREFIX_SID_EFLG); new->label_in = index2label(new->sid, OspfSR.self->srgb); new->nhlfe.label_out = MPLS_LABEL_IMPLICIT_NULL; } @@ -2505,7 +2519,7 @@ DEFUN (sr_prefix_sid, if (srp != new) listnode_add(OspfSR.self->ext_prefix, new); - /* Install Prefix SID if SR is UP and a valid input label set */ + /* Update Prefix SID if SR is UP */ if (OspfSR.status == SR_UP) { if (CHECK_FLAG(new->flags, EXT_SUBTLV_PREFIX_SID_NPFLG) && !CHECK_FLAG(new->flags, EXT_SUBTLV_PREFIX_SID_EFLG)) 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 4132452069..e6835ffc72 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", @@ -140,44 +140,37 @@ int ospf_oi_count(struct interface *ifp) all_vrf = strmatch(vrf_name, "all"); \ } -static struct ospf *ospf_cmd_lookup_ospf(struct vty *vty, - struct cmd_token *argv[], - const int argc, uint32_t enable, - unsigned short *instance) +static int ospf_router_cmd_parse(struct vty *vty, struct cmd_token *argv[], + const int argc, unsigned short *instance, + const char **vrf_name) { - struct ospf *ospf = NULL; int idx_vrf = 0, idx_inst = 0; - const char *vrf_name = NULL; - bool created = false; *instance = 0; - if (argv_find(argv, argc, "(1-65535)", &idx_inst)) + if (argv_find(argv, argc, "(1-65535)", &idx_inst)) { + if (ospf_instance == 0) { + vty_out(vty, + "%% OSPF is not running in instance mode\n"); + return CMD_WARNING_CONFIG_FAILED; + } + *instance = strtoul(argv[idx_inst]->arg, NULL, 10); + } + *vrf_name = NULL; if (argv_find(argv, argc, "vrf", &idx_vrf)) { - vrf_name = argv[idx_vrf + 1]->arg; - if (vrf_name == NULL || strmatch(vrf_name, VRF_DEFAULT_NAME)) - vrf_name = NULL; - if (enable) { - /* Allocate VRF aware instance */ - ospf = ospf_get(*instance, vrf_name, &created); - } else { - ospf = ospf_lookup_by_inst_name(*instance, vrf_name); - } - } else { - if (enable) { - ospf = ospf_get(*instance, NULL, &created); - } else { - ospf = ospf_lookup_instance(*instance); + if (ospf_instance != 0) { + vty_out(vty, + "%% VRF is not supported in instance mode\n"); + return CMD_WARNING_CONFIG_FAILED; } - } - if (created) { - if (DFLT_OSPF_LOG_ADJACENCY_CHANGES) - SET_FLAG(ospf->config, OSPF_LOG_ADJACENCY_CHANGES); + *vrf_name = argv[idx_vrf + 1]->arg; + if (*vrf_name && strmatch(*vrf_name, VRF_DEFAULT_NAME)) + *vrf_name = NULL; } - return ospf; + return CMD_SUCCESS; } static void ospf_show_vrf_name(struct ospf *ospf, struct vty *vty, @@ -213,28 +206,35 @@ DEFUN_NOSH (router_ospf, "Instance ID\n" VRF_CMD_HELP_STR) { - struct ospf *ospf = NULL; - int ret = CMD_SUCCESS; - unsigned short instance = 0; + unsigned short instance; + const char *vrf_name; + bool created = false; + struct ospf *ospf; + int ret; - ospf = ospf_cmd_lookup_ospf(vty, argv, argc, 1, &instance); - if (!ospf) - return CMD_WARNING_CONFIG_FAILED; + ret = ospf_router_cmd_parse(vty, argv, argc, &instance, &vrf_name); + if (ret != CMD_SUCCESS) + return ret; - /* The following logic to set the vty qobj index is in place to be able - to ignore the commands which dont belong to this instance. */ - if (ospf->instance != instance) { + if (instance != ospf_instance) { VTY_PUSH_CONTEXT_NULL(OSPF_NODE); - ret = CMD_NOT_MY_INSTANCE; - } else { - if (IS_DEBUG_OSPF_EVENT) - zlog_debug( - "Config command 'router ospf %d' received, vrf %s id %u oi_running %u", - instance, ospf->name ? ospf->name : "NIL", - ospf->vrf_id, ospf->oi_running); - VTY_PUSH_CONTEXT(OSPF_NODE, ospf); + return CMD_NOT_MY_INSTANCE; } + ospf = ospf_get(instance, vrf_name, &created); + + if (created) + if (DFLT_OSPF_LOG_ADJACENCY_CHANGES) + SET_FLAG(ospf->config, OSPF_LOG_ADJACENCY_CHANGES); + + if (IS_DEBUG_OSPF_EVENT) + zlog_debug( + "Config command 'router ospf %d' received, vrf %s id %u oi_running %u", + ospf->instance, ospf->name ? ospf->name : "NIL", + ospf->vrf_id, ospf->oi_running); + + VTY_PUSH_CONTEXT(OSPF_NODE, ospf); + return ret; } @@ -247,19 +247,25 @@ DEFUN (no_router_ospf, "Instance ID\n" VRF_CMD_HELP_STR) { + unsigned short instance; + const char *vrf_name; struct ospf *ospf; - unsigned short instance = 0; + int ret; - ospf = ospf_cmd_lookup_ospf(vty, argv, argc, 0, &instance); - if (ospf == NULL) { - if (instance) - return CMD_NOT_MY_INSTANCE; - else - return CMD_WARNING; - } - ospf_finish(ospf); + ret = ospf_router_cmd_parse(vty, argv, argc, &instance, &vrf_name); + if (ret != CMD_SUCCESS) + return ret; - return CMD_SUCCESS; + if (instance != ospf_instance) + return CMD_NOT_MY_INSTANCE; + + ospf = ospf_lookup(instance, vrf_name); + if (ospf) + ospf_finish(ospf); + else + ret = CMD_WARNING_CONFIG_FAILED; + + return ret; } @@ -3381,11 +3387,11 @@ DEFUN (show_ip_ospf_instance, json_object *json = NULL; instance = strtoul(argv[idx_number]->arg, NULL, 10); - ospf = ospf_lookup_instance(instance); - if (ospf == NULL) + if (instance != ospf_instance) return CMD_NOT_MY_INSTANCE; - if (!ospf->oi_running) + ospf = ospf_lookup_instance(instance); + if (!ospf || !ospf->oi_running) return CMD_SUCCESS; if (uj) @@ -3770,7 +3776,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); @@ -4131,11 +4138,11 @@ DEFUN (show_ip_ospf_instance_interface, json_object *json = NULL; instance = strtoul(argv[idx_number]->arg, NULL, 10); - ospf = ospf_lookup_instance(instance); - if (ospf == NULL) + if (instance != ospf_instance) return CMD_NOT_MY_INSTANCE; - if (!ospf->oi_running) + ospf = ospf_lookup_instance(instance); + if (!ospf || !ospf->oi_running) return CMD_SUCCESS; if (uj) @@ -4526,11 +4533,11 @@ DEFUN (show_ip_ospf_instance_neighbor, int ret = CMD_SUCCESS; instance = strtoul(argv[idx_number]->arg, NULL, 10); - ospf = ospf_lookup_instance(instance); - if (ospf == NULL) + if (instance != ospf_instance) return CMD_NOT_MY_INSTANCE; - if (!ospf->oi_running) + ospf = ospf_lookup_instance(instance); + if (!ospf || !ospf->oi_running) return CMD_SUCCESS; if (uj) @@ -4741,11 +4748,11 @@ DEFUN (show_ip_ospf_instance_neighbor_all, int ret = CMD_SUCCESS; instance = strtoul(argv[idx_number]->arg, NULL, 10); - ospf = ospf_lookup_instance(instance); - if (ospf == NULL) + if (instance != ospf_instance) return CMD_NOT_MY_INSTANCE; - if (!ospf->oi_running) + ospf = ospf_lookup_instance(instance); + if (!ospf || !ospf->oi_running) return CMD_SUCCESS; if (uj) json = json_object_new_object(); @@ -4881,11 +4888,11 @@ DEFUN (show_ip_ospf_instance_neighbor_int, show_ip_ospf_neighbour_header(vty); instance = strtoul(argv[idx_number]->arg, NULL, 10); - ospf = ospf_lookup_instance(instance); - if (ospf == NULL) + if (instance != ospf_instance) return CMD_NOT_MY_INSTANCE; - if (!ospf->oi_running) + ospf = ospf_lookup_instance(instance); + if (!ospf || !ospf->oi_running) return CMD_SUCCESS; if (!uj) @@ -5276,7 +5283,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); @@ -5359,11 +5366,11 @@ DEFPY (show_ip_ospf_instance_neighbor_id, { struct ospf *ospf; - ospf = ospf_lookup_instance(instance); - if (ospf == NULL) + if (instance != ospf_instance) return CMD_NOT_MY_INSTANCE; - if (!ospf->oi_running) + ospf = ospf_lookup_instance(instance); + if (!ospf || !ospf->oi_running) return CMD_SUCCESS; return show_ip_ospf_neighbor_id_common(vty, ospf, &router_id, !!json, @@ -5532,11 +5539,11 @@ DEFUN (show_ip_ospf_instance_neighbor_detail, int ret = CMD_SUCCESS; instance = strtoul(argv[idx_number]->arg, NULL, 10); - ospf = ospf_lookup_instance(instance); - if (ospf == NULL) + if (instance != ospf_instance) return CMD_NOT_MY_INSTANCE; - if (!ospf->oi_running) + ospf = ospf_lookup_instance(instance); + if (!ospf || !ospf->oi_running) return CMD_SUCCESS; if (uj) @@ -5727,11 +5734,11 @@ DEFUN (show_ip_ospf_instance_neighbor_detail_all, int ret = CMD_SUCCESS; instance = strtoul(argv[idx_number]->arg, NULL, 10); - ospf = ospf_lookup_instance(instance); - if (ospf == NULL) + if (instance != ospf_instance) return CMD_NOT_MY_INSTANCE; - if (!ospf->oi_running) + ospf = ospf_lookup_instance(instance); + if (!ospf || !ospf->oi_running) return CMD_SUCCESS; if (uj) @@ -5859,11 +5866,11 @@ DEFUN (show_ip_ospf_instance_neighbor_int_detail, bool uj = use_json(argc, argv); instance = strtoul(argv[idx_number]->arg, NULL, 10); - ospf = ospf_lookup_instance(instance); - if (ospf == NULL) + if (instance != ospf_instance) return CMD_NOT_MY_INSTANCE; - if (!ospf->oi_running) + ospf = ospf_lookup_instance(instance); + if (!ospf || !ospf->oi_running) return CMD_SUCCESS; return show_ip_ospf_neighbor_int_detail_common(vty, ospf, idx_ifname, @@ -7103,14 +7110,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" @@ -7118,77 +7125,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); - ospf = ospf_lookup_instance(instance); - if (ospf == NULL) - return CMD_NOT_MY_INSTANCE; - if (!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, @@ -7212,15 +7148,12 @@ DEFUN (show_ip_ospf_instance_database_max, json = json_object_new_object(); instance = strtoul(argv[idx_number]->arg, NULL, 10); - - ospf = ospf_lookup_instance(instance); - if (ospf == NULL) + if (instance != ospf_instance) return CMD_NOT_MY_INSTANCE; - if (!ospf->oi_running) { - vty_out(vty, "%% OSPF instance not found\n"); + ospf = ospf_lookup_instance(instance); + if (!ospf || !ospf->oi_running) return CMD_SUCCESS; - } show_ip_ospf_database_common(vty, ospf, 1, argc, argv, 0, json, uj); @@ -7234,6 +7167,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, @@ -7323,14 +7270,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" @@ -7339,7 +7286,6 @@ 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; @@ -7353,20 +7299,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); - ospf = ospf_lookup_instance(instance); - if (ospf == NULL) - return CMD_NOT_MY_INSTANCE; - if (!ospf->oi_running) { - vty_out(vty, "%% OSPF instance not found\n"); - 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) { @@ -7413,8 +7345,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, @@ -8819,7 +8793,7 @@ DEFUN (ip_ospf_area, else ospf = ospf_lookup_instance(instance); - if (instance && ospf == NULL) { + if (instance && instance != ospf_instance) { /* * At this point we know we have received * an instance and there is no ospf instance @@ -8944,7 +8918,7 @@ DEFUN (no_ip_ospf_area, else ospf = ospf_lookup_instance(instance); - if (instance && ospf == NULL) + if (instance && instance != ospf_instance) return CMD_NOT_MY_INSTANCE; argv_find(argv, argc, "area", &idx); @@ -10918,11 +10892,11 @@ DEFUN (show_ip_ospf_instance_border_routers, unsigned short instance = 0; instance = strtoul(argv[idx_number]->arg, NULL, 10); - ospf = ospf_lookup_instance(instance); - if (ospf == NULL) + if (instance != ospf_instance) return CMD_NOT_MY_INSTANCE; - if (!ospf->oi_running) + ospf = ospf_lookup_instance(instance); + if (!ospf || !ospf->oi_running) return CMD_SUCCESS; return show_ip_ospf_border_routers_common(vty, ospf, 0); @@ -11086,11 +11060,11 @@ DEFUN (show_ip_ospf_instance_route, unsigned short instance = 0; instance = strtoul(argv[idx_number]->arg, NULL, 10); - ospf = ospf_lookup_instance(instance); - if (ospf == NULL) + if (instance != ospf_instance) return CMD_NOT_MY_INSTANCE; - if (!ospf->oi_running) + ospf = ospf_lookup_instance(instance); + if (!ospf || !ospf->oi_running) return CMD_SUCCESS; return show_ip_ospf_route_common(vty, ospf, NULL, 0); @@ -11189,8 +11163,7 @@ DEFPY (clear_ip_ospf_neighbor, */ if (instance != 0) { /* This means clear only the particular ospf process */ - ospf = ospf_lookup_instance(instance); - if (ospf == NULL) + if (instance != ospf_instance) return CMD_NOT_MY_INSTANCE; } @@ -11220,8 +11193,7 @@ DEFPY (clear_ip_ospf_process, /* Check if instance is not passed as an argument */ if (instance != 0) { /* This means clear only the particular ospf process */ - ospf = ospf_lookup_instance(instance); - if (ospf == NULL) + if (instance != ospf_instance) return CMD_NOT_MY_INSTANCE; } @@ -11545,7 +11517,6 @@ static int config_write_interface_one(struct vty *vty, struct vrf *vrf) struct ospf_if_params *params; const char *auth_str; int write = 0; - struct ospf *ospf = vrf->info; FOR_ALL_INTERFACES (vrf, ifp) { @@ -11698,9 +11669,9 @@ static int config_write_interface_one(struct vty *vty, struct vrf *vrf) /* Area print. */ if (OSPF_IF_PARAM_CONFIGURED(params, if_area)) { - if (ospf && ospf->instance) + if (ospf_instance) vty_out(vty, " ip ospf %d", - ospf->instance); + ospf_instance); else vty_out(vty, " ip ospf"); @@ -11716,7 +11687,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. */ @@ -12375,8 +12346,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); diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c index aaab274570..56b2f8d660 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. */ @@ -622,7 +622,7 @@ void ospf_zebra_update_prefix_sid(const struct sr_prefix *srp) znh->labels[0] = path->srni.label_out; osr_debug(" |- labels %u/%u", srp->label_in, - srp->nhlfe.label_out); + path->srni.label_out); /* Set TI-LFA backup nexthop info if present */ if (path->srni.backup_label_stack) { diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c index 04397d50a5..9856e60130 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; @@ -70,6 +71,8 @@ static struct ospf_master ospf_master; /* OSPF process wide configuration pointer to export. */ struct ospf_master *om; +unsigned short ospf_instance; + extern struct zclient *zclient; @@ -109,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) { @@ -511,36 +514,28 @@ static void ospf_init(struct ospf *ospf) ospf_router_id_update(ospf); } -struct ospf *ospf_get(unsigned short instance, const char *name, bool *created) +struct ospf *ospf_lookup(unsigned short instance, const char *name) { struct ospf *ospf; - /* vrf name provided call inst and name based api - * in case of no name pass default ospf instance */ - if (name) + if (ospf_instance) { + ospf = ospf_lookup_instance(instance); + } else { ospf = ospf_lookup_by_inst_name(instance, name); - else - ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT); - - *created = (ospf == NULL); - if (ospf == NULL) { - ospf = ospf_new(instance, name); - ospf_add(ospf); - - ospf_init(ospf); } return ospf; } -struct ospf *ospf_get_instance(unsigned short instance, bool *created) +struct ospf *ospf_get(unsigned short instance, const char *name, bool *created) { struct ospf *ospf; - ospf = ospf_lookup_instance(instance); + ospf = ospf_lookup(instance, name); + *created = (ospf == NULL); if (ospf == NULL) { - ospf = ospf_new(instance, NULL /* VRF_DEFAULT*/); + ospf = ospf_new(instance, name); ospf_add(ospf); ospf_init(ospf); @@ -1937,6 +1932,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 954a469b68..5d64ee9ba2 100644 --- a/ospfd/ospfd.h +++ b/ospfd/ospfd.h @@ -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; @@ -633,6 +633,7 @@ struct ospf_nbr_nbma { /* Extern variables. */ extern struct ospf_master *om; +extern unsigned short ospf_instance; extern const int ospf_redistributed_proto_max; extern struct zclient *zclient; extern struct thread_master *master; @@ -642,10 +643,10 @@ extern struct zebra_privs_t ospfd_privs; /* Prototypes. */ extern const char *ospf_redist_string(unsigned int route_type); extern struct ospf *ospf_lookup_instance(unsigned short); +extern struct ospf *ospf_lookup(unsigned short instance, const char *name); extern struct ospf *ospf_get(unsigned short instance, const char *name, bool *created); extern struct ospf *ospf_new_alloc(unsigned short instance, const char *name); -extern struct ospf *ospf_get_instance(unsigned short, bool *created); 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); diff --git a/ospfd/subdir.am b/ospfd/subdir.am index 28d58452df..25ddef358f 100644 --- a/ospfd/subdir.am +++ b/ospfd/subdir.am @@ -113,7 +113,7 @@ 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 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.c b/pathd/path_memory.c deleted file mode 100644 index ad4904a298..0000000000 --- a/pathd/path_memory.c +++ /dev/null @@ -1,25 +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_memory.h" - -DEFINE_MGROUP(PATHD, "pathd") 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_pcep.c b/pathd/path_pcep.c index 2f9ff4f0f0..d6cd48ecdb 100644 --- a/pathd/path_pcep.c +++ b/pathd/path_pcep.c @@ -17,8 +17,9 @@ */ #include <zebra.h> -#include <pcep_utils_counters.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. @@ -215,29 +216,10 @@ int pcep_main_event_update_candidate(struct path *path) ret = path_pcep_config_update_path(path); if (ret != PATH_NB_ERR && path->srp_id != 0) { - /* ODL and Cisco requires the first reported - * LSP to have a DOWN status, the later status changes - * will be comunicated through hook calls. - */ - enum pcep_lsp_operational_status real_status; if ((resp = path_pcep_config_get_path(&path->nbkey))) { resp->srp_id = path->srp_id; - real_status = resp->status; - resp->status = PCEP_LSP_OPERATIONAL_DOWN; - pcep_ctrl_send_report(pcep_g->fpt, path->pcc_id, resp); - /* If the update did not have any effect and the real - * status is not DOWN, we need to send a second report - * so the PCE is aware of the real status. This is due - * to the fact that NO notification will be received - * if the update did not apply any changes */ - if ((ret == PATH_NB_NO_CHANGE) - && (real_status != PCEP_LSP_OPERATIONAL_DOWN)) { - resp->status = real_status; - resp->srp_id = 0; - pcep_ctrl_send_report(pcep_g->fpt, path->pcc_id, - resp); - } - pcep_free_path(resp); + pcep_ctrl_send_report(pcep_g->fpt, path->pcc_id, resp, + ret == PATH_NB_NO_CHANGE); } } return ret; @@ -336,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 1896c265c1..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 <pcep_utils_logging.h> -#include <pcep_pcc_api.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 add3391f22..14404b1d08 100644 --- a/pathd/path_pcep_cli.c +++ b/pathd/path_pcep_cli.c @@ -18,8 +18,8 @@ */ #include <zebra.h> -#include <pcep_utils_counters.h> -#include <pcep_session_logic.h> +#include "pceplib/pcep_utils_counters.h" +#include "pceplib/pcep_session_logic.h" #include "log.h" #include "command.h" @@ -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" @@ -321,8 +320,9 @@ pcep_cli_merge_pcep_pce_config_options(struct pce_opts_cli *pce_opts_cli) default_pcep_config_group_opts_g.tcp_md5_auth; } } - strncpy(pce_opts_cli->pce_opts.config_opts.tcp_md5_auth, - tcp_md5_auth_str, TCP_MD5SIG_MAXKEYLEN); + strlcpy(pce_opts_cli->pce_opts.config_opts.tcp_md5_auth, + tcp_md5_auth_str, + sizeof(pce_opts_cli->pce_opts.config_opts.tcp_md5_auth)); struct ipaddr *source_ip = &pce_opts_cli->pce_config_group_opts.source_ip; @@ -525,8 +525,9 @@ static int path_pcep_cli_show_srte_pcep_counters(struct vty *vty) tm_info = localtime(&group->start_time); strftime(tm_buffer, sizeof(tm_buffer), "%Y-%m-%d %H:%M:%S", tm_info); - vty_out(vty, "PCEP counters since %s (%luh %lum %lus):\n", tm_buffer, - diff_time / 3600, (diff_time / 60) % 60, diff_time % 60); + vty_out(vty, "PCEP counters since %s (%uh %um %us):\n", tm_buffer, + (uint32_t)(diff_time / 3600), (uint32_t)((diff_time / 60) % 60), + (uint32_t)(diff_time % 60)); /* Prepare table. */ tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]); @@ -815,7 +816,8 @@ static int path_pcep_cli_peer_tcp_md5_auth(struct vty *vty, return CMD_ERR_NO_MATCH; } - strncpy(pce_config->tcp_md5_auth, tcp_md5_auth, TCP_MD5SIG_MAXKEYLEN); + strlcpy(pce_config->tcp_md5_auth, tcp_md5_auth, + sizeof(pce_config->tcp_md5_auth)); return CMD_SUCCESS; } @@ -1043,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)) { @@ -1220,8 +1222,9 @@ static void print_pcep_session(struct vty *vty, struct pce_opts *pce_opts, localtime_r(¤t_time, <); gmtime_r(&session->time_connected, <); vty_out(vty, - " Connected for %ld seconds, since %d-%02d-%02d %02d:%02d:%02d UTC\n", - (current_time - session->time_connected), + " Connected for %u seconds, since %d-%02d-%02d %02d:%02d:%02d UTC\n", + (uint32_t)(current_time + - session->time_connected), lt.tm_year + 1900, lt.tm_mon + 1, lt.tm_mday, lt.tm_hour, lt.tm_min, lt.tm_sec); } diff --git a/pathd/path_pcep_config.c b/pathd/path_pcep_config.c index 989223ebc3..107475bec9 100644 --- a/pathd/path_pcep_config.c +++ b/pathd/path_pcep_config.c @@ -19,7 +19,7 @@ #include <northbound.h> #include <yang.h> #include <printfrr.h> -#include <pcep-objects.h> +#include "pceplib/pcep_msg_objects.h" #include "pathd/pathd.h" #include "pathd/path_pcep.h" #include "pathd/path_pcep_config.h" @@ -45,14 +45,13 @@ status_int_to_ext(enum srte_policy_status status); static enum pcep_sr_subobj_nai pcep_nai_type(enum srte_segment_nai_type type); static enum srte_segment_nai_type srte_nai_type(enum pcep_sr_subobj_nai type); -static int path_pcep_config_lookup_cb(struct thread *t) +void path_pcep_refine_path(struct path *path) { - struct path *path = THREAD_ARG(t); struct srte_candidate *candidate = lookup_candidate(&path->nbkey); struct srte_lsp *lsp; if (candidate == NULL) - return 0; + return; lsp = candidate->lsp; @@ -65,16 +64,6 @@ static int path_pcep_config_lookup_cb(struct thread *t) if ((path->update_origin == SRTE_ORIGIN_UNDEFINED) && (lsp->segment_list != NULL)) path->update_origin = lsp->segment_list->protocol_origin; - - return 0; -} - -void path_pcep_config_lookup(struct path *path) -{ - /* - * Configuration access is strictly done via the main thread - */ - thread_execute(master, path_pcep_config_lookup_cb, path, 0); } struct path *path_pcep_config_get_path(struct lsp_nb_key *key) @@ -346,9 +335,11 @@ int path_pcep_config_update_path(struct path *path) SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED); for (metric = path->first_metric; metric != NULL; metric = metric->next) - srte_lsp_set_metric(candidate->lsp, metric->type, metric->value, - metric->enforce, metric->is_bound, - metric->is_computed); + srte_lsp_set_metric( + candidate->lsp, + (enum srte_candidate_metric_type)metric->type, + metric->value, metric->enforce, metric->is_bound, + metric->is_computed); if (path->has_bandwidth) srte_lsp_set_bandwidth(candidate->lsp, path->bandwidth, diff --git a/pathd/path_pcep_config.h b/pathd/path_pcep_config.h index de29ab29c1..223dd10c82 100644 --- a/pathd/path_pcep_config.h +++ b/pathd/path_pcep_config.h @@ -31,10 +31,11 @@ typedef int (*path_list_cb_t)(struct path *path, void *arg); /* Lookup the candidate path and fill up the missing path attributes like name - and type. Used for path generated from PCEP message received from the PCE - so they contains more information about the candidate path. If no matching - policy or candidate path is found, nothing is changed */ -void path_pcep_config_lookup(struct path *path); + * and type. Used for path generated from PCEP message received from the PCE + * so they contains more information about the candidate path. If no matching + * policy or candidate path is found, nothing is changed. + * MUST BE CALLED FROM THE MAIN THREAD */ +void path_pcep_refine_path(struct path *path); struct path *path_pcep_config_get_path(struct lsp_nb_key *key); void path_pcep_config_list_path(path_list_cb_t cb, void *arg); int path_pcep_config_update_path(struct path *path); diff --git a/pathd/path_pcep_controller.c b/pathd/path_pcep_controller.c index f4871a4d8d..db7d2b55a5 100644 --- a/pathd/path_pcep_controller.c +++ b/pathd/path_pcep_controller.c @@ -55,7 +55,9 @@ enum pcep_ctrl_event_type { EV_SYNC_PATH, EV_SYNC_DONE, EV_PCEPLIB_EVENT, - EV_RESET_PCC_SESSION + EV_RESET_PCC_SESSION, + EV_SEND_REPORT, + EV_PATH_REFINED }; struct pcep_ctrl_event_data { @@ -73,18 +75,20 @@ struct pcep_main_event_data { void *payload; }; -/* Synchronous call arguments */ - -struct get_counters_args { +struct pcep_refine_path_event_data { struct ctrl_state *ctrl_state; int pcc_id; - struct counters_group *counters; + pcep_refine_callback_t continue_lsp_update_handler; + struct path *path; + void *payload; }; -struct send_report_args { +/* Synchronous call arguments */ + +struct get_counters_args { struct ctrl_state *ctrl_state; int pcc_id; - struct path *path; + struct counters_group *counters; }; struct get_pcep_session_args { @@ -95,13 +99,10 @@ struct get_pcep_session_args { /* Internal Functions Called From Main Thread */ static int pcep_ctrl_halt_cb(struct frr_pthread *fpt, void **res); +static int pcep_refine_path_event_cb(struct thread *thread); /* Internal Functions Called From Controller Thread */ static int pcep_thread_finish_event_handler(struct thread *thread); -static int pcep_thread_get_counters_callback(struct thread *t); -static int pcep_thread_send_report_callback(struct thread *t); -static int pcep_thread_get_pcep_session_callback(struct thread *t); -static int pcep_thread_get_pcc_info_callback(struct thread *t); /* Controller Thread Timer Handler */ static int schedule_thread_timer(struct ctrl_state *ctrl_state, int pcc_id, @@ -148,6 +149,9 @@ static int pcep_thread_event_sync_done(struct ctrl_state *ctrl_state, static int pcep_thread_event_pathd_event(struct ctrl_state *ctrl_state, enum pcep_pathd_event_type type, struct path *path); +static void +pcep_thread_path_refined_event(struct ctrl_state *ctrl_state, + struct pcep_refine_path_event_data *data); /* Main Thread Event Handler */ static int send_to_main(struct ctrl_state *ctrl_state, int pcc_id, @@ -280,48 +284,50 @@ struct counters_group *pcep_ctrl_get_counters(struct frr_pthread *fpt, int pcc_id) { struct ctrl_state *ctrl_state = get_ctrl_state(fpt); - struct get_counters_args args = { - .ctrl_state = ctrl_state, .pcc_id = pcc_id, .counters = NULL}; - thread_execute(ctrl_state->self, pcep_thread_get_counters_callback, - &args, 0); - return args.counters; + struct counters_group *counters = NULL; + struct pcc_state *pcc_state; + pcc_state = pcep_pcc_get_pcc_by_id(ctrl_state->pcc, pcc_id); + if (pcc_state) { + counters = pcep_lib_copy_counters(pcc_state->sess); + } + return counters; } pcep_session *pcep_ctrl_get_pcep_session(struct frr_pthread *fpt, int pcc_id) { struct ctrl_state *ctrl_state = get_ctrl_state(fpt); - struct get_pcep_session_args args = {.ctrl_state = ctrl_state, - .pcc_id = pcc_id, - .pcep_session = NULL}; - thread_execute(ctrl_state->self, pcep_thread_get_pcep_session_callback, - &args, 0); - return args.pcep_session; + struct pcc_state *pcc_state; + pcep_session *session = NULL; + + pcc_state = pcep_pcc_get_pcc_by_id(ctrl_state->pcc, pcc_id); + if (pcc_state) { + session = pcep_lib_copy_pcep_session(pcc_state->sess); + } + return session; } struct pcep_pcc_info *pcep_ctrl_get_pcc_info(struct frr_pthread *fpt, const char *pce_name) { struct ctrl_state *ctrl_state = get_ctrl_state(fpt); - struct pcep_pcc_info *args = XCALLOC(MTYPE_PCEP, sizeof(*args)); - args->ctrl_state = ctrl_state; - strncpy(args->pce_name, pce_name, sizeof(args->pce_name)); - thread_execute(ctrl_state->self, pcep_thread_get_pcc_info_callback, - args, 0); + struct pcep_pcc_info *pcc_info = XCALLOC(MTYPE_PCEP, sizeof(*pcc_info)); + if( pcc_info && ctrl_state){ + strlcpy(pcc_info->pce_name, pce_name, sizeof(pcc_info->pce_name)); + pcep_pcc_copy_pcc_info(ctrl_state->pcc, pcc_info); + } - return args; + return pcc_info; } -void pcep_ctrl_send_report(struct frr_pthread *fpt, int pcc_id, - struct path *path) +int pcep_ctrl_send_report(struct frr_pthread *fpt, int pcc_id, + struct path *path, bool is_stable) { - /* Sends a report stynchronously */ struct ctrl_state *ctrl_state = get_ctrl_state(fpt); - struct send_report_args args = { - .ctrl_state = ctrl_state, .pcc_id = pcc_id, .path = path}; - thread_execute(ctrl_state->self, pcep_thread_send_report_callback, - &args, 0); + return send_to_thread(ctrl_state, pcc_id, EV_SEND_REPORT, is_stable, + path); } + /* ------------ Internal Functions Called from Main Thread ------------ */ int pcep_ctrl_halt_cb(struct frr_pthread *fpt, void **res) @@ -333,6 +339,20 @@ int pcep_ctrl_halt_cb(struct frr_pthread *fpt, void **res) return 0; } +int pcep_refine_path_event_cb(struct thread *thread) +{ + struct pcep_refine_path_event_data *data = THREAD_ARG(thread); + assert(data != NULL); + struct ctrl_state *ctrl_state = data->ctrl_state; + struct path *path = data->path; + assert(path != NULL); + int pcc_id = data->pcc_id; + + + path_pcep_refine_path(path); + return send_to_thread(ctrl_state, pcc_id, EV_PATH_REFINED, 0, data); +} + /* ------------ API Functions Called From Controller Thread ------------ */ @@ -442,6 +462,41 @@ int pcep_thread_pcc_count(struct ctrl_state *ctrl_state) return ctrl_state->pcc_count; } +int pcep_thread_refine_path(struct ctrl_state *ctrl_state, int pcc_id, + pcep_refine_callback_t cb, struct path *path, + void *payload) +{ + struct pcep_refine_path_event_data *data; + + data = XCALLOC(MTYPE_PCEP, sizeof(*data)); + data->ctrl_state = ctrl_state; + data->path = path; + data->pcc_id = pcc_id; + data->continue_lsp_update_handler = cb; + data->payload = payload; + + thread_add_event(ctrl_state->main, pcep_refine_path_event_cb, + (void *)data, 0, NULL); + return 0; +} + +void pcep_thread_path_refined_event(struct ctrl_state *ctrl_state, + struct pcep_refine_path_event_data *data) +{ + assert(data != NULL); + int pcc_id = data->pcc_id; + pcep_refine_callback_t continue_lsp_update_handler = data->continue_lsp_update_handler; + assert(continue_lsp_update_handler != NULL); + struct path *path = data->path; + void *payload = data->payload; + struct pcc_state *pcc_state = NULL; + XFREE(MTYPE_PCEP, data); + + pcc_state = pcep_pcc_get_pcc_by_id(ctrl_state->pcc, pcc_id); + continue_lsp_update_handler(ctrl_state, pcc_state, path, payload); +} + + /* ------------ Internal Functions Called From Controller Thread ------------ */ int pcep_thread_finish_event_handler(struct thread *thread) @@ -467,78 +522,6 @@ int pcep_thread_finish_event_handler(struct thread *thread) return 0; } -int pcep_thread_get_counters_callback(struct thread *t) -{ - struct get_counters_args *args = THREAD_ARG(t); - assert(args != NULL); - struct ctrl_state *ctrl_state = args->ctrl_state; - assert(ctrl_state != NULL); - struct pcc_state *pcc_state; - - pcc_state = pcep_pcc_get_pcc_by_id(ctrl_state->pcc, args->pcc_id); - if (pcc_state) { - args->counters = pcep_lib_copy_counters(pcc_state->sess); - } else { - args->counters = NULL; - } - - return 0; -} - -int pcep_thread_send_report_callback(struct thread *t) -{ - struct send_report_args *args = THREAD_ARG(t); - assert(args != NULL); - struct ctrl_state *ctrl_state = args->ctrl_state; - assert(ctrl_state != NULL); - struct pcc_state *pcc_state; - - if (args->pcc_id == 0) { - for (int i = 0; i < MAX_PCC; i++) { - if (ctrl_state->pcc[i]) { - pcep_pcc_send_report(ctrl_state, - ctrl_state->pcc[i], - args->path); - } - } - } else { - pcc_state = - pcep_pcc_get_pcc_by_id(ctrl_state->pcc, args->pcc_id); - pcep_pcc_send_report(ctrl_state, pcc_state, args->path); - } - - return 0; -} - -int pcep_thread_get_pcep_session_callback(struct thread *t) -{ - struct get_pcep_session_args *args = THREAD_ARG(t); - assert(args != NULL); - struct ctrl_state *ctrl_state = args->ctrl_state; - assert(ctrl_state != NULL); - struct pcc_state *pcc_state; - - pcc_state = pcep_pcc_get_pcc_by_id(ctrl_state->pcc, args->pcc_id); - if (pcc_state) { - args->pcep_session = - pcep_lib_copy_pcep_session(pcc_state->sess); - } - - return 0; -} - -int pcep_thread_get_pcc_info_callback(struct thread *t) -{ - struct pcep_pcc_info *args = THREAD_ARG(t); - assert(args != NULL); - struct ctrl_state *ctrl_state = args->ctrl_state; - assert(ctrl_state != NULL); - - pcep_pcc_copy_pcc_info(ctrl_state->pcc, args); - - return 0; -} - /* ------------ Controller Thread Timer Handler ------------ */ int schedule_thread_timer_with_cb(struct ctrl_state *ctrl_state, int pcc_id, @@ -752,11 +735,14 @@ int pcep_thread_event_handler(struct thread *thread) /* Possible sub-type values */ enum pcep_pathd_event_type path_event_type = PCEP_PATH_UNDEFINED; - /* Possible payload values */ + /* Possible payload values, maybe an union would be better... */ struct path *path = NULL; struct pcc_opts *pcc_opts = NULL; struct pce_opts *pce_opts = NULL; struct pcc_state *pcc_state = NULL; + struct pcep_refine_path_event_data *refine_data = NULL; + + struct path *path_copy = NULL; switch (type) { case EV_UPDATE_PCC_OPTS: @@ -808,6 +794,30 @@ int pcep_thread_event_handler(struct thread *thread) (const char *)payload); } break; + case EV_SEND_REPORT: + assert(payload != NULL); + path = (struct path *)payload; + if (pcc_id == 0) { + for (int i = 0; i < MAX_PCC; i++) { + if (ctrl_state->pcc[i]) { + path_copy = pcep_copy_path(path); + pcep_pcc_send_report( + ctrl_state, ctrl_state->pcc[i], + path_copy, (bool)sub_type); + } + } + } else { + pcc_state = + pcep_pcc_get_pcc_by_id(ctrl_state->pcc, pcc_id); + pcep_pcc_send_report(ctrl_state, pcc_state, path, + (bool)sub_type); + } + break; + case EV_PATH_REFINED: + assert(payload != NULL); + refine_data = (struct pcep_refine_path_event_data *)payload; + pcep_thread_path_refined_event(ctrl_state, refine_data); + break; default: flog_warn(EC_PATH_PCEP_RECOVERABLE_INTERNAL_ERROR, "Unexpected event received in controller thread: %u", @@ -984,6 +994,7 @@ int pcep_main_event_handler(struct thread *thread) /* ------------ Helper functions ------------ */ + void set_ctrl_state(struct frr_pthread *fpt, struct ctrl_state *ctrl_state) { assert(fpt != NULL); diff --git a/pathd/path_pcep_controller.h b/pathd/path_pcep_controller.h index f6eaa0ca2a..1b7c3a4c72 100644 --- a/pathd/path_pcep_controller.h +++ b/pathd/path_pcep_controller.h @@ -21,16 +21,21 @@ #include "pathd/path_pcep.h" +struct ctrl_state; +struct pcc_state; enum pcep_main_event_type { PCEP_MAIN_EVENT_UNDEFINED = 0, PCEP_MAIN_EVENT_START_SYNC, PCEP_MAIN_EVENT_UPDATE_CANDIDATE, - PCEP_MAIN_EVENT_REMOVE_CANDIDATE_LSP + PCEP_MAIN_EVENT_REMOVE_CANDIDATE_LSP, }; typedef int (*pcep_main_event_handler_t)(enum pcep_main_event_type type, int pcc_id, void *payload); +typedef void (*pcep_refine_callback_t)(struct ctrl_state *ctrl_state, + struct pcc_state *pcc_state, + struct path *path, void *payload); enum pcep_pathd_event_type { PCEP_PATH_UNDEFINED = 0, @@ -124,10 +129,13 @@ pcep_session *pcep_ctrl_get_pcep_session(struct frr_pthread *fpt, int pcc_id); struct pcep_pcc_info *pcep_ctrl_get_pcc_info(struct frr_pthread *fpt, const char *pce_name); -/* Synchronously send a report, the caller is responsible to free the path, - * If `pcc_id` is `0` the report is sent by all PCCs */ -void pcep_ctrl_send_report(struct frr_pthread *fpt, int pcc_id, - struct path *path); +/* Asynchronously send a report. The caller is giving away the path structure, + * it shouldn't be allocated on the stack. If `pcc_id` is `0` the report is + * sent by all PCCs. The parameter is_stable is used to hint wether the status + * will soon change, this is used to ensure all report updates are sent even + * when missing status update events */ +int pcep_ctrl_send_report(struct frr_pthread *fpt, int pcc_id, + struct path *path, bool is_stable); /* Functions called from the controller thread */ void pcep_thread_start_sync(struct ctrl_state *ctrl_state, int pcc_id); @@ -162,5 +170,9 @@ int pcep_thread_send_ctrl_event(void *fpt, void *payload, pcep_ctrl_thread_callback cb); int pcep_thread_pcep_event(struct thread *thread); int pcep_thread_pcc_count(struct ctrl_state *ctrl_state); +/* Called by the PCC to refine a path in the main thread */ +int pcep_thread_refine_path(struct ctrl_state *ctrl_state, int pcc_id, + pcep_refine_callback_t cb, struct path *path, + void *payload); #endif // _PATH_PCEP_CONTROLLER_H_ diff --git a/pathd/path_pcep_debug.c b/pathd/path_pcep_debug.c index bcaadfe4d8..d222371bbb 100644 --- a/pathd/path_pcep_debug.c +++ b/pathd/path_pcep_debug.c @@ -636,8 +636,8 @@ const char *pcep_message_type_name(enum pcep_message_types pcep_message_type) return "UPDATE"; case PCEP_TYPE_INITIATE: return "INITIATE"; - case PCEP_TYPE_UNKOWN_MSG: - return "UNKOWN_MSG"; + case PCEP_TYPE_START_TLS: + return "START_TLS"; default: return "UNKNOWN"; } @@ -1288,7 +1288,7 @@ void _format_path_hop(int ps, struct path_hop *hop) &hop->nai.remote_addr.ipaddr_v6); break; case PCEP_SR_SUBOBJ_NAI_UNNUMBERED_IPV4_ADJACENCY: - PATHD_FORMAT("%*sNAI: %pI4(%u)/%pI4(%u)\n", ps, "", + PATHD_FORMAT("%*sNAI: %pI6(%u)/%pI6(%u)\n", ps, "", &hop->nai.local_addr.ipaddr_v6, hop->nai.local_iface, &hop->nai.remote_addr.ipaddr_v6, diff --git a/pathd/path_pcep_debug.h b/pathd/path_pcep_debug.h index 68b29ab657..5a504e4e1a 100644 --- a/pathd/path_pcep_debug.h +++ b/pathd/path_pcep_debug.h @@ -20,8 +20,8 @@ #define _PATH_PCEP_DEBUG_H_ #include "pathd/path_debug.h" -#include <pcep_pcc_api.h> -#include <pcep-objects.h> +#include "pceplib/pcep_pcc_api.h" +#include "pceplib/pcep_msg_objects.h" #include "pathd/path_pcep.h" #include "pathd/path_pcep_controller.h" #include "pathd/path_pcep_pcc.h" diff --git a/pathd/path_pcep_lib.c b/pathd/path_pcep_lib.c index bb6bfb1336..e9d699de47 100644 --- a/pathd/path_pcep_lib.c +++ b/pathd/path_pcep_lib.c @@ -16,15 +16,20 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#include <zebra.h> + +#include "memory.h" + #include <debug.h> -#include <pcep_utils_counters.h> -#include <pcep_timers.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 @@ -176,11 +181,11 @@ pcep_lib_connect(struct ipaddr *src_addr, int src_port, struct ipaddr *dst_addr, /* TODO when available in the pceplib, set it here pcep_options->state_timeout_inteval_seconds;*/ - if (pcep_options->tcp_md5_auth != NULL - && pcep_options->tcp_md5_auth[0] != '\0') { + if (pcep_options->tcp_md5_auth[0] != '\0') { config->is_tcp_auth_md5 = true; - strncpy(config->tcp_authentication_str, - pcep_options->tcp_md5_auth, TCP_MD5SIG_MAXKEYLEN); + strlcpy(config->tcp_authentication_str, + pcep_options->tcp_md5_auth, + sizeof(config->tcp_authentication_str)); } else { config->is_tcp_auth_md5 = false; } diff --git a/pathd/path_pcep_lib.h b/pathd/path_pcep_lib.h index 3bea28432d..3f34edcb3f 100644 --- a/pathd/path_pcep_lib.h +++ b/pathd/path_pcep_lib.h @@ -20,7 +20,7 @@ #define _PATH_PCEP_LIB_H_ #include <stdbool.h> -#include <pcep_pcc_api.h> +#include "pceplib/pcep_pcc_api.h" #include "frr_pthread.h" #include "pathd/path_pcep.h" 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 c1f60edd22..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" @@ -55,6 +54,7 @@ #define MAX_ERROR_MSG_SIZE 256 #define MAX_COMPREQ_TRIES 3 +pthread_mutex_t g_pcc_info_mtx = PTHREAD_MUTEX_INITIALIZER; /* PCEP Event Handler */ static void handle_pcep_open(struct ctrl_state *ctrl_state, @@ -63,12 +63,15 @@ static void handle_pcep_open(struct ctrl_state *ctrl_state, static void handle_pcep_message(struct ctrl_state *ctrl_state, struct pcc_state *pcc_state, struct pcep_message *msg); +static void handle_pcep_lsp_initiate(struct ctrl_state *ctrl_state, + struct pcc_state *pcc_state, + struct pcep_message *msg); static void handle_pcep_lsp_update(struct ctrl_state *ctrl_state, struct pcc_state *pcc_state, struct pcep_message *msg); -static void handle_pcep_lsp_initiate(struct ctrl_state *ctrl_state, +static void continue_pcep_lsp_update(struct ctrl_state *ctrl_state, struct pcc_state *pcc_state, - struct pcep_message *msg); + struct path *path, void *payload); static void handle_pcep_comp_reply(struct ctrl_state *ctrl_state, struct pcc_state *pcc_state, struct pcep_message *msg); @@ -143,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) @@ -344,9 +347,6 @@ void pcep_pcc_reconnect(struct ctrl_state *ctrl_state, int pcep_pcc_enable(struct ctrl_state *ctrl_state, struct pcc_state *pcc_state) { - char pcc_buff[40]; - char pce_buff[40]; - assert(pcc_state->status == PCEP_PCC_DISCONNECTED); assert(pcc_state->sess == NULL); @@ -362,17 +362,14 @@ int pcep_pcc_enable(struct ctrl_state *ctrl_state, struct pcc_state *pcc_state) if (!CHECK_FLAG(pcc_state->flags, F_PCC_STATE_HAS_IPV4)) { if (pcc_state->retry_count < OTHER_FAMILY_MAX_RETRIES) { flog_warn(EC_PATH_PCEP_MISSING_SOURCE_ADDRESS, - "skipping connection to PCE %s:%d due to " - "missing PCC IPv4 address", - ipaddr2str(&pcc_state->pce_opts->addr, - pce_buff, sizeof(pce_buff)), + "skipping connection to PCE %pIA:%d due to missing PCC IPv4 address", + &pcc_state->pce_opts->addr, pcc_state->pce_opts->port); schedule_reconnect(ctrl_state, pcc_state); return 0; } else { flog_warn(EC_PATH_PCEP_MISSING_SOURCE_ADDRESS, - "missing IPv4 PCC address, IPv4 candidate " - "paths will be ignored"); + "missing IPv4 PCC address, IPv4 candidate paths will be ignored"); } } @@ -381,17 +378,14 @@ int pcep_pcc_enable(struct ctrl_state *ctrl_state, struct pcc_state *pcc_state) if (!CHECK_FLAG(pcc_state->flags, F_PCC_STATE_HAS_IPV6)) { if (pcc_state->retry_count < OTHER_FAMILY_MAX_RETRIES) { flog_warn(EC_PATH_PCEP_MISSING_SOURCE_ADDRESS, - "skipping connection to PCE %s:%d due to " - "missing PCC IPv6 address", - ipaddr2str(&pcc_state->pce_opts->addr, - pce_buff, sizeof(pce_buff)), + "skipping connection to PCE %pIA:%d due to missing PCC IPv6 address", + &pcc_state->pce_opts->addr, pcc_state->pce_opts->port); schedule_reconnect(ctrl_state, pcc_state); return 0; } else { flog_warn(EC_PATH_PCEP_MISSING_SOURCE_ADDRESS, - "missing IPv6 PCC address, IPv6 candidate " - "paths will be ignored"); + "missing IPv6 PCC address, IPv6 candidate paths will be ignored"); } } @@ -399,10 +393,8 @@ int pcep_pcc_enable(struct ctrl_state *ctrl_state, struct pcc_state *pcc_state) * have been spent, we still need the one for the transport familly */ if (pcc_state->pcc_addr_tr.ipa_type == IPADDR_NONE) { flog_warn(EC_PATH_PCEP_MISSING_SOURCE_ADDRESS, - "skipping connection to PCE %s:%d due to missing " - "PCC address", - ipaddr2str(&pcc_state->pce_opts->addr, pce_buff, - sizeof(pce_buff)), + "skipping connection to PCE %pIA:%d due to missing PCC address", + &pcc_state->pce_opts->addr, pcc_state->pce_opts->port); schedule_reconnect(ctrl_state, pcc_state); return 0; @@ -416,12 +408,10 @@ int pcep_pcc_enable(struct ctrl_state *ctrl_state, struct pcc_state *pcc_state) if (pcc_state->sess == NULL) { flog_warn(EC_PATH_PCEP_LIB_CONNECT, - "failed to connect to PCE %s:%d from %s:%d", - ipaddr2str(&pcc_state->pce_opts->addr, pce_buff, - sizeof(pce_buff)), + "failed to connect to PCE %pIA:%d from %pIA:%d", + &pcc_state->pce_opts->addr, pcc_state->pce_opts->port, - ipaddr2str(&pcc_state->pcc_addr_tr, pcc_buff, - sizeof(pcc_buff)), + &pcc_state->pcc_addr_tr, pcc_state->pcc_opts->port); schedule_reconnect(ctrl_state, pcc_state); return 0; @@ -494,8 +484,7 @@ void pcep_pcc_sync_path(struct ctrl_state *ctrl_state, send_report(pcc_state, path); } else { PCEP_DEBUG( - "%s Skipping %s candidate path %s " - "synchronization", + "%s Skipping %s candidate path %s synchronization", pcc_state->tag, ipaddr_type_name(&path->nbkey.endpoint), path->name); @@ -543,23 +532,43 @@ void pcep_pcc_sync_done(struct ctrl_state *ctrl_state, } void pcep_pcc_send_report(struct ctrl_state *ctrl_state, - struct pcc_state *pcc_state, struct path *path) + struct pcc_state *pcc_state, struct path *path, + bool is_stable) { - if (pcc_state->status != PCEP_PCC_OPERATING) + if ((pcc_state->status != PCEP_PCC_OPERATING) + || (!pcc_state->caps.is_stateful)) { + pcep_free_path(path); return; + } - if (pcc_state->caps.is_stateful) { - PCEP_DEBUG("%s Send report for candidate path %s", - pcc_state->tag, path->name); + PCEP_DEBUG("%s Send report for candidate path %s", pcc_state->tag, + path->name); + + /* ODL and Cisco requires the first reported + * LSP to have a DOWN status, the later status changes + * will be comunicated through hook calls. + */ + enum pcep_lsp_operational_status real_status = path->status; + path->status = PCEP_LSP_OPERATIONAL_DOWN; + send_report(pcc_state, path); + + /* If no update is expected and the real status wasn't down, we need to + * send a second report with the real status */ + if (is_stable && (real_status != PCEP_LSP_OPERATIONAL_DOWN)) { + path->srp_id = 0; + path->status = real_status; send_report(pcc_state, path); } + + pcep_free_path(path); } + /* ------------ Timeout handler ------------ */ void pcep_pcc_timeout_handler(struct ctrl_state *ctrl_state, struct pcc_state *pcc_state, - enum pcep_ctrl_timer_type type, void *param) + enum pcep_ctrl_timeout_type type, void *param) { struct req_entry *req; @@ -926,6 +935,7 @@ int pcep_pcc_calculate_best_pce(struct pcc_state **pcc) // Changed of state so ... if (step_0_best != best_pce) { + pthread_mutex_lock(&g_pcc_info_mtx); // Calculate previous previous_best_pce = step_0_best; // Clean state @@ -970,6 +980,7 @@ int pcep_pcc_calculate_best_pce(struct pcc_state **pcc) } } } + pthread_mutex_unlock(&g_pcc_info_mtx); } return ((best_pce == -1) ? 0 : pcc[best_pce]->id); @@ -1094,18 +1105,24 @@ void pcep_pcc_copy_pcc_info(struct pcc_state **pcc, } pcc_info->ctrl_state = NULL; - pcc_info->msd = pcc_state->pcc_opts->msd; - pcc_info->pcc_port = pcc_state->pcc_opts->port; + if(pcc_state->pcc_opts){ + pcc_info->msd = pcc_state->pcc_opts->msd; + pcc_info->pcc_port = pcc_state->pcc_opts->port; + } pcc_info->next_plspid = pcc_state->next_plspid; pcc_info->next_reqid = pcc_state->next_reqid; pcc_info->status = pcc_state->status; pcc_info->pcc_id = pcc_state->id; + pthread_mutex_lock(&g_pcc_info_mtx); pcc_info->is_best_multi_pce = pcc_state->is_best; pcc_info->previous_best = pcc_state->previous_best; + pthread_mutex_unlock(&g_pcc_info_mtx); pcc_info->precedence = pcc_state->pce_opts ? pcc_state->pce_opts->precedence : 0; - memcpy(&pcc_info->pcc_addr, &pcc_state->pcc_addr_tr, - sizeof(struct ipaddr)); + if(pcc_state->pcc_addr_tr.ipa_type != IPADDR_NONE){ + memcpy(&pcc_info->pcc_addr, &pcc_state->pcc_addr_tr, + sizeof(struct ipaddr)); + } } @@ -1154,12 +1171,19 @@ void handle_pcep_lsp_update(struct ctrl_state *ctrl_state, struct pcc_state *pcc_state, struct pcep_message *msg) { - char err[MAX_ERROR_MSG_SIZE] = ""; struct path *path; path = pcep_lib_parse_path(msg); lookup_nbkey(pcc_state, path); - /* TODO: Investigate if this is safe to do in the controller thread */ - path_pcep_config_lookup(path); + pcep_thread_refine_path(ctrl_state, pcc_state->id, + &continue_pcep_lsp_update, path, NULL); +} + +void continue_pcep_lsp_update(struct ctrl_state *ctrl_state, + struct pcc_state *pcc_state, struct path *path, + void *payload) +{ + char err[MAX_ERROR_MSG_SIZE] = {0}; + specialize_incoming_path(pcc_state, path); PCEP_DEBUG("%s Received LSP update", pcc_state->tag); PCEP_DEBUG_PATH("%s", format_path(path)); @@ -1204,8 +1228,7 @@ void handle_pcep_comp_reply(struct ctrl_state *ctrl_state, * the connection if more that a given rate. */ PCEP_DEBUG( - "%s Received computation reply for unknown request " - "%d", + "%s Received computation reply for unknown request %d", pcc_state->tag, path->req_id); PCEP_DEBUG_PATH("%s", format_path(path)); send_pcep_error(pcc_state, PCEP_ERRT_UNKNOWN_REQ_REF, @@ -1309,13 +1332,13 @@ void select_transport_address(struct pcc_state *pcc_state) * address */ if (IS_IPADDR_V4(&pcc_state->pce_opts->addr)) { if (CHECK_FLAG(pcc_state->flags, F_PCC_STATE_HAS_IPV4)) { - taddr->ipa_type = IPADDR_V4; taddr->ipaddr_v4 = pcc_state->pcc_addr_v4; + taddr->ipa_type = IPADDR_V4; } } else { if (CHECK_FLAG(pcc_state->flags, F_PCC_STATE_HAS_IPV6)) { - taddr->ipa_type = IPADDR_V6; taddr->ipaddr_v6 = pcc_state->pcc_addr_v6; + taddr->ipa_type = IPADDR_V6; } } } @@ -1535,7 +1558,6 @@ void send_comp_request(struct ctrl_state *ctrl_state, assert(lookup_reqid(pcc_state, req->path) == req->path->req_id); int timeout; - char buff[40]; struct pcep_message *msg; if (!pcc_state->is_best) { @@ -1546,10 +1568,9 @@ void send_comp_request(struct ctrl_state *ctrl_state, specialize_outgoing_path(pcc_state, req->path); PCEP_DEBUG( - "%s Sending computation request %d for path %s to %s (retry %d)", + "%s Sending computation request %d for path %s to %pIA (retry %d)", pcc_state->tag, req->path->req_id, req->path->name, - ipaddr2str(&req->path->nbkey.endpoint, buff, sizeof(buff)), - req->retry_count); + &req->path->nbkey.endpoint, req->retry_count); PCEP_DEBUG_PATH("%s Computation request path %s: %s", pcc_state->tag, req->path->name, format_path(req->path)); @@ -1582,7 +1603,6 @@ void cancel_comp_requests(struct ctrl_state *ctrl_state, void cancel_comp_request(struct ctrl_state *ctrl_state, struct pcc_state *pcc_state, struct req_entry *req) { - char buff[40]; struct pcep_message *msg; if (req->was_sent) { @@ -1592,10 +1612,9 @@ void cancel_comp_request(struct ctrl_state *ctrl_state, } PCEP_DEBUG( - "%s Canceling computation request %d for path %s to %s (retry %d)", + "%s Canceling computation request %d for path %s to %pIA (retry %d)", pcc_state->tag, req->path->req_id, req->path->name, - ipaddr2str(&req->path->nbkey.endpoint, buff, sizeof(buff)), - req->retry_count); + &req->path->nbkey.endpoint, req->retry_count); PCEP_DEBUG_PATH("%s Canceled computation request path %s: %s", pcc_state->tag, req->path->name, format_path(req->path)); diff --git a/pathd/path_pcep_pcc.h b/pathd/path_pcep_pcc.h index a466d92d50..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; @@ -113,13 +113,18 @@ void pcep_pcc_pathd_event_handler(struct ctrl_state *ctrl_state, struct path *path); void pcep_pcc_timeout_handler(struct ctrl_state *ctrl_state, struct pcc_state *pcc_state, - enum pcep_ctrl_timer_type type, void *param); + enum pcep_ctrl_timeout_type type, void *param); void pcep_pcc_sync_path(struct ctrl_state *ctrl_state, struct pcc_state *pcc_state, struct path *path); void pcep_pcc_sync_done(struct ctrl_state *ctrl_state, struct pcc_state *pcc_state); +/* Send a report explicitly. When doing so the PCC may send multiple reports + * due to expectations from vendors for the first report to be with a DOWN + * status. The parameter is_stable is used for that purpose as a hint wheter + * to expect an update for the report */ void pcep_pcc_send_report(struct ctrl_state *ctrl_state, - struct pcc_state *pcc_state, struct path *path); + struct pcc_state *pcc_state, struct path *path, + bool is_stable); int pcep_pcc_multi_pce_sync_path(struct ctrl_state *ctrl_state, int pcc_id, struct pcc_state **pcc_state_list); int pcep_pcc_multi_pce_remove_pcc(struct ctrl_state *ctrl_state, diff --git a/pathd/pathd.c b/pathd/pathd.c index e2c7c95728..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); @@ -624,8 +625,7 @@ void srte_candidate_set_metric(struct srte_candidate *candidate, char endpoint[46]; ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint)); zlog_debug( - "SR-TE(%s, %u): candidate %s %sconfig metric %s (%u) set to %f " - "(is-bound: %s; is_computed: %s)", + "SR-TE(%s, %u): candidate %s %sconfig metric %s (%u) set to %f (is-bound: %s; is_computed: %s)", endpoint, policy->color, candidate->name, required ? "required " : "", srte_candidate_metric_name(type), type, value, is_bound ? "true" : "false", @@ -659,8 +659,7 @@ void srte_lsp_set_metric(struct srte_lsp *lsp, char endpoint[46]; ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint)); zlog_debug( - "SR-TE(%s, %u): candidate %s %slsp metric %s (%u) set to %f " - "(is-bound: %s; is_computed: %s)", + "SR-TE(%s, %u): candidate %s %slsp metric %s (%u) set to %f (is-bound: %s; is_computed: %s)", endpoint, policy->color, candidate->name, required ? "required " : "", srte_candidate_metric_name(type), type, value, is_bound ? "true" : "false", @@ -981,8 +980,7 @@ void srte_candidate_unset_segment_list(const char *originator, bool force) if (segment_list->protocol_origin == SRTE_ORIGIN_LOCAL) { zlog_warn( - "Cannot unset segment list %s because it " - "was created locally", + "Cannot unset segment list %s because it was created locally", segment_list->name); continue; } 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 520a8c696a..b4501214bf 100644 --- a/pathd/subdir.am +++ b/pathd/subdir.am @@ -11,7 +11,7 @@ vtysh_daemons += pathd # TODO add man page #man8 += $(MANBUILD)/pathd.8 -if HAVE_PATHD_PCEP +if PATHD_PCEP vtysh_scan += $(top_srcdir)/pathd/path_pcep_cli.c module_LTLIBRARIES += pathd/pathd_pcep.la endif @@ -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,10 +62,18 @@ 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 + +if PATHD_PCEP +pathd_pathd_pcep_la_CPPFLAGS = -I./pceplib $(AM_CPPFLAGS) +pathd_pathd_pcep_la_LIBADD = pceplib/libpcep_pcc.la +else +pathd_pathd_pcep_la_CPPFLAGS = $(AM_CPPFLAGS) +pathd_pathd_pcep_la_LIBADD = +endif + + pathd_pathd_pcep_la_CFLAGS = $(WERROR) pathd_pathd_pcep_la_LDFLAGS = -avoid-version -module -shared -export-dynamic -pathd_pathd_pcep_la_LIBADD = @PATHD_PCEP_LIBS@ 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 new file mode 100644 index 0000000000..5861f25a41 --- /dev/null +++ b/pceplib/.gitignore @@ -0,0 +1,14 @@ +pcep_pcc +test/pcep_msg_tests +test/pcep_pcc_api_tests +test/pcep_session_logic_tests +test/pcep_socket_comm_tests +test/pcep_timers_tests +test/pcep_utils_tests +test/valgrind.pcep_msg_tests.log +test/valgrind.pcep_pcc_api_tests.log +test/valgrind.pcep_session_logic_tests.log +test/valgrind.pcep_socket_comm_tests.log +test/valgrind.pcep_timers_tests.log +test/valgrind.pcep_utils_tests.log +../test-driver diff --git a/pceplib/pcep.h b/pceplib/pcep.h new file mode 100644 index 0000000000..278ab9d5dc --- /dev/null +++ b/pceplib/pcep.h @@ -0,0 +1,48 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Javier Garcia <javier.garcia@voltanet.io> + * + */ + + +#ifndef PCEP_H_ +#define PCEP_H_ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#if defined(linux) || defined(GNU_LINUX) +//#include <netinet/in.h> +#define ipv6_u __in6_u +#else +// bsd family +#define TCP_MD5SIG_MAXKEYLEN 80 +//#include <netinet/in.h> +#define ipv6_u __u6_addr +#ifdef __FreeBSD__ +#include <sys/endian.h> +#else +#include <endian.h> +#endif /* __FreeBSD__ */ +#endif + +#include <sys/socket.h> +#include <netinet/in.h> +#include <pthread.h> +#endif diff --git a/pceplib/pcep_msg_encoding.h b/pceplib/pcep_msg_encoding.h new file mode 100644 index 0000000000..d835b87f94 --- /dev/null +++ b/pceplib/pcep_msg_encoding.h @@ -0,0 +1,140 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Brady Johnson <brady@voltanet.io> + * + */ + + +/* + * Definitions for encoding and decoding PCEP messages, objects, and TLVs. + */ + +#ifndef PCEP_ENCODING_H +#define PCEP_ENCODING_H + +#include <stdbool.h> + +#include "pcep_msg_messages.h" +#include "pcep_msg_objects.h" +#include "pcep_msg_tlvs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct pcep_versioning { + bool draft_ietf_pce_segment_routing_07; /* If false, use draft16 */ + /* As more draft versions are incorporated, add appropriate attributes + */ +}; + +#define MESSAGE_HEADER_LENGTH 4 +#define PCEP_MESSAGE_LENGTH 65535 +#define OBJECT_HEADER_LENGTH 4 +#define OBJECT_RO_SUBOBJ_HEADER_LENGTH 2 +#define TLV_HEADER_LENGTH 4 +#define LENGTH_1WORD sizeof(uint32_t) +#define LENGTH_2WORDS sizeof(uint32_t) * 2 +#define LENGTH_3WORDS sizeof(uint32_t) * 3 +#define LENGTH_4WORDS sizeof(uint32_t) * 4 +#define LENGTH_5WORDS sizeof(uint32_t) * 5 +#define LENGTH_6WORDS sizeof(uint32_t) * 6 +#define LENGTH_7WORDS sizeof(uint32_t) * 7 +#define LENGTH_8WORDS sizeof(uint32_t) * 8 +#define LENGTH_9WORDS sizeof(uint32_t) * 9 +#define LENGTH_10WORDS sizeof(uint32_t) * 10 +#define LENGTH_11WORDS sizeof(uint32_t) * 11 +#define LENGTH_12WORDS sizeof(uint32_t) * 12 +#define LENGTH_13WORDS sizeof(uint32_t) * 13 + +/* When iterating sub-objects or TLVs, limit to 10 in case corrupt data is + * received */ +#define MAX_ITERATIONS 10 + +struct pcep_versioning *create_default_pcep_versioning(void); +void destroy_pcep_versioning(struct pcep_versioning *versioning); + +/* + * Message encoding / decoding functions + */ + +/* Called before sending messages to encode the message to a byte buffer in + * Network byte order. This function will also encode all the objects and their + * TLVs in the message. The result will be stored in the encoded_message field + * in the pcep_message. Implemented in pcep-messages-encoding.c */ +void pcep_encode_message(struct pcep_message *message, + struct pcep_versioning *versioning); + +/* Decode the message header and return the message length. + * Returns < 0 for invalid message headers. */ +int32_t pcep_decode_validate_msg_header(const uint8_t *msg_buf); + +/* Decode the entire message */ +struct pcep_message *pcep_decode_message(const uint8_t *message_buffer); + + +/* + * Object encoding / decoding functions + */ + +/* Implemented in pcep-objects-encoding.c + * Encode the object in struct pcep_object_header* into the uint8_t *buf, + * and return the encoded object_length. */ +uint16_t pcep_encode_object(struct pcep_object_header *object_hdr, + struct pcep_versioning *versioning, uint8_t *buf); + +/* Implemented in pcep-objects-encoding.c + * Decode the object, including the TLVs (if any) and return the object. + * Returns object on success, NULL otherwise. */ +struct pcep_object_header *pcep_decode_object(const uint8_t *msg_buf); + +/* Internal util functions implemented in pcep-objects-encoding.c */ +void encode_ipv6(struct in6_addr *src_ipv6, uint32_t *dst); +void decode_ipv6(const uint32_t *src, struct in6_addr *dst_ipv6); +uint16_t normalize_pcep_tlv_length(uint16_t length); +bool pcep_object_has_tlvs(struct pcep_object_header *object_hdr); +uint16_t pcep_object_get_length_by_hdr(struct pcep_object_header *object_hdr); +uint16_t pcep_object_get_length(enum pcep_object_classes object_class, + enum pcep_object_types object_type); + + +/* + * TLV encoding / decoding functions + */ + +/* Implemented in pcep-tlv-encoding.c + * Encode the tlv in struct pcep_tlv_header* into the uint8_t *buf, + * and return the encoded tlv_length. */ +uint16_t pcep_encode_tlv(struct pcep_object_tlv_header *tlv_hdr, + struct pcep_versioning *versioning, uint8_t *buf); + +/* Decode the TLV in tlv_buf and return a pointer to the object */ +struct pcep_object_tlv_header *pcep_decode_tlv(const uint8_t *tlv_buf); + + +/* + * utils mainly for testing purposes + */ +bool validate_message_objects(struct pcep_message *msg); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/pceplib/pcep_msg_messages.c b/pceplib/pcep_msg_messages.c new file mode 100644 index 0000000000..ec2a237f30 --- /dev/null +++ b/pceplib/pcep_msg_messages.c @@ -0,0 +1,308 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Brady Johnson <brady@voltanet.io> + * + */ + + +/* + * This is the implementation of a High Level PCEP message API. + */ + +#include <string.h> +#include <arpa/inet.h> +#include <stdarg.h> +#include <unistd.h> + +#include "pcep_msg_encoding.h" +#include "pcep_msg_messages.h" +#include "pcep_msg_objects.h" +#include "pcep_utils_double_linked_list.h" +#include "pcep_utils_logging.h" +#include "pcep_utils_memory.h" + +static struct pcep_message * +pcep_msg_create_common_with_obj_list(enum pcep_message_types msg_type, + double_linked_list *obj_list) +{ + struct pcep_message *message = + pceplib_malloc(PCEPLIB_MESSAGES, sizeof(struct pcep_message)); + memset(message, 0, sizeof(struct pcep_message)); + message->msg_header = pceplib_malloc( + PCEPLIB_MESSAGES, sizeof(struct pcep_message_header)); + memset(message->msg_header, 0, sizeof(struct pcep_message_header)); + message->msg_header->type = msg_type; + message->msg_header->pcep_version = PCEP_MESSAGE_HEADER_VERSION; + message->obj_list = ((obj_list == NULL) ? dll_initialize() : obj_list); + + return message; +} + +static struct pcep_message * +pcep_msg_create_common(enum pcep_message_types msg_type) +{ + return pcep_msg_create_common_with_obj_list(msg_type, NULL); +} + +struct pcep_message *pcep_msg_create_open(uint8_t keepalive, uint8_t deadtimer, + uint8_t sid) +{ + struct pcep_message *message = pcep_msg_create_common(PCEP_TYPE_OPEN); + dll_append(message->obj_list, + pcep_obj_create_open(keepalive, deadtimer, sid, NULL)); + + return message; +} + +struct pcep_message * +pcep_msg_create_open_with_tlvs(uint8_t keepalive, uint8_t deadtimer, + uint8_t sid, double_linked_list *tlv_list) +{ + struct pcep_message *message = pcep_msg_create_common(PCEP_TYPE_OPEN); + dll_append(message->obj_list, + pcep_obj_create_open(keepalive, deadtimer, sid, tlv_list)); + + return message; +} + + +struct pcep_message * +pcep_msg_create_request(struct pcep_object_rp *rp, + struct pcep_object_endpoints_ipv4 *endpoints, + double_linked_list *object_list) +{ + if ((rp == NULL) || (endpoints == NULL)) { + return NULL; + } + + struct pcep_message *message = pcep_msg_create_common_with_obj_list( + PCEP_TYPE_PCREQ, object_list); + dll_prepend(message->obj_list, endpoints); + dll_prepend(message->obj_list, rp); + + return message; +} + +struct pcep_message * +pcep_msg_create_request_ipv6(struct pcep_object_rp *rp, + struct pcep_object_endpoints_ipv6 *endpoints, + double_linked_list *object_list) +{ + if ((rp == NULL) || (endpoints == NULL)) { + return NULL; + } + + struct pcep_message *message = pcep_msg_create_common_with_obj_list( + PCEP_TYPE_PCREQ, object_list); + dll_prepend(message->obj_list, endpoints); + dll_prepend(message->obj_list, rp); + + return message; +} + +struct pcep_message *pcep_msg_create_reply(struct pcep_object_rp *rp, + double_linked_list *object_list) +{ + struct pcep_message *message = pcep_msg_create_common_with_obj_list( + PCEP_TYPE_PCREP, object_list); + + if (rp != NULL) { + dll_prepend(message->obj_list, rp); + } + + return message; +} + +struct pcep_message *pcep_msg_create_close(uint8_t reason) +{ + struct pcep_message *message = pcep_msg_create_common(PCEP_TYPE_CLOSE); + dll_append(message->obj_list, pcep_obj_create_close(reason)); + + return message; +} + +struct pcep_message *pcep_msg_create_error(uint8_t error_type, + uint8_t error_value) +{ + struct pcep_message *message = pcep_msg_create_common(PCEP_TYPE_ERROR); + dll_append(message->obj_list, + pcep_obj_create_error(error_type, error_value)); + + return message; +} + +struct pcep_message * +pcep_msg_create_error_with_objects(uint8_t error_type, uint8_t error_value, + double_linked_list *object_list) +{ + struct pcep_message *message = pcep_msg_create_common_with_obj_list( + PCEP_TYPE_ERROR, object_list); + dll_prepend(message->obj_list, + pcep_obj_create_error(error_type, error_value)); + + return message; +} + +struct pcep_message *pcep_msg_create_keepalive() +{ + return (pcep_msg_create_common(PCEP_TYPE_KEEPALIVE)); +} + +struct pcep_message * +pcep_msg_create_report(double_linked_list *state_report_object_list) +{ + return (state_report_object_list == NULL + ? NULL + : pcep_msg_create_common_with_obj_list( + PCEP_TYPE_REPORT, state_report_object_list)); +} + +struct pcep_message * +pcep_msg_create_update(double_linked_list *update_request_object_list) +{ + if (update_request_object_list == NULL) { + pcep_log( + LOG_INFO, + "%s: pcep_msg_create_update NULL update_request_object_list", + __func__); + return NULL; + } + + /* There must be at least 3 objects: + * These 3 are mandatory: SRP, LSP, and ERO. The ERO may be empty */ + if (update_request_object_list->num_entries < 3) { + pcep_log( + LOG_INFO, + "%s: pcep_msg_create_update there must be at least 3 update objects", + __func__); + return NULL; + } + + double_linked_list_node *node = update_request_object_list->head; + struct pcep_object_header *obj_hdr = + (struct pcep_object_header *)node->data; + + /* Check for the mandatory first SRP object */ + if (obj_hdr->object_class != PCEP_OBJ_CLASS_SRP) { + /* If the SRP object is missing, the receiving PCC MUST send a + * PCErr message with Error-type=6 (Mandatory Object missing) + * and Error-value=10 (SRP object missing). */ + pcep_log( + LOG_INFO, + "%s: pcep_msg_create_update missing mandatory first SRP object", + __func__); + return NULL; + } + + /* Check for the mandatory 2nd LSP object */ + node = node->next_node; + obj_hdr = (struct pcep_object_header *)node->data; + if (obj_hdr->object_class != PCEP_OBJ_CLASS_LSP) { + /* If the LSP object is missing, the receiving PCC MUST send a + * PCErr message with Error-type=6 (Mandatory Object missing) + * and Error-value=8 (LSP object missing). */ + pcep_log( + LOG_INFO, + "%s: pcep_msg_create_update missing mandatory second LSP object", + __func__); + return NULL; + } + + /* Check for the mandatory 3rd ERO object */ + node = node->next_node; + obj_hdr = (struct pcep_object_header *)node->data; + if (obj_hdr->object_class != PCEP_OBJ_CLASS_ERO) { + /* If the ERO object is missing, the receiving PCC MUST send a + * PCErr message with Error-type=6 (Mandatory Object missing) + * and Error-value=9 (ERO object missing). */ + pcep_log( + LOG_INFO, + "%s: pcep_msg_create_update missing mandatory third ERO object", + __func__); + return NULL; + } + + return (pcep_msg_create_common_with_obj_list( + PCEP_TYPE_UPDATE, update_request_object_list)); +} + +struct pcep_message * +pcep_msg_create_initiate(double_linked_list *lsp_object_list) +{ + if (lsp_object_list == NULL) { + pcep_log( + LOG_INFO, + "%s: pcep_msg_create_initiate NULL update_request_object_list", + __func__); + return NULL; + } + + /* There must be at least 2 objects: SRP and LSP. */ + if (lsp_object_list->num_entries < 2) { + pcep_log( + LOG_INFO, + "%s: pcep_msg_create_initiate there must be at least 2 objects", + __func__); + return NULL; + } + + double_linked_list_node *node = lsp_object_list->head; + struct pcep_object_header *obj_hdr = + (struct pcep_object_header *)node->data; + + /* Check for the mandatory first SRP object */ + if (obj_hdr->object_class != PCEP_OBJ_CLASS_SRP) { + pcep_log( + LOG_INFO, + "%s: pcep_msg_create_initiate missing mandatory first SRP object", + __func__); + return NULL; + } + + /* Check for the mandatory 2nd LSP object */ + node = node->next_node; + obj_hdr = (struct pcep_object_header *)node->data; + if (obj_hdr->object_class != PCEP_OBJ_CLASS_LSP) { + pcep_log( + LOG_INFO, + "%s: pcep_msg_create_initiate missing mandatory second LSP object", + __func__); + return NULL; + } + + return (pcep_msg_create_common_with_obj_list(PCEP_TYPE_INITIATE, + lsp_object_list)); +} + +struct pcep_message *pcep_msg_create_notify(struct pcep_object_notify *notify, + double_linked_list *object_list) +{ + if (notify == NULL) { + pcep_log(LOG_INFO, + "%s: pcep_msg_create_notify NULL notify object", + __func__); + return NULL; + } + + struct pcep_message *message = pcep_msg_create_common_with_obj_list( + PCEP_TYPE_PCNOTF, object_list); + dll_prepend(message->obj_list, notify); + + return message; +} diff --git a/pceplib/pcep_msg_messages.h b/pceplib/pcep_msg_messages.h new file mode 100644 index 0000000000..8542ea10e7 --- /dev/null +++ b/pceplib/pcep_msg_messages.h @@ -0,0 +1,132 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Brady Johnson <brady@voltanet.io> + */ + + +/* + * This is a High Level PCEP message API. + */ + +#ifndef PCEP_MESSAGES_H +#define PCEP_MESSAGES_H + +#include <stdint.h> +#include <netinet/in.h> /* struct in_addr */ + +#include "pcep_utils_double_linked_list.h" +#include "pcep_msg_objects.h" + +#ifdef __cplusplus +extern "C" { +#endif + +enum pcep_message_types { + PCEP_TYPE_OPEN = 1, + PCEP_TYPE_KEEPALIVE = 2, + PCEP_TYPE_PCREQ = 3, + PCEP_TYPE_PCREP = 4, + PCEP_TYPE_PCNOTF = 5, + PCEP_TYPE_ERROR = 6, + PCEP_TYPE_CLOSE = 7, + PCEP_TYPE_REPORT = 10, + PCEP_TYPE_UPDATE = 11, + PCEP_TYPE_INITIATE = 12, + PCEP_TYPE_START_TLS = 13, + PCEP_TYPE_MAX, +}; + +#define PCEP_MESSAGE_HEADER_VERSION 1 + +struct pcep_message_header { + uint8_t pcep_version; /* Current version is 1. */ + enum pcep_message_types + type; /* Defines message type: + OPEN/KEEPALIVE/PCREQ/PCREP/PCNOTF/ERROR/CLOSE */ +}; + +/* The obj_list is a double_linked_list of struct pcep_object_header pointers. + */ +struct pcep_message { + struct pcep_message_header *msg_header; + double_linked_list *obj_list; + uint8_t *encoded_message; + uint16_t encoded_message_length; +}; + + +/* + * Regarding memory usage: + * When creating messages, any objects and tlvs passed into these APIs will be + * free'd when the pcep_message is free'd. That includes the + * double_linked_list's. So, just create the objects and TLVs, put them in their + * double_linked_list's, and everything will be managed internally. The message + * will be deleted by pcep_msg_free_message() or pcep_msg_free_message_list() + * which, in turn will call one of: pcep_obj_free_object() and + * pcep_obj_free_tlv(). For received messages, call pcep_msg_free_message() to + * free them. + */ + +struct pcep_message *pcep_msg_create_open(uint8_t keepalive, uint8_t deadtimer, + uint8_t sid); +struct pcep_message * +pcep_msg_create_open_with_tlvs(uint8_t keepalive, uint8_t deadtimer, + uint8_t sid, double_linked_list *tlv_list); +struct pcep_message * +pcep_msg_create_request(struct pcep_object_rp *rp, + struct pcep_object_endpoints_ipv4 *endpoints, + double_linked_list *object_list); +struct pcep_message * +pcep_msg_create_request_ipv6(struct pcep_object_rp *rp, + struct pcep_object_endpoints_ipv6 *endpoints, + double_linked_list *object_list); +struct pcep_message *pcep_msg_create_reply(struct pcep_object_rp *rp, + double_linked_list *object_list); +struct pcep_message *pcep_msg_create_close(uint8_t reason); +struct pcep_message *pcep_msg_create_error(uint8_t error_type, + uint8_t error_value); +struct pcep_message *pcep_msg_create_error_with_objects( + uint8_t error_type, uint8_t error_value, + double_linked_list *object_list); /* include the offending objects */ +struct pcep_message *pcep_msg_create_keepalive(void); +struct pcep_message *pcep_msg_create_notify(struct pcep_object_notify *notify, + double_linked_list *object_list); + +/* Message defined in RFC 8231 section 6.1. Expecting double_linked_list of + * struct pcep_object_header* objects of type SRP, LSP, or path (ERO, Bandwidth, + * metrics, and RRO objects). */ +struct pcep_message * +pcep_msg_create_report(double_linked_list *state_report_object_list); +/* Message defined in RFC 8231. Expecting double_linked_list of at least 3 + * struct pcep_object_header* objects of type SRP, LSP, and path (ERO and + * intended-attribute-list). The ERO must be present, but may be empty if + * the PCE cannot find a valid path for a delegated LSP. */ +struct pcep_message * +pcep_msg_create_update(double_linked_list *update_request_object_list); +/* Message defined in RFC 8281. Expecting double_linked_list of at least 2 + * struct pcep_object_header* objects of type SRP and LSP for LSP deletion, and + * may also contain Endpoints, ERO and an attribute list for LSP creation. */ +struct pcep_message * +pcep_msg_create_initiate(double_linked_list *lsp_object_list); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/pceplib/pcep_msg_messages_encoding.c b/pceplib/pcep_msg_messages_encoding.c new file mode 100644 index 0000000000..7c8e1b3a1f --- /dev/null +++ b/pceplib/pcep_msg_messages_encoding.c @@ -0,0 +1,359 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Brady Johnson <brady@voltanet.io> + * + */ + + +/* + * Encoding and decoding for PCEP messages. + */ + +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "pcep_msg_encoding.h" +#include "pcep_msg_messages.h" +#include "pcep_msg_objects.h" +#include "pcep_msg_tools.h" +#include "pcep_utils_logging.h" +#include "pcep_utils_memory.h" + +#define ANY_OBJECT 0 +#define NO_OBJECT -1 +#define NUM_CHECKED_OBJECTS 4 +/* It wont compile with this definition: + static const int + MANDATORY_MESSAGE_OBJECT_CLASSES[PCEP_TYPE_INITIATE+1][NUM_CHECKED_OBJECTS] + */ +static const enum pcep_object_classes MANDATORY_MESSAGE_OBJECT_CLASSES[13][4] = + { + {NO_OBJECT, NO_OBJECT, NO_OBJECT, + NO_OBJECT}, /* unsupported message ID = 0 */ + {PCEP_OBJ_CLASS_OPEN, NO_OBJECT, NO_OBJECT, + NO_OBJECT}, /* PCEP_TYPE_OPEN = 1 */ + {NO_OBJECT, NO_OBJECT, NO_OBJECT, + NO_OBJECT}, /* PCEP_TYPE_KEEPALIVE = 2 */ + {PCEP_OBJ_CLASS_RP, PCEP_OBJ_CLASS_ENDPOINTS, ANY_OBJECT, + ANY_OBJECT}, /* PCEP_TYPE_PCREQ = 3 */ + {PCEP_OBJ_CLASS_RP, ANY_OBJECT, ANY_OBJECT, + ANY_OBJECT}, /* PCEP_TYPE_PCREP = 4 */ + {PCEP_OBJ_CLASS_NOTF, ANY_OBJECT, ANY_OBJECT, + ANY_OBJECT}, /* PCEP_TYPE_PCNOTF = 5 */ + {PCEP_OBJ_CLASS_ERROR, ANY_OBJECT, ANY_OBJECT, + ANY_OBJECT}, /* PCEP_TYPE_ERROR = 6 */ + {PCEP_OBJ_CLASS_CLOSE, NO_OBJECT, NO_OBJECT, + NO_OBJECT}, /* PCEP_TYPE_CLOSE = 7 */ + {NO_OBJECT, NO_OBJECT, NO_OBJECT, + NO_OBJECT}, /* unsupported message ID = 8 */ + {NO_OBJECT, NO_OBJECT, NO_OBJECT, + NO_OBJECT}, /* unsupported message ID = 9 */ + {PCEP_OBJ_CLASS_SRP, PCEP_OBJ_CLASS_LSP, ANY_OBJECT, + ANY_OBJECT}, /* PCEP_TYPE_REPORT = 10 */ + {PCEP_OBJ_CLASS_SRP, PCEP_OBJ_CLASS_LSP, ANY_OBJECT, + ANY_OBJECT}, /* PCEP_TYPE_UPDATE = 11 */ + {PCEP_OBJ_CLASS_SRP, PCEP_OBJ_CLASS_LSP, ANY_OBJECT, + ANY_OBJECT}, /* PCEP_TYPE_INITIATE = 12 */ +}; + +/* PCEP Message Common Header, According to RFC 5440 + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Ver | Flags | Message-Type | Message-Length | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * Ver (Version - 3 bits): PCEP version number. Current version is version 1. + * + * Flags (5 bits): No flags are currently defined. Unassigned bits are + * considered as reserved. They MUST be set to zero on transmission + * and MUST be ignored on receipt. + */ +void pcep_encode_message(struct pcep_message *message, + struct pcep_versioning *versioning) +{ + if (message == NULL) { + return; + } + + if (message->msg_header == NULL) { + return; + } + + /* Internal buffer used for the entire message. Later, once the entire + * length is known, memory will be allocated and this buffer will be + * copied. */ + uint8_t message_buffer[PCEP_MESSAGE_LENGTH] = {0}; + + /* Write the message header. The message header length will be + * written when the entire length is known. */ + uint32_t message_length = MESSAGE_HEADER_LENGTH; + uint16_t net_order_length = 0; + message_buffer[0] = (message->msg_header->pcep_version << 5) & 0xf0; + message_buffer[1] = message->msg_header->type; + + if (message->obj_list == NULL) { + net_order_length = htons(message_length); + memcpy(message_buffer + 2, &net_order_length, + sizeof(net_order_length)); + message->encoded_message = + pceplib_malloc(PCEPLIB_MESSAGES, message_length); + memcpy(message->encoded_message, message_buffer, + message_length); + message->encoded_message_length = message_length; + + return; + } + + /* Encode each of the objects */ + double_linked_list_node *node = message->obj_list->head; + for (; node != NULL; node = node->next_node) { + message_length += + pcep_encode_object(node->data, versioning, + message_buffer + message_length); + if (message_length >= PCEP_MESSAGE_LENGTH) { + message->encoded_message = NULL; + message->encoded_message_length = 0; + return; + } + } + + net_order_length = htons(message_length); + memcpy(message_buffer + 2, &net_order_length, sizeof(net_order_length)); + message->encoded_message = + pceplib_malloc(PCEPLIB_MESSAGES, message_length); + memcpy(message->encoded_message, message_buffer, message_length); + message->encoded_message_length = message_length; +} + +/* + * Decoding functions + */ + +/* Expecting Host byte ordered header */ +static bool validate_msg_header(uint8_t msg_version, uint8_t msg_flags, + uint8_t msg_type, uint16_t msg_length) +{ + /* Invalid message if the length is less than the header + * size or if its not a multiple of 4 */ + if (msg_length < MESSAGE_HEADER_LENGTH || (msg_length % 4) != 0) { + pcep_log(LOG_INFO, + "%s: Invalid PCEP message header length [%d]", + __func__, msg_length); + return false; + } + + if (msg_version != PCEP_MESSAGE_HEADER_VERSION) { + pcep_log( + LOG_INFO, + "%s: Invalid PCEP message header version [0x%x] expected version [0x%x]", + __func__, msg_version, PCEP_MESSAGE_HEADER_VERSION); + return false; + } + + if (msg_flags != 0) { + pcep_log(LOG_INFO, + "%s: Invalid PCEP message header flags [0x%x]", + __func__, msg_flags); + return false; + } + + switch (msg_type) { + /* Supported message types */ + case PCEP_TYPE_OPEN: + case PCEP_TYPE_KEEPALIVE: + case PCEP_TYPE_PCREQ: + case PCEP_TYPE_PCREP: + case PCEP_TYPE_PCNOTF: + case PCEP_TYPE_ERROR: + case PCEP_TYPE_CLOSE: + case PCEP_TYPE_REPORT: + case PCEP_TYPE_UPDATE: + case PCEP_TYPE_INITIATE: + break; + default: + pcep_log(LOG_INFO, "%s: Invalid PCEP message header type [%d]", + __func__, msg_type); + return false; + break; + } + + return true; +} + +/* Internal util function */ +static uint16_t pcep_decode_msg_header(const uint8_t *msg_buf, + uint8_t *msg_version, uint8_t *msg_flags, + uint8_t *msg_type) +{ + // Check RFC 5440 for version and flags position. + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + //| Ver | Flags | Message-Type | Message-Length | + //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + *msg_version = (msg_buf[0] >> 5) & 0x07; + *msg_flags = (msg_buf[0] & 0x1f); + *msg_type = msg_buf[1]; + uint16_t host_order_length; + memcpy(&host_order_length, msg_buf + 2, sizeof(host_order_length)); + return ntohs(host_order_length); +} + +/* Decode the message header and return the message length */ +int32_t pcep_decode_validate_msg_header(const uint8_t *msg_buf) +{ + uint8_t msg_version; + uint8_t msg_flags; + uint8_t msg_type; + uint32_t msg_length; + + msg_length = pcep_decode_msg_header(msg_buf, &msg_version, &msg_flags, + &msg_type); + + return ((validate_msg_header(msg_version, msg_flags, msg_type, + msg_length) + == false) + ? -1 + : (int32_t)msg_length); +} + +bool validate_message_objects(struct pcep_message *msg) +{ + if (msg->msg_header->type >= PCEP_TYPE_START_TLS) { + pcep_log( + LOG_INFO, + "%s: Rejecting received message: Unknown message type [%d]", + __func__, msg->msg_header->type); + return false; + } + + const enum pcep_object_classes *object_classes = + MANDATORY_MESSAGE_OBJECT_CLASSES[msg->msg_header->type]; + double_linked_list_node *node; + int index; + for (node = (msg->obj_list == NULL ? NULL : msg->obj_list->head), + index = 0; + index < NUM_CHECKED_OBJECTS; + index++, (node = (node == NULL ? NULL : node->next_node))) { + struct pcep_object_header *obj = + ((node == NULL) + ? NULL + : (struct pcep_object_header *)node->data); + + if ((int)object_classes[index] == NO_OBJECT) { + if (node != NULL) { + pcep_log( + LOG_INFO, + "%s: Rejecting received message: Unexpected object [%d] present", + __func__, obj->object_class); + return false; + } + } else if (object_classes[index] != ANY_OBJECT) { + if (node == NULL) { + pcep_log( + LOG_INFO, + "%s: Rejecting received message: Expecting object in position [%d], but none received", + __func__, index); + return false; + } else if (object_classes[index] != obj->object_class) { + pcep_log( + LOG_INFO, + "%s: Rejecting received message: Unexpected Object Class received [%d]", + __func__, object_classes[index]); + return false; + } + } + } + + return true; +} + +struct pcep_message *pcep_decode_message(const uint8_t *msg_buf) +{ + uint8_t msg_version; + uint8_t msg_flags; + uint8_t msg_type; + uint16_t msg_length; + + 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)); + + msg->msg_header = pceplib_malloc(PCEPLIB_MESSAGES, + sizeof(struct pcep_message_header)); + msg->msg_header->pcep_version = msg_version; + msg->msg_header->type = msg_type; + + msg->obj_list = dll_initialize(); + msg->encoded_message = pceplib_malloc(PCEPLIB_MESSAGES, msg_length); + memcpy(msg->encoded_message, msg_buf, msg_length); + msg->encoded_message_length = msg_length; + + uint16_t bytes_read = MESSAGE_HEADER_LENGTH; + while ((msg_length - bytes_read) >= OBJECT_HEADER_LENGTH) { + struct pcep_object_header *obj_hdr = + pcep_decode_object(msg_buf + bytes_read); + + if (obj_hdr == NULL) { + pcep_log(LOG_INFO, "%s: Discarding invalid message", + __func__); + pcep_msg_free_message(msg); + + return NULL; + } + + dll_append(msg->obj_list, obj_hdr); + bytes_read += obj_hdr->encoded_object_length; + } + + if (validate_message_objects(msg) == false) { + pcep_log(LOG_INFO, "%s: Discarding invalid message", __func__); + pcep_msg_free_message(msg); + + return NULL; + } + + return msg; +} + +struct pcep_versioning *create_default_pcep_versioning() +{ + struct pcep_versioning *versioning = + pceplib_malloc(PCEPLIB_INFRA, sizeof(struct pcep_versioning)); + memset(versioning, 0, sizeof(struct pcep_versioning)); + + return versioning; +} + +void destroy_pcep_versioning(struct pcep_versioning *versioning) +{ + pceplib_free(PCEPLIB_INFRA, versioning); +} diff --git a/pceplib/pcep_msg_object_error_types.c b/pceplib/pcep_msg_object_error_types.c new file mode 100644 index 0000000000..a4fd8151cd --- /dev/null +++ b/pceplib/pcep_msg_object_error_types.c @@ -0,0 +1,389 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Brady Johnson <brady@voltanet.io> + */ + +#include <stdlib.h> + +#include "pcep_msg_object_error_types.h" +#include "pcep_utils_logging.h" + +/* All of these values were copied from: + * https://www.iana.org/assignments/pcep/pcep.xhtml#pcep-error-object + * Which was last updated 2020-06-02 */ + +static const char *error_type_strings[] = { + "Reserved", + "PCEP session establishment failure", + "Capability not supported", + "Unknown Object", + "Not supported object", + "Policy violation", + "Mandatory Object missing", + "Synchronized path computation request missing", + "Unknown request reference", + "Attempt to establish a second PCEP session", + + "Reception of an invalid object", /* 10 */ + "Unrecognized EXRS subobject", + "Diffserv-aware TE error", + "BRPC procedure completion failure", + "Unassigned 14", + "Global Concurrent Optimization Error", + "P2MP Capability Error", + "P2MP END-POINTS Error", + "P2MP Fragmentation Error", + "Invalid Operation", + + "LSP State Synchronization Error", /* 20 */ + "Invalid traffic engineering path setup type", + "Unassigned 22", + "Bad parameter value", + "LSP instantiation error", + "PCEP StartTLS failure", + "Association Error", + "WSON RWA Error", + "H-PCE Error", + "Path computation failure", + "Unassigned 30"}; + +static const char *error_value_strings[MAX_ERROR_TYPE][MAX_ERROR_VALUE] = { + + /* 0 Reserved */ + {"Unassigned"}, + + /* 1 PCEP session establishment failure */ + { + "Unassigned", + "reception of an invalid Open message or a non Open message.", + "no Open message received before the expiration of the OpenWait timer", + "unacceptable and non negotiable session characteristics", + "unacceptable but negotiable session characteristics", + "reception of a second Open message with still unacceptable session characteristics", + "reception of a PCErr message proposing unacceptable session characteristics", + "No Keepalive or PCErr message received before the expiration of the KeepWait timer", + "PCEP version not supported", + }, + + /* 2 Capability not supported */ + {"Unassigned"}, + + /* 3 Unknown Object */ + { + "Unassigned", + "Unrecognized object class", + "Unrecognized object Type", + }, + + /* 4 Not supported object */ + { + "Unassigned", + "Not supported object class", + "Not supported object Type", + "Unassigned", + "Unsupported parameter", + "Unsupported network performance constraint", + "Bandwidth Object type 3 or 4 not supported", + "Unsupported endpoint type in END-POINTS Generalized Endpoint object type", + "Unsupported TLV present in END-POINTS Generalized Endpoint object type", + "Unsupported granularity in the RP object flags", + }, + + /* 5 Policy violation */ + { + "Unassigned", + "C bit of the METRIC object set (request rejected)", + "O bit of the RP object cleared (request rejected)", + "objective function not allowed (request rejected)", + "OF bit of the RP object set (request rejected)", + "Global concurrent optimization not allowed", + "Monitoring message supported but rejected due to policy violation", + "P2MP Path computation is not allowed", + "Not allowed network performance constraint", + }, + + /* 6 Mandatory Object missing */ + { + "Unassigned", + "RP object missing", + "RRO missing for a reoptimization request (R bit of the RP object set)", + "END-POINTS object missing", + "MONITORING object missing", + "Unassigned", + "Unassigned", + "Unassigned", + "LSP object missing", + "ERO object missing", + "SRP object missing", + "LSP-IDENTIFIERS TLV missing", + "LSP-DB-VERSION TLV missing", + "S2LS object missing", + "P2MP-LSP-IDENTIFIERS TLV missing", + "DISJOINTNESS-CONFIGURATION TLV missing", + }, + + /* 7 Synchronized path computation request missing */ + {"Unassigned"}, + + /* 8 Unknown request reference */ + {"Unassigned"}, + + /* 9 Attempt to establish a second PCEP session */ + {"Unassigned"}, + + /* 10 Reception of an invalid object */ + { + "Unassigned", + "reception of an object with P flag not set although the P-flag must be set according to this specification.", + "Bad label value", + "Unsupported number of SR-ERO subobjects", + "Bad label format", + "ERO mixes SR-ERO subobjects with other subobject types", + "Both SID and NAI are absent in the SR-ERO subobject", + "Both SID and NAI are absent in the SR-RRO subobject", + "SYMBOLIC-PATH-NAME TLV missing", + "MSD exceeds the default for the PCEP session", + "RRO mixes SR-RRO subobjects with other subobject types", + "Malformed object", + "Missing PCE-SR-CAPABILITY sub-TLV", + "Unsupported NAI Type in the SR-ERO/SR-RRO subobject", + "Unknown SID", + "NAI cannot be resolved to a SID", + "Could not find SRGB", + "SID index exceeds SRGB size", + "Could not find SRLB", + "SID index exceeds SRLB size", + "Inconsistent SIDs in SR-ERO / SR-RRO subobjects", + "MSD must be nonzero", + "Mismatch of O field in S2LS and LSP object", + "Incompatible OF codes in H-PCE", + "Bad Bandwidth Object type 3 (Generalized bandwidth) or 4 (Generalized bandwidth of existing TE-LSP for which a reoptimization is requested)", + "Unsupported LSP Protection Flags in PROTECTION-ATTRIBUTE TLV", + "Unsupported Secondary LSP Protection Flags in PROTECTION-ATTRIBUTE TLV", + "Unsupported Link Protection Type in PROTECTION-ATTRIBUTE TLV", + "LABEL-SET TLV present with 0 bit set but without R bit set in RP", + "Wrong LABEL-SET TLV present with 0 and L bit set", + "Wrong LABEL-SET with O bit set and wrong format", + "Missing GMPLS-CAPABILITY TLV", + "Incompatible OF code", + }, + + /* 11 Unrecognized EXRS subobject */ + {"Unassigned"}, + + /* 12 Diffserv-aware TE error */ + { + "Unassigned", + "Unsupported class-type", + "Invalid class-type", + "Class-Type and setup priority do not form a configured TE-class", + }, + + /* 13 BRPC procedure completion failure */ + { + "Unassigned", + "BRPC procedure not supported by one or more PCEs along the domain path", + }, + + /* 14 Unassigned */ + {"Unassigned"}, + + /* 15 Global Concurrent Optimization Error */ + { + "Unassigned", + "Insufficient memory", + "Global concurrent optimization not supported", + }, + + /* 16 P2MP Capability Error */ + { + "Unassigned", + "The PCE cannot satisfy the request due to insufficient memory", + "The PCE is not capable of P2MP computation", + }, + + /* 17 P2MP END-POINTS Error */ + { + "Unassigned", + "The PCE cannot satisfy the request due to no END-POINTS with leaf type 2", + "The PCE cannot satisfy the request due to no END-POINTS with leaf type 3", + "The PCE cannot satisfy the request due to no END-POINTS with leaf type 4", + "The PCE cannot satisfy the request due to inconsistent END-POINTS", + }, + + /* 18 P2MP Fragmentation Error */ + { + "Unassigned", + "Fragmented request failure", + "Fragmented Report failure", + "Fragmented Update failure", + "Fragmented Instantiation failure", + }, + + /* 19 Invalid Operation */ + { + "Unassigned", + "Attempted LSP Update Request for a non-delegated LSP. The PCEP-ERROR object is followed by the LSP object that identifies the LSP.", + "Attempted LSP Update Request if the stateful PCE capability was not advertised.", + "Attempted LSP Update Request for an LSP identified by an unknown PLSP-ID.", + "Unassigned", + "Attempted LSP State Report if active stateful PCE capability was not advertised.", + "PCE-initiated LSP limit reached", + "Delegation for PCE-initiated LSP cannot be revoked", + "Non-zero PLSP-ID in LSP Initiate Request", + "LSP is not PCE initiated", + "PCE-initiated operation-frequency limit reached", + "Attempted LSP State Report for P2MP if stateful PCE capability for P2MP was not advertised", + "Attempted LSP Update Request for P2MP if active stateful PCE capability for P2MP was not advertised", + "Attempted LSP Instantiation Request for P2MP if stateful PCE instantiation capability for P2MP was not advertised", + "Auto-Bandwidth capability was not advertised", + }, + + /* 20 LSP State Synchronization Error */ + { + "Unassigned", + "A PCE indicates to a PCC that it cannot process (an otherwise valid) LSP State Report. The PCEP- ERROR object is followed by the LSP object that identifies the LSP.", + "LSP-DB version mismatch.", + "Attempt to trigger synchronization before PCE trigger.", + "Attempt to trigger a synchronization when the PCE triggered synchronization capability has not been advertised.", + "A PCC indicates to a PCE that it cannot complete the State Synchronization.", + "Received an invalid LSP-DB Version Number.", + "Received an invalid Speaker Entity Identifier.", + }, + + /* 21 Invalid traffic engineering path setup type */ + { + "Unassigned", + "Unsupported path setup type", + "Mismatched path setup type", + }, + + /* 22 Unassigned */ + {"Unassigned"}, + + /* 23 Bad parameter value */ + { + "Unassigned", + "SYMBOLIC-PATH-NAME in use", + "Speaker identity included for an LSP that is not PCE initiated", + }, + + /* 24 LSP instantiation error */ + { + "Unassigned", + "Unacceptable instantiation parameters", + "Internal error", + "Signaling error", + }, + + /* 25 PCEP StartTLS failure */ + { + "Unassigned", + "Reception of StartTLS after any PCEP exchange", + "Reception of any other message apart from StartTLS, Open, or PCErr", + "Failure, connection without TLS is not possible", + "Failure, connection without TLS is possible", + "No StartTLS message (nor PCErr/Open) before StartTLSWait timer expiry", + }, + + /* 26 Association Error */ + { + "Unassigned", + "Association Type is not supported", + "Too many LSPs in the association group", + "Too many association groups", + "Association unknown", + "Operator-configured association information mismatch", + "Association information mismatch", + "Cannot join the association group", + "Association ID not in range", + "Tunnel ID or End points mismatch for Path Protection Association", + "Attempt to add another working/protection LSP for Path Protection Association", + "Protection type is not supported", + }, + + /* 27 WSON RWA Error */ + { + "Unassigned", + "Insufficient Memory", + "RWA computation Not supported", + "Syntactical Encoding error", + }, + + /* 28 H-PCE Error */ + { + "Unassigned", + "H-PCE Capability not advertised", + "Parent PCE Capability cannot be provided", + }, + + /* 29 Path computation failure */ + { + "Unassigned", + "Unacceptable request message", + "Generalized bandwidth value not supported", + "Label Set constraint could not be met", + "Label constraint could not be met", + } + + /* 30-255 Unassigned */ +}; + + +const char *get_error_type_str(enum pcep_error_type error_type) +{ + if (error_type < 0 || error_type >= MAX_ERROR_TYPE) { + pcep_log( + LOG_DEBUG, + "%s: get_error_type_str: error_type [%d] out of range [0..%d]", + __func__, error_type, MAX_ERROR_TYPE); + + return NULL; + } + + return error_type_strings[error_type]; +} + +const char *get_error_value_str(enum pcep_error_type error_type, + enum pcep_error_value error_value) +{ + if (error_type < 0 || error_type >= MAX_ERROR_TYPE) { + pcep_log( + LOG_DEBUG, + "%s: get_error_value_str: error_type [%d] out of range [0..%d]", + __func__, error_type, MAX_ERROR_TYPE); + + return NULL; + } + + if (error_value < 0 || error_value >= MAX_ERROR_VALUE) { + pcep_log( + LOG_DEBUG, + "%s: get_error_value_str: error_value [%d] out of range [0..%d]", + __func__, error_value, MAX_ERROR_VALUE); + + return NULL; + } + + if (error_value_strings[error_type][error_value] == NULL) { + return "Unassigned"; + } + + return error_value_strings[error_type][error_value]; +} diff --git a/pceplib/pcep_msg_object_error_types.h b/pceplib/pcep_msg_object_error_types.h new file mode 100644 index 0000000000..d62cc7e277 --- /dev/null +++ b/pceplib/pcep_msg_object_error_types.h @@ -0,0 +1,284 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Brady Johnson <brady@voltanet.io> + */ + + +/* + * Error Object Type and Value definitions + */ + +#ifndef PCEP_OBJECT_ERROR_TYPES_H +#define PCEP_OBJECT_ERROR_TYPES_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define MAX_ERROR_TYPE 30 +#define MAX_ERROR_VALUE 255 + +enum pcep_error_type { + PCEP_ERRT_SESSION_FAILURE = 1, + PCEP_ERRT_CAPABILITY_NOT_SUPPORTED = 2, + PCEP_ERRT_UNKNOW_OBJECT = 3, + PCEP_ERRT_NOT_SUPPORTED_OBJECT = 4, + PCEP_ERRT_POLICY_VIOLATION = 5, + PCEP_ERRT_MANDATORY_OBJECT_MISSING = 6, + PCEP_ERRT_SYNC_PC_REQ_MISSING = 7, + PCEP_ERRT_UNKNOWN_REQ_REF = 8, + PCEP_ERRT_ATTEMPT_TO_ESTABLISH_2ND_PCEP_SESSION = 9, + PCEP_ERRT_RECEPTION_OF_INV_OBJECT = 10, + + PCEP_ERRT_UNRECOGNIZED_EXRS_SUBOBJ = 11, + PCEP_ERRT_DIFFSERV_AWARE_TE_ERROR = 12, + PCEP_ERRT_BRPC_PROC_COMPLETION_ERROR = 13, + PCEP_ERRT_UNASSIGNED14 = 14, + PCEP_ERRT_GLOBAL_CONCURRENT_ERROR = 15, + PCEP_ERRT_P2PMP_CAP_ERROR = 16, + PCEP_ERRT_P2P_ENDPOINTS_ERROR = 17, + PCEP_ERRT_P2P_FRAGMENTATION_ERROR = 18, + PCEP_ERRT_INVALID_OPERATION = 19, + PCEP_ERRT_LSP_STATE_SYNC_ERROR = 20, + + PCEP_ERRT_INVALID_TE_PATH_SETUP_TYPE = 21, + PCEP_ERRT_UNASSIGNED22 = 22, + PCEP_ERRT_BAD_PARAMETER_VALUE = 23, + PCEP_ERRT_LSP_INSTANTIATE_ERROR = 24, + PCEP_ERRT_START_TLS_FAILURE = 25, + PCEP_ERRT_ASSOCIATION_ERROR = 26, + PCEP_ERRT_WSON_RWA_ERROR = 27, + PCEP_ERRT_H_PCE_ERROR = 28, + PCEP_ERRT_PATH_COMP_FAILURE = 29, + PCEP_ERRT_UNASSIGNED30 = 30 /* 30 - 255 Unassigned */ +}; + +enum pcep_error_value { + /* Error Value for Error Types that do not use an Error Value: + * PCEP_ERRT_CAPABILITY_NOT_SUPPORTED=2 + * PCEP_ERRT_SYNC_PC_REQ_MISSING=7 + * PCEP_ERRT_UNKNOWN_REQ_REF=8 + * PCEP_ERRT_ATTEMPT_TO_ESTABLISH_2ND_PCEP_SESSION=9 + * PCEP_ERRT_UNRECOGNIZED_EXRS_SUBOBJ=11 */ + PCEP_ERRV_UNASSIGNED = 0, + + /* Error Values for PCEP_ERRT_SESSION_FAILURE=1 */ + PCEP_ERRV_RECVD_INVALID_OPEN_MSG = 1, + PCEP_ERRV_OPENWAIT_TIMED_OUT = 2, + PCEP_ERRV_UNACCEPTABLE_OPEN_MSG_NO_NEG = 3, + PCEP_ERRV_UNACCEPTABLE_OPEN_MSG_NEG = 4, + PCEP_ERRV_RECVD_SECOND_OPEN_MSG_UNACCEPTABLE = 5, + PCEP_ERRV_RECVD_PCERR = 6, + PCEP_ERRV_KEEPALIVEWAIT_TIMED_OUT = 7, + PCEP_ERRV_PCEP_VERSION_NOT_SUPPORTED = 8, + + /* Error Values for PCEP_ERRT_UNKNOW_OBJECT=3 */ + PCEP_ERRV_UNREC_OBJECT_CLASS = 1, + PCEP_ERRV_UNREC_OBJECT_TYPE = 2, + + /* Error Values for PCEP_ERRT_NOT_SUPPORTED_OBJECT=4 */ + PCEP_ERRV_NOT_SUPPORTED_OBJECT_CLASS = 1, + PCEP_ERRV_NOT_SUPPORTED_OBJECT_TYPE = 2, + /* 3: Unassigned */ + PCEP_ERRV_UNSUPPORTED_PARAM = 4, + PCEP_ERRV_UNSUPPORTED_NW_PERF_CONSTRAINT = 5, + PCEP_ERRV_NOT_SUPPORTED_BW_OBJECT_3_4 = 6, + PCEP_ERRV_UNSUPPORTED_ENDPOINT_TYPE = 7, + PCEP_ERRV_UNSUPPORTED_ENDPOINT_TLV = 8, + PCEP_ERRV_UNSUPPORTED_RP_FLAG_GRANULARITY = 9, + + /* Error Values for PCEP_ERRT_POLICY_VIOLATION=5 */ + PCEP_ERRV_C_BIT_SET_IN_METRIC_OBJECT = 1, + PCEP_ERRV_O_BIT_CLEARD_IN_RP_OBJECT = 2, + PCEP_ERRV_OBJECTIVE_FUNC_NOT_ALLOWED = 3, + PCEP_ERRV_RP_OF_BIT_SET = 4, + PCEP_ERRV_GLOBAL_CONCURRENCY_NOT_ALLOWED = 5, + PCEP_ERRV_MONITORING_MSG_REJECTED = 6, + PCEP_ERRV_P2MP_PATH_COMP_NOT_ALLOWED = 7, + PCEP_ERRV_UNALLOWED_NW_PERF_CONSTRAINT = 8, + + /* Error Values for PCEP_ERRT_MANDATORY_OBJECT_MISSING=6 */ + PCEP_ERRV_RP_OBJECT_MISSING = 1, + PCEP_ERRV_RRO_OBJECT_MISSING_FOR_REOP = 2, + PCEP_ERRV_EP_OBJECT_MISSING = 3, + PCEP_ERRV_MONITOR_OBJECT_MISSING = 4, + /* 5 - 7 Unassigned */ + PCEP_ERRV_LSP_OBJECT_MISSING = 8, + PCEP_ERRV_ERO_OBJECT_MISSING = 9, + PCEP_ERRV_SRP_OBJECT_MISSING = 10, + PCEP_ERRV_LSP_ID_TLV_MISSING = 11, + PCEP_ERRV_LSP_DB_TLV_MISSING = 12, + PCEP_ERRV_S2LS_OBJECT_MISSING = 13, + PCEP_ERRV_P2MP_LSP_ID_TLV_MISSING = 14, + PCEP_ERRV_DISJOINTED_CONF_TLV_MISSING = 15, + + /* Error Values for PCEP_ERRT_RECEPTION_OF_INV_OBJECT=10 */ + PCEP_ERRV_P_FLAG_NOT_CORRECT_IN_OBJECT = 1, + PCEP_ERRV_BAD_LABEL_VALUE = 2, + PCEP_ERRV_UNSUPPORTED_NUM_SR_ERO_SUBOBJECTS = 3, + PCEP_ERRV_BAD_LABEL_FORMAT = 4, + PCEP_ERRV_ERO_SR_ERO_MIX = 5, + PCEP_ERRV_SR_ERO_SID_NAI_ABSENT = 6, + PCEP_ERRV_SR_RRO_SID_NAI_ABSENT = 7, + PCEP_ERRV_SYMBOLIC_PATH_NAME_TLV_MISSING = 8, + PCEP_ERRV_MSD_EXCEEDS_PCEP_SESSION_MAX = 9, + + PCEP_ERRV_RRO_SR_RRO_MIX = 10, + PCEP_ERRV_MALFORMED_OBJECT = 11, + PCEP_ERRV_MISSING_PCE_SR_CAP_TLV = 12, + PCEP_ERRV_UNSUPPORTED_NAI = 13, + PCEP_ERRV_UNKNOWN_SID = 14, + PCEP_ERRV_CANNOT_RESOLVE_NAI_TO_SID = 15, + PCEP_ERRV_COULD_NOT_FIND_SRGB = 16, + PCEP_ERRV_SID_EXCEEDS_SRGB = 17, + PCEP_ERRV_COULD_NOT_FIND_SRLB = 18, + PCEP_ERRV_SID_EXCEEDS_SRLB = 19, + + PCEP_ERRV_INCONSISTENT_SID = 20, + PCEP_ERRV_MSD_MUST_BE_NONZERO = 21, + PCEP_ERRV_MISMATCH_O_S2LS_LSP = 22, + PCEP_ERRV_INCOMPATIBLE_H_PCE_OF = 23, + PCEP_ERRV_BAD_BANDWIDTH_TYPE_3_4 = 24, + PCEP_ERRV_UNSUPPORTED_LSP_PROT_FLAGS = 25, + PCEP_ERRV_UNSUPPORTED_2ND_LSP_PROT_FLAGS = 26, + PCEP_ERRV_UNSUPPORTED_LINK_PROT_TYPE = 27, + PCEP_ERRV_LABEL_SET_TLV_NO_RP_R = 28, + PCEP_ERRV_WRONG_LABEL_SET_TLV_O_L_SET = 29, + + PCEP_ERRV_WRONG_LABEL_SET_O_SET = 30, + PCEP_ERRV_MISSING_GMPLS_CAP_TLV = 31, + PCEP_ERRV_INCOMPATIBLE_OF_CODE = 32, + + /* PCEP_ERRT_DIFFSERV_AWARE_TE_ERROR = 12 */ + PCEP_ERRV_UNSUPPORTED_CLASS_TYPE = 1, + PCEP_ERRV_INVALID_CLASS_TYPE = 2, + PCEP_ERRV_CLASS_SETUP_TYPE_NOT_TE_CLASS = 3, + + /* PCEP_ERRT_BRPC_PROC_COMPLETION_ERROR = 13 */ + PCEP_ERRV_BRPC_PROC_NOT_SUPPORTED = 1, + + /* PCEP_ERRT_UNASSIGNED14 = 14 */ + + /* PCEP_ERRT_GLOBAL_CONCURRENT_ERROR = 15 */ + PCEP_ERRV_INSUFFICIENT_MEMORY = 1, + PCEP_ERRV_GLOBAL_CONCURRENT_OPT_NOT_SUPPORTED = 2, + + /* PCEP_ERRT_P2PMP_CAP_ERROR = 16 */ + PCEP_ERRV_PCE_INSUFFICIENT_MEMORY = 1, + PCEP_ERRV_PCE_NOT_CAPABLE_P2MP_COMP = 2, + + /* PCEP_ERRT_P2P_ENDPOINTS_ERROR = 17 */ + PCEP_ERRV_NO_EP_WITH_LEAF_TYPE2 = 1, + PCEP_ERRV_NO_EP_WITH_LEAF_TYPE3 = 2, + PCEP_ERRV_NO_EP_WITH_LEAF_TYPE4 = 3, + PCEP_ERRV_INCONSITENT_EP = 4, + + /* PCEP_ERRT_P2P_FRAGMENTATION_ERROR = 18 */ + PCEP_ERRV_FRAG_REQUEST_FAILURE = 1, + PCEP_ERRV_FRAG_REPORT_FAILURE = 2, + PCEP_ERRV_FRAG_UPDATE_FAILURE = 3, + PCEP_ERRV_FRAG_INSTANTIATION_FAILURE = 4, + + /* Error Values for PCEP_ERRT_INVALID_OPERATION=19 */ + PCEP_ERRV_LSP_UPDATE_FOR_NON_DELEGATED_LSP = 1, + PCEP_ERRV_LSP_UPDATE_NON_ADVERTISED_PCE = 2, + PCEP_ERRV_LSP_UPDATE_UNKNOWN_PLSP_ID = 3, + /* 4: unassigned */ + PCEP_ERRV_LSP_REPORT_NON_ADVERTISED_PCE = 5, + PCEP_ERRV_PCE_INIT_LSP_LIMIT_REACHED = 6, + PCEP_ERRV_PCE_INIT_LSP_DELEGATION_CANT_REVOKE = 7, + PCEP_ERRV_LSP_INIT_NON_ZERO_PLSP_ID = 8, + PCEP_ERRV_LSP_NOT_PCE_INITIATED = 9, + PCEP_ERRV_PCE_INIT_OP_FREQ_LIMIT_REACHED = 10, + PCEP_ERRV_LSP_REPORT_P2MP_NOT_ADVERTISED = 11, + PCEP_ERRV_LSP_UPDATE_P2MP_NOT_ADVERTISED = 12, + PCEP_ERRV_LSP_INSTANTIATION_P2MP_NOT_ADVERTISED = 13, + PCEP_ERRV_AUTO_BW_CAP_NOT_ADVERTISED = 14, + + /* Error Values for PCEP_ERRT_LSP_STATE_SYNC_ERROR=20 */ + PCEP_ERRV_PCE_CANT_PROCESS_LSP_REPORT = 1, + PCEP_ERRV_LSP_DB_VERSION_MISMATCH = 2, + PCEP_ERRV_TRIGGER_ATTEMPT_BEFORE_PCE_TRIGGER = 3, + PCEP_ERRV_TRIGGER_ATTEMPT_NO_PCE_TRIGGER_CAP = 4, + PCEP_ERRV_PCC_CANT_COMPLETE_STATE_SYNC = 5, + PCEP_ERRV_INVALID_LSP_DB_VERSION_NUMBER = 6, + PCEP_ERRV_INVALID_SPEAKER_ENTITY_ID = 7, + + /* PCEP_ERRT_INVALID_TE_PATH_SETUP_TYPE = 21 */ + PCEP_ERRV_UNSUPPORTED_PATH_SETUP_TYPE = 1, + PCEP_ERRV_MISMATCHED_PATH_SETUP_TYPE = 2, + + /* PCEP_ERRT_UNASSIGNED22 = 22 */ + + /* Error Values for PCEP_ERRT_BAD_PARAMETER_VALUE=23 */ + PCEP_ERRV_SYMBOLIC_PATH_NAME_IN_USE = 1, + PCEP_ERRV_LSP_SPEAKER_ID_NOT_PCE_INITIATED = 2, + + /* Error Values for PCEP_ERRT_LSP_INSTANTIATE_ERROR=24 */ + PCEP_ERRV_UNACCEPTABLE_INSTANTIATE_ERROR = 1, + PCEP_ERRV_INTERNAL_ERROR = 2, + PCEP_ERRV_SIGNALLING_ERROR = 3, + + /* PCEP_ERRT_START_TLS_FAILURE = 25 */ + PCEP_ERRV_START_TLS_AFTER_PCEP_EXCHANGE = 1, + PCEP_ERRV_MSG_NOT_START_TLS_OPEN_ERROR = 2, + PCEP_ERRV_CONNECTION_WO_TLS_NOT_POSSIBLE = 3, + PCEP_ERRV_CONNECTION_WO_TLS_IS_POSSIBLE = 4, + PCEP_ERRV_NO_START_TLS_BEFORE_START_TLS_WAIT_TIMER = 5, + + /* PCEP_ERRT_ASSOCIATION_ERROR = 26 */ + PCEP_ERRV_ASSOC_TYPE_NOT_SUPPORTED = 1, + PCEP_ERRV_TOO_MANY_LSPS_IN_ASSOC_GRP = 2, + PCEP_ERRV_TOO_MANY_ASSOC_GROUPS = 3, + PCEP_ERRV_ASSOCIATION_UNKNOWN = 4, + PCEP_ERRV_OP_CONF_ASSOC_INFO_MISMATCH = 5, + PCEP_ERRV_ASSOC_INFO_MISMATCH = 6, + PCEP_ERRV_CANNOT_JOIN_ASSOC_GROUP = 7, + PCEP_ERRV_ASSOC_ID_NOT_IN_RANGE = 8, + PCEP_ERRV_TUNNEL_EP_MISMATCH_PATH_PROT_ASSOC = 9, + PCEP_ERRV_ATTEMPTED_ADD_LSP_PATH_PROT_ASSOC = 10, + PCEP_ERRV_PROTECTION_TYPE_NOT_SUPPORTED = 11, + + /* PCEP_ERRT_WSON_RWA_ERROR = 27 */ + PCEP_ERRV_RWA_INSUFFICIENT_MEMORY = 1, + PCEP_ERRV_RWA_COMP_NOT_SUPPORTED = 2, + PCEP_ERRV_SYNTAX_ENC_ERROR = 3, + + /* PCEP_ERRT_H_PCE_ERROR = 28 */ + PCEP_ERRV_H_PCE_CAP_NOT_ADVERTISED = 1, + PCEP_ERRV_PARENT_PCE_CAP_CANT_BE_PROVIDED = 2, + + /* PCEP_ERRT_PATH_COMP_FAILURE = 29 */ + PCEP_ERRV_UNACCEPTABLE_REQUEST_MSG = 1, + PCEP_ERRV_GENERALIZED_BW_VAL_NOT_SUPPORTED = 2, + PCEP_ERRV_LABEL_SET_CONSTRAINT_COULD_NOT_BE_MET = 3, + PCEP_ERRV_LABEL_CONSTRAINT_COULD_NOT_BE_MET = 4, + +}; + +const char *get_error_type_str(enum pcep_error_type error_type); +const char *get_error_value_str(enum pcep_error_type error_type, + enum pcep_error_value error_value); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/pceplib/pcep_msg_objects.c b/pceplib/pcep_msg_objects.c new file mode 100644 index 0000000000..6c943ddc2a --- /dev/null +++ b/pceplib/pcep_msg_objects.c @@ -0,0 +1,854 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Brady Johnson <brady@voltanet.io> + * + */ + + +/* + * This is the implementation of a High Level PCEP message object API. + */ + +#include <string.h> +#include <arpa/inet.h> +#include <stdarg.h> +#include <unistd.h> + +#include "pcep_msg_objects.h" +#include "pcep_msg_tlvs.h" +#include "pcep_utils_double_linked_list.h" +#include "pcep_utils_logging.h" +#include "pcep_utils_memory.h" + +/* Internal common function used to create a pcep_object and populate the header + */ +static struct pcep_object_header *pcep_obj_create_common_with_tlvs( + uint8_t obj_length, enum pcep_object_classes object_class, + enum pcep_object_types object_type, double_linked_list *tlv_list) +{ + uint8_t *buffer = pceplib_malloc(PCEPLIB_MESSAGES, obj_length); + memset(buffer, 0, obj_length); + + /* The flag_p and flag_i flags will be set externally */ + struct pcep_object_header *hdr = (struct pcep_object_header *)buffer; + hdr->object_class = object_class; + hdr->object_type = object_type; + hdr->tlv_list = tlv_list; + + return hdr; +} + +static struct pcep_object_header * +pcep_obj_create_common(uint8_t obj_length, + enum pcep_object_classes object_class, + enum pcep_object_types object_type) +{ + return pcep_obj_create_common_with_tlvs(obj_length, object_class, + object_type, NULL); +} + +struct pcep_object_open *pcep_obj_create_open(uint8_t keepalive, + uint8_t deadtimer, uint8_t sid, + double_linked_list *tlv_list) +{ + struct pcep_object_open *open = + (struct pcep_object_open *)pcep_obj_create_common_with_tlvs( + sizeof(struct pcep_object_open), PCEP_OBJ_CLASS_OPEN, + PCEP_OBJ_TYPE_OPEN, tlv_list); + + open->open_version = + PCEP_OBJECT_OPEN_VERSION; /* PCEP version. Current version is 1 + /No flags are currently defined. */ + open->open_keepalive = + keepalive; /* Maximum period of time between two consecutive + PCEP messages sent by the sender. */ + open->open_deadtimer = deadtimer; /* Specifies the amount of time before + closing the session down. */ + open->open_sid = sid; /* PCEP session number that identifies the current + session. */ + + return open; +} + +struct pcep_object_rp *pcep_obj_create_rp(uint8_t priority, bool flag_r, + bool flag_b, bool flag_s, + bool flag_of, uint32_t reqid, + double_linked_list *tlv_list) +{ + if (priority > OBJECT_RP_MAX_PRIORITY) { + pcep_log( + LOG_INFO, + "%s: Error creating RP object, invalid priority [%d], max priority [%d].", + __func__, priority, OBJECT_RP_MAX_PRIORITY); + return NULL; + } + + struct pcep_object_rp *obj = + (struct pcep_object_rp *)pcep_obj_create_common_with_tlvs( + sizeof(struct pcep_object_rp), PCEP_OBJ_CLASS_RP, + PCEP_OBJ_TYPE_RP, tlv_list); + + obj->priority = priority; + obj->flag_reoptimization = flag_r; + obj->flag_bidirectional = flag_b; + obj->flag_strict = flag_s; + obj->flag_of = flag_of; + obj->request_id = reqid; + + return obj; +} + +struct pcep_object_notify * +pcep_obj_create_notify(enum pcep_notification_types notification_type, + enum pcep_notification_values notification_value) +{ + struct pcep_object_notify *obj = + (struct pcep_object_notify *)pcep_obj_create_common( + sizeof(struct pcep_object_notify), PCEP_OBJ_CLASS_NOTF, + PCEP_OBJ_TYPE_NOTF); + + obj->notification_type = notification_type; + obj->notification_value = notification_value; + + return obj; +} + +struct pcep_object_nopath * +pcep_obj_create_nopath(uint8_t ni, bool flag_c, + enum pcep_nopath_tlv_err_codes error_code) +{ + struct pcep_object_tlv_nopath_vector *tlv = + pcep_tlv_create_nopath_vector(error_code); + double_linked_list *tlv_list = dll_initialize(); + dll_append(tlv_list, tlv); + + struct pcep_object_nopath *obj = + (struct pcep_object_nopath *)pcep_obj_create_common_with_tlvs( + sizeof(struct pcep_object_nopath), + PCEP_OBJ_CLASS_NOPATH, PCEP_OBJ_TYPE_NOPATH, tlv_list); + + obj->ni = ni; + obj->flag_c = flag_c; + obj->err_code = error_code; + + return obj; +} + +struct pcep_object_association_ipv4 * +pcep_obj_create_association_ipv4(bool r_flag, uint16_t association_type, + uint16_t association_id, struct in_addr src) +{ + struct pcep_object_association_ipv4 *obj = + (struct pcep_object_association_ipv4 *)pcep_obj_create_common( + sizeof(struct pcep_object_association_ipv4), + PCEP_OBJ_CLASS_ASSOCIATION, + PCEP_OBJ_TYPE_ASSOCIATION_IPV4); + + obj->R_flag = r_flag; + obj->association_type = association_type; + obj->association_id = association_id; + obj->src = src; + + return obj; +} +struct pcep_object_association_ipv6 * +pcep_obj_create_association_ipv6(bool r_flag, uint16_t association_type, + uint16_t association_id, struct in6_addr src) +{ + struct pcep_object_association_ipv6 *obj = + (struct pcep_object_association_ipv6 *)pcep_obj_create_common( + sizeof(struct pcep_object_association_ipv6), + PCEP_OBJ_CLASS_ASSOCIATION, + PCEP_OBJ_TYPE_ASSOCIATION_IPV6); + + obj->R_flag = r_flag; + obj->association_type = association_type; + obj->association_id = association_id; + obj->src = src; + + return obj; +} +struct pcep_object_endpoints_ipv4 * +pcep_obj_create_endpoint_ipv4(const struct in_addr *src_ipv4, + const struct in_addr *dst_ipv4) +{ + if (src_ipv4 == NULL || dst_ipv4 == NULL) { + return NULL; + } + + struct pcep_object_endpoints_ipv4 *obj = + (struct pcep_object_endpoints_ipv4 *)pcep_obj_create_common( + sizeof(struct pcep_object_endpoints_ipv4), + PCEP_OBJ_CLASS_ENDPOINTS, PCEP_OBJ_TYPE_ENDPOINT_IPV4); + + obj->src_ipv4.s_addr = src_ipv4->s_addr; + obj->dst_ipv4.s_addr = dst_ipv4->s_addr; + + return obj; +} + +struct pcep_object_endpoints_ipv6 * +pcep_obj_create_endpoint_ipv6(const struct in6_addr *src_ipv6, + const struct in6_addr *dst_ipv6) +{ + if (src_ipv6 == NULL || dst_ipv6 == NULL) { + return NULL; + } + + struct pcep_object_endpoints_ipv6 *obj = + (struct pcep_object_endpoints_ipv6 *)pcep_obj_create_common( + sizeof(struct pcep_object_endpoints_ipv6), + PCEP_OBJ_CLASS_ENDPOINTS, PCEP_OBJ_TYPE_ENDPOINT_IPV6); + + memcpy(&obj->src_ipv6, src_ipv6, sizeof(struct in6_addr)); + memcpy(&obj->dst_ipv6, dst_ipv6, sizeof(struct in6_addr)); + + return obj; +} + +struct pcep_object_bandwidth *pcep_obj_create_bandwidth(float bandwidth) +{ + struct pcep_object_bandwidth *obj = + (struct pcep_object_bandwidth *)pcep_obj_create_common( + sizeof(struct pcep_object_bandwidth), + PCEP_OBJ_CLASS_BANDWIDTH, PCEP_OBJ_TYPE_BANDWIDTH_REQ); + + obj->bandwidth = bandwidth; + + return obj; +} + +struct pcep_object_metric *pcep_obj_create_metric(enum pcep_metric_types type, + bool flag_b, bool flag_c, + float value) +{ + struct pcep_object_metric *obj = + (struct pcep_object_metric *)pcep_obj_create_common( + sizeof(struct pcep_object_metric), + PCEP_OBJ_CLASS_METRIC, PCEP_OBJ_TYPE_METRIC); + + obj->flag_b = flag_b; + obj->flag_c = flag_c; + obj->type = type; + obj->value = value; + + return obj; +} + +struct pcep_object_lspa * +pcep_obj_create_lspa(uint32_t exclude_any, uint32_t include_any, + uint32_t include_all, uint8_t setup_priority, + uint8_t holding_priority, bool flag_local_protection) +{ + struct pcep_object_lspa *obj = + (struct pcep_object_lspa *)pcep_obj_create_common( + sizeof(struct pcep_object_lspa), PCEP_OBJ_CLASS_LSPA, + PCEP_OBJ_TYPE_LSPA); + + obj->lspa_exclude_any = exclude_any; + obj->lspa_include_any = include_any; + obj->lspa_include_all = include_all; + obj->setup_priority = setup_priority; + obj->holding_priority = holding_priority; + obj->flag_local_protection = flag_local_protection; + + return obj; +} + +struct pcep_object_svec * +pcep_obj_create_svec(bool srlg, bool node, bool link, + double_linked_list *request_id_list) +{ + if (request_id_list == NULL) { + return NULL; + } + + struct pcep_object_svec *obj = + (struct pcep_object_svec *)pcep_obj_create_common( + sizeof(struct pcep_object_svec), PCEP_OBJ_CLASS_SVEC, + PCEP_OBJ_TYPE_SVEC); + + obj->flag_srlg_diverse = srlg; + obj->flag_node_diverse = node; + obj->flag_link_diverse = link; + obj->request_id_list = request_id_list; + + return obj; +} + +struct pcep_object_error * +pcep_obj_create_error(enum pcep_error_type error_type, + enum pcep_error_value error_value) +{ + struct pcep_object_error *obj = + (struct pcep_object_error *)pcep_obj_create_common( + sizeof(struct pcep_object_error), PCEP_OBJ_CLASS_ERROR, + PCEP_OBJ_TYPE_ERROR); + + obj->error_type = error_type; + obj->error_value = error_value; + + return obj; +} + +struct pcep_object_close *pcep_obj_create_close(enum pcep_close_reason reason) +{ + struct pcep_object_close *obj = + (struct pcep_object_close *)pcep_obj_create_common( + sizeof(struct pcep_object_close), PCEP_OBJ_CLASS_CLOSE, + PCEP_OBJ_TYPE_CLOSE); + + obj->reason = reason; + + return obj; +} + +struct pcep_object_srp *pcep_obj_create_srp(bool lsp_remove, + uint32_t srp_id_number, + double_linked_list *tlv_list) +{ + struct pcep_object_srp *obj = + (struct pcep_object_srp *)pcep_obj_create_common_with_tlvs( + sizeof(struct pcep_object_srp), PCEP_OBJ_CLASS_SRP, + PCEP_OBJ_TYPE_SRP, tlv_list); + + obj->flag_lsp_remove = lsp_remove; + obj->srp_id_number = srp_id_number; + + return obj; +} + +struct pcep_object_lsp * +pcep_obj_create_lsp(uint32_t plsp_id, enum pcep_lsp_operational_status status, + bool c_flag, bool a_flag, bool r_flag, bool s_flag, + bool d_flag, double_linked_list *tlv_list) +{ + /* The plsp_id is only 20 bits */ + if (plsp_id > MAX_PLSP_ID) { + pcep_log( + LOG_INFO, + "%s: pcep_obj_create_lsp invalid plsp_id [%d] max value [%d]", + __func__, plsp_id, MAX_PLSP_ID); + return NULL; + } + + /* The status is only 3 bits */ + if (status > MAX_LSP_STATUS) { + pcep_log( + LOG_INFO, + "%s: pcep_obj_create_lsp invalid status [%d] max value [%d]", + __func__, plsp_id, MAX_PLSP_ID); + return NULL; + } + + struct pcep_object_lsp *obj = + (struct pcep_object_lsp *)pcep_obj_create_common_with_tlvs( + sizeof(struct pcep_object_lsp), PCEP_OBJ_CLASS_LSP, + PCEP_OBJ_TYPE_LSP, tlv_list); + + obj->plsp_id = plsp_id; + obj->operational_status = status; + obj->flag_c = c_flag; + obj->flag_a = a_flag; + obj->flag_r = r_flag; + obj->flag_s = s_flag; + obj->flag_d = d_flag; + + return obj; +} + +struct pcep_object_vendor_info * +pcep_obj_create_vendor_info(uint32_t enterprise_number, + uint32_t enterprise_spec_info) +{ + struct pcep_object_vendor_info *obj = + (struct pcep_object_vendor_info *)pcep_obj_create_common( + sizeof(struct pcep_object_vendor_info), + PCEP_OBJ_CLASS_VENDOR_INFO, PCEP_OBJ_TYPE_VENDOR_INFO); + + obj->enterprise_number = enterprise_number; + obj->enterprise_specific_info = enterprise_spec_info; + + return obj; +} + +struct pcep_object_inter_layer * +pcep_obj_create_inter_layer(bool flag_i, bool flag_m, bool flag_t) +{ + struct pcep_object_inter_layer *obj = + (struct pcep_object_inter_layer *)pcep_obj_create_common( + sizeof(struct pcep_object_inter_layer), + PCEP_OBJ_CLASS_INTER_LAYER, PCEP_OBJ_TYPE_INTER_LAYER); + + obj->flag_i = flag_i; + obj->flag_m = flag_m; + obj->flag_t = flag_t; + + return obj; +} + +struct pcep_object_switch_layer * +pcep_obj_create_switch_layer(double_linked_list *switch_layer_rows) +{ + struct pcep_object_switch_layer *obj = + (struct pcep_object_switch_layer *)pcep_obj_create_common( + sizeof(struct pcep_object_switch_layer), + PCEP_OBJ_CLASS_SWITCH_LAYER, + PCEP_OBJ_TYPE_SWITCH_LAYER); + + obj->switch_layer_rows = switch_layer_rows; + + return obj; +} + +struct pcep_object_req_adap_cap * +pcep_obj_create_req_adap_cap(enum pcep_switching_capability sw_cap, + enum pcep_lsp_encoding_type encoding) +{ + struct pcep_object_req_adap_cap *obj = + (struct pcep_object_req_adap_cap *)pcep_obj_create_common( + sizeof(struct pcep_object_req_adap_cap), + PCEP_OBJ_CLASS_REQ_ADAP_CAP, + PCEP_OBJ_TYPE_REQ_ADAP_CAP); + + obj->switching_capability = sw_cap; + obj->encoding = encoding; + + return obj; +} + +struct pcep_object_server_indication * +pcep_obj_create_server_indication(enum pcep_switching_capability sw_cap, + enum pcep_lsp_encoding_type encoding, + double_linked_list *tlv_list) +{ + struct pcep_object_server_indication *obj = + (struct pcep_object_server_indication *) + pcep_obj_create_common_with_tlvs( + sizeof(struct pcep_object_server_indication), + PCEP_OBJ_CLASS_SERVER_IND, + PCEP_OBJ_TYPE_SERVER_IND, tlv_list); + + obj->switching_capability = sw_cap; + obj->encoding = encoding; + + return obj; +} + +struct pcep_object_objective_function * +pcep_obj_create_objective_function(uint16_t of_code, + double_linked_list *tlv_list) +{ + struct pcep_object_objective_function *obj = + (struct pcep_object_objective_function *) + pcep_obj_create_common_with_tlvs( + sizeof(struct pcep_object_objective_function), + PCEP_OBJ_CLASS_OF, PCEP_OBJ_TYPE_OF, tlv_list); + + obj->of_code = of_code; + + return obj; +} + +/* Wrap a list of ro subobjects in a structure with an object header */ +struct pcep_object_ro *pcep_obj_create_ero(double_linked_list *ero_list) +{ + struct pcep_object_ro *ero = + (struct pcep_object_ro *)pcep_obj_create_common( + sizeof(struct pcep_object_ro), PCEP_OBJ_CLASS_ERO, + PCEP_OBJ_TYPE_ERO); + ero->sub_objects = ero_list; + + return ero; +} + +/* Wrap a list of ro subobjects in a structure with an object header */ +struct pcep_object_ro *pcep_obj_create_iro(double_linked_list *iro_list) +{ + struct pcep_object_ro *iro = + (struct pcep_object_ro *)pcep_obj_create_common( + sizeof(struct pcep_object_ro), PCEP_OBJ_CLASS_IRO, + PCEP_OBJ_TYPE_IRO); + iro->sub_objects = iro_list; + + return iro; +} + +/* Wrap a list of ro subobjects in a structure with an object header */ +struct pcep_object_ro *pcep_obj_create_rro(double_linked_list *rro_list) +{ + struct pcep_object_ro *rro = + (struct pcep_object_ro *)pcep_obj_create_common( + sizeof(struct pcep_object_ro), PCEP_OBJ_CLASS_RRO, + PCEP_OBJ_TYPE_RRO); + rro->sub_objects = rro_list; + + return rro; +} + +/* + * Route Object Sub-object creation functions + */ + +static struct pcep_object_ro_subobj * +pcep_obj_create_ro_subobj_common(uint8_t subobj_size, + enum pcep_ro_subobj_types ro_subobj_type, + bool flag_subobj_loose_hop) +{ + struct pcep_object_ro_subobj *ro_subobj = + pceplib_malloc(PCEPLIB_MESSAGES, subobj_size); + memset(ro_subobj, 0, subobj_size); + ro_subobj->flag_subobj_loose_hop = flag_subobj_loose_hop; + ro_subobj->ro_subobj_type = ro_subobj_type; + + return ro_subobj; +} + +struct pcep_ro_subobj_ipv4 * +pcep_obj_create_ro_subobj_ipv4(bool loose_hop, const struct in_addr *rro_ipv4, + uint8_t prefix_length, bool flag_local_prot) +{ + if (rro_ipv4 == NULL) { + return NULL; + } + + struct pcep_ro_subobj_ipv4 *obj = + (struct pcep_ro_subobj_ipv4 *)pcep_obj_create_ro_subobj_common( + sizeof(struct pcep_ro_subobj_ipv4), RO_SUBOBJ_TYPE_IPV4, + loose_hop); + obj->ip_addr.s_addr = rro_ipv4->s_addr; + obj->prefix_length = prefix_length; + obj->flag_local_protection = flag_local_prot; + + return obj; +} + +struct pcep_ro_subobj_ipv6 * +pcep_obj_create_ro_subobj_ipv6(bool loose_hop, const struct in6_addr *rro_ipv6, + uint8_t prefix_length, bool flag_local_prot) +{ + if (rro_ipv6 == NULL) { + return NULL; + } + + struct pcep_ro_subobj_ipv6 *obj = + (struct pcep_ro_subobj_ipv6 *)pcep_obj_create_ro_subobj_common( + sizeof(struct pcep_ro_subobj_ipv6), RO_SUBOBJ_TYPE_IPV6, + loose_hop); + obj->prefix_length = prefix_length; + obj->flag_local_protection = flag_local_prot; + memcpy(&obj->ip_addr, rro_ipv6, sizeof(struct in6_addr)); + + return obj; +} + +struct pcep_ro_subobj_unnum * +pcep_obj_create_ro_subobj_unnum(struct in_addr *router_id, uint32_t if_id) +{ + if (router_id == NULL) { + return NULL; + } + + struct pcep_ro_subobj_unnum *obj = + (struct pcep_ro_subobj_unnum *)pcep_obj_create_ro_subobj_common( + sizeof(struct pcep_ro_subobj_unnum), + RO_SUBOBJ_TYPE_UNNUM, false); + obj->interface_id = if_id; + obj->router_id.s_addr = router_id->s_addr; + + return obj; +} + +struct pcep_ro_subobj_32label * +pcep_obj_create_ro_subobj_32label(bool flag_global_label, uint8_t class_type, + uint32_t label) +{ + struct pcep_ro_subobj_32label *obj = (struct pcep_ro_subobj_32label *) + pcep_obj_create_ro_subobj_common( + sizeof(struct pcep_ro_subobj_32label), + RO_SUBOBJ_TYPE_LABEL, false); + obj->class_type = class_type; + obj->flag_global_label = flag_global_label; + obj->label = label; + + return obj; +} + +struct pcep_ro_subobj_asn *pcep_obj_create_ro_subobj_asn(uint16_t asn) +{ + struct pcep_ro_subobj_asn *obj = + (struct pcep_ro_subobj_asn *)pcep_obj_create_ro_subobj_common( + sizeof(struct pcep_ro_subobj_asn), RO_SUBOBJ_TYPE_ASN, + false); + obj->asn = asn; + + return obj; +} + +/* Internal util function to create pcep_ro_subobj_sr sub-objects */ +static struct pcep_ro_subobj_sr * +pcep_obj_create_ro_subobj_sr_common(enum pcep_sr_subobj_nai nai_type, + bool loose_hop, bool f_flag, bool s_flag, + bool c_flag_in, bool m_flag_in) +{ + struct pcep_ro_subobj_sr *obj = + (struct pcep_ro_subobj_sr *)pcep_obj_create_ro_subobj_common( + sizeof(struct pcep_ro_subobj_sr), RO_SUBOBJ_TYPE_SR, + loose_hop); + + /* Flag logic according to draft-ietf-pce-segment-routing-16 */ + bool c_flag = c_flag_in; + bool m_flag = m_flag_in; + if (s_flag) { + c_flag = false; + m_flag = false; + } + + if (m_flag == false) { + c_flag = false; + } + + obj->nai_type = nai_type; + obj->flag_f = f_flag; + obj->flag_s = s_flag; + obj->flag_c = c_flag; + obj->flag_m = m_flag; + + return obj; +} + +struct pcep_ro_subobj_sr *pcep_obj_create_ro_subobj_sr_nonai(bool loose_hop, + uint32_t sid, + bool c_flag, + bool m_flag) +{ + /* According to draft-ietf-pce-segment-routing-16#section-5.2.1 + * If NT=0, the F bit MUST be 1, the S bit MUST be zero and the + * Length MUST be 8. */ + struct pcep_ro_subobj_sr *obj = pcep_obj_create_ro_subobj_sr_common( + PCEP_SR_SUBOBJ_NAI_ABSENT, loose_hop, true, false, c_flag, + m_flag); + obj->sid = sid; + + return obj; +} + +struct pcep_ro_subobj_sr * +pcep_obj_create_ro_subobj_sr_ipv4_node(bool loose_hop, bool sid_absent, + bool c_flag, bool m_flag, uint32_t sid, + struct in_addr *ipv4_node_id) +{ + if (ipv4_node_id == NULL) { + return NULL; + } + + /* According to draft-ietf-pce-segment-routing-16#section-5.2.1 + * If NT=1, the F bit MUST be zero. If the S bit is 1, the Length + * MUST be 8, otherwise the Length MUST be 12 */ + struct pcep_ro_subobj_sr *obj = pcep_obj_create_ro_subobj_sr_common( + PCEP_SR_SUBOBJ_NAI_IPV4_NODE, loose_hop, false, sid_absent, + c_flag, m_flag); + + if (!sid_absent) { + obj->sid = sid; + } + obj->nai_list = dll_initialize(); + /* Since the IP has to be stored in the list, copy it so the caller + * doesnt have any restrictions about the type of memory used externally + * for the IP. This memory will be freed with the object is freed. */ + struct in_addr *ipv4_node_id_copy = + pceplib_malloc(PCEPLIB_MESSAGES, sizeof(struct in_addr)); + ipv4_node_id_copy->s_addr = ipv4_node_id->s_addr; + dll_append(obj->nai_list, ipv4_node_id_copy); + + return obj; +} + +struct pcep_ro_subobj_sr * +pcep_obj_create_ro_subobj_sr_ipv6_node(bool loose_hop, bool sid_absent, + bool c_flag, bool m_flag, uint32_t sid, + struct in6_addr *ipv6_node_id) +{ + if (ipv6_node_id == NULL) { + return NULL; + } + + /* According to draft-ietf-pce-segment-routing-16#section-5.2.1 + * If NT=2, the F bit MUST be zero. If the S bit is 1, the Length + * MUST be 20, otherwise the Length MUST be 24. */ + struct pcep_ro_subobj_sr *obj = pcep_obj_create_ro_subobj_sr_common( + PCEP_SR_SUBOBJ_NAI_IPV6_NODE, loose_hop, false, sid_absent, + c_flag, m_flag); + + if (!sid_absent) { + obj->sid = sid; + } + obj->nai_list = dll_initialize(); + struct in6_addr *ipv6_node_id_copy = + pceplib_malloc(PCEPLIB_MESSAGES, sizeof(struct in6_addr)); + memcpy(ipv6_node_id_copy, ipv6_node_id, sizeof(struct in6_addr)); + dll_append(obj->nai_list, ipv6_node_id_copy); + + return obj; +} + +struct pcep_ro_subobj_sr *pcep_obj_create_ro_subobj_sr_ipv4_adj( + bool loose_hop, bool sid_absent, bool c_flag, bool m_flag, uint32_t sid, + struct in_addr *local_ipv4, struct in_addr *remote_ipv4) +{ + if (local_ipv4 == NULL || remote_ipv4 == NULL) { + return NULL; + } + + /* According to draft-ietf-pce-segment-routing-16#section-5.2.1 + * If NT=3, the F bit MUST be zero. If the S bit is 1, the Length + * MUST be 12, otherwise the Length MUST be 16 */ + struct pcep_ro_subobj_sr *obj = pcep_obj_create_ro_subobj_sr_common( + PCEP_SR_SUBOBJ_NAI_IPV4_ADJACENCY, loose_hop, false, sid_absent, + c_flag, m_flag); + + if (!sid_absent) { + obj->sid = sid; + } + obj->nai_list = dll_initialize(); + struct in_addr *local_ipv4_copy = + pceplib_malloc(PCEPLIB_MESSAGES, sizeof(struct in_addr)); + struct in_addr *remote_ipv4_copy = + pceplib_malloc(PCEPLIB_MESSAGES, sizeof(struct in_addr)); + local_ipv4_copy->s_addr = local_ipv4->s_addr; + remote_ipv4_copy->s_addr = remote_ipv4->s_addr; + dll_append(obj->nai_list, local_ipv4_copy); + dll_append(obj->nai_list, remote_ipv4_copy); + + return obj; +} + +struct pcep_ro_subobj_sr *pcep_obj_create_ro_subobj_sr_ipv6_adj( + bool loose_hop, bool sid_absent, bool c_flag, bool m_flag, uint32_t sid, + struct in6_addr *local_ipv6, struct in6_addr *remote_ipv6) +{ + if (local_ipv6 == NULL || remote_ipv6 == NULL) { + return NULL; + } + + /* According to draft-ietf-pce-segment-routing-16#section-5.2.1 + * If NT=4, the F bit MUST be zero. If the S bit is 1, the Length + * MUST be 36, otherwise the Length MUST be 40 */ + struct pcep_ro_subobj_sr *obj = pcep_obj_create_ro_subobj_sr_common( + PCEP_SR_SUBOBJ_NAI_IPV6_ADJACENCY, loose_hop, false, sid_absent, + c_flag, m_flag); + + if (!sid_absent) { + obj->sid = sid; + } + obj->nai_list = dll_initialize(); + struct in6_addr *local_ipv6_copy = + pceplib_malloc(PCEPLIB_MESSAGES, sizeof(struct in6_addr)); + struct in6_addr *remote_ipv6_copy = + pceplib_malloc(PCEPLIB_MESSAGES, sizeof(struct in6_addr)); + memcpy(local_ipv6_copy, local_ipv6, sizeof(struct in6_addr)); + memcpy(remote_ipv6_copy, remote_ipv6, sizeof(struct in6_addr)); + dll_append(obj->nai_list, local_ipv6_copy); + dll_append(obj->nai_list, remote_ipv6_copy); + + return obj; +} + +struct pcep_ro_subobj_sr *pcep_obj_create_ro_subobj_sr_unnumbered_ipv4_adj( + bool loose_hop, bool sid_absent, bool c_flag, bool m_flag, uint32_t sid, + uint32_t local_node_id, uint32_t local_if_id, uint32_t remote_node_id, + uint32_t remote_if_id) +{ + /* According to draft-ietf-pce-segment-routing-16#section-5.2.1 + * If NT=5, the F bit MUST be zero. If the S bit is 1, the Length + * MUST be 20, otherwise the Length MUST be 24. */ + struct pcep_ro_subobj_sr *obj = pcep_obj_create_ro_subobj_sr_common( + PCEP_SR_SUBOBJ_NAI_UNNUMBERED_IPV4_ADJACENCY, loose_hop, false, + sid_absent, c_flag, m_flag); + + if (!sid_absent) { + obj->sid = sid; + } + + obj->nai_list = dll_initialize(); + uint32_t *local_node_id_copy = + pceplib_malloc(PCEPLIB_MESSAGES, sizeof(uint32_t)); + *local_node_id_copy = local_node_id; + dll_append(obj->nai_list, local_node_id_copy); + + uint32_t *local_if_id_copy = + pceplib_malloc(PCEPLIB_MESSAGES, sizeof(uint32_t)); + *local_if_id_copy = local_if_id; + dll_append(obj->nai_list, local_if_id_copy); + + uint32_t *remote_node_id_copy = + pceplib_malloc(PCEPLIB_MESSAGES, sizeof(uint32_t)); + *remote_node_id_copy = remote_node_id; + dll_append(obj->nai_list, remote_node_id_copy); + + uint32_t *remote_if_id_copy = + pceplib_malloc(PCEPLIB_MESSAGES, sizeof(uint32_t)); + *remote_if_id_copy = remote_if_id; + dll_append(obj->nai_list, remote_if_id_copy); + + return obj; +} + +struct pcep_ro_subobj_sr *pcep_obj_create_ro_subobj_sr_linklocal_ipv6_adj( + bool loose_hop, bool sid_absent, bool c_flag, bool m_flag, uint32_t sid, + struct in6_addr *local_ipv6, uint32_t local_if_id, + struct in6_addr *remote_ipv6, uint32_t remote_if_id) +{ + if (local_ipv6 == NULL || remote_ipv6 == NULL) { + return NULL; + } + + /* According to draft-ietf-pce-segment-routing-16#section-5.2.1 + * If NT=6, the F bit MUST be zero. If the S bit is 1, the Length + * MUST be 44, otherwise the Length MUST be 48 */ + struct pcep_ro_subobj_sr *obj = pcep_obj_create_ro_subobj_sr_common( + PCEP_SR_SUBOBJ_NAI_LINK_LOCAL_IPV6_ADJACENCY, loose_hop, false, + sid_absent, c_flag, m_flag); + + if (!sid_absent) { + obj->sid = sid; + } + obj->nai_list = dll_initialize(); + struct in6_addr *local_ipv6_copy = + pceplib_malloc(PCEPLIB_MESSAGES, sizeof(struct in6_addr)); + memcpy(local_ipv6_copy, local_ipv6, sizeof(struct in6_addr)); + dll_append(obj->nai_list, local_ipv6_copy); + + uint32_t *local_if_id_copy = + pceplib_malloc(PCEPLIB_MESSAGES, sizeof(uint32_t)); + *local_if_id_copy = local_if_id; + dll_append(obj->nai_list, local_if_id_copy); + + struct in6_addr *remote_ipv6_copy = + pceplib_malloc(PCEPLIB_MESSAGES, sizeof(struct in6_addr)); + memcpy(remote_ipv6_copy, remote_ipv6, sizeof(struct in6_addr)); + dll_append(obj->nai_list, remote_ipv6_copy); + + uint32_t *remote_if_id_copy = + pceplib_malloc(PCEPLIB_MESSAGES, sizeof(uint32_t)); + *remote_if_id_copy = remote_if_id; + dll_append(obj->nai_list, remote_if_id_copy); + + return obj; +} diff --git a/pceplib/pcep_msg_objects.h b/pceplib/pcep_msg_objects.h new file mode 100644 index 0000000000..959a6f8cf6 --- /dev/null +++ b/pceplib/pcep_msg_objects.h @@ -0,0 +1,741 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Brady Johnson <brady@voltanet.io> + */ + + +/* + * This is a High Level PCEP message object API. + */ + +#ifndef PCEP_OBJECTS_H +#define PCEP_OBJECTS_H + +#include <stdbool.h> +#include <stdint.h> + +#include "pcep.h" +#include "pcep_utils_double_linked_list.h" +#include "pcep_msg_object_error_types.h" +#include "pcep_msg_tlvs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Regarding memory usage: + * When creating objects, any objects passed into these APIs will be free'd when + * the enclosing pcep_message is free'd. That includes the double_linked_list's. + * So, just create the objects and TLVs, put them in their double_linked_list's, + * and everything will be managed internally. The enclosing message will be + * deleted by pcep_msg_free_message() or pcep_msg_free_message_list() which, + * in turn will call one of: pcep_obj_free_object() and pcep_obj_free_tlv(). + * For received messages with objects, call pcep_msg_free_message() to free + * them. + */ + +enum pcep_object_classes { + PCEP_OBJ_CLASS_OPEN = 1, + PCEP_OBJ_CLASS_RP = 2, + PCEP_OBJ_CLASS_NOPATH = 3, + PCEP_OBJ_CLASS_ENDPOINTS = 4, + PCEP_OBJ_CLASS_BANDWIDTH = 5, + PCEP_OBJ_CLASS_METRIC = 6, + PCEP_OBJ_CLASS_ERO = 7, + PCEP_OBJ_CLASS_RRO = 8, + PCEP_OBJ_CLASS_LSPA = 9, + PCEP_OBJ_CLASS_IRO = 10, + PCEP_OBJ_CLASS_SVEC = 11, + PCEP_OBJ_CLASS_NOTF = 12, + PCEP_OBJ_CLASS_ERROR = 13, + PCEP_OBJ_CLASS_CLOSE = 15, + PCEP_OBJ_CLASS_OF = 21, + PCEP_OBJ_CLASS_LSP = 32, + PCEP_OBJ_CLASS_SRP = 33, + PCEP_OBJ_CLASS_VENDOR_INFO = 34, + PCEP_OBJ_CLASS_INTER_LAYER = 36, /* RFC 8282 */ + PCEP_OBJ_CLASS_SWITCH_LAYER = 37, /* RFC 8282 */ + PCEP_OBJ_CLASS_REQ_ADAP_CAP = 38, /* RFC 8282 */ + PCEP_OBJ_CLASS_SERVER_IND = 39, /* RFC 8282 */ + PCEP_OBJ_CLASS_ASSOCIATION = 40, /*draft-ietf-pce-association-group-10*/ + PCEP_OBJ_CLASS_MAX, +}; + +enum pcep_object_types { + PCEP_OBJ_TYPE_OPEN = 1, + PCEP_OBJ_TYPE_RP = 1, + PCEP_OBJ_TYPE_NOPATH = 1, + PCEP_OBJ_TYPE_ENDPOINT_IPV4 = 1, + PCEP_OBJ_TYPE_ENDPOINT_IPV6 = 2, + PCEP_OBJ_TYPE_BANDWIDTH_REQ = 1, + PCEP_OBJ_TYPE_BANDWIDTH_TELSP = 2, + PCEP_OBJ_TYPE_BANDWIDTH_CISCO = + 5, /* IANA unassigned, but rcvd from Cisco PCE */ + PCEP_OBJ_TYPE_SRP = 1, + PCEP_OBJ_TYPE_VENDOR_INFO = 1, + PCEP_OBJ_TYPE_LSP = 1, + PCEP_OBJ_TYPE_METRIC = 1, + PCEP_OBJ_TYPE_ERO = 1, + PCEP_OBJ_TYPE_RRO = 1, + PCEP_OBJ_TYPE_LSPA = 1, + PCEP_OBJ_TYPE_IRO = 1, + PCEP_OBJ_TYPE_SVEC = 1, + PCEP_OBJ_TYPE_NOTF = 1, + PCEP_OBJ_TYPE_ERROR = 1, + PCEP_OBJ_TYPE_CLOSE = 1, + PCEP_OBJ_TYPE_INTER_LAYER = 1, + PCEP_OBJ_TYPE_SWITCH_LAYER = 1, + PCEP_OBJ_TYPE_REQ_ADAP_CAP = 1, + PCEP_OBJ_TYPE_SERVER_IND = 1, + PCEP_OBJ_TYPE_ASSOCIATION_IPV4 = + 1, /*draft-ietf-pce-association-group-10*/ + PCEP_OBJ_TYPE_ASSOCIATION_IPV6 = + 2, /*draft-ietf-pce-association-group-10*/ + PCEP_OBJ_TYPE_OF = 1, + PCEP_OBJ_TYPE_MAX = 2, +}; + +#define OBJECT_HEADER_FLAG_I 0x01 +#define OBJECT_HEADER_FLAG_P 0x02 + +/* The flag_p and flag_i arent set via the APIs, if they need to be set, just + * set them on the returned object once it has been created. */ +struct pcep_object_header { + enum pcep_object_classes object_class; + enum pcep_object_types object_type; + bool flag_p; /* PCC Processing rule bit: When set, the object MUST be + taken into account, when cleared the object is optional. + */ + bool flag_i; /* PCE Ignore bit: indicates to a PCC whether or not an + optional object was processed */ + double_linked_list *tlv_list; + /* Pointer into encoded_message field from the pcep_message */ + const uint8_t *encoded_object; + uint16_t encoded_object_length; +}; + +#define PCEP_OBJECT_OPEN_VERSION 1 + +struct pcep_object_open { + struct pcep_object_header header; + uint8_t open_version; /* PCEP version. Current version is 1 */ + uint8_t open_keepalive; /* Maximum period of time between two + consecutive PCEP messages sent by the sender. + */ + uint8_t open_deadtimer; /* Specifies the amount of time before closing + the session down. */ + uint8_t open_sid; /* PCEP session number that identifies the current + session. */ +}; + +#define OBJECT_RP_FLAG_R 0x08 +#define OBJECT_RP_FLAG_B 0x10 +#define OBJECT_RP_FLAG_O 0x20 +#define OBJECT_RP_FLAG_OF 0x80 +#define OBJECT_RP_MAX_PRIORITY 0x07 + +struct pcep_object_rp { + struct pcep_object_header header; + uint8_t priority; /* 3 bit priority, max priority is 7 */ + bool flag_reoptimization; + bool flag_bidirectional; + bool flag_strict; /* when set, a loose path is acceptable */ + bool flag_of; /* Supply Objective Function on Response */ + uint32_t request_id; /* The Request-id-number value combined with the + source for PCC & PCE creates a uniquely number. + */ +}; + +enum pcep_notification_types { + PCEP_NOTIFY_TYPE_PENDING_REQUEST_CANCELLED = 1, + PCEP_NOTIFY_TYPE_PCE_OVERLOADED = 2 +}; + +enum pcep_notification_values { + PCEP_NOTIFY_VALUE_PCC_CANCELLED_REQUEST = 1, + PCEP_NOTIFY_VALUE_PCE_CANCELLED_REQUEST = 2, + PCEP_NOTIFY_VALUE_PCE_CURRENTLY_OVERLOADED = 1, + PCEP_NOTIFY_VALUE_PCE_NO_LONGER_OVERLOADED = 2 +}; + +struct pcep_object_notify { + struct pcep_object_header header; + enum pcep_notification_types notification_type; + enum pcep_notification_values notification_value; +}; + +enum pcep_association_type { + PCEP_ASSOCIATION_TYPE_PATH_PROTECTION_ASSOCIATION = + 1, // iana unique value define as 2020-01-08! + PCEP_ASSOCIATION_TYPE_SR_POLICY_ASSOCIATION_TYPE = + 65535 // TBD1 draft-barth-pce-segment-routing-policy-cp-04 +}; +#define OBJECT_ASSOCIATION_FLAG_R 0x01 +struct pcep_object_association_ipv4 { // draft-ietf-pce-association-group-10 + struct pcep_object_header header; + bool R_flag; + uint16_t association_type; + uint16_t association_id; + struct in_addr src; +}; + +struct pcep_object_association_ipv6 { // draft-ietf-pce-association-group-10 + struct pcep_object_header header; + bool R_flag; + uint16_t association_type; + uint16_t association_id; + struct in6_addr src; +}; + + +enum pcep_nopath_nature_of_issue { + PCEP_NOPATH_NI_NO_PATH_FOUND = 0, + PCEP_NOPATH_NI_PCE_CHAIN_BROKEN = 1, +}; + +enum pcep_nopath_tlv_err_codes { + PCEP_NOPATH_TLV_ERR_NO_TLV = 0, + PCEP_NOPATH_TLV_ERR_PCE_UNAVAILABLE = 1, + PCEP_NOPATH_TLV_ERR_UNKNOWN_DST = 2, + PCEP_NOPATH_TLV_ERR_UNKNOWN_SRC = 3 +}; + +#define OBJECT_NOPATH_FLAG_C 0x80 + +struct pcep_object_nopath { + struct pcep_object_header header; + uint8_t ni; /* Nature of Issue, reports the nature of the issue that led + to a negative reply */ + bool flag_c; /* when set, indicates the unsatisfied constraints by + including relevant PCEP objects. */ + enum pcep_nopath_tlv_err_codes + err_code; /* When set other than 0, an appropriate TLV will be + included */ +}; + +struct pcep_object_endpoints_ipv4 { + struct pcep_object_header header; + struct in_addr src_ipv4; + struct in_addr dst_ipv4; +}; + +struct pcep_object_endpoints_ipv6 { + struct pcep_object_header header; + struct in6_addr src_ipv6; + struct in6_addr dst_ipv6; +}; + +/* PCEP floats are encoded according to: + * https://en.wikipedia.org/wiki/IEEE_754-1985 + * Luckily, this is the same encoding used by C */ +struct pcep_object_bandwidth { + struct pcep_object_header header; + float bandwidth; +}; + +enum pcep_metric_types { + /* RFC 5440 */ + PCEP_METRIC_IGP = 1, + PCEP_METRIC_TE = 2, + PCEP_METRIC_HOP_COUNT = 3, + /* RFC 5541 */ + PCEP_METRIC_AGGREGATE_BW = 4, + PCEP_METRIC_MOST_LOADED_LINK = 5, + PCEP_METRIC_CUMULATIVE_IGP = 6, + PCEP_METRIC_CUMULATIVE_TE = 7, + /* RFC 8306 */ + PCEP_METRIC_P2MP_IGP = 8, + PCEP_METRIC_P2MP_TE = 9, + PCEP_METRIC_P2MP_HOP_COUNT = 10, + /* RFC 8864 */ + PCEP_METRIC_SEGMENT_ID_DEPTH = 11, + /* RFC 8233 */ + PCEP_METRIC_PATH_DELAY = 12, + PCEP_METRIC_PATH_DELAY_VARIATION = 13, + PCEP_METRIC_PATH_LOSS = 14, + PCEP_METRIC_P2MP_PATH_DELAY = 15, + PCEP_METRIC_P2MP_PATH_DELAY_VARIATION = 16, + PCEP_METRIC_P2MP_PATH_LOSS = 17, + /* RFC 8282 */ + PCEP_METRIC_NUM_PATH_ADAPTATIONS = 18, + PCEP_METRIC_NUM_PATH_LAYERS = 19, + /* RFC 8685 */ + PCEP_METRIC_DOMAIN_COUNT = 20, + PCEP_METRIC_BORDER_NODE_COUNT = 21, +}; + +#define OBJECT_METRIC_FLAC_B 0x01 +#define OBJECT_METRIC_FLAC_C 0x02 + +/* PCEP floats are encoded according to: + * https://en.wikipedia.org/wiki/IEEE_754-1985 + * Luckily, this is the same encoding used by C */ +struct pcep_object_metric { + struct pcep_object_header header; + enum pcep_metric_types type; + bool flag_b; /* Bound flag */ + bool flag_c; /* Computed metric */ + float value; /* Metric value in 32 bits */ +}; + +#define OBJECT_LSPA_FLAG_L 0x01 + +struct pcep_object_lspa { + struct pcep_object_header header; + uint32_t lspa_exclude_any; + uint32_t lspa_include_any; + uint32_t lspa_include_all; + uint8_t setup_priority; + uint8_t holding_priority; + bool flag_local_protection; /* Local protection desired bit */ +}; + +/* The SVEC object with some custom extensions. */ +#define OBJECT_SVEC_FLAG_L 0x01 +#define OBJECT_SVEC_FLAG_N 0x02 +#define OBJECT_SVEC_FLAG_S 0x04 + +struct pcep_object_svec { + struct pcep_object_header header; + bool flag_link_diverse; + bool flag_node_diverse; + bool flag_srlg_diverse; + double_linked_list + *request_id_list; /* list of 32-bit request ID pointers */ +}; + +struct pcep_object_error { + struct pcep_object_header header; + enum pcep_error_type error_type; + enum pcep_error_value error_value; +}; + +struct pcep_object_load_balancing { + struct pcep_object_header header; + uint8_t load_maxlsp; /* Maximum number of TE LSPs in the set */ + uint32_t load_minband; /* Specifies the minimum bandwidth of each + element */ +}; + +enum pcep_close_reason { + PCEP_CLOSE_REASON_NO = 1, + PCEP_CLOSE_REASON_DEADTIMER = 2, + PCEP_CLOSE_REASON_FORMAT = 3, + PCEP_CLOSE_REASON_UNKNOWN_REQ = 4, + PCEP_CLOSE_REASON_UNREC_MSG = 5 +}; + +struct pcep_object_close { + struct pcep_object_header header; + enum pcep_close_reason reason; +}; + +/* Stateful PCE Request Parameters RFC 8231, 8281 */ + +#define OBJECT_SRP_FLAG_R 0x01 + +struct pcep_object_srp { + struct pcep_object_header header; + bool flag_lsp_remove; /* RFC 8281 */ + uint32_t srp_id_number; +}; + +/* Label Switched Path Object RFC 8231 */ +enum pcep_lsp_operational_status { + PCEP_LSP_OPERATIONAL_DOWN = 0, + PCEP_LSP_OPERATIONAL_UP = 1, + PCEP_LSP_OPERATIONAL_ACTIVE = 2, + PCEP_LSP_OPERATIONAL_GOING_DOWN = 3, + PCEP_LSP_OPERATIONAL_GOING_UP = 4, +}; + +#define MAX_PLSP_ID 0x000fffff /* The plsp_id is only 20 bits */ +#define MAX_LSP_STATUS 0x0007 /* The status is only 3 bits */ +#define OBJECT_LSP_FLAG_D 0x01 +#define OBJECT_LSP_FLAG_S 0x02 +#define OBJECT_LSP_FLAG_R 0x04 +#define OBJECT_LSP_FLAG_A 0x08 +#define OBJECT_LSP_FLAG_C 0x80 + +struct pcep_object_lsp { + struct pcep_object_header header; + uint32_t plsp_id; /* plsp_id is 20 bits, must be <= MAX_PLSP_ID*/ + enum pcep_lsp_operational_status operational_status; /* max 3 bits */ + bool flag_d; + bool flag_s; + bool flag_r; + bool flag_a; + bool flag_c; +}; + +/* RFC 7470 */ +struct pcep_object_vendor_info { + struct pcep_object_header header; + uint32_t enterprise_number; + uint32_t enterprise_specific_info; +}; + +/* RFC 8282 */ +#define OBJECT_INTER_LAYER_FLAG_I 0x01 +#define OBJECT_INTER_LAYER_FLAG_M 0x02 +#define OBJECT_INTER_LAYER_FLAG_T 0x04 + +struct pcep_object_inter_layer { + struct pcep_object_header header; + bool flag_i; + bool flag_m; + bool flag_t; +}; + +/* RFC 8282 */ +#define OBJECT_SWITCH_LAYER_FLAG_I 0x01 +enum pcep_lsp_encoding_type { + /* Values taken from RFC 3471 as suggested by RFC 8282 */ + PCEP_LSP_ENC_PACKET = 1, + PCEP_LSP_ENC_ETHERNET = 2, + PCEP_LSP_ENC_PDH = 3, + PCEP_LSP_ENC_RESERVED4 = 4, + PCEP_LSP_ENC_SDH_SONET = 5, + PCEP_LSP_ENC_RESERVED6 = 6, + PCEP_LSP_ENC_DIG_WRAPPER = 7, + PCEP_LSP_ENC_LAMBDA = 8, + PCEP_LSP_ENC_FIBER = 9, + PCEP_LSP_ENC_RESERVED10 = 10, + PCEP_LSP_ENC_FIBER_CHAN = 11 +}; + +enum pcep_switching_capability { + /* Switching capability values taken from RFC 4203/3471 as suggested by + RFC 8282 */ + PCEP_SW_CAP_PSC1 = 1, /* Packet-Switch Capable-1 (PSC-1) */ + PCEP_SW_CAP_PSC2 = 2, + PCEP_SW_CAP_PSC3 = 3, + PCEP_SW_CAP_PSC4 = 4, + PCEP_SW_CAP_L2SC = 51, /* Layer-2 Switch Capable */ + PCEP_SW_CAP_TDM = 100, /* Time-Division-Multiplex Capable */ + PCEP_SW_CAP_LSC = 150, /* Lambda-Switch Capable */ + PCEP_SW_CAP_FSC = 200 /* Fiber-Switch Capable */ +}; + +struct pcep_object_switch_layer_row { + enum pcep_lsp_encoding_type lsp_encoding_type; + enum pcep_switching_capability switching_type; + bool flag_i; +}; + +struct pcep_object_switch_layer { + struct pcep_object_header header; + double_linked_list + *switch_layer_rows; /* list of struct + pcep_object_switch_layer_row */ +}; + +/* RFC 8282 + * Requested Adaptation capability */ + +struct pcep_object_req_adap_cap { + struct pcep_object_header header; + enum pcep_switching_capability switching_capability; + enum pcep_lsp_encoding_type encoding; +}; + +/* RFC 8282 */ + +struct pcep_object_server_indication { + struct pcep_object_header header; + enum pcep_switching_capability switching_capability; + enum pcep_lsp_encoding_type encoding; + /* This object is identical to req_adap_cap, except it allows TLVs */ +}; + +/* Objective Function Object: RFC 5541 */ + +struct pcep_object_objective_function { + struct pcep_object_header header; + uint16_t of_code; +}; + +/* + * Common Route Object sub-object definitions + * used by ERO, IRO, and RRO + */ + +/* Common Route Object sub-object types + * used by ERO, IRO, and RRO */ +enum pcep_ro_subobj_types { + RO_SUBOBJ_TYPE_IPV4 = 1, /* RFC 3209 */ + RO_SUBOBJ_TYPE_IPV6 = 2, /* RFC 3209 */ + RO_SUBOBJ_TYPE_LABEL = 3, /* RFC 3209 */ + RO_SUBOBJ_TYPE_UNNUM = 4, /* RFC 3477 */ + RO_SUBOBJ_TYPE_ASN = 32, /* RFC 3209, Section 4.3.3.4 */ + RO_SUBOBJ_TYPE_SR = 36, /* RFC 8408, draft-ietf-pce-segment-routing-16. + Type 5 for draft07 has been assigned to + something else. */ + RO_SUBOBJ_UNKNOWN +}; + +struct pcep_object_ro { + struct pcep_object_header header; + double_linked_list + *sub_objects; /* list of struct pcep_object_ro_subobj */ +}; + +struct pcep_object_ro_subobj { + bool flag_subobj_loose_hop; /* L subobj flag */ + enum pcep_ro_subobj_types ro_subobj_type; +}; + +#define OBJECT_SUBOBJ_IP_FLAG_LOCAL_PROT 0x01 + +struct pcep_ro_subobj_ipv4 { + struct pcep_object_ro_subobj ro_subobj; + struct in_addr ip_addr; + uint8_t prefix_length; + bool flag_local_protection; +}; + +struct pcep_ro_subobj_ipv6 { + struct pcep_object_ro_subobj ro_subobj; + struct in6_addr ip_addr; + uint8_t prefix_length; + bool flag_local_protection; +}; + +struct pcep_ro_subobj_unnum { + struct pcep_object_ro_subobj ro_subobj; + struct in_addr router_id; + uint32_t interface_id; +}; + +#define OBJECT_SUBOBJ_LABEL_FLAG_GLOGAL 0x01 +struct pcep_ro_subobj_32label { + struct pcep_object_ro_subobj ro_subobj; + bool flag_global_label; + uint8_t class_type; /* label class-type (generalized label = 2) */ + uint32_t label; /* label supported */ +}; + +struct pcep_ro_subobj_asn { + struct pcep_object_ro_subobj ro_subobj; + uint16_t asn; /* Autonomous system number */ +}; + +/* The SR ERO and SR RRO subojbects are the same, except + * the SR-RRO does not have the L flag in the Type field. + * Defined in draft-ietf-pce-segment-routing-16 */ +enum pcep_sr_subobj_nai { + PCEP_SR_SUBOBJ_NAI_ABSENT = 0, + PCEP_SR_SUBOBJ_NAI_IPV4_NODE = 1, + PCEP_SR_SUBOBJ_NAI_IPV6_NODE = 2, + PCEP_SR_SUBOBJ_NAI_IPV4_ADJACENCY = 3, + PCEP_SR_SUBOBJ_NAI_IPV6_ADJACENCY = 4, + PCEP_SR_SUBOBJ_NAI_UNNUMBERED_IPV4_ADJACENCY = 5, + PCEP_SR_SUBOBJ_NAI_LINK_LOCAL_IPV6_ADJACENCY = 6, + PCEP_SR_SUBOBJ_NAI_UNKNOWN +}; + +#define OBJECT_SUBOBJ_SR_FLAG_M 0x01 +#define OBJECT_SUBOBJ_SR_FLAG_C 0x02 +#define OBJECT_SUBOBJ_SR_FLAG_S 0x04 +#define OBJECT_SUBOBJ_SR_FLAG_F 0x08 + +struct pcep_ro_subobj_sr { + struct pcep_object_ro_subobj ro_subobj; + enum pcep_sr_subobj_nai nai_type; + bool flag_f; + bool flag_s; + bool flag_c; + bool flag_m; + + /* The SID and NAI are optional depending on the flags, + * and the NAI can be variable length */ + uint32_t sid; + double_linked_list + *nai_list; /* double linked list of in_addr or in6_addr */ +}; + +/* Macros to make a SID Label + * + * 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Label + | Label | TC |S| TTL | Stack + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Entry + */ +#define ENCODE_SR_ERO_SID(label_20bits, tc_3bits, stack_bottom_bit, ttl_8bits) \ + ((((label_20bits) << 12) & 0xfffff000) \ + | (((tc_3bits) << 9) & 0x00000e00) \ + | (((stack_bottom_bit) << 8) & 0x00000100) | ((ttl_8bits)&0xff)) +#define GET_SR_ERO_SID_LABEL(SID) ((SID & 0xfffff000) >> 12) +#define GET_SR_ERO_SID_TC(SID) ((SID & 0x00000e00) >> 9) +#define GET_SR_ERO_SID_S(SID) ((SID & 0x00000100) >> 8) +#define GET_SR_ERO_SID_TTL(SID) ((SID & 0x000000ff)) + +/* + * All created objects will be in Host byte order, except for IPs. + * All IP addresses are expected to be passed-in in Network byte order, + * and any objects received will have their IPs in Network byte order. + * The message containing the objects should be converted to Network byte order + * with pcep_encode_msg_header() before sending, which will also convert the + * Objects, TLVs, and sub-objects. + */ + +struct pcep_object_open *pcep_obj_create_open(uint8_t keepalive, + uint8_t deadtimer, uint8_t sid, + double_linked_list *tlv_list); +struct pcep_object_rp *pcep_obj_create_rp(uint8_t priority, bool flag_r, + bool flag_b, bool flag_s, + bool flag_of, uint32_t reqid, + double_linked_list *tlv_list); +struct pcep_object_notify * +pcep_obj_create_notify(enum pcep_notification_types notification_type, + enum pcep_notification_values notification_value); +struct pcep_object_nopath * +pcep_obj_create_nopath(uint8_t ni, bool flag_c, + enum pcep_nopath_tlv_err_codes error_code); +struct pcep_object_association_ipv4 * +pcep_obj_create_association_ipv4(bool r_flag, uint16_t association_type, + uint16_t association_id, struct in_addr src); +struct pcep_object_association_ipv6 * +pcep_obj_create_association_ipv6(bool r_flag, uint16_t association_type, + uint16_t association_id, struct in6_addr src); +struct pcep_object_endpoints_ipv4 * +pcep_obj_create_endpoint_ipv4(const struct in_addr *src_ipv4, + const struct in_addr *dst_ipv4); +struct pcep_object_endpoints_ipv6 * +pcep_obj_create_endpoint_ipv6(const struct in6_addr *src_ipv6, + const struct in6_addr *dst_ipv6); +struct pcep_object_bandwidth *pcep_obj_create_bandwidth(float bandwidth); +struct pcep_object_metric *pcep_obj_create_metric(enum pcep_metric_types type, + bool flag_b, bool flag_c, + float value); +struct pcep_object_lspa * +pcep_obj_create_lspa(uint32_t exclude_any, uint32_t include_any, + uint32_t include_all, uint8_t setup_priority, + uint8_t holding_priority, bool flag_local_protection); +struct pcep_object_svec * +pcep_obj_create_svec(bool srlg, bool node, bool link, + double_linked_list *request_id_list); +struct pcep_object_error * +pcep_obj_create_error(enum pcep_error_type error_type, + enum pcep_error_value error_value); +struct pcep_object_close *pcep_obj_create_close(enum pcep_close_reason reason); +struct pcep_object_srp *pcep_obj_create_srp(bool lsp_remove, + uint32_t srp_id_number, + double_linked_list *tlv_list); +struct pcep_object_lsp * +pcep_obj_create_lsp(uint32_t plsp_id, enum pcep_lsp_operational_status status, + bool c_flag, bool a_flag, bool r_flag, bool s_flag, + bool d_flag, double_linked_list *tlv_list); +struct pcep_object_vendor_info * +pcep_obj_create_vendor_info(uint32_t enterprise_number, + uint32_t enterprise_spec_info); +struct pcep_object_inter_layer * +pcep_obj_create_inter_layer(bool flag_i, bool flag_m, bool flag_t); +struct pcep_object_switch_layer * +pcep_obj_create_switch_layer(double_linked_list *switch_layer_rows); +struct pcep_object_req_adap_cap * +pcep_obj_create_req_adap_cap(enum pcep_switching_capability sw_cap, + enum pcep_lsp_encoding_type encoding); +struct pcep_object_server_indication * +pcep_obj_create_server_indication(enum pcep_switching_capability sw_cap, + enum pcep_lsp_encoding_type encoding, + double_linked_list *tlv_list); +struct pcep_object_objective_function * +pcep_obj_create_objective_function(uint16_t of_code, + double_linked_list *tlv_list); + +/* Route Object (Explicit ero, Reported rro, and Include iro) functions + * First, the sub-objects should be created and appended to a + * double_linked_list, then call one of these Route Object creation functions + * with the subobj list */ +struct pcep_object_ro *pcep_obj_create_ero(double_linked_list *ero_list); +struct pcep_object_ro *pcep_obj_create_rro(double_linked_list *rro_list); +struct pcep_object_ro *pcep_obj_create_iro(double_linked_list *iro_list); +/* Route Object sub-object creation functions */ +struct pcep_ro_subobj_ipv4 * +pcep_obj_create_ro_subobj_ipv4(bool loose_hop, const struct in_addr *ro_ipv4, + uint8_t prefix_len, bool flag_local_prot); +struct pcep_ro_subobj_ipv6 * +pcep_obj_create_ro_subobj_ipv6(bool loose_hop, const struct in6_addr *ro_ipv6, + uint8_t prefix_len, bool flag_local_prot); +struct pcep_ro_subobj_unnum * +pcep_obj_create_ro_subobj_unnum(struct in_addr *router_id, uint32_t if_id); +struct pcep_ro_subobj_32label * +pcep_obj_create_ro_subobj_32label(bool flag_global_label, uint8_t class_type, + uint32_t label); +struct pcep_ro_subobj_asn *pcep_obj_create_ro_subobj_asn(uint16_t asn); + +/* SR ERO and SR RRO creation functions for different NAI (Node/Adj ID) types. + * - The loose_hop is only used for sr ero and must always be false for sr rro. + * - The NAI value will be set internally, depending on which function is used. + * m_flag: + * - If this flag is true, the SID value represents an MPLS label stack + * entry as specified in [RFC3032]. Otherwise, the SID value is an + * administratively configured value which represents an index into + * an MPLS label space (either SRGB or SRLB) per [RFC8402]. + * c_flag: + * - If the M flag and the C flag are both true, then the TC, S, and TTL + * fields in the MPLS label stack entry are specified by the PCE. However, + * a PCC MAY choose to override these values according to its local policy + * and MPLS forwarding rules. + * - If the M flag is true but the C flag is false, then the TC, S, and TTL + * fields MUST be ignored by the PCC. + * - The PCC MUST set these fields according to its local policy and MPLS + * forwarding rules. + * - If the M flag is false then the C bit MUST be false. */ +struct pcep_ro_subobj_sr *pcep_obj_create_ro_subobj_sr_nonai(bool loose_hop, + uint32_t sid, + bool c_flag, + bool m_flag); + +/* The ipv4_node_id will be copied internally */ +struct pcep_ro_subobj_sr * +pcep_obj_create_ro_subobj_sr_ipv4_node(bool loose_hop, bool sid_absent, + bool c_flag, bool m_flag, uint32_t sid, + struct in_addr *ipv4_node_id); +/* The ipv6_node_id will be copied internally */ +struct pcep_ro_subobj_sr * +pcep_obj_create_ro_subobj_sr_ipv6_node(bool loose_hop, bool sid_absent, + bool c_flag, bool m_flag, uint32_t sid, + struct in6_addr *ipv6_node_id); +/* The local_ipv4 and remote_ipv4 will be copied internally */ +struct pcep_ro_subobj_sr *pcep_obj_create_ro_subobj_sr_ipv4_adj( + bool loose_hop, bool sid_absent, bool c_flag, bool m_flag, uint32_t sid, + struct in_addr *local_ipv4, struct in_addr *remote_ipv4); +/* The local_ipv6 and remote_ipv6 will be copied internally */ +struct pcep_ro_subobj_sr *pcep_obj_create_ro_subobj_sr_ipv6_adj( + bool loose_hop, bool sid_absent, bool c_flag, bool m_flag, uint32_t sid, + struct in6_addr *local_ipv6, struct in6_addr *remote_ipv6); +struct pcep_ro_subobj_sr *pcep_obj_create_ro_subobj_sr_unnumbered_ipv4_adj( + bool loose_hop, bool sid_absent, bool c_flag, bool m_flag, uint32_t sid, + uint32_t local_node_id, uint32_t local_if_id, uint32_t remote_node_id, + uint32_t remote_if_id); +/* The local_ipv6 and remote_ipv6 will be copied internally */ +struct pcep_ro_subobj_sr *pcep_obj_create_ro_subobj_sr_linklocal_ipv6_adj( + bool loose_hop, bool sid_absent, bool c_flag, bool m_flag, uint32_t sid, + struct in6_addr *local_ipv6, uint32_t local_if_id, + struct in6_addr *remote_ipv6, uint32_t remote_if_id); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/pceplib/pcep_msg_objects_encoding.c b/pceplib/pcep_msg_objects_encoding.c new file mode 100644 index 0000000000..c4089ba5ec --- /dev/null +++ b/pceplib/pcep_msg_objects_encoding.c @@ -0,0 +1,1720 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Brady Johnson <brady@voltanet.io> + * + */ + + +/* + * Encoding and decoding for PCEP Objects. + */ + +#include <stdlib.h> +#include <string.h> + +#include "pcep_msg_objects.h" +#include "pcep_msg_encoding.h" +#include "pcep_utils_logging.h" +#include "pcep_utils_memory.h" + +void write_object_header(struct pcep_object_header *object_hdr, + uint16_t object_length, uint8_t *buf); +void pcep_decode_object_hdr(const uint8_t *obj_buf, + struct pcep_object_header *obj_hdr); +void set_ro_subobj_fields(struct pcep_object_ro_subobj *subobj, bool flag_l, + uint8_t subobj_type); + +/* + * forward declarations for initialize_object_encoders() + */ +uint16_t pcep_encode_obj_open(struct pcep_object_header *obj, + struct pcep_versioning *versioning, uint8_t *buf); +uint16_t pcep_encode_obj_rp(struct pcep_object_header *obj, + struct pcep_versioning *versioning, uint8_t *buf); +uint16_t pcep_encode_obj_nopath(struct pcep_object_header *obj, + struct pcep_versioning *versioning, + uint8_t *buf); +uint16_t pcep_encode_obj_endpoints(struct pcep_object_header *obj, + struct pcep_versioning *versioning, + uint8_t *buf); +uint16_t pcep_encode_obj_association(struct pcep_object_header *obj, + struct pcep_versioning *versioning, + uint8_t *buf); +uint16_t pcep_encode_obj_bandwidth(struct pcep_object_header *obj, + struct pcep_versioning *versioning, + uint8_t *buf); +uint16_t pcep_encode_obj_metric(struct pcep_object_header *obj, + struct pcep_versioning *versioning, + uint8_t *buf); +uint16_t pcep_encode_obj_ro(struct pcep_object_header *obj, + struct pcep_versioning *versioning, uint8_t *buf); +uint16_t pcep_encode_obj_lspa(struct pcep_object_header *obj, + struct pcep_versioning *versioning, uint8_t *buf); +uint16_t pcep_encode_obj_svec(struct pcep_object_header *obj, + struct pcep_versioning *versioning, uint8_t *buf); +uint16_t pcep_encode_obj_notify(struct pcep_object_header *obj, + struct pcep_versioning *versioning, + uint8_t *buf); +uint16_t pcep_encode_obj_error(struct pcep_object_header *error, + struct pcep_versioning *versioning, + uint8_t *buf); +uint16_t pcep_encode_obj_close(struct pcep_object_header *close, + struct pcep_versioning *versioning, + uint8_t *buf); +uint16_t pcep_encode_obj_srp(struct pcep_object_header *obj, + struct pcep_versioning *versioning, uint8_t *buf); +uint16_t pcep_encode_obj_lsp(struct pcep_object_header *obj, + struct pcep_versioning *versioning, uint8_t *buf); +uint16_t pcep_encode_obj_vendor_info(struct pcep_object_header *obj, + struct pcep_versioning *versioning, + uint8_t *buf); +uint16_t pcep_encode_obj_inter_layer(struct pcep_object_header *obj, + struct pcep_versioning *versioning, + uint8_t *buf); +uint16_t pcep_encode_obj_switch_layer(struct pcep_object_header *obj, + struct pcep_versioning *versioning, + uint8_t *buf); +uint16_t pcep_encode_obj_req_adap_cap(struct pcep_object_header *obj, + struct pcep_versioning *versioning, + uint8_t *buf); +uint16_t pcep_encode_obj_server_ind(struct pcep_object_header *obj, + struct pcep_versioning *versioning, + uint8_t *buf); +uint16_t pcep_encode_obj_objective_function(struct pcep_object_header *obj, + struct pcep_versioning *versioning, + uint8_t *buf); +typedef uint16_t (*object_encoder_funcptr)(struct pcep_object_header *, + struct pcep_versioning *versioning, + uint8_t *buf); + +#define MAX_OBJECT_ENCODER_INDEX 64 + +#define PCEP_ENCODERS_ARGS \ + struct pcep_object_header *, struct pcep_versioning *versioning, \ + uint8_t *buf +uint16_t (*const object_encoders[MAX_OBJECT_ENCODER_INDEX])( + PCEP_ENCODERS_ARGS) = { + [PCEP_OBJ_CLASS_OPEN] = pcep_encode_obj_open, + [PCEP_OBJ_CLASS_RP] = pcep_encode_obj_rp, + [PCEP_OBJ_CLASS_NOPATH] = pcep_encode_obj_nopath, + [PCEP_OBJ_CLASS_ENDPOINTS] = pcep_encode_obj_endpoints, + [PCEP_OBJ_CLASS_BANDWIDTH] = pcep_encode_obj_bandwidth, + [PCEP_OBJ_CLASS_METRIC] = pcep_encode_obj_metric, + [PCEP_OBJ_CLASS_ERO] = pcep_encode_obj_ro, + [PCEP_OBJ_CLASS_RRO] = pcep_encode_obj_ro, + [PCEP_OBJ_CLASS_LSPA] = pcep_encode_obj_lspa, + [PCEP_OBJ_CLASS_IRO] = pcep_encode_obj_ro, + [PCEP_OBJ_CLASS_SVEC] = pcep_encode_obj_svec, + [PCEP_OBJ_CLASS_NOTF] = pcep_encode_obj_notify, + [PCEP_OBJ_CLASS_ERROR] = pcep_encode_obj_error, + [PCEP_OBJ_CLASS_CLOSE] = pcep_encode_obj_close, + [PCEP_OBJ_CLASS_LSP] = pcep_encode_obj_lsp, + [PCEP_OBJ_CLASS_SRP] = pcep_encode_obj_srp, + [PCEP_OBJ_CLASS_ASSOCIATION] = pcep_encode_obj_association, + [PCEP_OBJ_CLASS_INTER_LAYER] = pcep_encode_obj_inter_layer, + [PCEP_OBJ_CLASS_SWITCH_LAYER] = pcep_encode_obj_switch_layer, + [PCEP_OBJ_CLASS_REQ_ADAP_CAP] = pcep_encode_obj_req_adap_cap, + [PCEP_OBJ_CLASS_SERVER_IND] = pcep_encode_obj_server_ind, + [PCEP_OBJ_CLASS_VENDOR_INFO] = pcep_encode_obj_vendor_info, + [PCEP_OBJ_CLASS_OF] = pcep_encode_obj_objective_function, +}; +/* + * forward declarations for initialize_object_decoders() + */ +struct pcep_object_header *pcep_decode_obj_open(struct pcep_object_header *hdr, + const uint8_t *buf); +struct pcep_object_header *pcep_decode_obj_rp(struct pcep_object_header *hdr, + const uint8_t *buf); +struct pcep_object_header * +pcep_decode_obj_nopath(struct pcep_object_header *hdr, const uint8_t *buf); +struct pcep_object_header * +pcep_decode_obj_endpoints(struct pcep_object_header *hdr, const uint8_t *buf); +struct pcep_object_header * +pcep_decode_obj_association(struct pcep_object_header *hdr, const uint8_t *buf); +struct pcep_object_header * +pcep_decode_obj_bandwidth(struct pcep_object_header *hdr, const uint8_t *buf); +struct pcep_object_header * +pcep_decode_obj_metric(struct pcep_object_header *hdr, const uint8_t *buf); +struct pcep_object_header *pcep_decode_obj_ro(struct pcep_object_header *hdr, + const uint8_t *buf); +struct pcep_object_header *pcep_decode_obj_lspa(struct pcep_object_header *hdr, + const uint8_t *buf); +struct pcep_object_header *pcep_decode_obj_svec(struct pcep_object_header *hdr, + const uint8_t *buf); +struct pcep_object_header * +pcep_decode_obj_notify(struct pcep_object_header *hdr, const uint8_t *buf); +struct pcep_object_header *pcep_decode_obj_error(struct pcep_object_header *hdr, + const uint8_t *buf); +struct pcep_object_header *pcep_decode_obj_close(struct pcep_object_header *hdr, + const uint8_t *buf); +struct pcep_object_header *pcep_decode_obj_srp(struct pcep_object_header *hdr, + const uint8_t *buf); +struct pcep_object_header *pcep_decode_obj_lsp(struct pcep_object_header *hdr, + const uint8_t *buf); +struct pcep_object_header * +pcep_decode_obj_vendor_info(struct pcep_object_header *hdr, const uint8_t *buf); +struct pcep_object_header * +pcep_decode_obj_inter_layer(struct pcep_object_header *hdr, const uint8_t *buf); +struct pcep_object_header * +pcep_decode_obj_switch_layer(struct pcep_object_header *hdr, + const uint8_t *buf); +struct pcep_object_header * +pcep_decode_obj_req_adap_cap(struct pcep_object_header *hdr, + const uint8_t *buf); +struct pcep_object_header * +pcep_decode_obj_server_ind(struct pcep_object_header *hdr, const uint8_t *buf); +struct pcep_object_header * +pcep_decode_obj_objective_function(struct pcep_object_header *hdr, + const uint8_t *buf); +typedef struct pcep_object_header *(*object_decoder_funcptr)( + struct pcep_object_header *, const uint8_t *buf); + +#define PCEP_DECODERS_ARGS struct pcep_object_header *, const uint8_t *buf + +struct pcep_object_header *(*const object_decoders[MAX_OBJECT_ENCODER_INDEX])( + PCEP_DECODERS_ARGS) = { + [PCEP_OBJ_CLASS_OPEN] = pcep_decode_obj_open, + [PCEP_OBJ_CLASS_RP] = pcep_decode_obj_rp, + [PCEP_OBJ_CLASS_NOPATH] = pcep_decode_obj_nopath, + [PCEP_OBJ_CLASS_ENDPOINTS] = pcep_decode_obj_endpoints, + [PCEP_OBJ_CLASS_BANDWIDTH] = pcep_decode_obj_bandwidth, + [PCEP_OBJ_CLASS_METRIC] = pcep_decode_obj_metric, + [PCEP_OBJ_CLASS_ERO] = pcep_decode_obj_ro, + [PCEP_OBJ_CLASS_RRO] = pcep_decode_obj_ro, + [PCEP_OBJ_CLASS_LSPA] = pcep_decode_obj_lspa, + [PCEP_OBJ_CLASS_IRO] = pcep_decode_obj_ro, + [PCEP_OBJ_CLASS_SVEC] = pcep_decode_obj_svec, + [PCEP_OBJ_CLASS_NOTF] = pcep_decode_obj_notify, + [PCEP_OBJ_CLASS_ERROR] = pcep_decode_obj_error, + [PCEP_OBJ_CLASS_CLOSE] = pcep_decode_obj_close, + [PCEP_OBJ_CLASS_LSP] = pcep_decode_obj_lsp, + [PCEP_OBJ_CLASS_SRP] = pcep_decode_obj_srp, + [PCEP_OBJ_CLASS_ASSOCIATION] = pcep_decode_obj_association, + [PCEP_OBJ_CLASS_INTER_LAYER] = pcep_decode_obj_inter_layer, + [PCEP_OBJ_CLASS_SWITCH_LAYER] = pcep_decode_obj_switch_layer, + [PCEP_OBJ_CLASS_REQ_ADAP_CAP] = pcep_decode_obj_req_adap_cap, + [PCEP_OBJ_CLASS_SERVER_IND] = pcep_decode_obj_server_ind, + [PCEP_OBJ_CLASS_VENDOR_INFO] = pcep_decode_obj_vendor_info, + [PCEP_OBJ_CLASS_OF] = pcep_decode_obj_objective_function, +}; + +/* Object lengths, including the Object Header. + * Used by pcep_object_get_length() and pcep_object_has_tlvs() */ +static uint8_t pcep_object_class_lengths[] = { + 0, /* Object class 0 unused */ + 8, /* PCEP_OBJ_CLASS_OPEN = 1 */ + 12, /* PCEP_OBJ_CLASS_RP = 2 */ + 16, /* PCEP_OBJ_CLASS_NOPATH = 3, includes 8 for mandatory TLV */ + 0, /* PCEP_OBJ_CLASS_ENDPOINTS = 4, could be ipv4 or ipv6, setting to 0 + */ + 8, /* PCEP_OBJ_CLASS_BANDWIDTH = 5 */ + 12, /* PCEP_OBJ_CLASS_METRIC = 6 */ + 0, /* PCEP_OBJ_CLASS_ERO = 7, setting 0, ROs cannot have TLVs */ + 0, /* PCEP_OBJ_CLASS_RRO = 8, setting 0, ROs cannot have TLVs */ + 20, /* PCEP_OBJ_CLASS_LSPA = 9 */ + 0, /* PCEP_OBJ_CLASS_IRO = 10, setting 0, ROs cannot have TLVs */ + 0, /* PCEP_OBJ_CLASS_SVEC = 11, SVECs cannot have TLVs */ + 8, /* PCEP_OBJ_CLASS_NOTF = 12 */ + 8, /* PCEP_OBJ_CLASS_ERROR = 13 */ + 0, /* Object class 14 unused */ + 8, /* PCEP_OBJ_CLASS_CLOSE = 15 */ + 0, 0, 0, 0, 0, /* Object classes 16 - 20 are not used */ + 8, /* PCEP_OBJ_CLASS_OF = 21 */ + 0, 0, 0, 0, 0, /* Object classes 22 - 26 are not used */ + 0, 0, 0, 0, 0, /* Object classes 27 - 31 are not used */ + 8, /* PCEP_OBJ_CLASS_LSP = 32 */ + 12, /* PCEP_OBJ_CLASS_SRP = 33 */ + 12, /* PCEP_OBJ_CLASS_VENDOR_INFO = 34 */ + 0, /* Object class 35 unused */ + 0, /* PCEP_OBJ_CLASS_INTER_LAYER = 36, cannot have TLVs */ + 0, /* PCEP_OBJ_CLASS_SWITCH_LAYER = 37, cannot have TLVs */ + 0, /* PCEP_OBJ_CLASS_REQ_ADAP_CAP = 38, cannot have TLVs*/ + 8, /* PCEP_OBJ_CLASS_SERVER_IND = 39 */ + 0, /* PCEP_OBJ_CLASS_ASSOCIATION = 40, cannot have TLVs */ +}; + +/* + * The TLVs can have strange length values, since they do not include padding in + * the TLV header length, but that extra padding must be taken into account by + * the enclosing object by rounding up to the next 4 byte boundary. + * Example returned lengths: + * normalize_length(4) = 4, normalize_length(5) = 8, normalize_length(6) + * = 8, normalize_length(7) = 8, normalize_length(8) = 8 + * normalize_length(9) = 12, normalize_length(10) = 12, normalize_length(11) = + * 12, normalize_length(12) = 12, normalize_length(13) = 13... + */ +uint16_t normalize_pcep_tlv_length(uint16_t length) +{ + return (length % 4 == 0) ? length : (length + (4 - (length % 4))); +} + +/* + * Encoding functions + */ +uint16_t pcep_encode_object(struct pcep_object_header *object_hdr, + struct pcep_versioning *versioning, uint8_t *buf) +{ + + if (object_hdr->object_class >= MAX_OBJECT_ENCODER_INDEX) { + pcep_log(LOG_INFO, + "%s: Cannot encode unknown Object class [%d]", + __func__, object_hdr->object_class); + return 0; + } + + object_encoder_funcptr obj_encoder = + object_encoders[object_hdr->object_class]; + if (obj_encoder == NULL) { + pcep_log(LOG_INFO, + "%s: No object encoder found for Object class [%d]", + __func__, object_hdr->object_class); + return 0; + } + + uint16_t object_length = OBJECT_HEADER_LENGTH + + obj_encoder(object_hdr, versioning, + buf + OBJECT_HEADER_LENGTH); + double_linked_list_node *node = + (object_hdr->tlv_list == NULL ? NULL + : object_hdr->tlv_list->head); + for (; node != NULL; node = node->next_node) { + /* Returns the length of the TLV, including the TLV header */ + object_length += pcep_encode_tlv( + (struct pcep_object_tlv_header *)node->data, versioning, + buf + object_length); + } + object_length = normalize_pcep_tlv_length(object_length); + write_object_header(object_hdr, object_length, buf); + object_hdr->encoded_object = buf; + object_hdr->encoded_object_length = object_length; + + return object_length; +} + + +/* Object Header + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Object-Class | OT |Res|P|I| Object Length (bytes) | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | + * // (Object body) // + * | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + */ + +void write_object_header(struct pcep_object_header *object_hdr, + uint16_t object_length, uint8_t *buf) +{ + buf[0] = object_hdr->object_class; + buf[1] = ((object_hdr->object_type << 4) + | (object_hdr->flag_p ? OBJECT_HEADER_FLAG_P : 0x00) + | (object_hdr->flag_i ? OBJECT_HEADER_FLAG_I : 0x00)); + uint16_t net_order_length = htons(object_length); + memcpy(buf + 2, &net_order_length, sizeof(net_order_length)); +} + + +/* + * Functions to encode objects + * - they will be passed a pointer to a buffer to write the object body, + * which is past the object header. + * - they should return the object body length, not including the object header + * length. + */ + +uint16_t pcep_encode_obj_open(struct pcep_object_header *hdr, + struct pcep_versioning *versioning, + uint8_t *obj_body_buf) +{ + (void)versioning; + struct pcep_object_open *open = (struct pcep_object_open *)hdr; + obj_body_buf[0] = (open->open_version << 5) & 0xe0; + obj_body_buf[1] = open->open_keepalive; + obj_body_buf[2] = open->open_deadtimer; + obj_body_buf[3] = open->open_sid; + + return LENGTH_1WORD; +} + +uint16_t pcep_encode_obj_rp(struct pcep_object_header *hdr, + struct pcep_versioning *versioning, + uint8_t *obj_body_buf) +{ + (void)versioning; + struct pcep_object_rp *rp = (struct pcep_object_rp *)hdr; + obj_body_buf[3] = ((rp->flag_strict ? OBJECT_RP_FLAG_O : 0x00) + | (rp->flag_bidirectional ? OBJECT_RP_FLAG_B : 0x00) + | (rp->flag_reoptimization ? OBJECT_RP_FLAG_R : 0x00) + | (rp->flag_of ? OBJECT_RP_FLAG_OF : 0x00) + | (rp->priority & 0x07)); + uint32_t *uint32_ptr = (uint32_t *)(obj_body_buf + 4); + *uint32_ptr = htonl(rp->request_id); + + return LENGTH_2WORDS; +} + +uint16_t pcep_encode_obj_notify(struct pcep_object_header *hdr, + struct pcep_versioning *versioning, + uint8_t *obj_body_buf) +{ + (void)versioning; + struct pcep_object_notify *notify = (struct pcep_object_notify *)hdr; + obj_body_buf[2] = notify->notification_type; + obj_body_buf[3] = notify->notification_value; + + return LENGTH_1WORD; +} + +uint16_t pcep_encode_obj_nopath(struct pcep_object_header *hdr, + struct pcep_versioning *versioning, + uint8_t *obj_body_buf) +{ + (void)versioning; + struct pcep_object_nopath *nopath = (struct pcep_object_nopath *)hdr; + obj_body_buf[0] = nopath->ni; + obj_body_buf[1] = ((nopath->flag_c) ? OBJECT_NOPATH_FLAG_C : 0x00); + + return LENGTH_1WORD; +} + +uint16_t pcep_encode_obj_association(struct pcep_object_header *hdr, + struct pcep_versioning *versioning, + uint8_t *obj_body_buf) +{ + (void)versioning; + uint16_t *uint16_ptr = (uint16_t *)obj_body_buf; + uint32_t *uint32_ptr = (uint32_t *)obj_body_buf; + if (hdr->object_type == PCEP_OBJ_TYPE_ASSOCIATION_IPV4) { + struct pcep_object_association_ipv4 *ipv4 = + (struct pcep_object_association_ipv4 *)hdr; + obj_body_buf[3] = + (ipv4->R_flag ? OBJECT_ASSOCIATION_FLAG_R : 0x00); + uint16_ptr[2] = htons(ipv4->association_type); + uint16_ptr[3] = htons(ipv4->association_id); + uint32_ptr[2] = ipv4->src.s_addr; + + return LENGTH_3WORDS; + } else { + struct pcep_object_association_ipv6 *ipv6 = + (struct pcep_object_association_ipv6 *)hdr; + obj_body_buf[3] = + (ipv6->R_flag ? OBJECT_ASSOCIATION_FLAG_R : 0x00); + uint16_ptr[2] = htons(ipv6->association_type); + uint16_ptr[3] = htons(ipv6->association_id); + memcpy(uint32_ptr, &ipv6->src, sizeof(struct in6_addr)); + + return LENGTH_6WORDS; + } +} + +uint16_t pcep_encode_obj_endpoints(struct pcep_object_header *hdr, + struct pcep_versioning *versioning, + uint8_t *obj_body_buf) +{ + (void)versioning; + uint32_t *uint32_ptr = (uint32_t *)obj_body_buf; + if (hdr->object_type == PCEP_OBJ_TYPE_ENDPOINT_IPV4) { + struct pcep_object_endpoints_ipv4 *ipv4 = + (struct pcep_object_endpoints_ipv4 *)hdr; + uint32_ptr[0] = ipv4->src_ipv4.s_addr; + uint32_ptr[1] = ipv4->dst_ipv4.s_addr; + + return LENGTH_2WORDS; + } else { + struct pcep_object_endpoints_ipv6 *ipv6 = + (struct pcep_object_endpoints_ipv6 *)hdr; + memcpy(uint32_ptr, &ipv6->src_ipv6, sizeof(struct in6_addr)); + memcpy(&uint32_ptr[4], &ipv6->dst_ipv6, + sizeof(struct in6_addr)); + + return LENGTH_8WORDS; + } +} + +uint16_t pcep_encode_obj_bandwidth(struct pcep_object_header *hdr, + struct pcep_versioning *versioning, + uint8_t *obj_body_buf) +{ + (void)versioning; + struct pcep_object_bandwidth *bandwidth = + (struct pcep_object_bandwidth *)hdr; + uint32_t *uint32_ptr = (uint32_t *)obj_body_buf; + /* Seems like the compiler doesnt correctly copy the float, so memcpy() + * it */ + memcpy(uint32_ptr, &(bandwidth->bandwidth), sizeof(uint32_t)); + *uint32_ptr = htonl(*uint32_ptr); + + return LENGTH_1WORD; +} + +uint16_t pcep_encode_obj_metric(struct pcep_object_header *hdr, + struct pcep_versioning *versioning, + uint8_t *obj_body_buf) +{ + (void)versioning; + struct pcep_object_metric *metric = (struct pcep_object_metric *)hdr; + obj_body_buf[2] = ((metric->flag_c ? OBJECT_METRIC_FLAC_C : 0x00) + | (metric->flag_b ? OBJECT_METRIC_FLAC_B : 0x00)); + obj_body_buf[3] = metric->type; + uint32_t *uint32_ptr = (uint32_t *)(obj_body_buf + 4); + /* Seems like the compiler doesnt correctly copy the float, so memcpy() + * it */ + memcpy(uint32_ptr, &(metric->value), sizeof(uint32_t)); + *uint32_ptr = htonl(*uint32_ptr); + + return LENGTH_2WORDS; +} + +uint16_t pcep_encode_obj_lspa(struct pcep_object_header *hdr, + struct pcep_versioning *versioning, + uint8_t *obj_body_buf) +{ + (void)versioning; + struct pcep_object_lspa *lspa = (struct pcep_object_lspa *)hdr; + uint32_t *uint32_ptr = (uint32_t *)obj_body_buf; + uint32_ptr[0] = htonl(lspa->lspa_exclude_any); + uint32_ptr[1] = htonl(lspa->lspa_include_any); + uint32_ptr[2] = htonl(lspa->lspa_include_all); + obj_body_buf[12] = lspa->setup_priority; + obj_body_buf[13] = lspa->holding_priority; + obj_body_buf[14] = + (lspa->flag_local_protection ? OBJECT_LSPA_FLAG_L : 0x00); + + return LENGTH_4WORDS; +} + +uint16_t pcep_encode_obj_svec(struct pcep_object_header *hdr, + struct pcep_versioning *versioning, + uint8_t *obj_body_buf) +{ + (void)versioning; + struct pcep_object_svec *svec = (struct pcep_object_svec *)hdr; + obj_body_buf[3] = + ((svec->flag_srlg_diverse ? OBJECT_SVEC_FLAG_S : 0x00) + | (svec->flag_node_diverse ? OBJECT_SVEC_FLAG_N : 0x00) + | (svec->flag_link_diverse ? OBJECT_SVEC_FLAG_L : 0x00)); + + if (svec->request_id_list == NULL) { + return LENGTH_1WORD; + } + + int index = 1; + uint32_t *uint32_ptr = (uint32_t *)obj_body_buf; + double_linked_list_node *node = svec->request_id_list->head; + for (; node != NULL; node = node->next_node) { + uint32_ptr[index++] = htonl(*((uint32_t *)(node->data))); + } + + return LENGTH_1WORD + + (svec->request_id_list->num_entries * sizeof(uint32_t)); +} + +uint16_t pcep_encode_obj_error(struct pcep_object_header *hdr, + struct pcep_versioning *versioning, + uint8_t *obj_body_buf) +{ + (void)versioning; + struct pcep_object_error *error = (struct pcep_object_error *)hdr; + obj_body_buf[2] = error->error_type; + obj_body_buf[3] = error->error_value; + + return LENGTH_1WORD; +} + +uint16_t pcep_encode_obj_close(struct pcep_object_header *hdr, + struct pcep_versioning *versioning, + uint8_t *obj_body_buf) +{ + (void)versioning; + struct pcep_object_close *close = (struct pcep_object_close *)hdr; + obj_body_buf[3] = close->reason; + + return LENGTH_1WORD; +} + +uint16_t pcep_encode_obj_srp(struct pcep_object_header *hdr, + struct pcep_versioning *versioning, + uint8_t *obj_body_buf) +{ + (void)versioning; + struct pcep_object_srp *srp = (struct pcep_object_srp *)hdr; + obj_body_buf[3] = (srp->flag_lsp_remove ? OBJECT_SRP_FLAG_R : 0x00); + uint32_t *uint32_ptr = (uint32_t *)(obj_body_buf + 4); + *uint32_ptr = htonl(srp->srp_id_number); + + return LENGTH_2WORDS; +} + +uint16_t pcep_encode_obj_lsp(struct pcep_object_header *hdr, + struct pcep_versioning *versioning, + uint8_t *obj_body_buf) +{ + (void)versioning; + struct pcep_object_lsp *lsp = (struct pcep_object_lsp *)hdr; + uint32_t *uint32_ptr = (uint32_t *)obj_body_buf; + uint32_ptr[0] = htonl((lsp->plsp_id << 12) & 0xfffff000); + obj_body_buf[3] = ((lsp->flag_c ? OBJECT_LSP_FLAG_C : 0x00) + | ((lsp->operational_status << 4) & 0x70) + | (lsp->flag_a ? OBJECT_LSP_FLAG_A : 0x00) + | (lsp->flag_r ? OBJECT_LSP_FLAG_R : 0x00) + | (lsp->flag_s ? OBJECT_LSP_FLAG_S : 0x00) + | (lsp->flag_d ? OBJECT_LSP_FLAG_D : 0x00)); + + return LENGTH_1WORD; +} + +uint16_t pcep_encode_obj_vendor_info(struct pcep_object_header *hdr, + struct pcep_versioning *versioning, + uint8_t *obj_body_buf) +{ + (void)versioning; + struct pcep_object_vendor_info *obj = + (struct pcep_object_vendor_info *)hdr; + uint32_t *uint32_ptr = (uint32_t *)obj_body_buf; + uint32_ptr[0] = htonl(obj->enterprise_number); + uint32_ptr[1] = htonl(obj->enterprise_specific_info); + + return LENGTH_2WORDS; +} + +uint16_t pcep_encode_obj_inter_layer(struct pcep_object_header *hdr, + struct pcep_versioning *versioning, + uint8_t *obj_body_buf) +{ + (void)versioning; + struct pcep_object_inter_layer *obj = + (struct pcep_object_inter_layer *)hdr; + obj_body_buf[3] = ((obj->flag_i ? OBJECT_INTER_LAYER_FLAG_I : 0x00) + | (obj->flag_m ? OBJECT_INTER_LAYER_FLAG_M : 0x00) + | (obj->flag_t ? OBJECT_INTER_LAYER_FLAG_T : 0x00)); + + return LENGTH_1WORD; +} + +uint16_t pcep_encode_obj_switch_layer(struct pcep_object_header *hdr, + struct pcep_versioning *versioning, + uint8_t *obj_body_buf) +{ + (void)versioning; + struct pcep_object_switch_layer *obj = + (struct pcep_object_switch_layer *)hdr; + uint8_t buf_index = 0; + + double_linked_list_node *node = obj->switch_layer_rows->head; + while (node != NULL) { + struct pcep_object_switch_layer_row *row = node->data; + if (row == NULL) { + break; + } + + obj_body_buf[buf_index] = row->lsp_encoding_type; + obj_body_buf[buf_index + 1] = row->switching_type; + obj_body_buf[buf_index + 3] = + (row->flag_i ? OBJECT_SWITCH_LAYER_FLAG_I : 0x00); + + buf_index += LENGTH_1WORD; + } + + return buf_index; +} + +uint16_t pcep_encode_obj_req_adap_cap(struct pcep_object_header *hdr, + struct pcep_versioning *versioning, + uint8_t *obj_body_buf) +{ + (void)versioning; + struct pcep_object_req_adap_cap *obj = + (struct pcep_object_req_adap_cap *)hdr; + + obj_body_buf[0] = obj->switching_capability; + obj_body_buf[1] = obj->encoding; + + return LENGTH_1WORD; +} + +uint16_t pcep_encode_obj_server_ind(struct pcep_object_header *hdr, + struct pcep_versioning *versioning, + uint8_t *obj_body_buf) +{ + (void)versioning; + struct pcep_object_server_indication *obj = + (struct pcep_object_server_indication *)hdr; + + obj_body_buf[0] = obj->switching_capability; + obj_body_buf[1] = obj->encoding; + + return LENGTH_1WORD; +} + +uint16_t pcep_encode_obj_objective_function(struct pcep_object_header *hdr, + struct pcep_versioning *versioning, + uint8_t *obj_body_buf) +{ + (void)versioning; + struct pcep_object_objective_function *obj = + (struct pcep_object_objective_function *)hdr; + + uint16_t *uint16_ptr = (uint16_t *)obj_body_buf; + *uint16_ptr = htons(obj->of_code); + + return LENGTH_1WORD; +} + +uint16_t pcep_encode_obj_ro(struct pcep_object_header *hdr, + struct pcep_versioning *versioning, + uint8_t *obj_body_buf) +{ + (void)versioning; + struct pcep_object_ro *ro = (struct pcep_object_ro *)hdr; + if (ro == NULL || ro->sub_objects == NULL) { + return 0; + } + + /* RO Subobject format + * + * 0 1 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-------------//----------------+ + * |L| Type | Length | (Subobject contents) | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-------------//----------------+ + */ + + uint16_t index = 0; + double_linked_list_node *node = ro->sub_objects->head; + for (; node != NULL; node = node->next_node) { + struct pcep_object_ro_subobj *ro_subobj = node->data; + obj_body_buf[index++] = + ((ro_subobj->flag_subobj_loose_hop ? 0x80 : 0x00) + | (ro_subobj->ro_subobj_type)); + /* The length will be written below, depending on the subobj + * type */ + uint8_t *length_ptr = &(obj_body_buf[index++]); + uint32_t *uint32_ptr = (uint32_t *)(obj_body_buf + index); + + /* - The index has already been incremented past the header, + * and now points to the ro_subobj body. Below it just needs + * to be incremented past the body. + * + * - Each section below needs to write the total length, + * including the 2 byte subobj header. */ + + switch (ro_subobj->ro_subobj_type) { + case RO_SUBOBJ_TYPE_IPV4: { + struct pcep_ro_subobj_ipv4 *ipv4 = + (struct pcep_ro_subobj_ipv4 *)ro_subobj; + uint32_ptr[0] = ipv4->ip_addr.s_addr; + index += LENGTH_1WORD; + obj_body_buf[index++] = ipv4->prefix_length; + obj_body_buf[index++] = + (ipv4->flag_local_protection + ? OBJECT_SUBOBJ_IP_FLAG_LOCAL_PROT + : 0x00); + *length_ptr = LENGTH_2WORDS; + } break; + + case RO_SUBOBJ_TYPE_IPV6: { + struct pcep_ro_subobj_ipv6 *ipv6 = + (struct pcep_ro_subobj_ipv6 *)ro_subobj; + encode_ipv6(&ipv6->ip_addr, uint32_ptr); + index += LENGTH_4WORDS; + obj_body_buf[index++] = ipv6->prefix_length; + obj_body_buf[index++] = + (ipv6->flag_local_protection + ? OBJECT_SUBOBJ_IP_FLAG_LOCAL_PROT + : 0x00); + *length_ptr = LENGTH_5WORDS; + } break; + + case RO_SUBOBJ_TYPE_LABEL: { + struct pcep_ro_subobj_32label *label = + (struct pcep_ro_subobj_32label *)ro_subobj; + obj_body_buf[index++] = + (label->flag_global_label + ? OBJECT_SUBOBJ_LABEL_FLAG_GLOGAL + : 0x00); + obj_body_buf[index++] = label->class_type; + uint32_ptr = (uint32_t *)(obj_body_buf + index); + *uint32_ptr = htonl(label->label); + *length_ptr = LENGTH_2WORDS; + index += LENGTH_1WORD; + } break; + + case RO_SUBOBJ_TYPE_UNNUM: { + struct pcep_ro_subobj_unnum *unum = + (struct pcep_ro_subobj_unnum *)ro_subobj; + index += 2; /* increment past 2 reserved bytes */ + uint32_ptr = (uint32_t *)(obj_body_buf + index); + uint32_ptr[0] = unum->router_id.s_addr; + uint32_ptr[1] = htonl(unum->interface_id); + *length_ptr = LENGTH_3WORDS; + index += LENGTH_2WORDS; + } break; + + case RO_SUBOBJ_TYPE_ASN: { + struct pcep_ro_subobj_asn *asn = + (struct pcep_ro_subobj_asn *)ro_subobj; + uint16_t *uint16_ptr = + (uint16_t *)(obj_body_buf + index); + *uint16_ptr = htons(asn->asn); + *length_ptr = LENGTH_1WORD; + index += 2; + } break; + + case RO_SUBOBJ_TYPE_SR: { + /* SR-ERO subobject format + * + * 0 1 2 3 0 1 2 3 4 + * 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |L| Type=36 | Length | NT | Flags + * |F|S|C|M| + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | SID (optional) | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * // NAI (variable, optional) // + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + + struct pcep_ro_subobj_sr *sr_subobj = + (struct pcep_ro_subobj_sr *)ro_subobj; + obj_body_buf[index++] = + ((sr_subobj->nai_type << 4) & 0xf0); + obj_body_buf[index++] = + ((sr_subobj->flag_f ? OBJECT_SUBOBJ_SR_FLAG_F + : 0x00) + | (sr_subobj->flag_s ? OBJECT_SUBOBJ_SR_FLAG_S + : 0x00) + | (sr_subobj->flag_c ? OBJECT_SUBOBJ_SR_FLAG_C + : 0x00) + | (sr_subobj->flag_m ? OBJECT_SUBOBJ_SR_FLAG_M + : 0x00)); + uint32_ptr = (uint32_t *)(obj_body_buf + index); + /* Start with LENGTH_1WORD for the SubObj HDR + NT + + * Flags */ + uint8_t sr_base_length = LENGTH_1WORD; + /* If the sid_absent flag is true, then dont convert the + * sid */ + if (sr_subobj->flag_s == false) { + uint32_ptr[0] = htonl(sr_subobj->sid); + index += LENGTH_1WORD; + uint32_ptr = (uint32_t *)(obj_body_buf + index); + sr_base_length += LENGTH_1WORD; + } + + /* The lengths below need to include: + * - sr_base_length: set above to include SR SubObj Hdr + * and the SID if present + * - Number of bytes written to the NAI + * The index will only be incremented below by the + * number of bytes written to the NAI, since the RO SR + * subobj header and the SID have already been written. + */ + + double_linked_list_node *nai_node = + (sr_subobj->nai_list == NULL + ? NULL + : sr_subobj->nai_list->head); + if (nai_node == NULL) { + if (sr_subobj->nai_type + == PCEP_SR_SUBOBJ_NAI_ABSENT) { + *length_ptr = sr_base_length; + continue; + } else { + return 0; + } + } + switch (sr_subobj->nai_type) { + case PCEP_SR_SUBOBJ_NAI_IPV4_NODE: + uint32_ptr[0] = + ((struct in_addr *)nai_node->data) + ->s_addr; + *length_ptr = sr_base_length + LENGTH_1WORD; + index += LENGTH_1WORD; + break; + + case PCEP_SR_SUBOBJ_NAI_IPV6_NODE: + encode_ipv6((struct in6_addr *)nai_node->data, + uint32_ptr); + *length_ptr = sr_base_length + LENGTH_4WORDS; + index += LENGTH_4WORDS; + break; + + case PCEP_SR_SUBOBJ_NAI_UNNUMBERED_IPV4_ADJACENCY: + uint32_ptr[0] = + ((struct in_addr *)nai_node->data) + ->s_addr; + nai_node = nai_node->next_node; + uint32_ptr[1] = + ((struct in_addr *)nai_node->data) + ->s_addr; + nai_node = nai_node->next_node; + uint32_ptr[2] = + ((struct in_addr *)nai_node->data) + ->s_addr; + nai_node = nai_node->next_node; + uint32_ptr[3] = + ((struct in_addr *)nai_node->data) + ->s_addr; + *length_ptr = sr_base_length + LENGTH_4WORDS; + index += LENGTH_4WORDS; + break; + + case PCEP_SR_SUBOBJ_NAI_IPV4_ADJACENCY: + uint32_ptr[0] = + ((struct in_addr *)nai_node->data) + ->s_addr; + nai_node = nai_node->next_node; + uint32_ptr[1] = + ((struct in_addr *)nai_node->data) + ->s_addr; + *length_ptr = sr_base_length + LENGTH_2WORDS; + index += LENGTH_2WORDS; + break; + + case PCEP_SR_SUBOBJ_NAI_IPV6_ADJACENCY: + encode_ipv6((struct in6_addr *)nai_node->data, + uint32_ptr); + nai_node = nai_node->next_node; + encode_ipv6((struct in6_addr *)nai_node->data, + uint32_ptr + 4); + *length_ptr = sr_base_length + LENGTH_8WORDS; + index += LENGTH_8WORDS; + break; + + case PCEP_SR_SUBOBJ_NAI_LINK_LOCAL_IPV6_ADJACENCY: + encode_ipv6((struct in6_addr *)nai_node->data, + uint32_ptr); + nai_node = nai_node->next_node; + uint32_ptr[4] = + ((struct in_addr *)nai_node->data) + ->s_addr; + nai_node = nai_node->next_node; + encode_ipv6((struct in6_addr *)nai_node->data, + uint32_ptr + 5); + nai_node = nai_node->next_node; + uint32_ptr[9] = + ((struct in_addr *)nai_node->data) + ->s_addr; + *length_ptr = sr_base_length + LENGTH_10WORDS; + index += LENGTH_10WORDS; + break; + + default: + break; + } + } break; + + default: + break; + } + } + + return index; +} + +void encode_ipv6(struct in6_addr *src_ipv6, uint32_t *dst) +{ + memcpy(dst, src_ipv6, sizeof(struct in6_addr)); +} + +/* + * Decoding functions. + */ + +void pcep_decode_object_hdr(const uint8_t *obj_buf, + struct pcep_object_header *obj_hdr) +{ + memset(obj_hdr, 0, sizeof(struct pcep_object_header)); + + obj_hdr->object_class = obj_buf[0]; + obj_hdr->object_type = (obj_buf[1] >> 4) & 0x0f; + obj_hdr->flag_p = (obj_buf[1] & OBJECT_HEADER_FLAG_P); + obj_hdr->flag_i = (obj_buf[1] & OBJECT_HEADER_FLAG_I); + uint16_t net_order_length; + memcpy(&net_order_length, obj_buf + 2, sizeof(net_order_length)); + obj_hdr->encoded_object_length = ntohs(net_order_length); + obj_hdr->encoded_object = obj_buf; +} + +uint16_t pcep_object_get_length(enum pcep_object_classes object_class, + enum pcep_object_types object_type) +{ + uint8_t object_length = pcep_object_class_lengths[object_class]; + if (object_length == 0) { + if (object_class == PCEP_OBJ_CLASS_ENDPOINTS) { + if (object_type == PCEP_OBJ_TYPE_ENDPOINT_IPV4) { + return 12; + } else if (object_type == PCEP_OBJ_TYPE_ENDPOINT_IPV6) { + return 36; + } + } + + return 0; + } + + return object_length; +} + +uint16_t pcep_object_get_length_by_hdr(struct pcep_object_header *object_hdr) +{ + return (pcep_object_get_length(object_hdr->object_class, + object_hdr->object_type)); +} + +bool pcep_object_has_tlvs(struct pcep_object_header *object_hdr) +{ + uint8_t object_length = pcep_object_get_length_by_hdr(object_hdr); + if (object_length == 0) { + return false; + } + + return (object_hdr->encoded_object_length - object_length) > 0; +} + +struct pcep_object_header *pcep_decode_object(const uint8_t *obj_buf) +{ + + struct pcep_object_header object_hdr; + /* Only initializes and decodes the Object Header: class, type, flags, + * and length */ + pcep_decode_object_hdr(obj_buf, &object_hdr); + + if (object_hdr.object_class >= MAX_OBJECT_ENCODER_INDEX) { + pcep_log(LOG_INFO, + "%s: Cannot decode unknown Object class [%d]", + __func__, object_hdr.object_class); + return NULL; + } + + object_decoder_funcptr obj_decoder = + object_decoders[object_hdr.object_class]; + if (obj_decoder == NULL) { + pcep_log(LOG_INFO, + "%s: No object decoder found for Object class [%d]", + __func__, object_hdr.object_class); + return NULL; + } + + /* The object decoders will start decoding the object body, if + * anything from the header is needed, they have the object_hdr */ + struct pcep_object_header *object = + obj_decoder(&object_hdr, obj_buf + OBJECT_HEADER_LENGTH); + if (object == NULL) { + pcep_log(LOG_INFO, "%s: Unable to decode Object class [%d].", + __func__, object_hdr.object_class); + return NULL; + } + + if (pcep_object_has_tlvs(&object_hdr)) { + object->tlv_list = dll_initialize(); + int num_iterations = 0; + uint16_t tlv_index = pcep_object_get_length_by_hdr(&object_hdr); + while ((object->encoded_object_length - tlv_index) > 0 + && num_iterations++ < MAX_ITERATIONS) { + struct pcep_object_tlv_header *tlv = + pcep_decode_tlv(obj_buf + tlv_index); + if (tlv == NULL) { + /* TODO should we do anything else here ? */ + return object; + } + + /* The TLV length does not include the TLV header */ + tlv_index += normalize_pcep_tlv_length( + tlv->encoded_tlv_length + TLV_HEADER_LENGTH); + dll_append(object->tlv_list, tlv); + } + } + + return object; +} + +static struct pcep_object_header * +common_object_create(struct pcep_object_header *hdr, uint16_t new_obj_length) +{ + struct pcep_object_header *new_object = + pceplib_malloc(PCEPLIB_MESSAGES, new_obj_length); + memset(new_object, 0, new_obj_length); + memcpy(new_object, hdr, sizeof(struct pcep_object_header)); + + return new_object; +} + +/* + * Decoders + */ + +struct pcep_object_header *pcep_decode_obj_open(struct pcep_object_header *hdr, + const uint8_t *obj_buf) +{ + struct pcep_object_open *obj = + (struct pcep_object_open *)common_object_create( + hdr, sizeof(struct pcep_object_open)); + + obj->open_version = (obj_buf[0] >> 5) & 0x07; + obj->open_keepalive = obj_buf[1]; + obj->open_deadtimer = obj_buf[2]; + obj->open_sid = obj_buf[3]; + + return (struct pcep_object_header *)obj; +} + +struct pcep_object_header *pcep_decode_obj_rp(struct pcep_object_header *hdr, + const uint8_t *obj_buf) +{ + struct pcep_object_rp *obj = + (struct pcep_object_rp *)common_object_create( + hdr, sizeof(struct pcep_object_rp)); + + obj->flag_reoptimization = (obj_buf[3] & OBJECT_RP_FLAG_R); + obj->flag_bidirectional = (obj_buf[3] & OBJECT_RP_FLAG_B); + obj->flag_strict = (obj_buf[3] & OBJECT_RP_FLAG_O); + obj->flag_of = (obj_buf[3] & OBJECT_RP_FLAG_OF); + obj->priority = (obj_buf[3] & 0x07); + obj->request_id = ntohl(*((uint32_t *)(obj_buf + 4))); + + return (struct pcep_object_header *)obj; +} + +struct pcep_object_header * +pcep_decode_obj_notify(struct pcep_object_header *hdr, const uint8_t *obj_buf) +{ + struct pcep_object_notify *obj = + (struct pcep_object_notify *)common_object_create( + hdr, sizeof(struct pcep_object_notify)); + + obj->notification_type = obj_buf[2]; + obj->notification_value = obj_buf[3]; + + return (struct pcep_object_header *)obj; +} + +struct pcep_object_header * +pcep_decode_obj_nopath(struct pcep_object_header *hdr, const uint8_t *obj_buf) +{ + struct pcep_object_nopath *obj = + (struct pcep_object_nopath *)common_object_create( + hdr, sizeof(struct pcep_object_nopath)); + + obj->ni = (obj_buf[0] >> 1); + obj->flag_c = (obj_buf[0] & OBJECT_NOPATH_FLAG_C); + + return (struct pcep_object_header *)obj; +} + +struct pcep_object_header * +pcep_decode_obj_association(struct pcep_object_header *hdr, + const uint8_t *obj_buf) +{ + uint16_t *uint16_ptr = (uint16_t *)obj_buf; + uint32_t *uint32_ptr = (uint32_t *)obj_buf; + + if (hdr->object_type == PCEP_OBJ_TYPE_ASSOCIATION_IPV4) { + struct pcep_object_association_ipv4 *obj = + (struct pcep_object_association_ipv4 *) + common_object_create( + hdr, + sizeof(struct + pcep_object_association_ipv4)); + obj->R_flag = (obj_buf[3] & OBJECT_ASSOCIATION_FLAG_R); + obj->association_type = ntohs(uint16_ptr[2]); + obj->association_id = ntohs(uint16_ptr[3]); + obj->src.s_addr = uint32_ptr[2]; + + return (struct pcep_object_header *)obj; + } else if (hdr->object_type == PCEP_OBJ_TYPE_ENDPOINT_IPV6) { + struct pcep_object_association_ipv6 *obj = + (struct pcep_object_association_ipv6 *) + common_object_create( + hdr, + sizeof(struct + pcep_object_association_ipv6)); + + obj->R_flag = (obj_buf[3] & OBJECT_ASSOCIATION_FLAG_R); + obj->association_type = ntohs(uint16_ptr[2]); + obj->association_id = ntohs(uint16_ptr[3]); + memcpy(&obj->src, &uint32_ptr[2], sizeof(struct in6_addr)); + + return (struct pcep_object_header *)obj; + } + + return NULL; +} +struct pcep_object_header * +pcep_decode_obj_endpoints(struct pcep_object_header *hdr, + const uint8_t *obj_buf) +{ + uint32_t *uint32_ptr = (uint32_t *)obj_buf; + + if (hdr->object_type == PCEP_OBJ_TYPE_ENDPOINT_IPV4) { + struct pcep_object_endpoints_ipv4 *obj = + (struct pcep_object_endpoints_ipv4 *) + common_object_create( + hdr, + sizeof(struct + pcep_object_endpoints_ipv4)); + obj->src_ipv4.s_addr = uint32_ptr[0]; + obj->dst_ipv4.s_addr = uint32_ptr[1]; + + return (struct pcep_object_header *)obj; + } else if (hdr->object_type == PCEP_OBJ_TYPE_ENDPOINT_IPV6) { + struct pcep_object_endpoints_ipv6 *obj = + (struct pcep_object_endpoints_ipv6 *) + common_object_create( + hdr, + sizeof(struct + pcep_object_endpoints_ipv6)); + + memcpy(&obj->src_ipv6, &uint32_ptr[0], sizeof(struct in6_addr)); + memcpy(&obj->dst_ipv6, &uint32_ptr[4], sizeof(struct in6_addr)); + + return (struct pcep_object_header *)obj; + } + + return NULL; +} + +struct pcep_object_header * +pcep_decode_obj_bandwidth(struct pcep_object_header *hdr, + const uint8_t *obj_buf) +{ + struct pcep_object_bandwidth *obj = + (struct pcep_object_bandwidth *)common_object_create( + hdr, sizeof(struct pcep_object_bandwidth)); + + uint32_t value = ntohl(*((uint32_t *)obj_buf)); + /* Seems like the compiler doesnt correctly copy to the float, so + * memcpy() it */ + memcpy(&obj->bandwidth, &value, sizeof(uint32_t)); + + return (struct pcep_object_header *)obj; +} + +struct pcep_object_header * +pcep_decode_obj_metric(struct pcep_object_header *hdr, const uint8_t *obj_buf) +{ + struct pcep_object_metric *obj = + (struct pcep_object_metric *)common_object_create( + hdr, sizeof(struct pcep_object_metric)); + obj->flag_b = (obj_buf[2] & OBJECT_METRIC_FLAC_B); + obj->flag_c = (obj_buf[2] & OBJECT_METRIC_FLAC_C); + obj->type = obj_buf[3]; + uint32_t value = ntohl(*((uint32_t *)(obj_buf + 4))); + /* Seems like the compiler doesnt correctly copy to the float, so + * memcpy() it */ + memcpy(&obj->value, &value, sizeof(uint32_t)); + + return (struct pcep_object_header *)obj; +} + +struct pcep_object_header *pcep_decode_obj_lspa(struct pcep_object_header *hdr, + const uint8_t *obj_buf) +{ + struct pcep_object_lspa *obj = + (struct pcep_object_lspa *)common_object_create( + hdr, sizeof(struct pcep_object_lspa)); + uint32_t *uint32_ptr = (uint32_t *)obj_buf; + + obj->lspa_exclude_any = ntohl(uint32_ptr[0]); + obj->lspa_include_any = ntohl(uint32_ptr[1]); + obj->lspa_include_all = ntohl(uint32_ptr[2]); + obj->setup_priority = obj_buf[12]; + obj->holding_priority = obj_buf[13]; + obj->flag_local_protection = (obj_buf[14] & OBJECT_LSPA_FLAG_L); + + return (struct pcep_object_header *)obj; +} + +struct pcep_object_header *pcep_decode_obj_svec(struct pcep_object_header *hdr, + const uint8_t *obj_buf) +{ + struct pcep_object_svec *obj = + (struct pcep_object_svec *)common_object_create( + hdr, sizeof(struct pcep_object_svec)); + + obj->flag_link_diverse = (obj_buf[3] & OBJECT_SVEC_FLAG_L); + obj->flag_node_diverse = (obj_buf[3] & OBJECT_SVEC_FLAG_N); + obj->flag_srlg_diverse = (obj_buf[3] & OBJECT_SVEC_FLAG_S); + + if (hdr->encoded_object_length > LENGTH_2WORDS) { + obj->request_id_list = dll_initialize(); + uint16_t index = 1; + uint32_t *uint32_ptr = (uint32_t *)obj_buf; + for (; + index < ((hdr->encoded_object_length - LENGTH_2WORDS) / 4); + index++) { + uint32_t *req_id_ptr = pceplib_malloc(PCEPLIB_MESSAGES, + sizeof(uint32_t)); + *req_id_ptr = uint32_ptr[index]; + dll_append(obj->request_id_list, req_id_ptr); + } + } + + return (struct pcep_object_header *)obj; +} + +struct pcep_object_header *pcep_decode_obj_error(struct pcep_object_header *hdr, + const uint8_t *obj_buf) +{ + struct pcep_object_error *obj = + (struct pcep_object_error *)common_object_create( + hdr, sizeof(struct pcep_object_error)); + + obj->error_type = obj_buf[2]; + obj->error_value = obj_buf[3]; + + return (struct pcep_object_header *)obj; +} + +struct pcep_object_header *pcep_decode_obj_close(struct pcep_object_header *hdr, + const uint8_t *obj_buf) +{ + struct pcep_object_close *obj = + (struct pcep_object_close *)common_object_create( + hdr, sizeof(struct pcep_object_close)); + + obj->reason = obj_buf[3]; + + return (struct pcep_object_header *)obj; +} + +struct pcep_object_header *pcep_decode_obj_srp(struct pcep_object_header *hdr, + const uint8_t *obj_buf) +{ + struct pcep_object_srp *obj = + (struct pcep_object_srp *)common_object_create( + hdr, sizeof(struct pcep_object_srp)); + + obj->flag_lsp_remove = (obj_buf[3] & OBJECT_SRP_FLAG_R); + obj->srp_id_number = ntohl(*((uint32_t *)(obj_buf + 4))); + + return (struct pcep_object_header *)obj; +} + +struct pcep_object_header *pcep_decode_obj_lsp(struct pcep_object_header *hdr, + const uint8_t *obj_buf) +{ + struct pcep_object_lsp *obj = + (struct pcep_object_lsp *)common_object_create( + hdr, sizeof(struct pcep_object_lsp)); + + obj->flag_d = (obj_buf[3] & OBJECT_LSP_FLAG_D); + obj->flag_s = (obj_buf[3] & OBJECT_LSP_FLAG_S); + obj->flag_r = (obj_buf[3] & OBJECT_LSP_FLAG_R); + obj->flag_a = (obj_buf[3] & OBJECT_LSP_FLAG_A); + obj->flag_c = (obj_buf[3] & OBJECT_LSP_FLAG_C); + obj->operational_status = ((obj_buf[3] >> 4) & 0x07); + obj->plsp_id = ((ntohl(*((uint32_t *)obj_buf)) >> 12) & 0x000fffff); + + return (struct pcep_object_header *)obj; +} + +struct pcep_object_header * +pcep_decode_obj_vendor_info(struct pcep_object_header *hdr, + const uint8_t *obj_buf) +{ + struct pcep_object_vendor_info *obj = + (struct pcep_object_vendor_info *)common_object_create( + hdr, sizeof(struct pcep_object_vendor_info)); + obj->enterprise_number = ntohl(*((uint32_t *)(obj_buf))); + obj->enterprise_specific_info = ntohl(*((uint32_t *)(obj_buf + 4))); + + return (struct pcep_object_header *)obj; +} + +struct pcep_object_header * +pcep_decode_obj_inter_layer(struct pcep_object_header *hdr, + const uint8_t *obj_buf) +{ + struct pcep_object_inter_layer *obj = + (struct pcep_object_inter_layer *)common_object_create( + hdr, sizeof(struct pcep_object_inter_layer)); + obj->flag_t = (obj_buf[3] & OBJECT_INTER_LAYER_FLAG_T); + obj->flag_m = (obj_buf[3] & OBJECT_INTER_LAYER_FLAG_M); + obj->flag_i = (obj_buf[3] & OBJECT_INTER_LAYER_FLAG_I); + + return (struct pcep_object_header *)obj; +} + +struct pcep_object_header * +pcep_decode_obj_switch_layer(struct pcep_object_header *hdr, + const uint8_t *obj_buf) +{ + struct pcep_object_switch_layer *obj = + (struct pcep_object_switch_layer *)common_object_create( + hdr, sizeof(struct pcep_object_switch_layer)); + obj->switch_layer_rows = dll_initialize(); + int num_rows = ((hdr->encoded_object_length - 4) / 4); + uint8_t buf_index = 0; + + int i = 0; + for (; i < num_rows; i++) { + struct pcep_object_switch_layer_row *row = pceplib_malloc( + PCEPLIB_MESSAGES, + sizeof(struct pcep_object_switch_layer_row)); + row->lsp_encoding_type = obj_buf[buf_index]; + row->switching_type = obj_buf[buf_index + 1]; + row->flag_i = + (obj_buf[buf_index + 3] & OBJECT_SWITCH_LAYER_FLAG_I); + dll_append(obj->switch_layer_rows, row); + + buf_index += LENGTH_1WORD; + } + + return (struct pcep_object_header *)obj; +} + +struct pcep_object_header * +pcep_decode_obj_req_adap_cap(struct pcep_object_header *hdr, + const uint8_t *obj_buf) +{ + struct pcep_object_req_adap_cap *obj = + (struct pcep_object_req_adap_cap *)common_object_create( + hdr, sizeof(struct pcep_object_req_adap_cap)); + + obj->switching_capability = obj_buf[0]; + obj->encoding = obj_buf[1]; + + return (struct pcep_object_header *)obj; +} + +struct pcep_object_header * +pcep_decode_obj_server_ind(struct pcep_object_header *hdr, + const uint8_t *obj_buf) +{ + struct pcep_object_server_indication *obj = + (struct pcep_object_server_indication *)common_object_create( + hdr, sizeof(struct pcep_object_server_indication)); + + obj->switching_capability = obj_buf[0]; + obj->encoding = obj_buf[1]; + + return (struct pcep_object_header *)obj; +} + +struct pcep_object_header * +pcep_decode_obj_objective_function(struct pcep_object_header *hdr, + const uint8_t *obj_buf) +{ + struct pcep_object_objective_function *obj = + (struct pcep_object_objective_function *)common_object_create( + hdr, sizeof(struct pcep_object_objective_function)); + + uint16_t *uint16_ptr = (uint16_t *)obj_buf; + obj->of_code = ntohs(*uint16_ptr); + + return (struct pcep_object_header *)obj; +} + +void set_ro_subobj_fields(struct pcep_object_ro_subobj *subobj, bool flag_l, + uint8_t subobj_type) +{ + subobj->flag_subobj_loose_hop = flag_l; + subobj->ro_subobj_type = subobj_type; +} + +void decode_ipv6(const uint32_t *src, struct in6_addr *dst_ipv6) +{ + memcpy(dst_ipv6, src, sizeof(struct in6_addr)); +} +struct pcep_object_header *pcep_decode_obj_ro(struct pcep_object_header *hdr, + const uint8_t *obj_buf) +{ + struct pcep_object_ro *obj = + (struct pcep_object_ro *)common_object_create( + hdr, sizeof(struct pcep_object_ro)); + obj->sub_objects = dll_initialize(); + + /* RO Subobject format + * + * 0 1 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-------------//----------------+ + * |L| Type | Length | (Subobject contents) | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-------------//----------------+ + */ + + uint16_t read_count = 0; + int num_sub_objects = 1; + uint32_t *uint32_ptr; + uint16_t obj_body_length = + hdr->encoded_object_length - OBJECT_HEADER_LENGTH; + + while ((obj_body_length - read_count) > OBJECT_RO_SUBOBJ_HEADER_LENGTH + && num_sub_objects < MAX_ITERATIONS) { + num_sub_objects++; + /* Read the Sub-Object Header */ + bool flag_l = (obj_buf[read_count] & 0x80); + uint8_t subobj_type = (obj_buf[read_count++] & 0x7f); + uint8_t subobj_length = obj_buf[read_count++]; + + if (subobj_length <= OBJECT_RO_SUBOBJ_HEADER_LENGTH) { + pcep_log(LOG_INFO, + "%s: Invalid ro subobj type [%d] length [%d]", + __func__, subobj_type, subobj_length); + pceplib_free(PCEPLIB_MESSAGES, obj); + return NULL; + } + + switch (subobj_type) { + case RO_SUBOBJ_TYPE_IPV4: { + struct pcep_ro_subobj_ipv4 *ipv4 = pceplib_malloc( + PCEPLIB_MESSAGES, + sizeof(struct pcep_ro_subobj_ipv4)); + ipv4->ro_subobj.flag_subobj_loose_hop = flag_l; + ipv4->ro_subobj.ro_subobj_type = subobj_type; + uint32_ptr = (uint32_t *)(obj_buf + read_count); + ipv4->ip_addr.s_addr = *uint32_ptr; + read_count += LENGTH_1WORD; + ipv4->prefix_length = obj_buf[read_count++]; + ipv4->flag_local_protection = + (obj_buf[read_count++] + & OBJECT_SUBOBJ_IP_FLAG_LOCAL_PROT); + + dll_append(obj->sub_objects, ipv4); + } break; + + case RO_SUBOBJ_TYPE_IPV6: { + struct pcep_ro_subobj_ipv6 *ipv6 = pceplib_malloc( + PCEPLIB_MESSAGES, + sizeof(struct pcep_ro_subobj_ipv6)); + ipv6->ro_subobj.flag_subobj_loose_hop = flag_l; + ipv6->ro_subobj.ro_subobj_type = subobj_type; + decode_ipv6((uint32_t *)obj_buf, &ipv6->ip_addr); + read_count += LENGTH_4WORDS; + ipv6->prefix_length = obj_buf[read_count++]; + ipv6->flag_local_protection = + (obj_buf[read_count++] + & OBJECT_SUBOBJ_IP_FLAG_LOCAL_PROT); + + dll_append(obj->sub_objects, ipv6); + } break; + + case RO_SUBOBJ_TYPE_LABEL: { + struct pcep_ro_subobj_32label *label = pceplib_malloc( + PCEPLIB_MESSAGES, + sizeof(struct pcep_ro_subobj_32label)); + label->ro_subobj.flag_subobj_loose_hop = flag_l; + label->ro_subobj.ro_subobj_type = subobj_type; + label->flag_global_label = + (obj_buf[read_count++] + & OBJECT_SUBOBJ_LABEL_FLAG_GLOGAL); + label->class_type = obj_buf[read_count++]; + label->label = ntohl(obj_buf[read_count]); + read_count += LENGTH_1WORD; + + dll_append(obj->sub_objects, label); + } break; + + case RO_SUBOBJ_TYPE_UNNUM: { + struct pcep_ro_subobj_unnum *unum = pceplib_malloc( + PCEPLIB_MESSAGES, + sizeof(struct pcep_ro_subobj_unnum)); + unum->ro_subobj.flag_subobj_loose_hop = flag_l; + unum->ro_subobj.ro_subobj_type = subobj_type; + set_ro_subobj_fields( + (struct pcep_object_ro_subobj *)unum, flag_l, + subobj_type); + uint32_ptr = (uint32_t *)(obj_buf + read_count); + unum->interface_id = ntohl(uint32_ptr[0]); + unum->router_id.s_addr = uint32_ptr[1]; + read_count += 2; + + dll_append(obj->sub_objects, unum); + } break; + + case RO_SUBOBJ_TYPE_ASN: { + struct pcep_ro_subobj_asn *asn = pceplib_malloc( + PCEPLIB_MESSAGES, + sizeof(struct pcep_ro_subobj_asn)); + asn->ro_subobj.flag_subobj_loose_hop = flag_l; + asn->ro_subobj.ro_subobj_type = subobj_type; + uint16_t *uint16_ptr = + (uint16_t *)(obj_buf + read_count); + asn->asn = ntohs(*uint16_ptr); + read_count += 2; + + dll_append(obj->sub_objects, asn); + } break; + + case RO_SUBOBJ_TYPE_SR: { + /* SR-ERO subobject format + * + * 0 1 2 3 0 1 2 3 4 + * 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |L| Type=36 | Length | NT | Flags + * |F|S|C|M| + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | SID (optional) | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * // NAI (variable, optional) // + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + + struct pcep_ro_subobj_sr *sr_subobj = pceplib_malloc( + PCEPLIB_MESSAGES, + sizeof(struct pcep_ro_subobj_sr)); + sr_subobj->ro_subobj.flag_subobj_loose_hop = flag_l; + sr_subobj->ro_subobj.ro_subobj_type = subobj_type; + dll_append(obj->sub_objects, sr_subobj); + + sr_subobj->nai_list = dll_initialize(); + sr_subobj->nai_type = + ((obj_buf[read_count++] >> 4) & 0x0f); + sr_subobj->flag_f = + (obj_buf[read_count] & OBJECT_SUBOBJ_SR_FLAG_F); + sr_subobj->flag_s = + (obj_buf[read_count] & OBJECT_SUBOBJ_SR_FLAG_S); + sr_subobj->flag_c = + (obj_buf[read_count] & OBJECT_SUBOBJ_SR_FLAG_C); + sr_subobj->flag_m = + (obj_buf[read_count] & OBJECT_SUBOBJ_SR_FLAG_M); + read_count++; + + /* If the sid_absent flag is true, then dont decode the + * sid */ + uint32_ptr = (uint32_t *)(obj_buf + read_count); + if (sr_subobj->flag_s == false) { + sr_subobj->sid = ntohl(*uint32_ptr); + read_count += LENGTH_1WORD; + uint32_ptr += 1; + } + + switch (sr_subobj->nai_type) { + case PCEP_SR_SUBOBJ_NAI_IPV4_NODE: { + struct in_addr *ipv4 = + pceplib_malloc(PCEPLIB_MESSAGES, + sizeof(struct in_addr)); + ipv4->s_addr = *uint32_ptr; + dll_append(sr_subobj->nai_list, ipv4); + read_count += LENGTH_1WORD; + } break; + + case PCEP_SR_SUBOBJ_NAI_IPV6_NODE: { + struct in6_addr *ipv6 = + pceplib_malloc(PCEPLIB_MESSAGES, + sizeof(struct in6_addr)); + decode_ipv6(uint32_ptr, ipv6); + dll_append(sr_subobj->nai_list, ipv6); + read_count += LENGTH_4WORDS; + } break; + + case PCEP_SR_SUBOBJ_NAI_UNNUMBERED_IPV4_ADJACENCY: { + struct in_addr *ipv4 = + pceplib_malloc(PCEPLIB_MESSAGES, + sizeof(struct in_addr)); + ipv4->s_addr = uint32_ptr[0]; + dll_append(sr_subobj->nai_list, ipv4); + + ipv4 = pceplib_malloc(PCEPLIB_MESSAGES, + sizeof(struct in_addr)); + ipv4->s_addr = uint32_ptr[1]; + dll_append(sr_subobj->nai_list, ipv4); + + ipv4 = pceplib_malloc(PCEPLIB_MESSAGES, + sizeof(struct in_addr)); + ipv4->s_addr = uint32_ptr[2]; + dll_append(sr_subobj->nai_list, ipv4); + + ipv4 = pceplib_malloc(PCEPLIB_MESSAGES, + sizeof(struct in_addr)); + ipv4->s_addr = uint32_ptr[3]; + dll_append(sr_subobj->nai_list, ipv4); + + read_count += LENGTH_4WORDS; + } break; + + case PCEP_SR_SUBOBJ_NAI_IPV4_ADJACENCY: { + struct in_addr *ipv4 = + pceplib_malloc(PCEPLIB_MESSAGES, + sizeof(struct in_addr)); + ipv4->s_addr = uint32_ptr[0]; + dll_append(sr_subobj->nai_list, ipv4); + + ipv4 = pceplib_malloc(PCEPLIB_MESSAGES, + sizeof(struct in_addr)); + ipv4->s_addr = uint32_ptr[1]; + dll_append(sr_subobj->nai_list, ipv4); + + read_count += LENGTH_2WORDS; + } break; + + case PCEP_SR_SUBOBJ_NAI_IPV6_ADJACENCY: { + struct in6_addr *ipv6 = + pceplib_malloc(PCEPLIB_MESSAGES, + sizeof(struct in6_addr)); + decode_ipv6(uint32_ptr, ipv6); + dll_append(sr_subobj->nai_list, ipv6); + + ipv6 = pceplib_malloc(PCEPLIB_MESSAGES, + sizeof(struct in6_addr)); + decode_ipv6(uint32_ptr + 4, ipv6); + dll_append(sr_subobj->nai_list, ipv6); + + read_count += LENGTH_8WORDS; + } break; + + case PCEP_SR_SUBOBJ_NAI_LINK_LOCAL_IPV6_ADJACENCY: { + struct in6_addr *ipv6 = + pceplib_malloc(PCEPLIB_MESSAGES, + sizeof(struct in6_addr)); + decode_ipv6(uint32_ptr, ipv6); + dll_append(sr_subobj->nai_list, ipv6); + + struct in_addr *ipv4 = + pceplib_malloc(PCEPLIB_MESSAGES, + sizeof(struct in_addr)); + 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 + 5, ipv6); + dll_append(sr_subobj->nai_list, ipv6); + + ipv4 = pceplib_malloc(PCEPLIB_MESSAGES, + sizeof(struct in_addr)); + ipv4->s_addr = uint32_ptr[9]; + dll_append(sr_subobj->nai_list, ipv4); + + read_count += LENGTH_10WORDS; + } break; + + case PCEP_SR_SUBOBJ_NAI_ABSENT: + default: + break; + } + } break; + + default: + pcep_log( + LOG_INFO, + "%s: pcep_decode_obj_ro skipping unrecognized sub-object type [%d]", + __func__, subobj_type); + read_count += subobj_length; + break; + } + } + + return (struct pcep_object_header *)obj; +} diff --git a/pceplib/pcep_msg_tlvs.c b/pceplib/pcep_msg_tlvs.c new file mode 100644 index 0000000000..9c84e71ee1 --- /dev/null +++ b/pceplib/pcep_msg_tlvs.c @@ -0,0 +1,464 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Brady Johnson <brady@voltanet.io> + * + */ + + +/* + * This is the implementation of a High Level PCEP message object TLV API. + */ + +#include <stdbool.h> +#include <stdint.h> +#include <string.h> +#include <unistd.h> + +#include "pcep_msg_tlvs.h" +#include "pcep_msg_encoding.h" +#include "pcep_utils_memory.h" + +static struct pcep_object_tlv_header * +pcep_tlv_common_create(enum pcep_object_tlv_types type, uint16_t size) +{ + struct pcep_object_tlv_header *tlv = + pceplib_malloc(PCEPLIB_MESSAGES, size); + memset(tlv, 0, size); + tlv->type = type; + + return tlv; +} + +/* + * Open Object TLVs + */ + +struct pcep_object_tlv_stateful_pce_capability * +pcep_tlv_create_stateful_pce_capability( + bool flag_u_lsp_update_capability, bool flag_s_include_db_version, + bool flag_i_lsp_instantiation_capability, bool flag_t_triggered_resync, + bool flag_d_delta_lsp_sync, bool flag_f_triggered_initial_sync) +{ + struct pcep_object_tlv_stateful_pce_capability *tlv = + (struct pcep_object_tlv_stateful_pce_capability *) + pcep_tlv_common_create( + PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY, + sizeof(struct + pcep_object_tlv_stateful_pce_capability)); + tlv->flag_u_lsp_update_capability = flag_u_lsp_update_capability; + tlv->flag_s_include_db_version = flag_s_include_db_version; + tlv->flag_i_lsp_instantiation_capability = + flag_i_lsp_instantiation_capability; + tlv->flag_t_triggered_resync = flag_t_triggered_resync; + tlv->flag_d_delta_lsp_sync = flag_d_delta_lsp_sync; + tlv->flag_f_triggered_initial_sync = flag_f_triggered_initial_sync; + + return tlv; +} + +struct pcep_object_tlv_lsp_db_version * +pcep_tlv_create_lsp_db_version(uint64_t lsp_db_version) +{ + struct pcep_object_tlv_lsp_db_version *tlv = + (struct pcep_object_tlv_lsp_db_version *)pcep_tlv_common_create( + PCEP_OBJ_TLV_TYPE_LSP_DB_VERSION, + sizeof(struct pcep_object_tlv_lsp_db_version)); + tlv->lsp_db_version = lsp_db_version; + + return tlv; +} + +struct pcep_object_tlv_speaker_entity_identifier * +pcep_tlv_create_speaker_entity_id(double_linked_list *speaker_entity_id_list) +{ + if (speaker_entity_id_list == NULL) { + return NULL; + } + + if (speaker_entity_id_list->num_entries == 0) { + return NULL; + } + + struct pcep_object_tlv_speaker_entity_identifier *tlv = + (struct pcep_object_tlv_speaker_entity_identifier *) + pcep_tlv_common_create( + PCEP_OBJ_TLV_TYPE_SPEAKER_ENTITY_ID, + sizeof(struct + pcep_object_tlv_speaker_entity_identifier)); + tlv->speaker_entity_id_list = speaker_entity_id_list; + + return tlv; +} + +struct pcep_object_tlv_path_setup_type * +pcep_tlv_create_path_setup_type(uint8_t pst) +{ + struct pcep_object_tlv_path_setup_type *tlv = + (struct pcep_object_tlv_path_setup_type *) + pcep_tlv_common_create( + PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE, + sizeof(struct pcep_object_tlv_path_setup_type)); + tlv->path_setup_type = pst; + + return tlv; +} + +struct pcep_object_tlv_path_setup_type_capability * +pcep_tlv_create_path_setup_type_capability(double_linked_list *pst_list, + double_linked_list *sub_tlv_list) +{ + if (pst_list == NULL) { + return NULL; + } + + if (pst_list->num_entries == 0) { + return NULL; + } + + struct pcep_object_tlv_path_setup_type_capability *tlv = + (struct pcep_object_tlv_path_setup_type_capability *) + pcep_tlv_common_create( + PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE_CAPABILITY, + sizeof(struct + pcep_object_tlv_path_setup_type_capability)); + + tlv->pst_list = pst_list; + tlv->sub_tlv_list = sub_tlv_list; + + return tlv; +} + +struct pcep_object_tlv_sr_pce_capability * +pcep_tlv_create_sr_pce_capability(bool flag_n, bool flag_x, + uint8_t max_sid_depth) +{ + struct pcep_object_tlv_sr_pce_capability *tlv = + (struct pcep_object_tlv_sr_pce_capability *) + pcep_tlv_common_create( + PCEP_OBJ_TLV_TYPE_SR_PCE_CAPABILITY, + sizeof(struct + pcep_object_tlv_sr_pce_capability)); + tlv->flag_n = flag_n; + tlv->flag_x = flag_x; + tlv->max_sid_depth = max_sid_depth; + + return tlv; +} + +struct pcep_object_tlv_of_list * +pcep_tlv_create_of_list(double_linked_list *of_list) +{ + if (of_list == NULL) { + return NULL; + } + + struct pcep_object_tlv_of_list *tlv = + (struct pcep_object_tlv_of_list *)pcep_tlv_common_create( + PCEP_OBJ_TLV_TYPE_OBJECTIVE_FUNCTION_LIST, + sizeof(struct pcep_object_tlv_of_list)); + + tlv->of_list = of_list; + + return tlv; +} + +/* + * LSP Object TLVs + */ + +struct pcep_object_tlv_ipv4_lsp_identifier * +pcep_tlv_create_ipv4_lsp_identifiers(struct in_addr *ipv4_tunnel_sender, + struct in_addr *ipv4_tunnel_endpoint, + uint16_t lsp_id, uint16_t tunnel_id, + struct in_addr *extended_tunnel_id) +{ + if (ipv4_tunnel_sender == NULL || ipv4_tunnel_endpoint == NULL) { + return NULL; + } + + struct pcep_object_tlv_ipv4_lsp_identifier *tlv = + (struct pcep_object_tlv_ipv4_lsp_identifier *) + pcep_tlv_common_create( + PCEP_OBJ_TLV_TYPE_IPV4_LSP_IDENTIFIERS, + sizeof(struct + pcep_object_tlv_ipv4_lsp_identifier)); + tlv->ipv4_tunnel_sender.s_addr = ipv4_tunnel_sender->s_addr; + tlv->ipv4_tunnel_endpoint.s_addr = ipv4_tunnel_endpoint->s_addr; + tlv->lsp_id = lsp_id; + tlv->tunnel_id = tunnel_id; + tlv->extended_tunnel_id.s_addr = + (extended_tunnel_id == NULL ? INADDR_ANY + : extended_tunnel_id->s_addr); + + return tlv; +} + +struct pcep_object_tlv_ipv6_lsp_identifier * +pcep_tlv_create_ipv6_lsp_identifiers(struct in6_addr *ipv6_tunnel_sender, + struct in6_addr *ipv6_tunnel_endpoint, + uint16_t lsp_id, uint16_t tunnel_id, + struct in6_addr *extended_tunnel_id) +{ + if (ipv6_tunnel_sender == NULL || ipv6_tunnel_endpoint == NULL) { + return NULL; + } + + struct pcep_object_tlv_ipv6_lsp_identifier *tlv = + (struct pcep_object_tlv_ipv6_lsp_identifier *) + pcep_tlv_common_create( + PCEP_OBJ_TLV_TYPE_IPV6_LSP_IDENTIFIERS, + sizeof(struct + pcep_object_tlv_ipv6_lsp_identifier)); + + memcpy(&tlv->ipv6_tunnel_sender, ipv6_tunnel_sender, + sizeof(struct in6_addr)); + + tlv->tunnel_id = tunnel_id; + tlv->lsp_id = lsp_id; + + memcpy(&tlv->extended_tunnel_id, extended_tunnel_id, + sizeof(struct in6_addr)); + + memcpy(&tlv->ipv6_tunnel_endpoint, ipv6_tunnel_endpoint, + sizeof(struct in6_addr)); + + return tlv; +} + +struct pcep_object_tlv_symbolic_path_name * +pcep_tlv_create_symbolic_path_name(const char *symbolic_path_name, + uint16_t symbolic_path_name_length) +{ + /* symbolic_path_name_length should NOT include the null terminator and + * cannot be zero */ + if (symbolic_path_name == NULL || symbolic_path_name_length == 0) { + return NULL; + } + + struct pcep_object_tlv_symbolic_path_name *tlv = + (struct pcep_object_tlv_symbolic_path_name *) + pcep_tlv_common_create( + PCEP_OBJ_TLV_TYPE_SYMBOLIC_PATH_NAME, + sizeof(struct + pcep_object_tlv_symbolic_path_name)); + + uint16_t length = (symbolic_path_name_length > MAX_SYMBOLIC_PATH_NAME) + ? MAX_SYMBOLIC_PATH_NAME + : symbolic_path_name_length; + memcpy(tlv->symbolic_path_name, symbolic_path_name, length); + tlv->symbolic_path_name_length = length; + + return tlv; +} + +struct pcep_object_tlv_lsp_error_code * +pcep_tlv_create_lsp_error_code(enum pcep_tlv_lsp_error_codes lsp_error_code) +{ + struct pcep_object_tlv_lsp_error_code *tlv = + (struct pcep_object_tlv_lsp_error_code *)pcep_tlv_common_create( + PCEP_OBJ_TLV_TYPE_LSP_ERROR_CODE, + sizeof(struct pcep_object_tlv_lsp_error_code)); + tlv->lsp_error_code = lsp_error_code; + + return tlv; +} + +struct pcep_object_tlv_rsvp_error_spec * +pcep_tlv_create_rsvp_ipv4_error_spec(struct in_addr *error_node_ip, + uint8_t error_code, uint16_t error_value) +{ + if (error_node_ip == NULL) { + return NULL; + } + + struct pcep_object_tlv_rsvp_error_spec *tlv = + (struct pcep_object_tlv_rsvp_error_spec *) + pcep_tlv_common_create( + PCEP_OBJ_TLV_TYPE_RSVP_ERROR_SPEC, + sizeof(struct pcep_object_tlv_rsvp_error_spec)); + + tlv->c_type = RSVP_ERROR_SPEC_IPV4_CTYPE; + tlv->class_num = RSVP_ERROR_SPEC_CLASS_NUM; + tlv->error_code = error_code; + tlv->error_value = error_value; + tlv->error_spec_ip.ipv4_error_node_address.s_addr = + error_node_ip->s_addr; + + return tlv; +} + +struct pcep_object_tlv_rsvp_error_spec * +pcep_tlv_create_rsvp_ipv6_error_spec(struct in6_addr *error_node_ip, + uint8_t error_code, uint16_t error_value) +{ + if (error_node_ip == NULL) { + return NULL; + } + + struct pcep_object_tlv_rsvp_error_spec *tlv = + (struct pcep_object_tlv_rsvp_error_spec *) + pcep_tlv_common_create( + PCEP_OBJ_TLV_TYPE_RSVP_ERROR_SPEC, + sizeof(struct pcep_object_tlv_rsvp_error_spec)); + + tlv->c_type = RSVP_ERROR_SPEC_IPV6_CTYPE; + tlv->class_num = RSVP_ERROR_SPEC_CLASS_NUM; + tlv->error_code = error_code; + tlv->error_value = error_value; + memcpy(&tlv->error_spec_ip, error_node_ip, sizeof(struct in6_addr)); + + return tlv; +} + +struct pcep_object_tlv_nopath_vector * +pcep_tlv_create_nopath_vector(uint32_t error_code) +{ + struct pcep_object_tlv_nopath_vector *tlv = + (struct pcep_object_tlv_nopath_vector *)pcep_tlv_common_create( + PCEP_OBJ_TLV_TYPE_NO_PATH_VECTOR, + sizeof(struct pcep_object_tlv_nopath_vector)); + + tlv->error_code = error_code; + + return tlv; +} + +struct pcep_object_tlv_vendor_info * +pcep_tlv_create_vendor_info(uint32_t enterprise_number, + uint32_t enterprise_specific_info) +{ + struct pcep_object_tlv_vendor_info *tlv = + (struct pcep_object_tlv_vendor_info *)pcep_tlv_common_create( + PCEP_OBJ_TLV_TYPE_VENDOR_INFO, + sizeof(struct pcep_object_tlv_vendor_info)); + + tlv->enterprise_number = enterprise_number; + tlv->enterprise_specific_info = enterprise_specific_info; + + return tlv; +} + +/* + * SRPAG (SR Association Group) TLVs + */ + +struct pcep_object_tlv_srpag_pol_id * +pcep_tlv_create_srpag_pol_id_ipv4(uint32_t color, struct in_addr *ipv4) +{ + struct pcep_object_tlv_srpag_pol_id *tlv = + (struct pcep_object_tlv_srpag_pol_id *)pcep_tlv_common_create( + PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_ID, + sizeof(struct pcep_object_tlv_srpag_pol_id)); + tlv->color = color; + tlv->is_ipv4 = true; + memcpy(&tlv->end_point.ipv4.s_addr, ipv4, sizeof(struct in_addr)); + + return tlv; +} + +struct pcep_object_tlv_srpag_pol_id * +pcep_tlv_create_srpag_pol_id_ipv6(uint32_t color, struct in6_addr *ipv6) +{ + struct pcep_object_tlv_srpag_pol_id *tlv = + (struct pcep_object_tlv_srpag_pol_id *)pcep_tlv_common_create( + PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_ID, + sizeof(struct pcep_object_tlv_srpag_pol_id)); + tlv->color = color; + tlv->is_ipv4 = false; + memcpy(&tlv->end_point.ipv6, ipv6, sizeof(struct in6_addr)); + + return tlv; +} + + +struct pcep_object_tlv_srpag_pol_name * +pcep_tlv_create_srpag_pol_name(const char *pol_name, uint16_t pol_name_length) +{ + if (pol_name == NULL) { + return NULL; + } + struct pcep_object_tlv_srpag_pol_name *tlv = + (struct pcep_object_tlv_srpag_pol_name *)pcep_tlv_common_create( + PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_NAME, + sizeof(struct pcep_object_tlv_srpag_pol_name)); + uint16_t length = + (normalize_pcep_tlv_length(pol_name_length) > MAX_POLICY_NAME) + ? MAX_POLICY_NAME + : pol_name_length; + memcpy(tlv->name, pol_name, length); + tlv->name_length = length; + + return tlv; +} +struct pcep_object_tlv_srpag_cp_id * +pcep_tlv_create_srpag_cp_id(uint8_t proto_origin, uint32_t asn, + struct in6_addr *in6_addr_with_mapped_ipv4, + uint32_t discriminator) +{ + if (!in6_addr_with_mapped_ipv4) { + return NULL; + } + + struct pcep_object_tlv_srpag_cp_id *tlv = + (struct pcep_object_tlv_srpag_cp_id *)pcep_tlv_common_create( + PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_ID, + sizeof(struct pcep_object_tlv_srpag_cp_id)); + tlv->proto = proto_origin; + tlv->orig_asn = asn; + memcpy(&(tlv->orig_addres), in6_addr_with_mapped_ipv4, + sizeof(*in6_addr_with_mapped_ipv4)); + tlv->discriminator = discriminator; + + return tlv; +} +struct pcep_object_tlv_srpag_cp_pref * +pcep_tlv_create_srpag_cp_pref(uint32_t pref) +{ + + struct pcep_object_tlv_srpag_cp_pref *tlv = + (struct pcep_object_tlv_srpag_cp_pref *)pcep_tlv_common_create( + PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_PREFERENCE, + sizeof(struct pcep_object_tlv_srpag_cp_pref)); + tlv->preference = pref; + + return tlv; +} + +struct pcep_object_tlv_arbitrary * +pcep_tlv_create_tlv_arbitrary(const char *data, uint16_t data_length, + int tlv_id) +{ + if (data == NULL || data_length == 0) { + return NULL; + } + + struct pcep_object_tlv_arbitrary *tlv = + (struct pcep_object_tlv_arbitrary *)pcep_tlv_common_create( + PCEP_OBJ_TLV_TYPE_ARBITRARY, + sizeof(struct pcep_object_tlv_arbitrary)); + + uint16_t length = (data_length > MAX_ARBITRARY_SIZE) + ? MAX_ARBITRARY_SIZE + : data_length; + memcpy(tlv->data, data, length); + tlv->data_length = length; + tlv->arbitraty_type = tlv_id; + + return tlv; +} diff --git a/pceplib/pcep_msg_tlvs.h b/pceplib/pcep_msg_tlvs.h new file mode 100644 index 0000000000..5197201e40 --- /dev/null +++ b/pceplib/pcep_msg_tlvs.h @@ -0,0 +1,380 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Brady Johnson <brady@voltanet.io> + */ + + +/* + * This is a High Level PCEP message object TLV API. + */ + +#ifndef PCEP_TLVS_H_ +#define PCEP_TLVS_H_ + +#include <arpa/inet.h> +#include <stdint.h> + +#include "pcep.h" +#include "pcep_utils_double_linked_list.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Regarding memory usage: + * When creating TLVs, any TLVs passed into messages or objects with these APIs + * will be free'd when the the enclosing pcep_message is free'd. That includes + * the double_linked_list's. So, just create the objects and TLVs, put them in + * their double_linked_list's, and everything will be managed internally. The + * enclosing message will be deleted by pcep_msg_free_message() or + * pcep_msg_free_message_list() which, * in turn will call one of: + * pcep_obj_free_object() and pcep_obj_free_tlv(). + * For received messages, call pcep_msg_free_message() to free them. + */ + +/* These numbers can be found here: + * https://www.iana.org/assignments/pcep/pcep.xhtml */ +enum pcep_object_tlv_types { + PCEP_OBJ_TLV_TYPE_NO_PATH_VECTOR = 1, + PCEP_OBJ_TLV_TYPE_OBJECTIVE_FUNCTION_LIST = 4, /* RFC 5541 */ + PCEP_OBJ_TLV_TYPE_VENDOR_INFO = 7, /* RFC 7470 */ + PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY = 16, /* RFC 8231 */ + PCEP_OBJ_TLV_TYPE_SYMBOLIC_PATH_NAME = 17, /* RFC 8232 */ + PCEP_OBJ_TLV_TYPE_IPV4_LSP_IDENTIFIERS = 18, /* RFC 8231 */ + PCEP_OBJ_TLV_TYPE_IPV6_LSP_IDENTIFIERS = 19, /* RFC 8231 */ + PCEP_OBJ_TLV_TYPE_LSP_ERROR_CODE = 20, /* RFC 8232 */ + PCEP_OBJ_TLV_TYPE_RSVP_ERROR_SPEC = 21, /* RFC 8232 */ + PCEP_OBJ_TLV_TYPE_LSP_DB_VERSION = 23, /* RFC 8232 */ + PCEP_OBJ_TLV_TYPE_SPEAKER_ENTITY_ID = 24, /* RFC 8232 */ + PCEP_OBJ_TLV_TYPE_SR_PCE_CAPABILITY = + 26, /* draft-ietf-pce-segment-routing-16 */ + PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE = 28, /* RFC 8408 */ + PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE_CAPABILITY = + 34, /* RFC 8408, draft-ietf-pce-segment-routing-16 */ + PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_ID = + 60, /*TDB2 draft-barth-pce-segment-routing-policy-cp-04 */ + PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_NAME = + 61, /*TDB3 draft-barth-pce-segment-routing-policy-cp-04 */ + PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_ID = + 62, /*TDB4 draft-barth-pce-segment-routing-policy-cp-04 */ + PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_PREFERENCE = + 63, /*TDB5 draft-barth-pce-segment-routing-policy-cp-04 */ + PCEP_OBJ_TLV_TYPE_UNKNOWN = 128, + PCEP_OBJ_TLV_TYPE_ARBITRARY = + 65533 /* Max IANA To write arbitrary data */ +}; + +struct pcep_object_tlv_header { + enum pcep_object_tlv_types type; + /* Pointer into encoded_message field from the pcep_message */ + const uint8_t *encoded_tlv; + uint16_t encoded_tlv_length; +}; + +/* STATEFUL-PCE-CAPABILITY TLV, Used in Open Object. RFCs: 8231, 8232, 8281 */ +#define TLV_STATEFUL_PCE_CAP_FLAG_U 0x01 +#define TLV_STATEFUL_PCE_CAP_FLAG_S 0x02 +#define TLV_STATEFUL_PCE_CAP_FLAG_I 0x04 +#define TLV_STATEFUL_PCE_CAP_FLAG_T 0x08 +#define TLV_STATEFUL_PCE_CAP_FLAG_D 0x10 +#define TLV_STATEFUL_PCE_CAP_FLAG_F 0x20 + +struct pcep_object_tlv_stateful_pce_capability { + struct pcep_object_tlv_header header; + bool flag_u_lsp_update_capability; /* RFC 8231 */ + bool flag_s_include_db_version; /* RFC 8232 */ + bool flag_i_lsp_instantiation_capability; /* RFC 8281 */ + bool flag_t_triggered_resync; /* RFC 8232 */ + bool flag_d_delta_lsp_sync; /* RFC 8232 */ + bool flag_f_triggered_initial_sync; /* RFC 8232 */ +}; + +/* NOPATH-VECTOR TLV, Used in the Reply NoPath Object. */ +struct pcep_object_tlv_nopath_vector { + struct pcep_object_tlv_header header; + uint32_t error_code; +}; + +/* STATEFUL-PCE-CAPABILITY TLV, Used in Open Object. RFCs: 8232 */ +struct pcep_object_tlv_lsp_db_version { + struct pcep_object_tlv_header header; + uint64_t lsp_db_version; +}; + +/* Speaker Entity Identifier TLV, Used in Open Object. RFCs: 8232 */ +struct pcep_object_tlv_speaker_entity_identifier { + struct pcep_object_tlv_header header; + double_linked_list *speaker_entity_id_list; /* list of uint32_t speaker + entity ids */ +}; + +/* Ipv4 LSP Identifier TLV, Used in LSP Object. RFCs: 8231 */ +struct pcep_object_tlv_ipv4_lsp_identifier { + struct pcep_object_tlv_header header; + struct in_addr ipv4_tunnel_sender; + uint16_t lsp_id; + uint16_t tunnel_id; + struct in_addr extended_tunnel_id; + struct in_addr ipv4_tunnel_endpoint; +}; + +/* Ipv6 LSP Identifier TLV, Used in LSP Object. RFCs: 8231 */ +struct pcep_object_tlv_ipv6_lsp_identifier { + struct pcep_object_tlv_header header; + struct in6_addr ipv6_tunnel_sender; + uint16_t lsp_id; + uint16_t tunnel_id; + struct in6_addr extended_tunnel_id; + struct in6_addr ipv6_tunnel_endpoint; +}; + +/* Symbolic Path Name TLV, Used in LSP Object. RFCs: 8231 */ +#define MAX_SYMBOLIC_PATH_NAME 256 + +struct pcep_object_tlv_symbolic_path_name { + struct pcep_object_tlv_header header; + uint16_t symbolic_path_name_length; + char symbolic_path_name[MAX_SYMBOLIC_PATH_NAME]; +}; + +/* LSP Error Code TLV, Used in LSP Object. RFCs: 8231 */ +enum pcep_tlv_lsp_error_codes { + PCEP_TLV_LSP_ERROR_CODE_UNKNOWN = 1, + PCEP_TLV_LSP_ERROR_CODE_LSP_LIMIT_REACHED = 2, + PCEP_TLV_LSP_ERROR_CODE_TOO_MANY_PENDING_LSP_UPDATES = 3, + PCEP_TLV_LSP_ERROR_CODE_UNACCEPTABLE_PARAMS = 4, + PCEP_TLV_LSP_ERROR_CODE_INTERNAL_ERROR = 5, + PCEP_TLV_LSP_ERROR_CODE_LSP_BROUGHT_DOWN = 6, + PCEP_TLV_LSP_ERROR_CODE_LSP_PREEMPTED = 7, + PCEP_TLV_LSP_ERROR_CODE_RSVP_SIGNALING_ERROR = 8, +}; + +struct pcep_object_tlv_lsp_error_code { + struct pcep_object_tlv_header header; + enum pcep_tlv_lsp_error_codes lsp_error_code; +}; + +/* Path Setup Type TLV, Used in RP and SRP Object. RFCs: 8408, + * draft-ietf-pce-segment-routing-16 */ +#define SR_TE_PST 1 + +struct pcep_object_tlv_path_setup_type { + struct pcep_object_tlv_header header; + uint8_t path_setup_type; +}; + +/* Path Setup Type Capability TLV, Used in Open Object. RFCs: 8408, + * draft-ietf-pce-segment-routing-16 */ +struct pcep_object_tlv_path_setup_type_capability { + struct pcep_object_tlv_header header; + double_linked_list *pst_list; /* list of uint8_t PSTs */ + double_linked_list *sub_tlv_list; /* list of sub_tlvs */ +}; + +/* SR PCE Capability sub-TLV, Used in Open Object. RFCs: + * draft-ietf-pce-segment-routing-16 */ +#define TLV_SR_PCE_CAP_FLAG_X 0x01 +#define TLV_SR_PCE_CAP_FLAG_N 0x02 + +struct pcep_object_tlv_sr_pce_capability { + struct pcep_object_tlv_header header; + bool flag_n; + bool flag_x; + uint8_t max_sid_depth; +}; + + +/* RSVP Error Spec TLV, Used in LSP Object. RFCs: 8231, 2205 */ +#define RSVP_ERROR_SPEC_IPV4_CTYPE 1 +#define RSVP_ERROR_SPEC_IPV6_CTYPE 2 +#define RSVP_ERROR_SPEC_CLASS_NUM 6 + +struct pcep_object_tlv_rsvp_error_spec { + struct pcep_object_tlv_header header; + uint8_t class_num; + uint8_t c_type; + uint8_t error_code; + uint16_t error_value; + /* Use the c_type to determine which union entry to use */ + union error_spec_ip { + struct in_addr ipv4_error_node_address; + struct in6_addr ipv6_error_node_address; + } error_spec_ip; +}; + +/* SR Policy Identifier TLV Used in Association Object. + * draft-barth-pce-segment-routing-policy-cp-04*/ +struct pcep_object_tlv_srpag_pol_id { + struct pcep_object_tlv_header header; + uint32_t color; + bool is_ipv4; + union end_point_ { + struct in_addr ipv4; + struct in6_addr ipv6; + } end_point; +}; + +/*draft-ietf-spring-segment-routing-policy-06*/ +#define MAX_POLICY_NAME 256 + +/* SR Policy Name TLV Used in Association Object. + * draft-barth-pce-segment-routing-policy-cp-04*/ +struct pcep_object_tlv_srpag_pol_name { + struct pcep_object_tlv_header header; + uint16_t name_length; + char name[MAX_POLICY_NAME]; +}; + +/* SR Candidate Path Id TLV Used in Association Object. + * draft-barth-pce-segment-routing-policy-cp-04*/ +struct pcep_object_tlv_srpag_cp_id { + struct pcep_object_tlv_header header; + uint8_t proto; + uint32_t orig_asn; + struct in6_addr orig_addres; /*With ipv4 embedded*/ + uint32_t discriminator; +}; + +/* SR Candidate Preference TLV Used in Association Object. + * draft-barth-pce-segment-routing-policy-cp-04*/ +struct pcep_object_tlv_srpag_cp_pref { + struct pcep_object_tlv_header header; + uint32_t preference; +}; + +struct pcep_object_tlv_vendor_info { + struct pcep_object_tlv_header header; + uint32_t enterprise_number; + uint32_t enterprise_specific_info; +}; + +/* arbitrary TLV 65535 */ +#define MAX_ARBITRARY_SIZE 256 +struct pcep_object_tlv_arbitrary { + struct pcep_object_tlv_header header; + enum pcep_object_tlv_types arbitraty_type; + uint16_t data_length; + char data[MAX_ARBITRARY_SIZE]; +}; + +/* Objective Functions List RFC 5541 + * At least the following 6 OF codes must be supported */ +enum objective_function_codes { + PCEP_OF_CODE_MINIMUM_COST_PATH = 1, /* MCP */ + PCEP_OF_CODE_MINIMUM_LOAD_PATH = 2, /* MLP */ + PCEP_OF_CODE_MAXIMUM_BW_PATH = 3, /* MBP */ + PCEP_OF_CODE_MINIMIZE_AGGR_BW_CONSUMPTION = 4, /* MBC */ + PCEP_OF_CODE_MINIMIZE_MOST_LOADED_LINK = 5, /* MLL */ + PCEP_OF_CODE_MINIMIZE_CUMULATIVE_COST_PATHS = 6, /* MCC */ +}; + +struct pcep_object_tlv_of_list { + struct pcep_object_tlv_header header; + double_linked_list *of_list; /* list of uint16_t OF code points */ +}; + +/* + * TLV creation functions + */ + +/* + * Open Object TLVs + */ + +struct pcep_object_tlv_stateful_pce_capability * +pcep_tlv_create_stateful_pce_capability( + bool flag_u_lsp_update_capability, bool flag_s_include_db_version, + bool flag_i_lsp_instantiation_capability, bool flag_t_triggered_resync, + bool flag_d_delta_lsp_sync, bool flag_f_triggered_initial_sync); +struct pcep_object_tlv_lsp_db_version * +pcep_tlv_create_lsp_db_version(uint64_t lsp_db_version); +struct pcep_object_tlv_speaker_entity_identifier * +pcep_tlv_create_speaker_entity_id(double_linked_list *speaker_entity_id_list); +struct pcep_object_tlv_path_setup_type * +pcep_tlv_create_path_setup_type(uint8_t pst); +struct pcep_object_tlv_path_setup_type_capability * +pcep_tlv_create_path_setup_type_capability(double_linked_list *pst_list, + double_linked_list *sub_tlv_list); +struct pcep_object_tlv_sr_pce_capability * +pcep_tlv_create_sr_pce_capability(bool flag_n, bool flag_x, + uint8_t max_sid_depth); +struct pcep_object_tlv_of_list * +pcep_tlv_create_of_list(double_linked_list *of_list); + +/* + * LSP Object TLVs + */ + +struct pcep_object_tlv_ipv4_lsp_identifier * +pcep_tlv_create_ipv4_lsp_identifiers(struct in_addr *ipv4_tunnel_sender, + struct in_addr *ipv4_tunnel_endpoint, + uint16_t lsp_id, uint16_t tunnel_id, + struct in_addr *extended_tunnel_id); +struct pcep_object_tlv_ipv6_lsp_identifier * +pcep_tlv_create_ipv6_lsp_identifiers(struct in6_addr *ipv6_tunnel_sender, + struct in6_addr *extended_tunnel_id, + uint16_t lsp_id, uint16_t tunnel_id, + struct in6_addr *ipv6_tunnel_endpoint); +/* symbolic_path_name_length should NOT include the null terminator and cannot + * be zero */ +struct pcep_object_tlv_symbolic_path_name * +pcep_tlv_create_symbolic_path_name(const char *symbolic_path_name, + uint16_t symbolic_path_name_length); +struct pcep_object_tlv_lsp_error_code * +pcep_tlv_create_lsp_error_code(enum pcep_tlv_lsp_error_codes lsp_error_code); +struct pcep_object_tlv_rsvp_error_spec * +pcep_tlv_create_rsvp_ipv4_error_spec(struct in_addr *error_node_ip, + uint8_t error_code, uint16_t error_value); +struct pcep_object_tlv_rsvp_error_spec * +pcep_tlv_create_rsvp_ipv6_error_spec(struct in6_addr *error_node_ip, + uint8_t error_code, uint16_t error_value); + +struct pcep_object_tlv_nopath_vector * +pcep_tlv_create_nopath_vector(uint32_t error_code); +struct pcep_object_tlv_vendor_info * +pcep_tlv_create_vendor_info(uint32_t enterprise_number, + uint32_t enterprise_specific_info); + +struct pcep_object_tlv_arbitrary * +pcep_tlv_create_tlv_arbitrary(const char *data, uint16_t data_length, + int tlv_id); +/* + * SRPAG (SR Association Group) TLVs + */ + +struct pcep_object_tlv_srpag_pol_id * +pcep_tlv_create_srpag_pol_id_ipv4(uint32_t color, struct in_addr *ipv4); +struct pcep_object_tlv_srpag_pol_id * +pcep_tlv_create_srpag_pol_id_ipv6(uint32_t color, struct in6_addr *ipv6); +struct pcep_object_tlv_srpag_pol_name * +pcep_tlv_create_srpag_pol_name(const char *pol_name, uint16_t pol_name_length); +struct pcep_object_tlv_srpag_cp_id * +pcep_tlv_create_srpag_cp_id(uint8_t proto_origin, uint32_t asn, + struct in6_addr *in6_addr_with_mapped_ipv4, + uint32_t discriminator); +struct pcep_object_tlv_srpag_cp_pref * +pcep_tlv_create_srpag_cp_pref(uint32_t pref); + + +#ifdef __cplusplus +} +#endif + +#endif /* PCEP_TLVS_H_ */ diff --git a/pceplib/pcep_msg_tlvs_encoding.c b/pceplib/pcep_msg_tlvs_encoding.c new file mode 100644 index 0000000000..967f138143 --- /dev/null +++ b/pceplib/pcep_msg_tlvs_encoding.c @@ -0,0 +1,1282 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Brady Johnson <brady@voltanet.io> + * + */ + + +/* + * Encoding and decoding for PCEP Object TLVs. + */ + +#include <stdlib.h> +#include <string.h> + +#include "pcep.h" +#include "pcep_msg_encoding.h" +#include "pcep_msg_tlvs.h" +#include "pcep_utils_logging.h" +#include "pcep_utils_memory.h" + +void write_tlv_header(struct pcep_object_tlv_header *tlv_hdr, + uint16_t tlv_length, struct pcep_versioning *versioning, + uint8_t *buf); +void pcep_decode_tlv_hdr(const uint8_t *tlv_buf, + struct pcep_object_tlv_header *tlv_hdr); + +/* + * forward declarations for initialize_tlv_encoders() + */ +uint16_t pcep_encode_tlv_no_path_vector(struct pcep_object_tlv_header *tlv, + struct pcep_versioning *versioning, + uint8_t *tlv_body_buf); +uint16_t +pcep_encode_tlv_stateful_pce_capability(struct pcep_object_tlv_header *tlv, + struct pcep_versioning *versioning, + uint8_t *tlv_body_buf); +uint16_t pcep_encode_tlv_symbolic_path_name(struct pcep_object_tlv_header *tlv, + struct pcep_versioning *versioning, + uint8_t *tlv_body_buf); +uint16_t +pcep_encode_tlv_ipv4_lsp_identifiers(struct pcep_object_tlv_header *tlv, + struct pcep_versioning *versioning, + uint8_t *tlv_body_buf); +uint16_t +pcep_encode_tlv_ipv6_lsp_identifiers(struct pcep_object_tlv_header *tlv, + struct pcep_versioning *versioning, + uint8_t *tlv_body_buf); +uint16_t pcep_encode_tlv_lsp_error_code(struct pcep_object_tlv_header *tlv, + struct pcep_versioning *versioning, + uint8_t *tlv_body_buf); +uint16_t pcep_encode_tlv_rsvp_error_spec(struct pcep_object_tlv_header *tlv, + struct pcep_versioning *versioning, + uint8_t *tlv_body_buf); +uint16_t pcep_encode_tlv_lsp_db_version(struct pcep_object_tlv_header *tlv, + struct pcep_versioning *versioning, + uint8_t *tlv_body_buf); +uint16_t pcep_encode_tlv_speaker_entity_id(struct pcep_object_tlv_header *tlv, + struct pcep_versioning *versioning, + uint8_t *tlv_body_buf); +uint16_t pcep_encode_tlv_sr_pce_capability(struct pcep_object_tlv_header *tlv, + struct pcep_versioning *versioning, + uint8_t *tlv_body_buf); +uint16_t pcep_encode_tlv_path_setup_type(struct pcep_object_tlv_header *tlv, + struct pcep_versioning *versioning, + uint8_t *tlv_body_buf); +uint16_t +pcep_encode_tlv_path_setup_type_capability(struct pcep_object_tlv_header *tlv, + struct pcep_versioning *versioning, + uint8_t *tlv_body_buf); +uint16_t pcep_encode_tlv_pol_id(struct pcep_object_tlv_header *tlv, + struct pcep_versioning *versioning, + uint8_t *tlv_body_buf); +uint16_t pcep_encode_tlv_pol_name(struct pcep_object_tlv_header *tlv, + struct pcep_versioning *versioning, + uint8_t *tlv_body_buf); +uint16_t pcep_encode_tlv_cpath_id(struct pcep_object_tlv_header *tlv, + struct pcep_versioning *versioning, + uint8_t *tlv_body_buf); +uint16_t pcep_encode_tlv_cpath_preference(struct pcep_object_tlv_header *tlv, + struct pcep_versioning *versioning, + uint8_t *tlv_body_buf); +uint16_t pcep_encode_tlv_vendor_info(struct pcep_object_tlv_header *tlv, + struct pcep_versioning *versioning, + uint8_t *tlv_body_buf); +uint16_t pcep_encode_tlv_arbitrary(struct pcep_object_tlv_header *tlv, + struct pcep_versioning *versioning, + uint8_t *tlv_body_buf); +uint16_t pcep_encode_tlv_of_list(struct pcep_object_tlv_header *tlv, + struct pcep_versioning *versioning, + uint8_t *tlv_body_buf); +typedef uint16_t (*tlv_encoder_funcptr)(struct pcep_object_tlv_header *, + struct pcep_versioning *versioning, + uint8_t *tlv_body_buf); + +#define MAX_TLV_ENCODER_INDEX 65533 + 1 // 65 + +#define PCEP_TLV_ENCODERS_ARGS \ + struct pcep_object_tlv_header *, struct pcep_versioning *versioning, \ + uint8_t *tlv_body_buf +uint16_t (*const tlv_encoders[MAX_TLV_ENCODER_INDEX])( + PCEP_TLV_ENCODERS_ARGS) = { + [PCEP_OBJ_TLV_TYPE_NO_PATH_VECTOR] = pcep_encode_tlv_no_path_vector, + [PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY] = + pcep_encode_tlv_stateful_pce_capability, + [PCEP_OBJ_TLV_TYPE_SYMBOLIC_PATH_NAME] = + pcep_encode_tlv_symbolic_path_name, + [PCEP_OBJ_TLV_TYPE_IPV4_LSP_IDENTIFIERS] = + pcep_encode_tlv_ipv4_lsp_identifiers, + [PCEP_OBJ_TLV_TYPE_IPV6_LSP_IDENTIFIERS] = + pcep_encode_tlv_ipv6_lsp_identifiers, + [PCEP_OBJ_TLV_TYPE_LSP_ERROR_CODE] = pcep_encode_tlv_lsp_error_code, + [PCEP_OBJ_TLV_TYPE_RSVP_ERROR_SPEC] = pcep_encode_tlv_rsvp_error_spec, + [PCEP_OBJ_TLV_TYPE_LSP_DB_VERSION] = pcep_encode_tlv_lsp_db_version, + [PCEP_OBJ_TLV_TYPE_SPEAKER_ENTITY_ID] = + pcep_encode_tlv_speaker_entity_id, + [PCEP_OBJ_TLV_TYPE_SR_PCE_CAPABILITY] = + pcep_encode_tlv_sr_pce_capability, + [PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE] = pcep_encode_tlv_path_setup_type, + [PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE_CAPABILITY] = + pcep_encode_tlv_path_setup_type_capability, + [PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_ID] = pcep_encode_tlv_pol_id, + [PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_NAME] = pcep_encode_tlv_pol_name, + [PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_ID] = pcep_encode_tlv_cpath_id, + [PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_PREFERENCE] = + pcep_encode_tlv_cpath_preference, + [PCEP_OBJ_TLV_TYPE_VENDOR_INFO] = pcep_encode_tlv_vendor_info, + [PCEP_OBJ_TLV_TYPE_ARBITRARY] = pcep_encode_tlv_arbitrary, + [PCEP_OBJ_TLV_TYPE_OBJECTIVE_FUNCTION_LIST] = pcep_encode_tlv_of_list, +}; +/* + * forward declarations for initialize_tlv_decoders() + */ +struct pcep_object_tlv_header * +pcep_decode_tlv_no_path_vector(struct pcep_object_tlv_header *tlv_hdr, + const uint8_t *tlv_body_buf); +struct pcep_object_tlv_header * +pcep_decode_tlv_stateful_pce_capability(struct pcep_object_tlv_header *tlv_hdr, + const uint8_t *tlv_body_buf); +struct pcep_object_tlv_header * +pcep_decode_tlv_symbolic_path_name(struct pcep_object_tlv_header *tlv_hdr, + const uint8_t *tlv_body_buf); +struct pcep_object_tlv_header * +pcep_decode_tlv_ipv4_lsp_identifiers(struct pcep_object_tlv_header *tlv_hdr, + const uint8_t *tlv_body_buf); +struct pcep_object_tlv_header * +pcep_decode_tlv_ipv6_lsp_identifiers(struct pcep_object_tlv_header *tlv_hdr, + const uint8_t *tlv_body_buf); +struct pcep_object_tlv_header * +pcep_decode_tlv_lsp_error_code(struct pcep_object_tlv_header *tlv_hdr, + const uint8_t *tlv_body_buf); +struct pcep_object_tlv_header * +pcep_decode_tlv_rsvp_error_spec(struct pcep_object_tlv_header *tlv_hdr, + const uint8_t *tlv_body_buf); +struct pcep_object_tlv_header * +pcep_decode_tlv_lsp_db_version(struct pcep_object_tlv_header *tlv_hdr, + const uint8_t *tlv_body_buf); +struct pcep_object_tlv_header * +pcep_decode_tlv_speaker_entity_id(struct pcep_object_tlv_header *tlv_hdr, + const uint8_t *tlv_body_buf); +struct pcep_object_tlv_header * +pcep_decode_tlv_sr_pce_capability(struct pcep_object_tlv_header *tlv_hdr, + const uint8_t *tlv_body_buf); +struct pcep_object_tlv_header * +pcep_decode_tlv_path_setup_type(struct pcep_object_tlv_header *tlv_hdr, + const uint8_t *tlv_body_buf); +struct pcep_object_tlv_header *pcep_decode_tlv_path_setup_type_capability( + struct pcep_object_tlv_header *tlv_hdr, const uint8_t *tlv_body_buf); +struct pcep_object_tlv_header * +pcep_decode_tlv_pol_id(struct pcep_object_tlv_header *tlv_hdr, + const uint8_t *tlv_body_buf); +struct pcep_object_tlv_header * +pcep_decode_tlv_pol_name(struct pcep_object_tlv_header *tlv_hdr, + const uint8_t *tlv_body_buf); +struct pcep_object_tlv_header * +pcep_decode_tlv_cpath_id(struct pcep_object_tlv_header *tlv_hdr, + const uint8_t *tlv_body_buf); +struct pcep_object_tlv_header * +pcep_decode_tlv_cpath_preference(struct pcep_object_tlv_header *tlv_hdr, + const uint8_t *tlv_body_buf); +struct pcep_object_tlv_header * +pcep_decode_tlv_vendor_info(struct pcep_object_tlv_header *tlv_hdr, + const uint8_t *tlv_body_buf); +struct pcep_object_tlv_header * +pcep_decode_tlv_arbitrary(struct pcep_object_tlv_header *tlv_hdr, + const uint8_t *tlv_body_buf); +struct pcep_object_tlv_header * +pcep_decode_tlv_of_list(struct pcep_object_tlv_header *tlv_hdr, + const uint8_t *tlv_body_buf); +typedef struct pcep_object_tlv_header *(*tlv_decoder_funcptr)( + struct pcep_object_tlv_header *tlv_hdr, const uint8_t *tlv_body_buf); + +// tlv_decoder_funcptr tlv_decoders[MAX_TLV_ENCODER_INDEX]; + +#define PCEP_TLV_DECODERS_ARGS \ + struct pcep_object_tlv_header *tlv_hdr, const uint8_t *tlv_body_buf + +struct pcep_object_tlv_header *(*const tlv_decoders[MAX_TLV_ENCODER_INDEX])( + PCEP_TLV_DECODERS_ARGS) = { + [PCEP_OBJ_TLV_TYPE_NO_PATH_VECTOR] = pcep_decode_tlv_no_path_vector, + [PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY] = + pcep_decode_tlv_stateful_pce_capability, + [PCEP_OBJ_TLV_TYPE_SYMBOLIC_PATH_NAME] = + pcep_decode_tlv_symbolic_path_name, + [PCEP_OBJ_TLV_TYPE_IPV4_LSP_IDENTIFIERS] = + pcep_decode_tlv_ipv4_lsp_identifiers, + [PCEP_OBJ_TLV_TYPE_IPV6_LSP_IDENTIFIERS] = + pcep_decode_tlv_ipv6_lsp_identifiers, + [PCEP_OBJ_TLV_TYPE_LSP_ERROR_CODE] = pcep_decode_tlv_lsp_error_code, + [PCEP_OBJ_TLV_TYPE_RSVP_ERROR_SPEC] = pcep_decode_tlv_rsvp_error_spec, + [PCEP_OBJ_TLV_TYPE_LSP_DB_VERSION] = pcep_decode_tlv_lsp_db_version, + [PCEP_OBJ_TLV_TYPE_SPEAKER_ENTITY_ID] = + pcep_decode_tlv_speaker_entity_id, + [PCEP_OBJ_TLV_TYPE_SR_PCE_CAPABILITY] = + pcep_decode_tlv_sr_pce_capability, + [PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE] = pcep_decode_tlv_path_setup_type, + [PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE_CAPABILITY] = + pcep_decode_tlv_path_setup_type_capability, + [PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_ID] = pcep_decode_tlv_pol_id, + [PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_NAME] = pcep_decode_tlv_pol_name, + [PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_ID] = pcep_decode_tlv_cpath_id, + [PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_PREFERENCE] = + pcep_decode_tlv_cpath_preference, + [PCEP_OBJ_TLV_TYPE_VENDOR_INFO] = pcep_decode_tlv_vendor_info, + [PCEP_OBJ_TLV_TYPE_ARBITRARY] = pcep_decode_tlv_arbitrary, + [PCEP_OBJ_TLV_TYPE_OBJECTIVE_FUNCTION_LIST] = pcep_decode_tlv_of_list, +}; + +static void initialize_tlv_coders() +{ + static bool initialized = false; + + if (initialized == true) { + return; + } + + initialized = true; + + /* Encoders */ + /* + memset(tlv_encoders, 0, sizeof(tlv_encoder_funcptr) * + MAX_TLV_ENCODER_INDEX); tlv_encoders[PCEP_OBJ_TLV_TYPE_NO_PATH_VECTOR] = + pcep_encode_tlv_no_path_vector; + tlv_encoders[PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY] = + pcep_encode_tlv_stateful_pce_capability; + tlv_encoders[PCEP_OBJ_TLV_TYPE_SYMBOLIC_PATH_NAME] = + pcep_encode_tlv_symbolic_path_name; + tlv_encoders[PCEP_OBJ_TLV_TYPE_IPV4_LSP_IDENTIFIERS] = + pcep_encode_tlv_ipv4_lsp_identifiers; + tlv_encoders[PCEP_OBJ_TLV_TYPE_IPV6_LSP_IDENTIFIERS] = + pcep_encode_tlv_ipv6_lsp_identifiers; + tlv_encoders[PCEP_OBJ_TLV_TYPE_LSP_ERROR_CODE] = + pcep_encode_tlv_lsp_error_code; + tlv_encoders[PCEP_OBJ_TLV_TYPE_RSVP_ERROR_SPEC] = + pcep_encode_tlv_rsvp_error_spec; + tlv_encoders[PCEP_OBJ_TLV_TYPE_LSP_DB_VERSION] = + pcep_encode_tlv_lsp_db_version; + tlv_encoders[PCEP_OBJ_TLV_TYPE_SPEAKER_ENTITY_ID] = + pcep_encode_tlv_speaker_entity_id; + tlv_encoders[PCEP_OBJ_TLV_TYPE_SR_PCE_CAPABILITY] = + pcep_encode_tlv_sr_pce_capability; + tlv_encoders[PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE] = + pcep_encode_tlv_path_setup_type; + tlv_encoders[PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE_CAPABILITY] = + pcep_encode_tlv_path_setup_type_capability; + tlv_encoders[PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_ID] = + pcep_encode_tlv_pol_id; + tlv_encoders[PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_NAME] = + pcep_encode_tlv_pol_name; + tlv_encoders[PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_ID] = + pcep_encode_tlv_cpath_id; + tlv_encoders[PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_PREFERENCE] = + pcep_encode_tlv_cpath_preference; + tlv_encoders[PCEP_OBJ_TLV_TYPE_VENDOR_INFO] = + pcep_encode_tlv_vendor_info; tlv_encoders[PCEP_OBJ_TLV_TYPE_ARBITRARY] = + pcep_encode_tlv_arbitrary; + tlv_encoders[PCEP_OBJ_TLV_TYPE_OBJECTIVE_FUNCTION_LIST] = + pcep_encode_tlv_of_list; + */ + + /* Decoders */ + /* + memset(tlv_decoders, 0, sizeof(tlv_decoder_funcptr) * + MAX_TLV_ENCODER_INDEX); tlv_decoders[PCEP_OBJ_TLV_TYPE_NO_PATH_VECTOR] = + pcep_decode_tlv_no_path_vector; + tlv_decoders[PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY] = + pcep_decode_tlv_stateful_pce_capability; + tlv_decoders[PCEP_OBJ_TLV_TYPE_SYMBOLIC_PATH_NAME] = + pcep_decode_tlv_symbolic_path_name; + tlv_decoders[PCEP_OBJ_TLV_TYPE_IPV4_LSP_IDENTIFIERS] = + pcep_decode_tlv_ipv4_lsp_identifiers; + tlv_decoders[PCEP_OBJ_TLV_TYPE_IPV6_LSP_IDENTIFIERS] = + pcep_decode_tlv_ipv6_lsp_identifiers; + tlv_decoders[PCEP_OBJ_TLV_TYPE_LSP_ERROR_CODE] = + pcep_decode_tlv_lsp_error_code; + tlv_decoders[PCEP_OBJ_TLV_TYPE_RSVP_ERROR_SPEC] = + pcep_decode_tlv_rsvp_error_spec; + tlv_decoders[PCEP_OBJ_TLV_TYPE_LSP_DB_VERSION] = + pcep_decode_tlv_lsp_db_version; + tlv_decoders[PCEP_OBJ_TLV_TYPE_SPEAKER_ENTITY_ID] = + pcep_decode_tlv_speaker_entity_id; + tlv_decoders[PCEP_OBJ_TLV_TYPE_SR_PCE_CAPABILITY] = + pcep_decode_tlv_sr_pce_capability; + tlv_decoders[PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE] = + pcep_decode_tlv_path_setup_type; + tlv_decoders[PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE_CAPABILITY] = + pcep_decode_tlv_path_setup_type_capability; + tlv_decoders[PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_ID] = + pcep_decode_tlv_pol_id; + tlv_decoders[PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_NAME] = + pcep_decode_tlv_pol_name; + tlv_decoders[PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_ID] = + pcep_decode_tlv_cpath_id; + tlv_decoders[PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_PREFERENCE] = + pcep_decode_tlv_cpath_preference; + tlv_decoders[PCEP_OBJ_TLV_TYPE_VENDOR_INFO] = + pcep_decode_tlv_vendor_info; tlv_decoders[PCEP_OBJ_TLV_TYPE_ARBITRARY] = + pcep_decode_tlv_arbitrary; + tlv_decoders[PCEP_OBJ_TLV_TYPE_OBJECTIVE_FUNCTION_LIST] = + pcep_decode_tlv_of_list; + */ +} + +uint16_t pcep_encode_tlv(struct pcep_object_tlv_header *tlv_hdr, + struct pcep_versioning *versioning, uint8_t *buf) +{ + initialize_tlv_coders(); + + if (tlv_hdr->type >= MAX_TLV_ENCODER_INDEX) { + pcep_log(LOG_INFO, + "%s: Cannot encode unknown Object class [%d]", + __func__, tlv_hdr->type); + return 0; + } + + tlv_encoder_funcptr tlv_encoder = tlv_encoders[tlv_hdr->type]; + if (tlv_encoder == NULL) { + pcep_log(LOG_INFO, + "%s: No object encoder found for Object class [%d]", + __func__, tlv_hdr->type); + return 0; + } + + /* Notice: The length in the TLV header does not include the TLV header, + * so the length returned from the tlv_encoder() is only the TLV body. + */ + uint16_t tlv_length = + tlv_encoder(tlv_hdr, versioning, buf + TLV_HEADER_LENGTH); + write_tlv_header(tlv_hdr, tlv_length, versioning, buf); + tlv_hdr->encoded_tlv = buf; + tlv_hdr->encoded_tlv_length = tlv_length; + + return normalize_pcep_tlv_length(tlv_length + TLV_HEADER_LENGTH); +} + +/* TLV Header format + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type (2 bytes) | Length (2 bytes) | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Value (Variable) | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + +void write_tlv_header(struct pcep_object_tlv_header *tlv_hdr, + uint16_t tlv_length, struct pcep_versioning *versioning, + uint8_t *buf) +{ + (void)versioning; + uint16_t *uint16_ptr = (uint16_t *)buf; + uint16_ptr[0] = htons(tlv_hdr->type); + uint16_ptr[1] = htons(tlv_length); +} + +/* + * Functions to encode TLVs + */ + +uint16_t pcep_encode_tlv_no_path_vector(struct pcep_object_tlv_header *tlv, + struct pcep_versioning *versioning, + uint8_t *tlv_body_buf) +{ + (void)versioning; + struct pcep_object_tlv_nopath_vector *nopath_tlv = + (struct pcep_object_tlv_nopath_vector *)tlv; + uint32_t *uint32_ptr = (uint32_t *)tlv_body_buf; + *uint32_ptr = htonl(nopath_tlv->error_code); + + return LENGTH_1WORD; +} + +uint16_t +pcep_encode_tlv_stateful_pce_capability(struct pcep_object_tlv_header *tlv, + struct pcep_versioning *versioning, + uint8_t *tlv_body_buf) +{ + (void)versioning; + struct pcep_object_tlv_stateful_pce_capability *spc_tlv = + (struct pcep_object_tlv_stateful_pce_capability *)tlv; + tlv_body_buf[3] = + ((spc_tlv->flag_f_triggered_initial_sync == true + ? TLV_STATEFUL_PCE_CAP_FLAG_F + : 0x00) + | (spc_tlv->flag_d_delta_lsp_sync == true + ? TLV_STATEFUL_PCE_CAP_FLAG_D + : 0x00) + | (spc_tlv->flag_t_triggered_resync == true + ? TLV_STATEFUL_PCE_CAP_FLAG_T + : 0x00) + | (spc_tlv->flag_i_lsp_instantiation_capability == true + ? TLV_STATEFUL_PCE_CAP_FLAG_I + : 0x00) + | (spc_tlv->flag_s_include_db_version == true + ? TLV_STATEFUL_PCE_CAP_FLAG_S + : 0x00) + | (spc_tlv->flag_u_lsp_update_capability == true + ? TLV_STATEFUL_PCE_CAP_FLAG_U + : 0x00)); + + return LENGTH_1WORD; +} + +uint16_t pcep_encode_tlv_symbolic_path_name(struct pcep_object_tlv_header *tlv, + struct pcep_versioning *versioning, + uint8_t *tlv_body_buf) +{ + (void)versioning; + struct pcep_object_tlv_symbolic_path_name *spn_tlv = + (struct pcep_object_tlv_symbolic_path_name *)tlv; + memcpy(tlv_body_buf, spn_tlv->symbolic_path_name, + spn_tlv->symbolic_path_name_length); + + return spn_tlv->symbolic_path_name_length; +} + +uint16_t +pcep_encode_tlv_ipv4_lsp_identifiers(struct pcep_object_tlv_header *tlv, + struct pcep_versioning *versioning, + uint8_t *tlv_body_buf) +{ + (void)versioning; + struct pcep_object_tlv_ipv4_lsp_identifier *ipv4_lsp = + (struct pcep_object_tlv_ipv4_lsp_identifier *)tlv; + uint32_t *uint32_ptr = (uint32_t *)tlv_body_buf; + uint32_ptr[0] = ipv4_lsp->ipv4_tunnel_sender.s_addr; + /* uint32_t[1] is lsp_id and tunnel_id, below */ + uint32_ptr[2] = ipv4_lsp->extended_tunnel_id.s_addr; + uint32_ptr[3] = ipv4_lsp->ipv4_tunnel_endpoint.s_addr; + + uint16_t *uint16_ptr = (uint16_t *)(tlv_body_buf + LENGTH_1WORD); + uint16_ptr[0] = htons(ipv4_lsp->lsp_id); + uint16_ptr[1] = htons(ipv4_lsp->tunnel_id); + + return LENGTH_4WORDS; +} + +uint16_t +pcep_encode_tlv_ipv6_lsp_identifiers(struct pcep_object_tlv_header *tlv, + struct pcep_versioning *versioning, + uint8_t *tlv_body_buf) +{ + (void)versioning; + struct pcep_object_tlv_ipv6_lsp_identifier *ipv6_lsp = + (struct pcep_object_tlv_ipv6_lsp_identifier *)tlv; + uint32_t *uint32_ptr = (uint32_t *)tlv_body_buf; + encode_ipv6(&ipv6_lsp->ipv6_tunnel_sender, uint32_ptr); + encode_ipv6(&ipv6_lsp->extended_tunnel_id, uint32_ptr + 5); + encode_ipv6(&ipv6_lsp->ipv6_tunnel_endpoint, uint32_ptr + 9); + + uint16_t *uint16_ptr = (uint16_t *)(tlv_body_buf + LENGTH_4WORDS); + uint16_ptr[0] = htons(ipv6_lsp->lsp_id); + uint16_ptr[1] = htons(ipv6_lsp->tunnel_id); + + return LENGTH_13WORDS; +} + +uint16_t pcep_encode_tlv_lsp_error_code(struct pcep_object_tlv_header *tlv, + struct pcep_versioning *versioning, + uint8_t *tlv_body_buf) +{ + (void)versioning; + struct pcep_object_tlv_lsp_error_code *lsp_error_tlv = + (struct pcep_object_tlv_lsp_error_code *)tlv; + uint32_t *uint32_ptr = (uint32_t *)tlv_body_buf; + *uint32_ptr = htonl(lsp_error_tlv->lsp_error_code); + + return LENGTH_1WORD; +} + +uint16_t pcep_encode_tlv_rsvp_error_spec(struct pcep_object_tlv_header *tlv, + struct pcep_versioning *versioning, + uint8_t *tlv_body_buf) +{ + /* Same decode tlv function for both types: + pcep_create_tlv_rsvp_ipv4_error_spec(tlv); + pcep_create_tlv_rsvp_ipv6_error_spec(tlv); */ + + /* RSVP Object Header + * + * 0 1 2 3 + * +-------------+-------------+-------------+-------------+ + * | Length (bytes) | Class-Num | C-Type | + * +-------------+-------------+-------------+-------------+ + * | | + * // (Object contents) // + * | | + * +-------------+-------------+-------------+-------------+ + * + * IPv4 ERROR_SPEC object: Class = 6, C-Type = 1 + * +-------------+-------------+-------------+-------------+ + * | IPv4 Error Node Address (4 bytes) | + * +-------------+-------------+-------------+-------------+ + * | Flags | Error Code | Error Value | + * +-------------+-------------+-------------+-------------+ + * + * IPv6 ERROR_SPEC object: Class = 6, C-Type = 2 + * +-------------+-------------+-------------+-------------+ + * | IPv6 Error Node Address (16 bytes) | + * +-------------+-------------+-------------+-------------+ + * | Flags | Error Code | Error Value | + * +-------------+-------------+-------------+-------------+ + */ + + (void)versioning; + struct pcep_object_tlv_rsvp_error_spec *rsvp_hdr = + (struct pcep_object_tlv_rsvp_error_spec *)tlv; + tlv_body_buf[2] = rsvp_hdr->class_num; + tlv_body_buf[3] = rsvp_hdr->c_type; + + uint16_t *length_ptr = (uint16_t *)tlv_body_buf; + uint32_t *uint32_ptr = (uint32_t *)(tlv_body_buf + LENGTH_1WORD); + if (rsvp_hdr->c_type == RSVP_ERROR_SPEC_IPV4_CTYPE) { + *length_ptr = htons(LENGTH_3WORDS); + *uint32_ptr = + rsvp_hdr->error_spec_ip.ipv4_error_node_address.s_addr; + tlv_body_buf[LENGTH_2WORDS + 1] = rsvp_hdr->error_code; + uint16_t *uint16_ptr = + (uint16_t *)(tlv_body_buf + LENGTH_2WORDS + 2); + *uint16_ptr = htons(rsvp_hdr->error_value); + + return LENGTH_3WORDS; + } else if (rsvp_hdr->c_type == RSVP_ERROR_SPEC_IPV6_CTYPE) { + *length_ptr = htons(LENGTH_6WORDS); + encode_ipv6(&rsvp_hdr->error_spec_ip.ipv6_error_node_address, + uint32_ptr); + tlv_body_buf[LENGTH_5WORDS + 1] = rsvp_hdr->error_code; + uint16_t *uint16_ptr = + (uint16_t *)(tlv_body_buf + LENGTH_5WORDS + 2); + *uint16_ptr = htons(rsvp_hdr->error_value); + + return LENGTH_6WORDS; + } + + return 0; +} + +uint16_t pcep_encode_tlv_lsp_db_version(struct pcep_object_tlv_header *tlv, + struct pcep_versioning *versioning, + uint8_t *tlv_body_buf) +{ + (void)versioning; + struct pcep_object_tlv_lsp_db_version *lsp_db_ver = + (struct pcep_object_tlv_lsp_db_version *)tlv; + *((uint64_t *)tlv_body_buf) = htobe64(lsp_db_ver->lsp_db_version); + + return LENGTH_2WORDS; +} + +uint16_t pcep_encode_tlv_speaker_entity_id(struct pcep_object_tlv_header *tlv, + struct pcep_versioning *versioning, + uint8_t *tlv_body_buf) +{ + (void)versioning; + struct pcep_object_tlv_speaker_entity_identifier *speaker_id = + (struct pcep_object_tlv_speaker_entity_identifier *)tlv; + if (speaker_id->speaker_entity_id_list == NULL) { + return 0; + } + + int index = 0; + uint32_t *uint32_ptr = (uint32_t *)tlv_body_buf; + double_linked_list_node *node = + speaker_id->speaker_entity_id_list->head; + for (; node != NULL; node = node->next_node) { + uint32_ptr[index++] = htonl(*((uint32_t *)node->data)); + } + + return speaker_id->speaker_entity_id_list->num_entries * LENGTH_1WORD; +} + +uint16_t pcep_encode_tlv_sr_pce_capability(struct pcep_object_tlv_header *tlv, + struct pcep_versioning *versioning, + uint8_t *tlv_body_buf) +{ + (void)versioning; + struct pcep_object_tlv_sr_pce_capability *sr_pce_cap = + (struct pcep_object_tlv_sr_pce_capability *)tlv; + tlv_body_buf[2] = + ((sr_pce_cap->flag_n == true ? TLV_SR_PCE_CAP_FLAG_N : 0x00) + | (sr_pce_cap->flag_x == true ? TLV_SR_PCE_CAP_FLAG_X : 0x00)); + tlv_body_buf[3] = sr_pce_cap->max_sid_depth; + + return LENGTH_1WORD; +} + +uint16_t pcep_encode_tlv_path_setup_type(struct pcep_object_tlv_header *tlv, + struct pcep_versioning *versioning, + uint8_t *tlv_body_buf) +{ + (void)versioning; + struct pcep_object_tlv_path_setup_type *pst = + (struct pcep_object_tlv_path_setup_type *)tlv; + tlv_body_buf[3] = pst->path_setup_type; + + return LENGTH_1WORD; +} + +uint16_t +pcep_encode_tlv_path_setup_type_capability(struct pcep_object_tlv_header *tlv, + struct pcep_versioning *versioning, + uint8_t *tlv_body_buf) +{ + (void)versioning; + struct pcep_object_tlv_path_setup_type_capability *pst_cap = + (struct pcep_object_tlv_path_setup_type_capability *)tlv; + if (pst_cap->pst_list == NULL) { + return 0; + } + + tlv_body_buf[3] = pst_cap->pst_list->num_entries; + + /* Index past the reserved and NumPSTs fields */ + int index = 4; + double_linked_list_node *node = pst_cap->pst_list->head; + for (; node != NULL; node = node->next_node) { + tlv_body_buf[index++] = *((uint8_t *)node->data); + } + + uint16_t pst_length = normalize_pcep_tlv_length( + LENGTH_1WORD + pst_cap->pst_list->num_entries); + if (pst_cap->sub_tlv_list == NULL) { + return pst_length; + } + + /* Any padding used for the PSTs should not be included in the tlv + * header length */ + index = normalize_pcep_tlv_length(index); + uint16_t sub_tlvs_length = 0; + node = pst_cap->sub_tlv_list->head; + for (; node != NULL; node = node->next_node) { + struct pcep_object_tlv_header *sub_tlv = + (struct pcep_object_tlv_header *)node->data; + uint16_t sub_tlv_length = pcep_encode_tlv(sub_tlv, versioning, + tlv_body_buf + index); + index += sub_tlv_length; + sub_tlvs_length += sub_tlv_length; + } + + return sub_tlvs_length + pst_length; +} +uint16_t pcep_encode_tlv_pol_id(struct pcep_object_tlv_header *tlv, + struct pcep_versioning *versioning, + uint8_t *tlv_body_buf) +{ + (void)versioning; + uint32_t *uint32_ptr = (uint32_t *)tlv_body_buf; + struct pcep_object_tlv_srpag_pol_id *ipv4 = + (struct pcep_object_tlv_srpag_pol_id *)tlv; + if (ipv4->is_ipv4) { + uint32_ptr[0] = htonl(ipv4->color); + uint32_ptr[1] = ipv4->end_point.ipv4.s_addr; + return LENGTH_2WORDS; + } else { + struct pcep_object_tlv_srpag_pol_id *ipv6 = + (struct pcep_object_tlv_srpag_pol_id *)tlv; + uint32_ptr[0] = htonl(ipv6->color); + encode_ipv6(&ipv6->end_point.ipv6, &uint32_ptr[1]); + return LENGTH_5WORDS; + } +} + +uint16_t pcep_encode_tlv_pol_name(struct pcep_object_tlv_header *tlv, + struct pcep_versioning *versioning, + uint8_t *tlv_body_buf) +{ + (void)versioning; + struct pcep_object_tlv_srpag_pol_name *pol_name_tlv = + (struct pcep_object_tlv_srpag_pol_name *)tlv; + memcpy(tlv_body_buf, pol_name_tlv->name, pol_name_tlv->name_length); + + return normalize_pcep_tlv_length(pol_name_tlv->name_length); +} + +uint16_t pcep_encode_tlv_cpath_id(struct pcep_object_tlv_header *tlv, + struct pcep_versioning *versioning, + uint8_t *tlv_body_buf) +{ + (void)versioning; + struct pcep_object_tlv_srpag_cp_id *cpath_id_tlv = + (struct pcep_object_tlv_srpag_cp_id *)tlv; + + uint32_t *uint32_ptr = (uint32_t *)tlv_body_buf; + tlv_body_buf[0] = cpath_id_tlv->proto; + uint32_ptr[1] = htonl(cpath_id_tlv->orig_asn); + encode_ipv6(&cpath_id_tlv->orig_addres, &uint32_ptr[2]); + uint32_ptr[6] = htonl(cpath_id_tlv->discriminator); + + return sizeof(cpath_id_tlv->proto) + sizeof(cpath_id_tlv->orig_asn) + + sizeof(cpath_id_tlv->orig_addres) + + sizeof(cpath_id_tlv->discriminator); +} + +uint16_t pcep_encode_tlv_cpath_preference(struct pcep_object_tlv_header *tlv, + struct pcep_versioning *versioning, + uint8_t *tlv_body_buf) +{ + (void)versioning; + struct pcep_object_tlv_srpag_cp_pref *cpath_pref_tlv = + (struct pcep_object_tlv_srpag_cp_pref *)tlv; + + uint32_t *uint32_ptr = (uint32_t *)tlv_body_buf; + uint32_ptr[0] = htonl(cpath_pref_tlv->preference); + + return sizeof(cpath_pref_tlv->preference); +} + +uint16_t pcep_encode_tlv_vendor_info(struct pcep_object_tlv_header *tlv, + struct pcep_versioning *versioning, + uint8_t *tlv_body_buf) +{ + (void)versioning; + struct pcep_object_tlv_vendor_info *vendor_info = + (struct pcep_object_tlv_vendor_info *)tlv; + + uint32_t *uint32_ptr = (uint32_t *)tlv_body_buf; + uint32_ptr[0] = htonl(vendor_info->enterprise_number); + uint32_ptr[1] = htonl(vendor_info->enterprise_specific_info); + + return LENGTH_2WORDS; +} + +uint16_t pcep_encode_tlv_arbitrary(struct pcep_object_tlv_header *tlv, + struct pcep_versioning *versioning, + uint8_t *tlv_body_buf) +{ + (void)versioning; + struct pcep_object_tlv_arbitrary *tlv_arbitrary = + (struct pcep_object_tlv_arbitrary *)tlv; + memcpy(tlv_body_buf, tlv_arbitrary->data, tlv_arbitrary->data_length); + tlv->type = tlv_arbitrary->arbitraty_type; + + return tlv_arbitrary->data_length; +} + +uint16_t pcep_encode_tlv_of_list(struct pcep_object_tlv_header *tlv, + struct pcep_versioning *versioning, + uint8_t *tlv_body_buf) +{ + (void)versioning; + struct pcep_object_tlv_of_list *of_list = + (struct pcep_object_tlv_of_list *)tlv; + + if (of_list->of_list == NULL) { + return 0; + } + + int index = 0; + double_linked_list_node *node = of_list->of_list->head; + while (node != NULL) { + uint16_t *of_code = (uint16_t *)node->data; + if (of_code == NULL) { + return 0; + } + + uint16_t *uint16_ptr = (uint16_t *)(tlv_body_buf + index); + *uint16_ptr = *of_code; + index += 2; + + node = node->next_node; + } + + return of_list->of_list->num_entries * 2; +} + +/* + * Decoding functions + */ + +void pcep_decode_tlv_hdr(const uint8_t *tlv_buf, + struct pcep_object_tlv_header *tlv_hdr) +{ + memset(tlv_hdr, 0, sizeof(struct pcep_object_tlv_header)); + + uint16_t *uint16_ptr = (uint16_t *)tlv_buf; + tlv_hdr->type = ntohs(uint16_ptr[0]); + tlv_hdr->encoded_tlv_length = ntohs(uint16_ptr[1]); + tlv_hdr->encoded_tlv = tlv_buf; +} + +struct pcep_object_tlv_header *pcep_decode_tlv(const uint8_t *tlv_buf) +{ + initialize_tlv_coders(); + + struct pcep_object_tlv_header tlv_hdr; + /* Only initializes and decodes the Object Header: class, type, flags, + * and length */ + pcep_decode_tlv_hdr(tlv_buf, &tlv_hdr); + + if (tlv_hdr.type >= MAX_TLV_ENCODER_INDEX) { + pcep_log(LOG_INFO, "%s: Cannot decode unknown TLV type [%d]", + __func__, tlv_hdr.type); + return NULL; + } + + tlv_decoder_funcptr tlv_decoder = tlv_decoders[tlv_hdr.type]; + if (tlv_decoder == NULL) { + pcep_log(LOG_INFO, "%s: No TLV decoder found for TLV type [%d]", + __func__, tlv_hdr.type); + return NULL; + } + + return tlv_decoder(&tlv_hdr, tlv_buf + LENGTH_1WORD); +} + +static struct pcep_object_tlv_header * +common_tlv_create(struct pcep_object_tlv_header *hdr, uint16_t new_tlv_length) +{ + struct pcep_object_tlv_header *new_tlv = + pceplib_malloc(PCEPLIB_MESSAGES, new_tlv_length); + memset(new_tlv, 0, new_tlv_length); + memcpy(new_tlv, hdr, sizeof(struct pcep_object_tlv_header)); + + return new_tlv; +} + +struct pcep_object_tlv_header * +pcep_decode_tlv_no_path_vector(struct pcep_object_tlv_header *tlv_hdr, + const uint8_t *tlv_body_buf) +{ + struct pcep_object_tlv_nopath_vector *tlv = + (struct pcep_object_tlv_nopath_vector *)common_tlv_create( + tlv_hdr, sizeof(struct pcep_object_tlv_nopath_vector)); + + tlv->error_code = ntohl(*((uint32_t *)tlv_body_buf)); + + return (struct pcep_object_tlv_header *)tlv; +} + +struct pcep_object_tlv_header * +pcep_decode_tlv_stateful_pce_capability(struct pcep_object_tlv_header *tlv_hdr, + const uint8_t *tlv_body_buf) +{ + struct pcep_object_tlv_stateful_pce_capability *tlv = + (struct pcep_object_tlv_stateful_pce_capability *) + common_tlv_create( + tlv_hdr, + sizeof(struct + pcep_object_tlv_stateful_pce_capability)); + + tlv->flag_f_triggered_initial_sync = + (tlv_body_buf[3] & TLV_STATEFUL_PCE_CAP_FLAG_F); + tlv->flag_d_delta_lsp_sync = + (tlv_body_buf[3] & TLV_STATEFUL_PCE_CAP_FLAG_D); + tlv->flag_t_triggered_resync = + (tlv_body_buf[3] & TLV_STATEFUL_PCE_CAP_FLAG_T); + tlv->flag_i_lsp_instantiation_capability = + (tlv_body_buf[3] & TLV_STATEFUL_PCE_CAP_FLAG_I); + tlv->flag_s_include_db_version = + (tlv_body_buf[3] & TLV_STATEFUL_PCE_CAP_FLAG_S); + tlv->flag_u_lsp_update_capability = + (tlv_body_buf[3] & TLV_STATEFUL_PCE_CAP_FLAG_U); + + return (struct pcep_object_tlv_header *)tlv; +} + +struct pcep_object_tlv_header * +pcep_decode_tlv_symbolic_path_name(struct pcep_object_tlv_header *tlv_hdr, + const uint8_t *tlv_body_buf) +{ + struct pcep_object_tlv_symbolic_path_name *tlv = + (struct pcep_object_tlv_symbolic_path_name *)common_tlv_create( + tlv_hdr, + sizeof(struct pcep_object_tlv_symbolic_path_name)); + + uint16_t length = tlv_hdr->encoded_tlv_length; + if (length > MAX_SYMBOLIC_PATH_NAME) { + /* TODO should we also reset the tlv_hdr->encoded_tlv_length ? + */ + length = MAX_SYMBOLIC_PATH_NAME; + pcep_log( + LOG_INFO, + "%s: Decoding Symbolic Path Name TLV, truncate path name from [%d] to [%d].\",", + __func__, tlv_hdr->encoded_tlv_length, + MAX_SYMBOLIC_PATH_NAME); + } + + tlv->symbolic_path_name_length = length; + memcpy(tlv->symbolic_path_name, tlv_body_buf, length); + + return (struct pcep_object_tlv_header *)tlv; +} + +struct pcep_object_tlv_header * +pcep_decode_tlv_ipv4_lsp_identifiers(struct pcep_object_tlv_header *tlv_hdr, + const uint8_t *tlv_body_buf) +{ + struct pcep_object_tlv_ipv4_lsp_identifier *tlv = + (struct pcep_object_tlv_ipv4_lsp_identifier *)common_tlv_create( + tlv_hdr, + sizeof(struct pcep_object_tlv_ipv4_lsp_identifier)); + + uint32_t *uint32_ptr = (uint32_t *)tlv_body_buf; + tlv->ipv4_tunnel_sender.s_addr = uint32_ptr[0]; + /* uint32_t[1] is lsp_id and tunnel_id, below */ + tlv->extended_tunnel_id.s_addr = uint32_ptr[2]; + tlv->ipv4_tunnel_endpoint.s_addr = uint32_ptr[3]; + + uint16_t *uint16_ptr = (uint16_t *)(tlv_body_buf + LENGTH_1WORD); + tlv->lsp_id = ntohs(uint16_ptr[0]); + tlv->tunnel_id = ntohs(uint16_ptr[1]); + + return (struct pcep_object_tlv_header *)tlv; +} + +struct pcep_object_tlv_header * +pcep_decode_tlv_ipv6_lsp_identifiers(struct pcep_object_tlv_header *tlv_hdr, + const uint8_t *tlv_body_buf) +{ + struct pcep_object_tlv_ipv6_lsp_identifier *tlv = + (struct pcep_object_tlv_ipv6_lsp_identifier *)common_tlv_create( + tlv_hdr, + sizeof(struct pcep_object_tlv_ipv6_lsp_identifier)); + + uint32_t *uint32_ptr = (uint32_t *)tlv_body_buf; + decode_ipv6(uint32_ptr, &tlv->ipv6_tunnel_sender); + decode_ipv6(uint32_ptr + 5, &tlv->extended_tunnel_id); + decode_ipv6(uint32_ptr + 9, &tlv->ipv6_tunnel_endpoint); + + uint16_t *uint16_ptr = (uint16_t *)(tlv_body_buf + LENGTH_4WORDS); + tlv->lsp_id = htons(uint16_ptr[0]); + tlv->tunnel_id = htons(uint16_ptr[1]); + + return (struct pcep_object_tlv_header *)tlv; +} + +struct pcep_object_tlv_header * +pcep_decode_tlv_lsp_error_code(struct pcep_object_tlv_header *tlv_hdr, + const uint8_t *tlv_body_buf) +{ + struct pcep_object_tlv_lsp_error_code *tlv = + (struct pcep_object_tlv_lsp_error_code *)common_tlv_create( + tlv_hdr, sizeof(struct pcep_object_tlv_lsp_error_code)); + + tlv->lsp_error_code = ntohl(*((uint32_t *)tlv_body_buf)); + + return (struct pcep_object_tlv_header *)tlv; +} + +struct pcep_object_tlv_header * +pcep_decode_tlv_rsvp_error_spec(struct pcep_object_tlv_header *tlv_hdr, + const uint8_t *tlv_body_buf) +{ + uint8_t class_num = tlv_body_buf[2]; + uint8_t ctype = tlv_body_buf[3]; + + if (class_num != RSVP_ERROR_SPEC_CLASS_NUM) { + pcep_log( + LOG_INFO, + "%s: Decoding RSVP Error Spec TLV, unknown class num [%d]", + __func__, class_num); + return NULL; + } + + if (ctype != RSVP_ERROR_SPEC_IPV4_CTYPE + && ctype != RSVP_ERROR_SPEC_IPV6_CTYPE) { + pcep_log(LOG_INFO, + "%s: Decoding RSVP Error Spec TLV, unknown ctype [%d]", + __func__, ctype); + return NULL; + } + + struct pcep_object_tlv_rsvp_error_spec *tlv = + (struct pcep_object_tlv_rsvp_error_spec *)common_tlv_create( + tlv_hdr, + sizeof(struct pcep_object_tlv_rsvp_error_spec)); + + tlv->class_num = class_num; + tlv->c_type = ctype; + + uint32_t *uint32_ptr = (uint32_t *)(tlv_body_buf + LENGTH_1WORD); + if (ctype == RSVP_ERROR_SPEC_IPV4_CTYPE) { + tlv->error_spec_ip.ipv4_error_node_address.s_addr = *uint32_ptr; + tlv->error_code = tlv_body_buf[LENGTH_2WORDS + 1]; + tlv->error_value = ntohs( + *((uint16_t *)(tlv_body_buf + LENGTH_2WORDS + 2))); + } else /* RSVP_ERROR_SPEC_IPV6_CTYPE */ + { + decode_ipv6(uint32_ptr, + &tlv->error_spec_ip.ipv6_error_node_address); + tlv->error_code = tlv_body_buf[LENGTH_5WORDS + 1]; + tlv->error_value = ntohs( + *((uint16_t *)(tlv_body_buf + LENGTH_5WORDS + 2))); + } + + return (struct pcep_object_tlv_header *)tlv; +} + +struct pcep_object_tlv_header * +pcep_decode_tlv_lsp_db_version(struct pcep_object_tlv_header *tlv_hdr, + const uint8_t *tlv_body_buf) +{ + struct pcep_object_tlv_lsp_db_version *tlv = + (struct pcep_object_tlv_lsp_db_version *)common_tlv_create( + tlv_hdr, sizeof(struct pcep_object_tlv_lsp_db_version)); + + tlv->lsp_db_version = be64toh(*((uint64_t *)tlv_body_buf)); + + return (struct pcep_object_tlv_header *)tlv; +} + +struct pcep_object_tlv_header * +pcep_decode_tlv_speaker_entity_id(struct pcep_object_tlv_header *tlv_hdr, + const uint8_t *tlv_body_buf) +{ + struct pcep_object_tlv_speaker_entity_identifier *tlv = + (struct pcep_object_tlv_speaker_entity_identifier *) + common_tlv_create( + tlv_hdr, + sizeof(struct + pcep_object_tlv_speaker_entity_identifier)); + + uint8_t num_entity_ids = tlv_hdr->encoded_tlv_length / LENGTH_1WORD; + if (num_entity_ids > MAX_ITERATIONS) { + num_entity_ids = MAX_ITERATIONS; + pcep_log( + LOG_INFO, + "%s: Decode Speaker Entity ID, truncating num entities from [%d] to [%d].", + __func__, num_entity_ids, MAX_ITERATIONS); + } + + uint32_t *uint32_ptr = (uint32_t *)tlv_body_buf; + tlv->speaker_entity_id_list = dll_initialize(); + int i; + for (i = 0; i < num_entity_ids; i++) { + uint32_t *entity_id = + pceplib_malloc(PCEPLIB_MESSAGES, sizeof(uint32_t)); + *entity_id = ntohl(uint32_ptr[i]); + dll_append(tlv->speaker_entity_id_list, entity_id); + } + + return (struct pcep_object_tlv_header *)tlv; +} + +struct pcep_object_tlv_header * +pcep_decode_tlv_sr_pce_capability(struct pcep_object_tlv_header *tlv_hdr, + const uint8_t *tlv_body_buf) +{ + struct pcep_object_tlv_sr_pce_capability *tlv = + (struct pcep_object_tlv_sr_pce_capability *)common_tlv_create( + tlv_hdr, + sizeof(struct pcep_object_tlv_sr_pce_capability)); + + tlv->flag_n = (tlv_body_buf[2] & TLV_SR_PCE_CAP_FLAG_N); + tlv->flag_x = (tlv_body_buf[2] & TLV_SR_PCE_CAP_FLAG_X); + tlv->max_sid_depth = tlv_body_buf[3]; + + return (struct pcep_object_tlv_header *)tlv; +} + +struct pcep_object_tlv_header * +pcep_decode_tlv_path_setup_type(struct pcep_object_tlv_header *tlv_hdr, + const uint8_t *tlv_body_buf) +{ + struct pcep_object_tlv_path_setup_type *tlv = + (struct pcep_object_tlv_path_setup_type *)common_tlv_create( + tlv_hdr, + sizeof(struct pcep_object_tlv_path_setup_type)); + + tlv->path_setup_type = tlv_body_buf[3]; + + return (struct pcep_object_tlv_header *)tlv; +} + +struct pcep_object_tlv_header *pcep_decode_tlv_path_setup_type_capability( + struct pcep_object_tlv_header *tlv_hdr, const uint8_t *tlv_body_buf) +{ + struct pcep_object_tlv_path_setup_type_capability *tlv = + (struct pcep_object_tlv_path_setup_type_capability *) + common_tlv_create( + tlv_hdr, + sizeof(struct + pcep_object_tlv_path_setup_type_capability)); + + uint8_t num_psts = tlv_body_buf[3]; + if (num_psts > MAX_ITERATIONS) { + pcep_log( + LOG_INFO, + "%s: Decode Path Setup Type Capability num PSTs [%d] exceeds MAX [%d] continuing anyways", + __func__, num_psts, MAX_ITERATIONS); + } + + int i; + tlv->pst_list = dll_initialize(); + for (i = 0; i < num_psts; i++) { + uint8_t *pst = + pceplib_malloc(PCEPLIB_MESSAGES, sizeof(uint8_t)); + *pst = tlv_body_buf[i + LENGTH_1WORD]; + dll_append(tlv->pst_list, pst); + } + + if (tlv->header.encoded_tlv_length + == (TLV_HEADER_LENGTH + LENGTH_1WORD + num_psts)) { + return (struct pcep_object_tlv_header *)tlv; + } + + uint8_t num_iterations = 0; + tlv->sub_tlv_list = dll_initialize(); + 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) { + struct pcep_object_tlv_header *sub_tlv = + pcep_decode_tlv(tlv_body_buf + buf_index); + if (sub_tlv == NULL) { + pcep_log( + LOG_INFO, + "%s: Decode PathSetupType Capability sub-TLV decode returned NULL", + __func__); + return (struct pcep_object_tlv_header *)tlv; + } + + buf_index += + normalize_pcep_tlv_length(sub_tlv->encoded_tlv_length); + dll_append(tlv->sub_tlv_list, sub_tlv); + } + + return (struct pcep_object_tlv_header *)tlv; +} +struct pcep_object_tlv_header * +pcep_decode_tlv_pol_id(struct pcep_object_tlv_header *tlv_hdr, + const uint8_t *tlv_body_buf) +{ + uint32_t *uint32_ptr = (uint32_t *)tlv_body_buf; + struct pcep_object_tlv_srpag_pol_id *ipv4 = + (struct pcep_object_tlv_srpag_pol_id *)common_tlv_create( + tlv_hdr, sizeof(struct pcep_object_tlv_srpag_pol_id)); + if (tlv_hdr->encoded_tlv_length == 8) { + ipv4->is_ipv4 = true; + ipv4->color = ntohl(uint32_ptr[0]); + ipv4->end_point.ipv4.s_addr = uint32_ptr[1]; + return (struct pcep_object_tlv_header *)ipv4; + } else { + ipv4->is_ipv4 = false; + struct pcep_object_tlv_srpag_pol_id *ipv6 = + (struct pcep_object_tlv_srpag_pol_id *)ipv4; + ipv6->color = ntohl(uint32_ptr[0]); + decode_ipv6(&uint32_ptr[1], &ipv6->end_point.ipv6); + return (struct pcep_object_tlv_header *)ipv6; + } +} +struct pcep_object_tlv_header * +pcep_decode_tlv_pol_name(struct pcep_object_tlv_header *tlv_hdr, + const uint8_t *tlv_body_buf) +{ + struct pcep_object_tlv_srpag_pol_name *tlv = + (struct pcep_object_tlv_srpag_pol_name *)common_tlv_create( + tlv_hdr, sizeof(struct pcep_object_tlv_srpag_pol_name)); + + memcpy(tlv->name, tlv_body_buf, tlv->header.encoded_tlv_length); + + return (struct pcep_object_tlv_header *)tlv; +} +struct pcep_object_tlv_header * +pcep_decode_tlv_cpath_id(struct pcep_object_tlv_header *tlv_hdr, + const uint8_t *tlv_body_buf) +{ + uint32_t *uint32_ptr = (uint32_t *)tlv_body_buf; + struct pcep_object_tlv_srpag_cp_id *tlv = + (struct pcep_object_tlv_srpag_cp_id *)common_tlv_create( + tlv_hdr, sizeof(struct pcep_object_tlv_srpag_cp_id)); + + tlv->proto = tlv_body_buf[0]; + tlv->orig_asn = ntohl(uint32_ptr[1]); + decode_ipv6(&uint32_ptr[2], &tlv->orig_addres); + tlv->discriminator = ntohl(uint32_ptr[6]); + + return (struct pcep_object_tlv_header *)tlv; +} +struct pcep_object_tlv_header * +pcep_decode_tlv_cpath_preference(struct pcep_object_tlv_header *tlv_hdr, + const uint8_t *tlv_body_buf) +{ + uint32_t *uint32_ptr = (uint32_t *)tlv_body_buf; + struct pcep_object_tlv_srpag_cp_pref *tlv = + (struct pcep_object_tlv_srpag_cp_pref *)common_tlv_create( + tlv_hdr, sizeof(struct pcep_object_tlv_srpag_cp_pref)); + + tlv->preference = ntohl(uint32_ptr[0]); + + return (struct pcep_object_tlv_header *)tlv; +} + +struct pcep_object_tlv_header * +pcep_decode_tlv_vendor_info(struct pcep_object_tlv_header *tlv_hdr, + const uint8_t *tlv_body_buf) +{ + struct pcep_object_tlv_vendor_info *tlv = + (struct pcep_object_tlv_vendor_info *)common_tlv_create( + tlv_hdr, sizeof(struct pcep_object_tlv_vendor_info)); + + uint32_t *uint32_ptr = (uint32_t *)tlv_body_buf; + tlv->enterprise_number = ntohl(uint32_ptr[0]); + tlv->enterprise_specific_info = ntohl(uint32_ptr[1]); + + return (struct pcep_object_tlv_header *)tlv; +} + +struct pcep_object_tlv_header * +pcep_decode_tlv_arbitrary(struct pcep_object_tlv_header *tlv_hdr, + const uint8_t *tlv_body_buf) +{ + struct pcep_object_tlv_arbitrary *tlv_arbitrary = + (struct pcep_object_tlv_arbitrary *)common_tlv_create( + tlv_hdr, sizeof(struct pcep_object_tlv_arbitrary)); + + uint16_t length = tlv_hdr->encoded_tlv_length; + if (length > MAX_ARBITRARY_SIZE) { + /* TODO should we also reset the tlv_hdr->encoded_tlv_length ? + */ + length = MAX_ARBITRARY_SIZE; + pcep_log( + LOG_INFO, + "%s: Decoding Arbitrary TLV , truncate path name from [%d] to [%d].\",", + __func__, tlv_hdr->encoded_tlv_length, + MAX_ARBITRARY_SIZE); + } + + tlv_arbitrary->data_length = length; + tlv_arbitrary->arbitraty_type = tlv_hdr->type; + tlv_hdr->type = PCEP_OBJ_TLV_TYPE_ARBITRARY; + memcpy(tlv_arbitrary->data, tlv_body_buf, length); + + return (struct pcep_object_tlv_header *)tlv_arbitrary; +} + +struct pcep_object_tlv_header * +pcep_decode_tlv_of_list(struct pcep_object_tlv_header *tlv_hdr, + const uint8_t *tlv_body_buf) +{ + struct pcep_object_tlv_of_list *of_tlv = + (struct pcep_object_tlv_of_list *)common_tlv_create( + tlv_hdr, sizeof(struct pcep_object_tlv_of_list)); + + of_tlv->of_list = dll_initialize(); + uint16_t *uint16_ptr = (uint16_t *)tlv_body_buf; + int i = 0; + for (; i < tlv_hdr->encoded_tlv_length && i < MAX_ITERATIONS; i++) { + uint16_t *of_code_ptr = + pceplib_malloc(PCEPLIB_MESSAGES, sizeof(uint16_t)); + *of_code_ptr = ntohs(uint16_ptr[i]); + dll_append(of_tlv->of_list, of_code_ptr); + } + + return (struct pcep_object_tlv_header *)of_tlv; +} diff --git a/pceplib/pcep_msg_tools.c b/pceplib/pcep_msg_tools.c new file mode 100644 index 0000000000..e190d2a850 --- /dev/null +++ b/pceplib/pcep_msg_tools.c @@ -0,0 +1,479 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Brady Johnson <brady@voltanet.io> + * + */ + + +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +#include "pcep_msg_tools.h" +#include "pcep_msg_encoding.h" +#include "pcep_utils_logging.h" +#include "pcep_utils_memory.h" + +static const char *message_type_strs[] = {"NOT_IMPLEMENTED0", + "OPEN", + "KEEPALIVE", + "PCREQ", + "PCREP", + "PCNOTF", + "ERROR", + "CLOSE", + "NOT_IMPLEMENTED8", + "NOT_IMPLEMENTED9", + "REPORT", + "UPDATE", + "INITIATE", + "UNKOWN_MESSAGE_TYPE"}; + +static const char *object_class_strs[] = {"NOT_IMPLEMENTED0", + "OPEN", + "RP", + "NOPATH", + "ENDPOINTS", + "BANDWIDTH", + "METRIC", + "ERO", + "RRO", + "LSPA", + "IRO", + "SVEC", + "NOTF", + "ERROR", + "NOT_IMPLEMENTED14", + "CLOSE", + "NOT_IMPLEMENTED16", + "NOT_IMPLEMENTED17", + "NOT_IMPLEMENTED18", + "NOT_IMPLEMENTED19", + "NOT_IMPLEMENTED20", + "OBJECTIVE_FUNCTION", + "NOT_IMPLEMENTED22", + "NOT_IMPLEMENTED23", + "NOT_IMPLEMENTED24", + "NOT_IMPLEMENTED25", + "NOT_IMPLEMENTED26", + "NOT_IMPLEMENTED27", + "NOT_IMPLEMENTED28", + "NOT_IMPLEMENTED29", + "NOT_IMPLEMENTED30", + "NOT_IMPLEMENTED31", + "LSP", + "SRP", + "VENDOR_INFO", + "NOT_IMPLEMENTED35", + "INTER_LAYER", + "SWITCH_LAYER", + "REQ_ADAP_CAP", + "SERVER_IND", + "ASSOCIATION", /* 40 */ + "UNKNOWN_MESSAGE_TYPE"}; + + +double_linked_list *pcep_msg_read(int sock_fd) +{ + int ret; + uint8_t buffer[PCEP_MESSAGE_LENGTH] = {0}; + uint16_t buffer_read = 0; + + + ret = read(sock_fd, &buffer, PCEP_MESSAGE_LENGTH); + + if (ret < 0) { + pcep_log( + LOG_INFO, + "%s: pcep_msg_read: Failed to read from socket fd [%d] errno [%d %s]", + __func__, sock_fd, errno, strerror(errno)); + return NULL; + } else if (ret == 0) { + pcep_log(LOG_INFO, "%s: pcep_msg_read: Remote shutdown fd [%d]", + __func__, sock_fd); + return NULL; + } + + double_linked_list *msg_list = dll_initialize(); + struct pcep_message *msg = NULL; + + while (((uint16_t)ret - buffer_read) >= MESSAGE_HEADER_LENGTH) { + + /* Get the Message header, validate it, and return the msg + * length */ + int32_t msg_length = + pcep_decode_validate_msg_header(buffer + buffer_read); + 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( + LOG_INFO, + "%s: pcep_msg_read: Received an invalid message fd [%d]", + __func__, sock_fd); + return msg_list; + } + + /* 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_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); + + 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( + LOG_INFO, + "%s: pcep_msg_read: Did not manage to read enough data (%d != %d) fd [%d]", + __func__, read_ret, read_len, sock_fd); + return msg_list; + } + } + + msg = pcep_decode_message(buffer + buffer_read); + buffer_read += msg_length; + + if (msg == NULL) { + return msg_list; + } else { + dll_append(msg_list, msg); + } + } + + return msg_list; +} + +struct pcep_message *pcep_msg_get(double_linked_list *msg_list, uint8_t type) +{ + if (msg_list == NULL) { + return NULL; + } + + double_linked_list_node *node; + for (node = msg_list->head; node != NULL; node = node->next_node) { + if (((struct pcep_message *)node->data)->msg_header->type + == type) { + return (struct pcep_message *)node->data; + } + } + + return NULL; +} + +struct pcep_message *pcep_msg_get_next(double_linked_list *list, + struct pcep_message *current, + uint8_t type) +{ + if (list == NULL || current == NULL) { + return NULL; + } + + if (list->head == NULL) { + return NULL; + } + + double_linked_list_node *node; + for (node = list->head; node != NULL; node = node->next_node) { + if (node->data == current) { + continue; + } + + if (((struct pcep_message *)node->data)->msg_header->type + == type) { + return (struct pcep_message *)node->data; + } + } + + return NULL; +} + +struct pcep_object_header *pcep_obj_get(double_linked_list *list, + uint8_t object_class) +{ + if (list == NULL) { + return NULL; + } + + if (list->head == NULL) { + return NULL; + } + + double_linked_list_node *obj_item; + for (obj_item = list->head; obj_item != NULL; + obj_item = obj_item->next_node) { + if (((struct pcep_object_header *)obj_item->data)->object_class + == object_class) { + return (struct pcep_object_header *)obj_item->data; + } + } + + return NULL; +} + +struct pcep_object_header *pcep_obj_get_next(double_linked_list *list, + struct pcep_object_header *current, + uint8_t object_class) +{ + if (list == NULL || current == NULL) { + return NULL; + } + + if (list->head == NULL) { + return NULL; + } + + double_linked_list_node *node; + for (node = list->head; node != NULL; node = node->next_node) { + if (node->data == current) { + continue; + } + + if (((struct pcep_object_header *)node->data)->object_class + == object_class) { + return (struct pcep_object_header *)node->data; + } + } + + return NULL; +} + +void pcep_obj_free_tlv(struct pcep_object_tlv_header *tlv) +{ + /* Specific TLV freeing */ + switch (tlv->type) { + case PCEP_OBJ_TLV_TYPE_SPEAKER_ENTITY_ID: + if (((struct pcep_object_tlv_speaker_entity_identifier *)tlv) + ->speaker_entity_id_list + != NULL) { + dll_destroy_with_data_memtype( + ((struct + pcep_object_tlv_speaker_entity_identifier *) + tlv) + ->speaker_entity_id_list, + PCEPLIB_MESSAGES); + } + break; + + case PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE_CAPABILITY: + if (((struct pcep_object_tlv_path_setup_type_capability *)tlv) + ->pst_list + != NULL) { + dll_destroy_with_data_memtype( + ((struct + pcep_object_tlv_path_setup_type_capability *) + tlv) + ->pst_list, + PCEPLIB_MESSAGES); + } + + if (((struct pcep_object_tlv_path_setup_type_capability *)tlv) + ->sub_tlv_list + != NULL) { + dll_destroy_with_data_memtype( + ((struct + pcep_object_tlv_path_setup_type_capability *) + tlv) + ->sub_tlv_list, + PCEPLIB_MESSAGES); + } + break; + + default: + break; + } + + pceplib_free(PCEPLIB_MESSAGES, tlv); +} + +void pcep_obj_free_object(struct pcep_object_header *obj) +{ + /* Iterate the TLVs and free each one */ + if (obj->tlv_list != NULL) { + struct pcep_object_tlv_header *tlv; + while ((tlv = (struct pcep_object_tlv_header *) + dll_delete_first_node(obj->tlv_list)) + != NULL) { + pcep_obj_free_tlv(tlv); + } + + dll_destroy(obj->tlv_list); + } + + /* Specific object freeing */ + switch (obj->object_class) { + case PCEP_OBJ_CLASS_ERO: + case PCEP_OBJ_CLASS_IRO: + case PCEP_OBJ_CLASS_RRO: { + if (((struct pcep_object_ro *)obj)->sub_objects != NULL) { + double_linked_list_node *node = + ((struct pcep_object_ro *)obj) + ->sub_objects->head; + for (; node != NULL; node = node->next_node) { + struct pcep_object_ro_subobj *ro_subobj = + (struct pcep_object_ro_subobj *) + node->data; + if (ro_subobj->ro_subobj_type + == RO_SUBOBJ_TYPE_SR) { + if (((struct pcep_ro_subobj_sr *) + ro_subobj) + ->nai_list + != NULL) { + dll_destroy_with_data_memtype( + ((struct + pcep_ro_subobj_sr *) + ro_subobj) + ->nai_list, + PCEPLIB_MESSAGES); + } + } + } + dll_destroy_with_data_memtype( + ((struct pcep_object_ro *)obj)->sub_objects, + PCEPLIB_MESSAGES); + } + } break; + + case PCEP_OBJ_CLASS_SVEC: + if (((struct pcep_object_svec *)obj)->request_id_list != NULL) { + dll_destroy_with_data_memtype( + ((struct pcep_object_svec *)obj) + ->request_id_list, + PCEPLIB_MESSAGES); + } + break; + + case PCEP_OBJ_CLASS_SWITCH_LAYER: + if (((struct pcep_object_switch_layer *)obj)->switch_layer_rows + != NULL) { + dll_destroy_with_data_memtype( + ((struct pcep_object_switch_layer *)obj) + ->switch_layer_rows, + PCEPLIB_MESSAGES); + } + break; + + default: + break; + } + + pceplib_free(PCEPLIB_MESSAGES, obj); +} + +void pcep_msg_free_message(struct pcep_message *message) +{ + /* Iterate the objects and free each one */ + if (message->obj_list != NULL) { + struct pcep_object_header *obj; + while ((obj = (struct pcep_object_header *) + dll_delete_first_node(message->obj_list)) + != NULL) { + pcep_obj_free_object(obj); + } + + dll_destroy(message->obj_list); + } + + if (message->msg_header != NULL) { + pceplib_free(PCEPLIB_MESSAGES, message->msg_header); + } + + if (message->encoded_message != NULL) { + pceplib_free(PCEPLIB_MESSAGES, message->encoded_message); + } + + pceplib_free(PCEPLIB_MESSAGES, message); +} + +void pcep_msg_free_message_list(double_linked_list *list) +{ + /* Iterate the messages and free each one */ + struct pcep_message *msg; + while ((msg = (struct pcep_message *)dll_delete_first_node(list)) + != NULL) { + pcep_msg_free_message(msg); + } + + dll_destroy(list); +} + +const char *get_message_type_str(uint8_t type) +{ + uint8_t msg_type = + (type > PCEP_TYPE_INITIATE) ? PCEP_TYPE_INITIATE + 1 : type; + + return message_type_strs[msg_type]; +} + +const char *get_object_class_str(uint8_t class) +{ + uint8_t object_class = + (class > PCEP_OBJ_CLASS_SRP) ? PCEP_OBJ_CLASS_SRP + 1 : class; + + return object_class_strs[object_class]; +} + +/* Expecting a list of struct pcep_message pointers */ +void pcep_msg_print(double_linked_list *msg_list) +{ + double_linked_list_node *node; + for (node = msg_list->head; node != NULL; node = node->next_node) { + struct pcep_message *msg = (struct pcep_message *)node->data; + pcep_log(LOG_INFO, "%s: PCEP_MSG %s", __func__, + get_message_type_str(msg->msg_header->type)); + + double_linked_list_node *obj_node = + (msg->obj_list == NULL ? NULL : msg->obj_list->head); + for (; obj_node != NULL; obj_node = obj_node->next_node) { + struct pcep_object_header *obj_header = + ((struct pcep_object_header *)obj_node->data); + pcep_log( + LOG_INFO, "%s: PCEP_OBJ %s", __func__, + get_object_class_str(obj_header->object_class)); + } + } +} + +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, msg_length); +} diff --git a/pceplib/pcep_msg_tools.h b/pceplib/pcep_msg_tools.h new file mode 100644 index 0000000000..b62bdde1cf --- /dev/null +++ b/pceplib/pcep_msg_tools.h @@ -0,0 +1,71 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Brady Johnson <brady@voltanet.io> + */ + +#ifndef PCEP_TOOLS_H +#define PCEP_TOOLS_H + +#include <stdint.h> +#include <netinet/in.h> // struct in_addr + +#include "pcep_utils_double_linked_list.h" +#include "pcep_msg_messages.h" +#include "pcep_msg_objects.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define PCEP_MAX_SIZE 6000 + +/* Returns a double linked list of PCEP messages */ +double_linked_list *pcep_msg_read(int sock_fd); +/* Given a double linked list of PCEP messages, return the first node that has + * the same message type */ +struct pcep_message *pcep_msg_get(double_linked_list *msg_list, uint8_t type); +/* Given a double linked list of PCEP messages, return the next node after + * current node that has the same message type */ +struct pcep_message *pcep_msg_get_next(double_linked_list *msg_list, + struct pcep_message *current, + uint8_t type); +struct pcep_object_header *pcep_obj_get(double_linked_list *list, + uint8_t object_class); +struct pcep_object_header *pcep_obj_get_next(double_linked_list *list, + struct pcep_object_header *current, + uint8_t object_class); +struct pcep_object_tlv_header *pcep_tlv_get(double_linked_list *list, + uint16_t type); +struct pcep_object_tlv_header * +pcep_tlv_get_next(double_linked_list *list, + struct pcep_object_tlv_header *current, uint16_t type); +void pcep_obj_free_tlv(struct pcep_object_tlv_header *tlv); +void pcep_obj_free_object(struct pcep_object_header *obj); +void pcep_msg_free_message(struct pcep_message *message); +void pcep_msg_free_message_list(double_linked_list *list); +void pcep_msg_print(double_linked_list *list); +const char *get_message_type_str(uint8_t type); +const char *get_object_class_str(uint8_t class); +int pcep_msg_send(int sock_fd, struct pcep_message *hdr); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/pceplib/pcep_pcc.c b/pceplib/pcep_pcc.c new file mode 100644 index 0000000000..1a702a8b63 --- /dev/null +++ b/pceplib/pcep_pcc.c @@ -0,0 +1,520 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Brady Johnson <brady@voltanet.io> + * + */ + + +/* + * Sample PCC implementation + */ + +#include <zebra.h> + +#include <netdb.h> // gethostbyname +#include <netinet/tcp.h> +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <unistd.h> + +#include "pcep_pcc_api.h" +#include "pcep_utils_double_linked_list.h" +#include "pcep_utils_logging.h" +#include "pcep_utils_memory.h" + +/* + * PCEP PCC design spec: + * https://docs.google.com/presentation/d/1DYc3ZhYA1c_qg9A552HjhneJXQKdh_yrKW6v3NRYPtnbw/edit?usp=sharing + */ +#define MAX_SRC_IP_STR 40 +#define MAX_DST_IP_STR 40 +struct cmd_line_args { + char src_ip_str[MAX_SRC_IP_STR]; + char dest_ip_str[MAX_DST_IP_STR]; + short src_tcp_port; + short dest_tcp_port; + char tcp_md5_str[TCP_MD5SIG_MAXKEYLEN]; /* RFC 2385 */ + bool is_ipv6; + bool eventpoll; /* poll for pcep_event's, or use callback (default) */ +}; + +bool pcc_active_ = true; +pcep_session *session = NULL; +struct cmd_line_args *cmd_line_args = NULL; +/* pcep_event callback variables */ +bool pcep_event_condition = false; +struct pcep_event *event = NULL; +pthread_mutex_t pcep_event_mutex; +pthread_cond_t pcep_event_cond_var; + +static const char DEFAULT_DEST_HOSTNAME[] = "localhost"; +static const char DEFAULT_DEST_HOSTNAME_IPV6[] = "ip6-localhost"; +static const short DEFAULT_SRC_TCP_PORT = 4999; + +// Private fn's +struct cmd_line_args *get_cmdline_args(int argc, char *argv[]); +void handle_signal_action(int sig_number); +int setup_signals(void); +void send_pce_path_request_message(pcep_session *session); +void send_pce_report_message(pcep_session *session); +void print_queue_event(struct pcep_event *event); +void pcep_event_callback(void *cb_data, pcep_event *e); + +struct cmd_line_args *get_cmdline_args(int argc, char *argv[]) +{ + /* Allocate and set default values */ + struct cmd_line_args *cmd_line_args = + malloc(sizeof(struct cmd_line_args)); + memset(cmd_line_args, 0, sizeof(struct cmd_line_args)); + strlcpy(cmd_line_args->dest_ip_str, DEFAULT_DEST_HOSTNAME, + MAX_DST_IP_STR); + cmd_line_args->src_tcp_port = DEFAULT_SRC_TCP_PORT; + cmd_line_args->is_ipv6 = false; + + /* Parse the cmd_line args: + * -ipv6 + * -srcip localhost + * -destip 192.168.0.2 + * -srcport 4999 + * -dstport 4189 + * -tcpmd5 hello + * -event_poll */ + int i = 1; + for (; i < argc; ++i) { + if (strcmp(argv[i], "-help") == 0 + || strcmp(argv[i], "--help") == 0 + || strcmp(argv[i], "-h") == 0) { + pcep_log( + LOG_INFO, + "%s: pcep_pcc [-ipv6] [-srcip localhost] [-destip 192.168.0.1] [-srcport 4999] [-dstport 4189] [-tcpmd5 authstr] [-eventpoll]", + __func__); + free(cmd_line_args); + return NULL; + } else if (strcmp(argv[i], "-ipv6") == 0) { + cmd_line_args->is_ipv6 = true; + if (argc == 2) { + strlcpy(cmd_line_args->dest_ip_str, + DEFAULT_DEST_HOSTNAME_IPV6, + MAX_DST_IP_STR); + } + } else if (strcmp(argv[i], "-eventpoll") == 0) { + cmd_line_args->eventpoll = true; + } else if (strcmp(argv[i], "-srcip") == 0) { + if (argc >= i + 2) { + strlcpy(cmd_line_args->src_ip_str, argv[++i], + MAX_SRC_IP_STR); + } else { + pcep_log( + LOG_ERR, + "%s: Invalid number of cmd_line_args for \"-srcip\"", + __func__); + free(cmd_line_args); + return NULL; + } + } else if (strcmp(argv[i], "-destip") == 0) { + if (argc >= i + 2) { + strlcpy(cmd_line_args->dest_ip_str, argv[++i], + MAX_DST_IP_STR); + } else { + pcep_log( + LOG_ERR, + "%s: Invalid number of cmd_line_args for \"-destip\"", + __func__); + free(cmd_line_args); + return NULL; + } + } else if (strcmp(argv[i], "-srcport") == 0) { + if (argc >= i + 2) { + cmd_line_args->src_tcp_port = atoi(argv[++i]); + } else { + pcep_log( + LOG_ERR, + "%s: Invalid number of cmd_line_args for \"-srcport\"", + __func__); + free(cmd_line_args); + return NULL; + } + } else if (strcmp(argv[i], "-destport") == 0) { + if (argc >= i + 2) { + cmd_line_args->dest_tcp_port = atoi(argv[++i]); + } else { + pcep_log( + LOG_ERR, + "%s: Invalid number of cmd_line_args for \"-destport\"", + __func__); + free(cmd_line_args); + return NULL; + } + } else if (strcmp(argv[i], "-tcpmd5") == 0) { + if (argc >= i + 2) { + strlcpy(cmd_line_args->tcp_md5_str, argv[++i], + sizeof(cmd_line_args->tcp_md5_str)); + } else { + pcep_log( + LOG_ERR, + "%s: Invalid number of cmd_line_args for \"-tcpmd5\"", + __func__); + free(cmd_line_args); + return NULL; + } + } else { + pcep_log(LOG_ERR, "%s: Invalid cmd_line_arg[%d] = %s", + __func__, i, argv[i]); + free(cmd_line_args); + return NULL; + } + } + + return cmd_line_args; +} + +void handle_signal_action(int sig_number) +{ + if (sig_number == SIGINT) { + pcep_log(LOG_INFO, "%s: SIGINT was caught!", __func__); + pcc_active_ = false; + if (cmd_line_args->eventpoll == false) { + pthread_mutex_lock(&pcep_event_mutex); + pcep_event_condition = true; + pthread_cond_signal(&pcep_event_cond_var); + pthread_mutex_unlock(&pcep_event_mutex); + } + } else if (sig_number == SIGUSR1) { + pcep_log(LOG_INFO, "%s: SIGUSR1 was caught, dumping counters", + __func__); + dump_pcep_session_counters(session); + pceplib_memory_dump(); + } else if (sig_number == SIGUSR2) { + pcep_log(LOG_INFO, "%s: SIGUSR2 was caught, reseting counters", + __func__); + reset_pcep_session_counters(session); + } +} + + +int setup_signals() +{ + struct sigaction sa; + memset(&sa, 0, sizeof(struct sigaction)); + sa.sa_handler = handle_signal_action; + if (sigaction(SIGINT, &sa, 0) != 0) { + perror("sigaction()"); + return -1; + } + + if (sigaction(SIGUSR1, &sa, 0) != 0) { + perror("sigaction()"); + return -1; + } + + if (sigaction(SIGUSR2, &sa, 0) != 0) { + perror("sigaction()"); + return -1; + } + + return 0; +} + +void send_pce_path_request_message(pcep_session *session) +{ + struct in_addr src_ipv4; + struct in_addr dst_ipv4; + inet_pton(AF_INET, "1.2.3.4", &src_ipv4); + inet_pton(AF_INET, "10.20.30.40", &dst_ipv4); + + struct pcep_object_rp *rp_object = + pcep_obj_create_rp(1, false, false, false, false, 42, NULL); + struct pcep_object_endpoints_ipv4 *ep_object = + pcep_obj_create_endpoint_ipv4(&src_ipv4, &dst_ipv4); + + struct pcep_message *path_request = + pcep_msg_create_request(rp_object, ep_object, NULL); + send_message(session, path_request, true); +} + +void send_pce_report_message(pcep_session *session) +{ + double_linked_list *report_list = dll_initialize(); + + /* SRP Path Setup Type TLV */ + struct pcep_object_tlv_path_setup_type *pst_tlv = + pcep_tlv_create_path_setup_type(SR_TE_PST); + double_linked_list *srp_tlv_list = dll_initialize(); + dll_append(srp_tlv_list, pst_tlv); + + /* + * Create the SRP object + */ + uint32_t srp_id_number = 0x10203040; + struct pcep_object_header *obj = + (struct pcep_object_header *)pcep_obj_create_srp( + false, srp_id_number, srp_tlv_list); + if (obj == NULL) { + 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); + + /* LSP Symbolic path name TLV */ + char symbolic_path_name[] = "second-default"; + struct pcep_object_tlv_symbolic_path_name *spn_tlv = + pcep_tlv_create_symbolic_path_name(symbolic_path_name, 14); + double_linked_list *lsp_tlv_list = dll_initialize(); + dll_append(lsp_tlv_list, spn_tlv); + + /* LSP IPv4 LSP ID TLV */ + struct in_addr ipv4_tunnel_sender; + struct in_addr ipv4_tunnel_endpoint; + inet_pton(AF_INET, "9.9.1.1", &ipv4_tunnel_sender); + inet_pton(AF_INET, "9.9.2.1", &ipv4_tunnel_endpoint); + struct pcep_object_tlv_ipv4_lsp_identifier *ipv4_lsp_id_tlv = + pcep_tlv_create_ipv4_lsp_identifiers(&ipv4_tunnel_sender, + &ipv4_tunnel_endpoint, 42, + 1, NULL); + dll_append(lsp_tlv_list, ipv4_lsp_id_tlv); + + /* + * Create the LSP object + */ + uint32_t plsp_id = 42; + enum pcep_lsp_operational_status lsp_status = + PCEP_LSP_OPERATIONAL_ACTIVE; + bool c_flag = false; /* Lsp was created by PcInitiate msg */ + bool a_flag = false; /* Admin state, active / inactive */ + bool r_flag = false; /* true if LSP has been removed */ + bool s_flag = true; /* Synchronization */ + bool d_flag = false; /* Delegate LSP to PCE */ + obj = (struct pcep_object_header *)pcep_obj_create_lsp( + plsp_id, lsp_status, c_flag, a_flag, r_flag, s_flag, d_flag, + lsp_tlv_list); + if (obj == NULL) { + 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); + + /* Create 2 ERO NONAI sub-objects */ + double_linked_list *ero_subobj_list = dll_initialize(); + struct pcep_ro_subobj_sr *sr_subobj_nonai1 = + pcep_obj_create_ro_subobj_sr_nonai(false, 503808, true, true); + dll_append(ero_subobj_list, sr_subobj_nonai1); + + struct pcep_ro_subobj_sr *sr_subobj_nonai2 = + pcep_obj_create_ro_subobj_sr_nonai(false, 1867776, true, true); + dll_append(ero_subobj_list, sr_subobj_nonai2); + + /* Create ERO IPv4 node sub-object */ + struct in_addr sr_subobj_ipv4; + inet_pton(AF_INET, "9.9.9.1", &sr_subobj_ipv4); + struct pcep_ro_subobj_sr *sr_subobj_ipv4node = + pcep_obj_create_ro_subobj_sr_ipv4_node( + false, false, false, true, 16060, &sr_subobj_ipv4); + if (sr_subobj_ipv4node == NULL) { + pcep_log(LOG_WARNING, + "%s: send_pce_report_message ERO sub-object was NULL", + __func__); + return; + } + dll_append(ero_subobj_list, sr_subobj_ipv4node); + + /* + * Create the ERO object + */ + obj = (struct pcep_object_header *)pcep_obj_create_ero(ero_subobj_list); + if (obj == NULL) { + 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); + + /* + * Create the Metric object + */ + obj = (struct pcep_object_header *)pcep_obj_create_metric( + PCEP_METRIC_TE, false, true, 16.0); + dll_append(report_list, obj); + + /* Create and send the report message */ + struct pcep_message *report_msg = pcep_msg_create_report(report_list); + send_message(session, report_msg, true); +} + +void print_queue_event(struct pcep_event *event) +{ + pcep_log( + LOG_INFO, + "%s: [%ld-%ld] Received Event: type [%s] on session [%d] occurred at [%ld]", + __func__, time(NULL), pthread_self(), + get_event_type_str(event->event_type), + event->session->session_id, event->event_time); + + if (event->event_type == MESSAGE_RECEIVED) { + pcep_log( + LOG_INFO, "%s: \t Event message type [%s]", __func__, + get_message_type_str(event->message->msg_header->type)); + } +} + +/* Called by pcep_session_logic when pcep_event's are ready */ +void pcep_event_callback(void *cb_data, pcep_event *e) +{ + (void)cb_data; + pcep_log(LOG_NOTICE, "%s: [%ld-%ld] pcep_event_callback", __func__, + time(NULL), pthread_self()); + pthread_mutex_lock(&pcep_event_mutex); + event = e; + pcep_event_condition = true; + pthread_cond_signal(&pcep_event_cond_var); + pthread_mutex_unlock(&pcep_event_mutex); +} + +int main(int argc, char **argv) +{ + pcep_log(LOG_NOTICE, "%s: [%ld-%ld] starting pcc_pcep example client", + __func__, time(NULL), pthread_self()); + + cmd_line_args = get_cmdline_args(argc, argv); + if (cmd_line_args == NULL) { + return -1; + } + + setup_signals(); + + if (cmd_line_args->eventpoll == false) { + struct pceplib_infra_config infra_config; + memset(&infra_config, 0, sizeof(infra_config)); + infra_config.pcep_event_func = pcep_event_callback; + if (!initialize_pcc_infra(&infra_config)) { + pcep_log(LOG_ERR, + "%s: Error initializing PCC with infra.", + __func__); + return -1; + } + } else { + if (!initialize_pcc()) { + pcep_log(LOG_ERR, "%s: Error initializing PCC.", + __func__); + return -1; + } + } + + pcep_configuration *config = create_default_pcep_configuration(); + config->pcep_msg_versioning->draft_ietf_pce_segment_routing_07 = true; + config->src_pcep_port = cmd_line_args->src_tcp_port; + config->is_tcp_auth_md5 = true; + + strlcpy(config->tcp_authentication_str, cmd_line_args->tcp_md5_str, + sizeof(config->tcp_authentication_str)); + + int af = (cmd_line_args->is_ipv6 ? AF_INET6 : AF_INET); + struct hostent *host_info = + gethostbyname2(cmd_line_args->dest_ip_str, af); + if (host_info == NULL) { + pcep_log(LOG_ERR, "%s: Error getting IP address.", __func__); + return -1; + } + + if (cmd_line_args->is_ipv6) { + struct in6_addr host_address; + memcpy(&host_address, host_info->h_addr, host_info->h_length); + session = connect_pce_ipv6(config, &host_address); + } else { + struct in_addr host_address; + memcpy(&host_address, host_info->h_addr, host_info->h_length); + session = connect_pce(config, &host_address); + } + + if (session == NULL) { + pcep_log(LOG_WARNING, "%s: Error in connect_pce.", __func__); + destroy_pcep_configuration(config); + return -1; + } + + sleep(2); + + send_pce_report_message(session); + /*send_pce_path_request_message(session);*/ + + /* Wait for pcep_event's either by polling the event queue or by + * callback */ + if (cmd_line_args->eventpoll == true) { + /* Poll the pcep_event queue*/ + while (pcc_active_) { + if (event_queue_is_empty() == false) { + struct pcep_event *event = + event_queue_get_event(); + print_queue_event(event); + destroy_pcep_event(event); + } + + sleep(5); + } + } else { + /* Get events via callback and conditional variable */ + pthread_mutex_init(&pcep_event_mutex, NULL); + pthread_cond_init(&pcep_event_cond_var, NULL); + while (pcc_active_) { + pthread_mutex_lock(&pcep_event_mutex); + + /* this internal loop helps avoid spurious interrupts */ + while (!pcep_event_condition) { + pthread_cond_wait(&pcep_event_cond_var, + &pcep_event_mutex); + } + + /* Check if we have been interrupted by SIGINT */ + if (pcc_active_) { + print_queue_event(event); + destroy_pcep_event(event); + } + + pcep_event_condition = false; + pthread_mutex_unlock(&pcep_event_mutex); + } + + pthread_mutex_destroy(&pcep_event_mutex); + pthread_cond_destroy(&pcep_event_cond_var); + } + + pcep_log(LOG_NOTICE, "%s: Disconnecting from PCE", __func__); + disconnect_pce(session); + destroy_pcep_configuration(config); + free(cmd_line_args); + + if (!destroy_pcc()) { + pcep_log(LOG_NOTICE, "%s: Error stopping PCC.", __func__); + } + + pceplib_memory_dump(); + + return 0; +} diff --git a/pceplib/pcep_pcc_api.c b/pceplib/pcep_pcc_api.c new file mode 100644 index 0000000000..b7813c5a05 --- /dev/null +++ b/pceplib/pcep_pcc_api.c @@ -0,0 +1,392 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Brady Johnson <brady@voltanet.io> + * + */ + + +/* + * Public PCEPlib PCC API implementation + */ + +#include <zebra.h> + +#include <pthread.h> +#include <stdbool.h> +#include <stdio.h> +#include <string.h> + +#include "pcep_msg_messages.h" +#include "pcep_pcc_api.h" +#include "pcep_utils_counters.h" +#include "pcep_utils_logging.h" + +/* Not using an array here since the enum pcep_event_type indeces go into the + * 100's */ +const char MESSAGE_RECEIVED_STR[] = "MESSAGE_RECEIVED"; +const char PCE_CLOSED_SOCKET_STR[] = "PCE_CLOSED_SOCKET"; +const char PCE_SENT_PCEP_CLOSE_STR[] = "PCE_SENT_PCEP_CLOSE"; +const char PCE_DEAD_TIMER_EXPIRED_STR[] = "PCE_DEAD_TIMER_EXPIRED"; +const char PCE_OPEN_KEEP_WAIT_TIMER_EXPIRED_STR[] = + "PCE_OPEN_KEEP_WAIT_TIMER_EXPIRED"; +const char PCC_CONNECTED_TO_PCE_STR[] = "PCC_CONNECTED_TO_PCE"; +const char PCC_PCEP_SESSION_CLOSED_STR[] = "PCC_PCEP_SESSION_CLOSED"; +const char PCC_RCVD_INVALID_OPEN_STR[] = "PCC_RCVD_INVALID_OPEN"; +const char PCC_RCVD_MAX_INVALID_MSGS_STR[] = "PCC_RCVD_MAX_INVALID_MSGS"; +const char PCC_RCVD_MAX_UNKOWN_MSGS_STR[] = "PCC_RCVD_MAX_UNKOWN_MSGS"; +const char UNKNOWN_EVENT_STR[] = "UNKNOWN Event Type"; + +/* Session Logic Handle managed in pcep_session_logic.c */ +extern pcep_event_queue *session_logic_event_queue_; + +bool initialize_pcc() +{ + if (!run_session_logic()) { + pcep_log(LOG_ERR, "%s: Error initializing PCC session logic.", + __func__); + return false; + } + + return true; +} + + +bool initialize_pcc_infra(struct pceplib_infra_config *infra_config) +{ + if (infra_config == NULL) { + return initialize_pcc(); + } + + if (!run_session_logic_with_infra(infra_config)) { + pcep_log(LOG_ERR, + "%s: Error initializing PCC session logic with infra.", + __func__); + return false; + } + + return true; +} + + +/* this function is blocking */ +bool initialize_pcc_wait_for_completion() +{ + return run_session_logic_wait_for_completion(); +} + + +bool destroy_pcc() +{ + if (!stop_session_logic()) { + pcep_log(LOG_WARNING, "%s: Error stopping PCC session logic.", + __func__); + return false; + } + + return true; +} + + +pcep_configuration *create_default_pcep_configuration() +{ + pcep_configuration *config = + pceplib_malloc(PCEPLIB_INFRA, sizeof(pcep_configuration)); + memset(config, 0, sizeof(pcep_configuration)); + + config->keep_alive_seconds = DEFAULT_CONFIG_KEEP_ALIVE; + /* This value will possibly be overwritten later with PCE config data */ + config->keep_alive_pce_negotiated_timer_seconds = + DEFAULT_CONFIG_KEEP_ALIVE; + config->min_keep_alive_seconds = DEFAULT_MIN_CONFIG_KEEP_ALIVE; + config->max_keep_alive_seconds = DEFAULT_MAX_CONFIG_KEEP_ALIVE; + + config->dead_timer_seconds = DEFAULT_CONFIG_DEAD_TIMER; + /* This value will be overwritten later with PCE config data */ + config->dead_timer_pce_negotiated_seconds = DEFAULT_CONFIG_DEAD_TIMER; + config->min_dead_timer_seconds = DEFAULT_MIN_CONFIG_DEAD_TIMER; + config->max_dead_timer_seconds = DEFAULT_MAX_CONFIG_DEAD_TIMER; + + config->request_time_seconds = DEFAULT_CONFIG_REQUEST_TIME; + config->max_unknown_messages = DEFAULT_CONFIG_MAX_UNKNOWN_MESSAGES; + config->max_unknown_requests = DEFAULT_CONFIG_MAX_UNKNOWN_REQUESTS; + + config->socket_connect_timeout_millis = + DEFAULT_TCP_CONNECT_TIMEOUT_MILLIS; + config->support_stateful_pce_lsp_update = true; + config->support_pce_lsp_instantiation = true; + config->support_include_db_version = true; + config->lsp_db_version = 0; + config->support_lsp_triggered_resync = true; + config->support_lsp_delta_sync = true; + config->support_pce_triggered_initial_sync = true; + config->support_sr_te_pst = true; + config->pcc_can_resolve_nai_to_sid = true; + config->max_sid_depth = 0; + config->dst_pcep_port = 0; + config->src_pcep_port = 0; + config->src_ip.src_ipv4.s_addr = INADDR_ANY; + config->is_src_ipv6 = false; + config->pcep_msg_versioning = create_default_pcep_versioning(); + config->tcp_authentication_str[0] = '\0'; + config->is_tcp_auth_md5 = true; + + return config; +} + +void destroy_pcep_configuration(pcep_configuration *config) +{ + destroy_pcep_versioning(config->pcep_msg_versioning); + pceplib_free(PCEPLIB_INFRA, config); +} + +pcep_session *connect_pce(pcep_configuration *config, struct in_addr *pce_ip) +{ + return create_pcep_session(config, pce_ip); +} + +pcep_session *connect_pce_ipv6(pcep_configuration *config, + struct in6_addr *pce_ip) +{ + return create_pcep_session_ipv6(config, pce_ip); +} + +void disconnect_pce(pcep_session *session) +{ + if (session_exists(session) == false) { + pcep_log( + LOG_WARNING, + "%s: disconnect_pce session [%p] has already been deleted", + __func__, session); + return; + } + + if (session->socket_comm_session == NULL + || session->socket_comm_session->socket_fd < 0) { + /* If the socket has already been closed, just destroy the + * session */ + destroy_pcep_session(session); + } else { + /* This will cause the session to be destroyed AFTER the close + * message is sent */ + session->destroy_session_after_write = true; + + /* Send a PCEP close message */ + close_pcep_session(session); + } +} + +void send_message(pcep_session *session, struct pcep_message *msg, + bool free_after_send) +{ + if (session == NULL || msg == NULL) { + pcep_log(LOG_DEBUG, + "%s: send_message NULL params session [%p] msg [%p]", + __func__, session, msg); + + return; + } + + if (session_exists(session) == false) { + pcep_log( + LOG_WARNING, + "%s: send_message session [%p] has already been deleted", + __func__, session); + return; + } + + pcep_encode_message(msg, session->pcc_config.pcep_msg_versioning); + socket_comm_session_send_message( + session->socket_comm_session, (char *)msg->encoded_message, + msg->encoded_message_length, free_after_send); + + increment_message_tx_counters(session, msg); + + if (free_after_send == true) { + /* The encoded_message will be deleted once sent, so everything + * else in the message will be freed */ + msg->encoded_message = NULL; + pcep_msg_free_message(msg); + } +} + +/* Returns true if the queue is empty, false otherwise */ +bool event_queue_is_empty() +{ + if (session_logic_event_queue_ == NULL) { + pcep_log( + LOG_WARNING, + "%s: event_queue_is_empty Session Logic is not initialized yet", + __func__); + return false; + } + + pthread_mutex_lock(&session_logic_event_queue_->event_queue_mutex); + bool is_empty = + (session_logic_event_queue_->event_queue->num_entries == 0); + pthread_mutex_unlock(&session_logic_event_queue_->event_queue_mutex); + + return is_empty; +} + + +/* Return the number of events on the queue, 0 if empty */ +uint32_t event_queue_num_events_available() +{ + if (session_logic_event_queue_ == NULL) { + pcep_log( + LOG_WARNING, + "%s: event_queue_num_events_available Session Logic is not initialized yet", + __func__); + return 0; + } + + pthread_mutex_lock(&session_logic_event_queue_->event_queue_mutex); + uint32_t num_events = + session_logic_event_queue_->event_queue->num_entries; + pthread_mutex_unlock(&session_logic_event_queue_->event_queue_mutex); + + return num_events; +} + + +/* Return the next event on the queue, NULL if empty */ +struct pcep_event *event_queue_get_event() +{ + if (session_logic_event_queue_ == NULL) { + pcep_log( + LOG_WARNING, + "%s: event_queue_get_event Session Logic is not initialized yet", + __func__); + return NULL; + } + + pthread_mutex_lock(&session_logic_event_queue_->event_queue_mutex); + struct pcep_event *event = (struct pcep_event *)queue_dequeue( + session_logic_event_queue_->event_queue); + pthread_mutex_unlock(&session_logic_event_queue_->event_queue_mutex); + + return event; +} + + +/* Free the PCEP Event resources, including the PCEP message */ +void destroy_pcep_event(struct pcep_event *event) +{ + if (event == NULL) { + pcep_log(LOG_WARNING, + "%s: destroy_pcep_event cannot destroy NULL event", + __func__); + return; + } + + if (event->event_type == MESSAGE_RECEIVED && event->message != NULL) { + pcep_msg_free_message(event->message); + } + + pceplib_free(PCEPLIB_INFRA, event); +} + +const char *get_event_type_str(int event_type) +{ + switch (event_type) { + case MESSAGE_RECEIVED: + return MESSAGE_RECEIVED_STR; + break; + case PCE_CLOSED_SOCKET: + return PCE_CLOSED_SOCKET_STR; + break; + case PCE_SENT_PCEP_CLOSE: + return PCE_SENT_PCEP_CLOSE_STR; + break; + case PCE_DEAD_TIMER_EXPIRED: + return PCE_DEAD_TIMER_EXPIRED_STR; + break; + case PCE_OPEN_KEEP_WAIT_TIMER_EXPIRED: + return PCE_OPEN_KEEP_WAIT_TIMER_EXPIRED_STR; + break; + case PCC_CONNECTED_TO_PCE: + return PCC_CONNECTED_TO_PCE_STR; + break; + case PCC_PCEP_SESSION_CLOSED: + return PCC_PCEP_SESSION_CLOSED_STR; + break; + case PCC_RCVD_INVALID_OPEN: + return PCC_RCVD_INVALID_OPEN_STR; + break; + case PCC_RCVD_MAX_INVALID_MSGS: + return PCC_RCVD_MAX_INVALID_MSGS_STR; + break; + case PCC_RCVD_MAX_UNKOWN_MSGS: + return PCC_RCVD_MAX_UNKOWN_MSGS_STR; + break; + default: + return UNKNOWN_EVENT_STR; + break; + } +} + +void dump_pcep_session_counters(pcep_session *session) +{ + if (session_exists(session) == false) { + pcep_log( + LOG_WARNING, + "%s: dump_pcep_session_counters session [%p] has already been deleted", + __func__, session); + return; + } + + /* Update the counters group name so that the PCE session connected time + * is accurate */ + time_t now = time(NULL); + char counters_name[MAX_COUNTER_STR_LENGTH] = {0}; + char ip_str[40] = {0}; + if (session->socket_comm_session->is_ipv6) { + inet_ntop(AF_INET6, + &session->socket_comm_session->dest_sock_addr + .dest_sock_addr_ipv6.sin6_addr, + ip_str, 40); + } else { + inet_ntop(AF_INET, + &session->socket_comm_session->dest_sock_addr + .dest_sock_addr_ipv4.sin_addr, + ip_str, 40); + } + snprintf(counters_name, MAX_COUNTER_STR_LENGTH, + "PCEP Session [%d], connected to [%s] for [%u seconds]", + session->session_id, ip_str, + (uint32_t)(now - session->time_connected)); + strlcpy(session->pcep_session_counters->counters_group_name, + counters_name, + sizeof(session->pcep_session_counters->counters_group_name)); + + dump_counters_group_to_log(session->pcep_session_counters); +} + +void reset_pcep_session_counters(pcep_session *session) +{ + if (session_exists(session) == false) { + pcep_log( + LOG_WARNING, + "%s: reset_pcep_session_counters session [%p] has already been deleted", + session); + return; + } + + reset_group_counters(session->pcep_session_counters); +} diff --git a/pceplib/pcep_pcc_api.h b/pceplib/pcep_pcc_api.h new file mode 100644 index 0000000000..5756e23efc --- /dev/null +++ b/pceplib/pcep_pcc_api.h @@ -0,0 +1,103 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Brady Johnson <brady@voltanet.io> + * + */ + + +/* + * Public PCEPlib PCC API + */ + +#ifndef PCEPPCC_INCLUDE_PCEPPCCAPI_H_ +#define PCEPPCC_INCLUDE_PCEPPCCAPI_H_ + +#include <stdbool.h> + +#include "pcep_session_logic.h" +#include "pcep_timers.h" + +#define DEFAULT_PCEP_TCP_PORT 4189 +#define DEFAULT_CONFIG_KEEP_ALIVE 30 +#define DEFAULT_CONFIG_DEAD_TIMER DEFAULT_CONFIG_KEEP_ALIVE * 4 +#define DEFAULT_CONFIG_REQUEST_TIME 30 +#define DEFAULT_CONFIG_MAX_UNKNOWN_REQUESTS 5 +#define DEFAULT_CONFIG_MAX_UNKNOWN_MESSAGES 5 +#define DEFAULT_TCP_CONNECT_TIMEOUT_MILLIS 250 + +/* Acceptable MIN and MAX values used in deciding if the PCEP + * Open received from a PCE should be accepted or rejected. */ +#define DEFAULT_MIN_CONFIG_KEEP_ALIVE 5 +#define DEFAULT_MAX_CONFIG_KEEP_ALIVE 120 +#define DEFAULT_MIN_CONFIG_DEAD_TIMER DEFAULT_MIN_CONFIG_KEEP_ALIVE * 4 +#define DEFAULT_MAX_CONFIG_DEAD_TIMER DEFAULT_MAX_CONFIG_KEEP_ALIVE * 4 + +/* + * PCEP PCC library initialization/teardown functions + */ + +/* Later when this is integrated with FRR pathd, it will be changed + * to just initialize_pcc(struct pceplib_infra_config *infra_config) */ +bool initialize_pcc(void); +bool initialize_pcc_infra(struct pceplib_infra_config *infra_config); +/* this function is blocking */ +bool initialize_pcc_wait_for_completion(void); +bool destroy_pcc(void); + + +/* + * PCEP session functions + */ + +pcep_configuration *create_default_pcep_configuration(void); +void destroy_pcep_configuration(pcep_configuration *config); + +/* Uses the standard PCEP TCP src and dest port = 4189. + * To use a specific dest or src port, set them other than 0 in the + * pcep_configuration. If src_ip is not set, INADDR_ANY will be used. */ +pcep_session *connect_pce(pcep_configuration *config, struct in_addr *pce_ip); +pcep_session *connect_pce_ipv6(pcep_configuration *config, + struct in6_addr *pce_ip); +void disconnect_pce(pcep_session *session); +void send_message(pcep_session *session, struct pcep_message *msg, + bool free_after_send); + +void dump_pcep_session_counters(pcep_session *session); +void reset_pcep_session_counters(pcep_session *session); + +/* + * Event Queue functions + */ + +/* Returns true if the queue is empty, false otherwise */ +bool event_queue_is_empty(void); + +/* Return the number of events on the queue, 0 if empty */ +uint32_t event_queue_num_events_available(void); + +/* Return the next event on the queue, NULL if empty */ +struct pcep_event *event_queue_get_event(void); + +/* Free the PCEP Event resources, including the PCEP message */ +void destroy_pcep_event(struct pcep_event *event); + +const char *get_event_type_str(int event_type); + + +#endif /* PCEPPCC_INCLUDE_PCEPPCCAPI_H_ */ diff --git a/pceplib/pcep_session_logic.c b/pceplib/pcep_session_logic.c new file mode 100644 index 0000000000..52655914c6 --- /dev/null +++ b/pceplib/pcep_session_logic.c @@ -0,0 +1,683 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Brady Johnson <brady@voltanet.io> + * + */ + + +#include <errno.h> +#include <limits.h> +#include <pthread.h> +#include <stdbool.h> +#include <stdio.h> +#include <string.h> +#include <time.h> + +#include "pcep_msg_encoding.h" +#include "pcep_session_logic.h" +#include "pcep_session_logic_internals.h" +#include "pcep_timers.h" +#include "pcep_utils_counters.h" +#include "pcep_utils_ordered_list.h" +#include "pcep_utils_logging.h" +#include "pcep_utils_memory.h" + +/* + * public API function implementations for the session_logic + */ + +pcep_session_logic_handle *session_logic_handle_ = NULL; +pcep_event_queue *session_logic_event_queue_ = NULL; +int session_id_ = 0; + +void send_pcep_open(pcep_session *session); /* forward decl */ + +static bool run_session_logic_common() +{ + if (session_logic_handle_ != NULL) { + pcep_log(LOG_WARNING, + "%s: Session Logic is already initialized.", __func__); + return false; + } + + session_logic_handle_ = pceplib_malloc( + 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_list = + ordered_list_initialize(pointer_compare_function); + session_logic_handle_->session_event_queue = queue_initialize(); + + /* Initialize the event queue */ + session_logic_event_queue_ = + pceplib_malloc(PCEPLIB_INFRA, sizeof(pcep_event_queue)); + session_logic_event_queue_->event_queue = queue_initialize(); + if (pthread_mutex_init(&(session_logic_event_queue_->event_queue_mutex), + NULL) + != 0) { + pcep_log( + LOG_ERR, + "%s: Cannot initialize session_logic event queue mutex.", + __func__); + return false; + } + + pthread_cond_init(&(session_logic_handle_->session_logic_cond_var), + NULL); + + if (pthread_mutex_init(&(session_logic_handle_->session_logic_mutex), + NULL) + != 0) { + pcep_log(LOG_ERR, "%s: Cannot initialize session_logic mutex.", + __func__); + 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) { + pcep_log(LOG_ERR, "%s: Cannot initialize session_list mutex.", + __func__); + return false; + } + + return true; +} + + +bool run_session_logic() +{ + if (!run_session_logic_common()) { + return false; + } + + if (pthread_create(&(session_logic_handle_->session_logic_thread), NULL, + session_logic_loop, session_logic_handle_)) { + pcep_log(LOG_ERR, "%s: Cannot initialize session_logic thread.", + __func__); + return false; + } + + if (!initialize_timers(session_logic_timer_expire_handler)) { + pcep_log(LOG_ERR, "%s: Cannot initialize session_logic timers.", + __func__); + return false; + } + + /* No need to call initialize_socket_comm_loop() since it will be + * called internally when the first socket_comm_session is created. */ + + return true; +} + + +bool run_session_logic_with_infra(pceplib_infra_config *infra_config) +{ + if (infra_config == NULL) { + return run_session_logic(); + } + + /* Initialize the memory infrastructure before anything gets allocated + */ + if (infra_config->pceplib_infra_mt != NULL + && infra_config->pceplib_messages_mt != NULL) { + pceplib_memory_initialize( + infra_config->pceplib_infra_mt, + infra_config->pceplib_messages_mt, + infra_config->malloc_func, infra_config->calloc_func, + infra_config->realloc_func, infra_config->strdup_func, + infra_config->free_func); + } + + if (!run_session_logic_common()) { + return false; + } + + /* Create the pcep_session_logic pthread so it can be managed externally + */ + if (infra_config->pthread_create_func != NULL) { + if (infra_config->pthread_create_func( + &(session_logic_handle_->session_logic_thread), + NULL, session_logic_loop, session_logic_handle_, + "pcep_session_logic")) { + pcep_log( + LOG_ERR, + "%s: Cannot initialize external session_logic thread.", + __func__); + return false; + } + } else { + if (pthread_create( + &(session_logic_handle_->session_logic_thread), + NULL, session_logic_loop, session_logic_handle_)) { + pcep_log(LOG_ERR, + "%s: Cannot initialize session_logic thread.", + __func__); + return false; + } + } + + session_logic_event_queue_->event_callback = + infra_config->pcep_event_func; + session_logic_event_queue_->event_callback_data = + infra_config->external_infra_data; + + if (!initialize_timers_external_infra( + session_logic_timer_expire_handler, + infra_config->external_infra_data, + infra_config->timer_create_func, + infra_config->timer_cancel_func, + infra_config->pthread_create_func)) { + pcep_log( + LOG_ERR, + "%s: Cannot initialize session_logic timers with infra.", + __func__); + return false; + } + + /* We found a problem with the FRR sockets, where not all the KeepAlive + * messages were received, so if the pthread_create_func is set, the + * internal PCEPlib socket infrastructure will be used. */ + + /* For the SocketComm, the socket_read/write_func and the + * pthread_create_func are mutually exclusive. */ + if (infra_config->pthread_create_func != NULL) { + if (!initialize_socket_comm_external_infra( + infra_config->external_infra_data, NULL, NULL, + infra_config->pthread_create_func)) { + pcep_log( + LOG_ERR, + "%s: Cannot initialize session_logic socket comm with infra.", + __func__); + return false; + } + } else if (infra_config->socket_read_func != NULL + && infra_config->socket_write_func != NULL) { + if (!initialize_socket_comm_external_infra( + infra_config->external_infra_data, + infra_config->socket_read_func, + infra_config->socket_write_func, NULL)) { + pcep_log( + LOG_ERR, + "%s: Cannot initialize session_logic socket comm with infra.", + __func__); + return false; + } + } + + return true; +} + +bool run_session_logic_wait_for_completion() +{ + if (!run_session_logic()) { + return false; + } + + /* Blocking call, waits for session logic thread to complete */ + pthread_join(session_logic_handle_->session_logic_thread, NULL); + + return true; +} + + +bool stop_session_logic() +{ + if (session_logic_handle_ == NULL) { + pcep_log(LOG_WARNING, "%s: Session logic already stopped", + __func__); + return false; + } + + session_logic_handle_->active = false; + teardown_timers(); + + 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)); + pthread_join(session_logic_handle_->session_logic_thread, NULL); + + pthread_mutex_destroy(&(session_logic_handle_->session_logic_mutex)); + pthread_mutex_destroy(&(session_logic_handle_->session_list_mutex)); + ordered_list_destroy(session_logic_handle_->session_list); + queue_destroy(session_logic_handle_->session_event_queue); + + /* destroy the event_queue */ + pthread_mutex_destroy(&(session_logic_event_queue_->event_queue_mutex)); + queue_destroy(session_logic_event_queue_->event_queue); + pceplib_free(PCEPLIB_INFRA, session_logic_event_queue_); + + /* Explicitly stop the socket comm loop started by the pcep_sessions */ + destroy_socket_comm_loop(); + + pceplib_free(PCEPLIB_INFRA, session_logic_handle_); + session_logic_handle_ = NULL; + + return true; +} + + +void close_pcep_session(pcep_session *session) +{ + close_pcep_session_with_reason(session, PCEP_CLOSE_REASON_NO); +} + +void close_pcep_session_with_reason(pcep_session *session, + enum pcep_close_reason reason) +{ + struct pcep_message *close_msg = pcep_msg_create_close(reason); + + pcep_log( + LOG_INFO, + "%s: [%ld-%ld] pcep_session_logic send pcep_close message for session [%d]", + __func__, time(NULL), pthread_self(), session->session_id); + + session_send_message(session, close_msg); + socket_comm_session_close_tcp_after_write(session->socket_comm_session); + session->session_state = SESSION_STATE_INITIALIZED; +} + + +void destroy_pcep_session(pcep_session *session) +{ + if (session == NULL) { + pcep_log(LOG_WARNING, "%s: Cannot destroy NULL session", + __func__); + return; + } + + /* Remove the session from the session_list and synchronize session + * destroy with the session_logic_loop, so that no in-flight events + * will be handled now that the session is destroyed. */ + pthread_mutex_lock(&(session_logic_handle_->session_list_mutex)); + ordered_list_remove_first_node_equals( + session_logic_handle_->session_list, session); + pcep_log(LOG_DEBUG, + "%s: destroy_pcep_session delete session_list sessionPtr %p", + __func__, session); + + pcep_session_cancel_timers(session); + delete_counters_group(session->pcep_session_counters); + queue_destroy_with_data(session->num_unknown_messages_time_queue); + socket_comm_session_teardown(session->socket_comm_session); + + if (session->pcc_config.pcep_msg_versioning != NULL) { + pceplib_free(PCEPLIB_INFRA, + session->pcc_config.pcep_msg_versioning); + } + + if (session->pce_config.pcep_msg_versioning != NULL) { + pceplib_free(PCEPLIB_INFRA, + session->pce_config.pcep_msg_versioning); + } + + int session_id = session->session_id; + pceplib_free(PCEPLIB_INFRA, session); + pcep_log(LOG_INFO, "%s: [%ld-%ld] session [%d] destroyed", __func__, + time(NULL), pthread_self(), session_id); + pthread_mutex_unlock(&(session_logic_handle_->session_list_mutex)); +} + +void pcep_session_cancel_timers(pcep_session *session) +{ + if (session == NULL) { + return; + } + + if (session->timer_id_dead_timer != TIMER_ID_NOT_SET) { + cancel_timer(session->timer_id_dead_timer); + } + + if (session->timer_id_keep_alive != TIMER_ID_NOT_SET) { + cancel_timer(session->timer_id_keep_alive); + } + + if (session->timer_id_open_keep_wait != TIMER_ID_NOT_SET) { + cancel_timer(session->timer_id_open_keep_wait); + } + + if (session->timer_id_open_keep_alive != TIMER_ID_NOT_SET) { + cancel_timer(session->timer_id_open_keep_alive); + } +} + +/* Internal util function */ +static int get_next_session_id() +{ + if (session_id_ == INT_MAX) { + session_id_ = 0; + } + + return session_id_++; +} + +/* Internal util function */ +static pcep_session *create_pcep_session_pre_setup(pcep_configuration *config) +{ + if (config == NULL) { + pcep_log(LOG_WARNING, + "%s: Cannot create pcep session with NULL config", + __func__); + return NULL; + } + + pcep_session *session = + pceplib_malloc(PCEPLIB_INFRA, sizeof(pcep_session)); + memset(session, 0, sizeof(pcep_session)); + session->session_id = get_next_session_id(); + session->session_state = SESSION_STATE_INITIALIZED; + session->timer_id_open_keep_wait = TIMER_ID_NOT_SET; + session->timer_id_open_keep_alive = TIMER_ID_NOT_SET; + session->timer_id_dead_timer = TIMER_ID_NOT_SET; + session->timer_id_keep_alive = TIMER_ID_NOT_SET; + session->stateful_pce = false; + session->num_unknown_messages_time_queue = queue_initialize(); + session->pce_open_received = false; + session->pce_open_rejected = false; + session->pce_open_keep_alive_sent = false; + session->pcc_open_rejected = false; + session->pce_open_accepted = false; + session->pcc_open_accepted = false; + session->destroy_session_after_write = false; + session->lsp_db_version = config->lsp_db_version; + memcpy(&(session->pcc_config), config, sizeof(pcep_configuration)); + /* copy the pcc_config to the pce_config until we receive the open + * keep_alive response */ + memcpy(&(session->pce_config), config, sizeof(pcep_configuration)); + if (config->pcep_msg_versioning != NULL) { + session->pcc_config.pcep_msg_versioning = pceplib_malloc( + PCEPLIB_INFRA, sizeof(struct pcep_versioning)); + memcpy(session->pcc_config.pcep_msg_versioning, + config->pcep_msg_versioning, + sizeof(struct pcep_versioning)); + session->pce_config.pcep_msg_versioning = pceplib_malloc( + PCEPLIB_INFRA, sizeof(struct pcep_versioning)); + memcpy(session->pce_config.pcep_msg_versioning, + config->pcep_msg_versioning, + sizeof(struct pcep_versioning)); + } + + pthread_mutex_lock(&(session_logic_handle_->session_list_mutex)); + ordered_list_add_node(session_logic_handle_->session_list, session); + pcep_log( + LOG_DEBUG, + "%s: create_pcep_session_pre_setup add session_list sessionPtr %p", + __func__, session); + pthread_mutex_unlock(&(session_logic_handle_->session_list_mutex)); + + return session; +} + +/* Internal util function */ +static bool create_pcep_session_post_setup(pcep_session *session) +{ + if (!socket_comm_session_connect_tcp(session->socket_comm_session)) { + pcep_log(LOG_WARNING, "%s: Cannot establish TCP socket.", + __func__); + destroy_pcep_session(session); + + return false; + } + + session->time_connected = time(NULL); + create_session_counters(session); + + send_pcep_open(session); + + session->session_state = SESSION_STATE_PCEP_CONNECTING; + session->timer_id_open_keep_wait = + create_timer(session->pcc_config.keep_alive_seconds, session); + // session->session_state = SESSION_STATE_OPENED; + + return true; +} + +pcep_session *create_pcep_session(pcep_configuration *config, + struct in_addr *pce_ip) +{ + if (pce_ip == NULL) { + pcep_log(LOG_WARNING, + "%s: Cannot create pcep session with NULL pce_ip", + __func__); + return NULL; + } + + pcep_session *session = create_pcep_session_pre_setup(config); + if (session == NULL) { + return NULL; + } + + session->socket_comm_session = socket_comm_session_initialize_with_src( + NULL, session_logic_msg_ready_handler, + session_logic_message_sent_handler, + session_logic_conn_except_notifier, &(config->src_ip.src_ipv4), + ((config->src_pcep_port == 0) ? PCEP_TCP_PORT + : config->src_pcep_port), + pce_ip, + ((config->dst_pcep_port == 0) ? PCEP_TCP_PORT + : config->dst_pcep_port), + config->socket_connect_timeout_millis, + config->tcp_authentication_str, config->is_tcp_auth_md5, + session); + if (session->socket_comm_session == NULL) { + pcep_log(LOG_WARNING, + "%s: Cannot establish socket_comm_session.", __func__); + destroy_pcep_session(session); + + return NULL; + } + + if (create_pcep_session_post_setup(session) == false) { + return NULL; + } + + return session; +} + +pcep_session *create_pcep_session_ipv6(pcep_configuration *config, + struct in6_addr *pce_ip) +{ + if (pce_ip == NULL) { + pcep_log(LOG_WARNING, + "%s: Cannot create pcep session with NULL pce_ip", + __func__); + return NULL; + } + + pcep_session *session = create_pcep_session_pre_setup(config); + if (session == NULL) { + return NULL; + } + + session->socket_comm_session = + socket_comm_session_initialize_with_src_ipv6( + NULL, session_logic_msg_ready_handler, + session_logic_message_sent_handler, + session_logic_conn_except_notifier, + &(config->src_ip.src_ipv6), + ((config->src_pcep_port == 0) ? PCEP_TCP_PORT + : config->src_pcep_port), + pce_ip, + ((config->dst_pcep_port == 0) ? PCEP_TCP_PORT + : config->dst_pcep_port), + config->socket_connect_timeout_millis, + config->tcp_authentication_str, config->is_tcp_auth_md5, + session); + if (session->socket_comm_session == NULL) { + pcep_log(LOG_WARNING, + "%s: Cannot establish ipv6 socket_comm_session.", + __func__); + destroy_pcep_session(session); + + return NULL; + } + + if (create_pcep_session_post_setup(session) == false) { + return NULL; + } + + return session; +} + + +void session_send_message(pcep_session *session, struct pcep_message *message) +{ + pcep_encode_message(message, session->pcc_config.pcep_msg_versioning); + socket_comm_session_send_message(session->socket_comm_session, + (char *)message->encoded_message, + message->encoded_message_length, true); + + increment_message_tx_counters(session, message); + + /* The message->encoded_message will be freed in + * socket_comm_session_send_message() once sent. + * Setting to NULL here so pcep_msg_free_message() does not free it */ + message->encoded_message = NULL; + pcep_msg_free_message(message); +} + + +/* This function is also used in pcep_session_logic_states.c */ +struct pcep_message *create_pcep_open(pcep_session *session) +{ + /* create and send PCEP open + * with PCEP, the PCC sends the config the PCE should use in the open + * message, + * and the PCE will send an open with the config the PCC should use. */ + double_linked_list *tlv_list = dll_initialize(); + if (session->pcc_config.support_stateful_pce_lsp_update + || session->pcc_config.support_pce_lsp_instantiation + || session->pcc_config.support_include_db_version + || session->pcc_config.support_lsp_triggered_resync + || session->pcc_config.support_lsp_delta_sync + || session->pcc_config.support_pce_triggered_initial_sync) { + /* Prepend this TLV as the first in the list */ + dll_append( + tlv_list, + pcep_tlv_create_stateful_pce_capability( + /* U flag */ + session->pcc_config + .support_stateful_pce_lsp_update, + /* S flag */ + session->pcc_config.support_include_db_version, + /* I flag */ + session->pcc_config + .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) { + if (session->pcc_config.lsp_db_version != 0) { + dll_append(tlv_list, + pcep_tlv_create_lsp_db_version( + session->pcc_config.lsp_db_version)); + } + } + + if (session->pcc_config.support_sr_te_pst) { + bool flag_n = false; + bool flag_x = false; + if (session->pcc_config.pcep_msg_versioning + ->draft_ietf_pce_segment_routing_07 + == false) { + flag_n = session->pcc_config.pcc_can_resolve_nai_to_sid; + flag_x = (session->pcc_config.max_sid_depth == 0); + } + + struct pcep_object_tlv_sr_pce_capability *sr_pce_cap_tlv = + pcep_tlv_create_sr_pce_capability( + flag_n, flag_x, + session->pcc_config.max_sid_depth); + + double_linked_list *sub_tlv_list = NULL; + if (session->pcc_config.pcep_msg_versioning + ->draft_ietf_pce_segment_routing_07 + == true) { + /* With draft07, send the sr_pce_cap_tlv as a normal TLV + */ + dll_append(tlv_list, sr_pce_cap_tlv); + } else { + /* With draft16, send the sr_pce_cap_tlv as a sub-TLV in + * the path_setup_type_capability TLV */ + sub_tlv_list = dll_initialize(); + dll_append(sub_tlv_list, sr_pce_cap_tlv); + } + + uint8_t *pst = + pceplib_malloc(PCEPLIB_MESSAGES, sizeof(uint8_t)); + *pst = SR_TE_PST; + double_linked_list *pst_list = dll_initialize(); + dll_append(pst_list, pst); + dll_append(tlv_list, pcep_tlv_create_path_setup_type_capability( + pst_list, sub_tlv_list)); + } + + struct pcep_message *open_msg = pcep_msg_create_open_with_tlvs( + session->pcc_config.keep_alive_seconds, + session->pcc_config.dead_timer_seconds, session->session_id, + tlv_list); + + pcep_log( + LOG_INFO, + "%s: [%ld-%ld] pcep_session_logic create open message: TLVs [%d] for session [%d]", + __func__, time(NULL), pthread_self(), tlv_list->num_entries, + session->session_id); + + return (open_msg); +} + + +void send_pcep_open(pcep_session *session) +{ + session_send_message(session, create_pcep_open(session)); +} + +/* This is a blocking call, since it is synchronized with destroy_pcep_session() + * and session_logic_loop(). It may be possible that the session has been + * deleted but API users havent been informed yet. + */ +bool session_exists(pcep_session *session) +{ + if (session_logic_handle_ == NULL) { + pcep_log(LOG_DEBUG, + "%s: session_exists session_logic_handle_ is NULL", + __func__); + return false; + } + + pthread_mutex_lock(&(session_logic_handle_->session_list_mutex)); + bool retval = + (ordered_list_find(session_logic_handle_->session_list, session) + != NULL); + pthread_mutex_unlock(&(session_logic_handle_->session_list_mutex)); + + return retval; +} diff --git a/pceplib/pcep_session_logic.h b/pceplib/pcep_session_logic.h new file mode 100644 index 0000000000..a082ec66da --- /dev/null +++ b/pceplib/pcep_session_logic.h @@ -0,0 +1,290 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Brady Johnson <brady@voltanet.io> + * + */ + + +#ifndef INCLUDE_PCEPSESSIONLOGIC_H_ +#define INCLUDE_PCEPSESSIONLOGIC_H_ + +#include <stdbool.h> +#include <netinet/tcp.h> + +#include "pcep_msg_encoding.h" +#include "pcep_socket_comm.h" +#include "pcep_msg_objects.h" +#include "pcep_msg_tools.h" +#include "pcep_timers.h" +#include "pcep_utils_queue.h" +#include "pcep_utils_memory.h" + +#define PCEP_TCP_PORT 4189 + +typedef struct pcep_configuration_ { + /* These are the configuration values that will + * be sent to the PCE in the PCEP Open message */ + int keep_alive_seconds; + int dead_timer_seconds; + int dead_timer_pce_negotiated_seconds; /* Config data negotiated with + PCE */ + int keep_alive_pce_negotiated_timer_seconds; /* Config data negotiated + with PCE */ + int request_time_seconds; + + /* These are the acceptable ranges of values received by + * the PCE in the initial PCEP Open Message. If a value is + * received outside of these ranges, then the Open message + * will be rejected. */ + int min_keep_alive_seconds; + int max_keep_alive_seconds; + int min_dead_timer_seconds; + int max_dead_timer_seconds; + + /* If more than this many unknown messages/requests are received + * per minute, then the session will be closed. */ + int max_unknown_messages; + int max_unknown_requests; + + /* Maximum amount of time to wait to connect to the + * PCE TCP socket before failing, in milliseconds. */ + uint32_t socket_connect_timeout_millis; + + /* Set if the PCE/PCC will support stateful PCE LSP Updates + * according to RCF8231, section 7.1.1, defaults to true. + * Will cause an additional TLV to be sent from the PCC in + * the PCEP Open */ + bool support_stateful_pce_lsp_update; + + /* RFC 8281: I-bit, the PCC allows instantiation of an LSP by a PCE */ + bool support_pce_lsp_instantiation; + + /* RFC 8232: S-bit, the PCC will include the LSP-DB-VERSION + * TLV in each LSP object */ + bool support_include_db_version; + + /* Only set if support_include_db_version is true and if the LSP-DB + * survived a restart and is available. If this has a value other than + * 0, then a LSP-DB-VERSION TLV will be sent in the OPEN object. This + * value will be copied over to the pcep_session upon init. */ + uint64_t lsp_db_version; + + /* RFC 8232: T-bit, the PCE can trigger resynchronization of + * LSPs at any point in the life of the session */ + bool support_lsp_triggered_resync; + + /* RFC 8232: D-bit, the PCEP speaker allows incremental (delta) + * State Synchronization */ + bool support_lsp_delta_sync; + + /* RFC 8232: F-bit, the PCE SHOULD trigger initial (first) + * State Synchronization */ + bool support_pce_triggered_initial_sync; + + /* draft-ietf-pce-segment-routing-16: Send a SR PCE Capability + * sub-TLV in a Path Setup Type Capability TLV with a PST = 1, + * Path is setup using SR TE. */ + bool support_sr_te_pst; + /* Used in the SR PCE Capability sub-TLV */ + bool pcc_can_resolve_nai_to_sid; + /* Used in the SR TE Capability sub-TLV, 0 means there are no max sid + * limits */ + uint8_t max_sid_depth; + + /* If set to 0, then the default 4189 PCEP port will be used */ + uint16_t dst_pcep_port; + + /* If set to 0, then the default 4189 PCEP port will be used. + * This is according to the RFC5440, Section 5 */ + uint16_t src_pcep_port; + + union src_ip { + struct in_addr src_ipv4; + struct in6_addr src_ipv6; + } src_ip; + bool is_src_ipv6; + + struct pcep_versioning *pcep_msg_versioning; + + char tcp_authentication_str[TCP_MD5SIG_MAXKEYLEN]; + bool is_tcp_auth_md5; /* true: RFC 2385, false: RFC 5925 */ + +} pcep_configuration; + + +typedef enum pcep_session_state_ { + SESSION_STATE_UNKNOWN = 0, + SESSION_STATE_INITIALIZED = 1, + SESSION_STATE_PCEP_CONNECTING = 2, + SESSION_STATE_PCEP_CONNECTED = 3 + +} pcep_session_state; + + +typedef struct pcep_session_ { + int session_id; + pcep_session_state session_state; + int timer_id_open_keep_wait; + int timer_id_open_keep_alive; + int timer_id_dead_timer; + int timer_id_keep_alive; + bool pce_open_received; + bool pce_open_rejected; + bool pce_open_accepted; + bool pce_open_keep_alive_sent; + bool pcc_open_rejected; + bool pcc_open_accepted; + bool stateful_pce; + time_t time_connected; + uint64_t lsp_db_version; + queue_handle *num_unknown_messages_time_queue; + /* set this flag when finalizing the session */ + bool destroy_session_after_write; + pcep_socket_comm_session *socket_comm_session; + /* Configuration sent from the PCC to the PCE */ + pcep_configuration pcc_config; + /* Configuration received from the PCE, to be used in the PCC */ + pcep_configuration pce_config; + struct counters_group *pcep_session_counters; + +} pcep_session; + + +typedef enum pcep_event_type { + MESSAGE_RECEIVED = 0, + PCE_CLOSED_SOCKET = 1, + PCE_SENT_PCEP_CLOSE = 2, + PCE_DEAD_TIMER_EXPIRED = 3, + PCE_OPEN_KEEP_WAIT_TIMER_EXPIRED = 4, + PCC_CONNECTED_TO_PCE = 100, + PCC_CONNECTION_FAILURE = 101, + PCC_PCEP_SESSION_CLOSED = 102, + PCC_RCVD_INVALID_OPEN = 103, + PCC_SENT_INVALID_OPEN = 104, + PCC_RCVD_MAX_INVALID_MSGS = 105, + PCC_RCVD_MAX_UNKOWN_MSGS = 106 + +} pcep_event_type; + + +typedef struct pcep_event { + enum pcep_event_type event_type; + time_t event_time; + struct pcep_message *message; + pcep_session *session; + +} pcep_event; + +typedef void (*pceplib_pcep_event_callback)(void *cb_data, pcep_event *); +typedef int (*pthread_create_callback)(pthread_t *pthread_id, + const pthread_attr_t *attr, + void *(*start_routine)(void *), + void *data, const char *thread_name); + + +typedef struct pcep_event_queue { + /* The event_queue and event_callback are mutually exclusive. + * If the event_callback is configured, then the event_queue + * will not be used. */ + queue_handle *event_queue; + pthread_mutex_t event_queue_mutex; + pceplib_pcep_event_callback event_callback; + void *event_callback_data; + +} pcep_event_queue; + + +typedef struct pceplib_infra_config { + /* Memory infrastructure */ + void *pceplib_infra_mt; + void *pceplib_messages_mt; + pceplib_malloc_func malloc_func; + pceplib_calloc_func calloc_func; + pceplib_realloc_func realloc_func; + pceplib_strdup_func strdup_func; + pceplib_free_func free_func; + + /* External Timer and Socket infrastructure */ + void *external_infra_data; + ext_timer_create timer_create_func; + ext_timer_cancel timer_cancel_func; + ext_socket_write socket_write_func; + ext_socket_read socket_read_func; + + /* External pcep_event infrastructure */ + pceplib_pcep_event_callback pcep_event_func; + + /* Callback to create pthreads */ + pthread_create_callback pthread_create_func; + +} pceplib_infra_config; + +/* + * Counters Sub-groups definitions + */ +typedef enum pcep_session_counters_subgroup_ids { + COUNTER_SUBGROUP_ID_RX_MSG = 0, + COUNTER_SUBGROUP_ID_TX_MSG = 1, + COUNTER_SUBGROUP_ID_RX_OBJ = 2, + COUNTER_SUBGROUP_ID_TX_OBJ = 3, + COUNTER_SUBGROUP_ID_RX_SUBOBJ = 4, + COUNTER_SUBGROUP_ID_TX_SUBOBJ = 5, + COUNTER_SUBGROUP_ID_RX_RO_SR_SUBOBJ = 6, + COUNTER_SUBGROUP_ID_TX_RO_SR_SUBOBJ = 7, + COUNTER_SUBGROUP_ID_RX_TLV = 8, + COUNTER_SUBGROUP_ID_TX_TLV = 9, + COUNTER_SUBGROUP_ID_EVENT = 10 + +} pcep_session_counters_subgroup_ids; + +bool run_session_logic(void); +bool run_session_logic_with_infra(pceplib_infra_config *infra_config); + +bool run_session_logic_wait_for_completion(void); + +bool stop_session_logic(void); + +/* Uses the standard PCEP TCP dest port = 4189 and an ephemeral src port. + * To use a specific dest or src port, set them other than 0 in the + * pcep_configuration. */ +pcep_session *create_pcep_session(pcep_configuration *config, + struct in_addr *pce_ip); +pcep_session *create_pcep_session_ipv6(pcep_configuration *config, + struct in6_addr *pce_ip); + +/* Send a PCEP close for this pcep_session */ +void close_pcep_session(pcep_session *session); +void close_pcep_session_with_reason(pcep_session *session, + enum pcep_close_reason); + +/* Destroy the PCEP session, a PCEP close should have + * already been sent with close_pcep_session() */ +void destroy_pcep_session(pcep_session *session); + +void pcep_session_cancel_timers(pcep_session *session); + +/* Increments transmitted message counters, additionally counters for the + * objects, sub-objects, and TLVs in the message will be incremented. Received + * counters are incremented internally. */ +void increment_message_tx_counters(pcep_session *session, + struct pcep_message *message); + +bool session_exists(pcep_session *session); + +#endif /* INCLUDE_PCEPSESSIONLOGIC_H_ */ diff --git a/pceplib/pcep_session_logic_counters.c b/pceplib/pcep_session_logic_counters.c new file mode 100644 index 0000000000..a6bd41b4f1 --- /dev/null +++ b/pceplib/pcep_session_logic_counters.c @@ -0,0 +1,450 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Brady Johnson <brady@voltanet.io> + * + */ + + +/* + * PCEP session logic counters configuration. + */ + +#include <stdio.h> +#include <time.h> + +#include "pcep_session_logic.h" +#include "pcep_session_logic_internals.h" +#include "pcep_utils_counters.h" +#include "pcep_utils_logging.h" + +void increment_message_counters(pcep_session *session, + struct pcep_message *message, bool is_rx); + +void create_session_counters(pcep_session *session) +{ + /* + * Message RX and TX counters + */ + struct counters_subgroup *rx_msg_subgroup = create_counters_subgroup( + "RX Message counters", COUNTER_SUBGROUP_ID_RX_MSG, + PCEP_TYPE_MAX + 1); + create_subgroup_counter(rx_msg_subgroup, PCEP_TYPE_OPEN, + "Message Open"); + create_subgroup_counter(rx_msg_subgroup, PCEP_TYPE_KEEPALIVE, + "Message KeepAlive"); + create_subgroup_counter(rx_msg_subgroup, PCEP_TYPE_PCREQ, + "Message PcReq"); + create_subgroup_counter(rx_msg_subgroup, PCEP_TYPE_PCREP, + "Message PcRep"); + create_subgroup_counter(rx_msg_subgroup, PCEP_TYPE_PCNOTF, + "Message Notify"); + create_subgroup_counter(rx_msg_subgroup, PCEP_TYPE_ERROR, + "Message Error"); + create_subgroup_counter(rx_msg_subgroup, PCEP_TYPE_CLOSE, + "Message Close"); + create_subgroup_counter(rx_msg_subgroup, PCEP_TYPE_REPORT, + "Message Report"); + create_subgroup_counter(rx_msg_subgroup, PCEP_TYPE_UPDATE, + "Message Update"); + create_subgroup_counter(rx_msg_subgroup, PCEP_TYPE_INITIATE, + "Message Initiate"); + create_subgroup_counter(rx_msg_subgroup, PCEP_TYPE_START_TLS, + "Message StartTls"); + create_subgroup_counter(rx_msg_subgroup, PCEP_TYPE_MAX, + "Message Erroneous"); + + struct counters_subgroup *tx_msg_subgroup = + clone_counters_subgroup(rx_msg_subgroup, "TX Message counters", + COUNTER_SUBGROUP_ID_TX_MSG); + + /* + * Object RX and TX counters + */ + + /* For the Endpoints, the ID will be either 64 or 65, so setting + * num_counters to 100 */ + struct counters_subgroup *rx_obj_subgroup = create_counters_subgroup( + "RX Object counters", COUNTER_SUBGROUP_ID_RX_OBJ, 100); + create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_OPEN, + "Object Open"); + create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_RP, + "Object RP"); + create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_NOPATH, + "Object Nopath"); + create_subgroup_counter( + rx_obj_subgroup, + ((PCEP_OBJ_CLASS_ENDPOINTS << 4) | PCEP_OBJ_TYPE_ENDPOINT_IPV4), + "Object Endpoint IPv4"); + create_subgroup_counter( + rx_obj_subgroup, + ((PCEP_OBJ_CLASS_ENDPOINTS << 4) | PCEP_OBJ_TYPE_ENDPOINT_IPV6), + "Object Endpoint IPv6"); + create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_BANDWIDTH, + "Object Bandwidth"); + create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_METRIC, + "Object Metric"); + create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_ERO, + "Object ERO"); + create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_RRO, + "Object RRO"); + create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_LSPA, + "Object LSPA"); + create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_IRO, + "Object IRO"); + create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_SVEC, + "Object SVEC"); + create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_NOTF, + "Object Notify"); + create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_ERROR, + "Object Error"); + create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_CLOSE, + "Object Close"); + create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_LSP, + "Object LSP"); + create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_SRP, + "Object SRP"); + create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_VENDOR_INFO, + "Object Vendor Info"); + create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_INTER_LAYER, + "Object Inter-Layer"); + create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_SWITCH_LAYER, + "Object Switch-Layer"); + create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_REQ_ADAP_CAP, + "Object Requested Adap-Cap"); + create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_SERVER_IND, + "Object Server-Indication"); + create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_ASSOCIATION, + "Object Association"); + create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_MAX, + "Object Unknown"); + create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_MAX + 1, + "Object Erroneous"); + + struct counters_subgroup *tx_obj_subgroup = + clone_counters_subgroup(rx_obj_subgroup, "TX Object counters", + COUNTER_SUBGROUP_ID_TX_OBJ); + + /* + * Sub-Object RX and TX counters + */ + struct counters_subgroup *rx_subobj_subgroup = create_counters_subgroup( + "RX RO Sub-Object counters", COUNTER_SUBGROUP_ID_RX_SUBOBJ, + RO_SUBOBJ_UNKNOWN + 2); + create_subgroup_counter(rx_subobj_subgroup, RO_SUBOBJ_TYPE_IPV4, + "RO Sub-Object IPv4"); + create_subgroup_counter(rx_subobj_subgroup, RO_SUBOBJ_TYPE_IPV6, + "RO Sub-Object IPv6"); + create_subgroup_counter(rx_subobj_subgroup, RO_SUBOBJ_TYPE_LABEL, + "RO Sub-Object Label"); + create_subgroup_counter(rx_subobj_subgroup, RO_SUBOBJ_TYPE_UNNUM, + "RO Sub-Object Unnum"); + create_subgroup_counter(rx_subobj_subgroup, RO_SUBOBJ_TYPE_ASN, + "RO Sub-Object ASN"); + create_subgroup_counter(rx_subobj_subgroup, RO_SUBOBJ_TYPE_SR, + "RO Sub-Object SR"); + create_subgroup_counter(rx_subobj_subgroup, RO_SUBOBJ_UNKNOWN, + "RO Sub-Object Unknown"); + create_subgroup_counter(rx_subobj_subgroup, RO_SUBOBJ_UNKNOWN + 1, + "RO Sub-Object Erroneous"); + + struct counters_subgroup *tx_subobj_subgroup = clone_counters_subgroup( + rx_subobj_subgroup, "TX RO Sub-Object counters", + COUNTER_SUBGROUP_ID_TX_SUBOBJ); + + /* + * RO SR Sub-Object RX and TX counters + */ + struct counters_subgroup *rx_subobj_sr_nai_subgroup = + create_counters_subgroup("RX RO SR NAI Sub-Object counters", + COUNTER_SUBGROUP_ID_RX_RO_SR_SUBOBJ, + PCEP_SR_SUBOBJ_NAI_UNKNOWN + 1); + create_subgroup_counter(rx_subobj_sr_nai_subgroup, + PCEP_SR_SUBOBJ_NAI_ABSENT, + "RO Sub-Object SR NAI absent"); + create_subgroup_counter(rx_subobj_sr_nai_subgroup, + PCEP_SR_SUBOBJ_NAI_IPV4_NODE, + "RO Sub-Object SR NAI IPv4 Node"); + create_subgroup_counter(rx_subobj_sr_nai_subgroup, + PCEP_SR_SUBOBJ_NAI_IPV6_NODE, + "RO Sub-Object SR NAI IPv6 Node"); + create_subgroup_counter(rx_subobj_sr_nai_subgroup, + PCEP_SR_SUBOBJ_NAI_IPV4_ADJACENCY, + "RO Sub-Object SR NAI IPv4 Adj"); + create_subgroup_counter(rx_subobj_sr_nai_subgroup, + PCEP_SR_SUBOBJ_NAI_IPV6_ADJACENCY, + "RO Sub-Object SR NAI IPv6 Adj"); + create_subgroup_counter(rx_subobj_sr_nai_subgroup, + PCEP_SR_SUBOBJ_NAI_UNNUMBERED_IPV4_ADJACENCY, + "RO Sub-Object SR NAI Unnumbered IPv4 Adj"); + create_subgroup_counter(rx_subobj_sr_nai_subgroup, + PCEP_SR_SUBOBJ_NAI_LINK_LOCAL_IPV6_ADJACENCY, + "RO Sub-Object SR NAI Link Local IPv6 Adj"); + create_subgroup_counter(rx_subobj_sr_nai_subgroup, + PCEP_SR_SUBOBJ_NAI_UNKNOWN, + "RO Sub-Object SR NAI Unknown"); + + struct counters_subgroup *tx_subobj_sr_nai_subgroup = + clone_counters_subgroup(rx_subobj_sr_nai_subgroup, + "TX RO SR NAI Sub-Object counters", + COUNTER_SUBGROUP_ID_TX_RO_SR_SUBOBJ); + + /* + * TLV RX and TX counters + */ + struct counters_subgroup *rx_tlv_subgroup = create_counters_subgroup( + "RX TLV counters", COUNTER_SUBGROUP_ID_RX_TLV, + PCEP_OBJ_TLV_TYPE_UNKNOWN + 1); + create_subgroup_counter(rx_tlv_subgroup, + PCEP_OBJ_TLV_TYPE_NO_PATH_VECTOR, + "TLV No Path Vector"); + create_subgroup_counter(rx_tlv_subgroup, PCEP_OBJ_TLV_TYPE_VENDOR_INFO, + "TLV Vendor Info"); + create_subgroup_counter(rx_tlv_subgroup, + PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY, + "TLV Stateful PCE Capability"); + create_subgroup_counter(rx_tlv_subgroup, + PCEP_OBJ_TLV_TYPE_SYMBOLIC_PATH_NAME, + "TLV Symbolic Path Name"); + create_subgroup_counter(rx_tlv_subgroup, + PCEP_OBJ_TLV_TYPE_IPV4_LSP_IDENTIFIERS, + "TLV IPv4 LSP Identifier"); + create_subgroup_counter(rx_tlv_subgroup, + PCEP_OBJ_TLV_TYPE_IPV6_LSP_IDENTIFIERS, + "TLV IPv6 LSP Identifier"); + create_subgroup_counter(rx_tlv_subgroup, + PCEP_OBJ_TLV_TYPE_LSP_ERROR_CODE, + "TLV LSP Error Code"); + create_subgroup_counter(rx_tlv_subgroup, + PCEP_OBJ_TLV_TYPE_RSVP_ERROR_SPEC, + "TLV RSVP Error Spec"); + create_subgroup_counter(rx_tlv_subgroup, + PCEP_OBJ_TLV_TYPE_LSP_DB_VERSION, + "TLV LSP DB Version"); + create_subgroup_counter(rx_tlv_subgroup, + PCEP_OBJ_TLV_TYPE_SPEAKER_ENTITY_ID, + "TLV Speaker Entity ID"); + create_subgroup_counter(rx_tlv_subgroup, + PCEP_OBJ_TLV_TYPE_SR_PCE_CAPABILITY, + "TLV SR PCE Capability"); + create_subgroup_counter(rx_tlv_subgroup, + PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE, + "TLV Path Setup Type"); + create_subgroup_counter(rx_tlv_subgroup, + PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE_CAPABILITY, + "TLV Path Setup Type Capability"); + create_subgroup_counter(rx_tlv_subgroup, + PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_ID, + "TLV SR Policy PolId"); + create_subgroup_counter(rx_tlv_subgroup, + PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_NAME, + "TLV SR Policy PolName"); + create_subgroup_counter(rx_tlv_subgroup, + PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_ID, + "TLV SR Policy CpathId"); + create_subgroup_counter(rx_tlv_subgroup, + PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_PREFERENCE, + "TLV SR Policy CpathRef"); + create_subgroup_counter(rx_tlv_subgroup, PCEP_OBJ_TLV_TYPE_UNKNOWN, + "TLV Unknown"); + + struct counters_subgroup *tx_tlv_subgroup = clone_counters_subgroup( + rx_tlv_subgroup, "TX TLV counters", COUNTER_SUBGROUP_ID_TX_TLV); + + /* + * PCEP Event counters + */ + struct counters_subgroup *events_subgroup = create_counters_subgroup( + "Events counters", COUNTER_SUBGROUP_ID_EVENT, MAX_COUNTERS); + create_subgroup_counter(events_subgroup, + PCEP_EVENT_COUNTER_ID_PCC_CONNECT, + "PCC connect"); + create_subgroup_counter(events_subgroup, + PCEP_EVENT_COUNTER_ID_PCE_CONNECT, + "PCE connect"); + create_subgroup_counter(events_subgroup, + PCEP_EVENT_COUNTER_ID_PCC_DISCONNECT, + "PCC disconnect"); + create_subgroup_counter(events_subgroup, + PCEP_EVENT_COUNTER_ID_PCE_DISCONNECT, + "PCE disconnect"); + create_subgroup_counter(events_subgroup, + PCEP_EVENT_COUNTER_ID_TIMER_KEEPALIVE, + "Timer KeepAlive expired"); + create_subgroup_counter(events_subgroup, + PCEP_EVENT_COUNTER_ID_TIMER_DEADTIMER, + "Timer DeadTimer expired"); + create_subgroup_counter(events_subgroup, + PCEP_EVENT_COUNTER_ID_TIMER_OPENKEEPWAIT, + "Timer OpenKeepWait expired"); + create_subgroup_counter(events_subgroup, + PCEP_EVENT_COUNTER_ID_TIMER_OPENKEEPALIVE, + "Timer OpenKeepAlive expired"); + + /* + * Create the parent counters group + */ + time_t now = time(NULL); + char counters_name[MAX_COUNTER_STR_LENGTH] = {0}; + char ip_str[40] = {0}; + if (session->socket_comm_session->is_ipv6) { + inet_ntop(AF_INET6, + &session->socket_comm_session->dest_sock_addr + .dest_sock_addr_ipv6.sin6_addr, + ip_str, 40); + } else { + inet_ntop(AF_INET, + &session->socket_comm_session->dest_sock_addr + .dest_sock_addr_ipv4.sin_addr, + ip_str, 40); + } + snprintf(counters_name, MAX_COUNTER_STR_LENGTH, + "PCEP Session [%d], connected to [%s] for [%u seconds]", + session->session_id, ip_str, + (uint32_t)(now - session->time_connected)); + /* The (time(NULL) - session->time_connected) will probably be 0, + * so the group name will be updated when the counters are dumped */ + session->pcep_session_counters = + create_counters_group(counters_name, MAX_COUNTER_GROUPS); + + /* + * Add all the subgroups to the parent counters group + */ + add_counters_subgroup(session->pcep_session_counters, rx_msg_subgroup); + add_counters_subgroup(session->pcep_session_counters, tx_msg_subgroup); + add_counters_subgroup(session->pcep_session_counters, rx_obj_subgroup); + add_counters_subgroup(session->pcep_session_counters, tx_obj_subgroup); + add_counters_subgroup(session->pcep_session_counters, + rx_subobj_subgroup); + add_counters_subgroup(session->pcep_session_counters, + tx_subobj_subgroup); + add_counters_subgroup(session->pcep_session_counters, + rx_subobj_sr_nai_subgroup); + add_counters_subgroup(session->pcep_session_counters, + tx_subobj_sr_nai_subgroup); + add_counters_subgroup(session->pcep_session_counters, rx_tlv_subgroup); + add_counters_subgroup(session->pcep_session_counters, tx_tlv_subgroup); + add_counters_subgroup(session->pcep_session_counters, events_subgroup); +} + +/* Internal util function used by increment_message_rx_counters or + * increment_message_tx_counters */ +void increment_message_counters(pcep_session *session, + struct pcep_message *message, bool is_rx) +{ + uint16_t counter_subgroup_id_msg = (is_rx ? COUNTER_SUBGROUP_ID_RX_MSG + : COUNTER_SUBGROUP_ID_TX_MSG); + uint16_t counter_subgroup_id_obj = (is_rx ? COUNTER_SUBGROUP_ID_RX_OBJ + : COUNTER_SUBGROUP_ID_TX_OBJ); + uint16_t counter_subgroup_id_subobj = + (is_rx ? COUNTER_SUBGROUP_ID_RX_SUBOBJ + : COUNTER_SUBGROUP_ID_TX_SUBOBJ); + uint16_t counter_subgroup_id_ro_sr_subobj = + (is_rx ? COUNTER_SUBGROUP_ID_RX_RO_SR_SUBOBJ + : COUNTER_SUBGROUP_ID_TX_RO_SR_SUBOBJ); + uint16_t counter_subgroup_id_tlv = (is_rx ? COUNTER_SUBGROUP_ID_RX_TLV + : COUNTER_SUBGROUP_ID_TX_TLV); + + increment_counter(session->pcep_session_counters, + counter_subgroup_id_msg, message->msg_header->type); + + /* Iterate the objects */ + double_linked_list_node *obj_node = + (message->obj_list == NULL ? NULL : message->obj_list->head); + for (; obj_node != NULL; obj_node = obj_node->next_node) { + struct pcep_object_header *obj = + (struct pcep_object_header *)obj_node->data; + + /* Handle class: PCEP_OBJ_CLASS_ENDPOINTS, + * type: PCEP_OBJ_TYPE_ENDPOINT_IPV4 or + * PCEP_OBJ_TYPE_ENDPOINT_IPV6 */ + uint16_t obj_counter_id = + (obj->object_class == PCEP_OBJ_CLASS_ENDPOINTS + ? (obj->object_class << 4) | obj->object_type + : obj->object_class); + + increment_counter(session->pcep_session_counters, + counter_subgroup_id_obj, obj_counter_id); + + /* Iterate the RO Sub-objects */ + if (obj->object_class == PCEP_OBJ_CLASS_ERO + || obj->object_class == PCEP_OBJ_CLASS_IRO + || obj->object_class == PCEP_OBJ_CLASS_RRO) { + struct pcep_object_ro *ro_obj = + (struct pcep_object_ro *)obj; + + double_linked_list_node *ro_subobj_node = + (ro_obj->sub_objects == NULL + ? NULL + : ro_obj->sub_objects->head); + for (; ro_subobj_node != NULL; + ro_subobj_node = ro_subobj_node->next_node) { + struct pcep_object_ro_subobj *ro_subobj = + (struct pcep_object_ro_subobj *) + ro_subobj_node->data; + increment_counter( + session->pcep_session_counters, + counter_subgroup_id_subobj, + ro_subobj->ro_subobj_type); + + /* Handle the ro subobj type RO_SUBOBJ_TYPE_SR + * different NAI types */ + if (ro_subobj->ro_subobj_type + == RO_SUBOBJ_TYPE_SR) { + struct pcep_ro_subobj_sr *ro_sr_subobj = + (struct pcep_ro_subobj_sr *) + ro_subobj; + increment_counter( + session->pcep_session_counters, + counter_subgroup_id_ro_sr_subobj, + ro_sr_subobj->nai_type); + } + } + } + + /* Iterate the TLVs */ + double_linked_list_node *tlv_node = + (obj->tlv_list == NULL ? NULL : obj->tlv_list->head); + for (; tlv_node != NULL; tlv_node = tlv_node->next_node) { + struct pcep_object_tlv_header *tlv = + (struct pcep_object_tlv_header *)tlv_node->data; + increment_counter(session->pcep_session_counters, + counter_subgroup_id_tlv, tlv->type); + } + } +} + +void increment_message_rx_counters(pcep_session *session, + struct pcep_message *message) +{ + increment_message_counters(session, message, true); +} + +void increment_message_tx_counters(pcep_session *session, + struct pcep_message *message) +{ + increment_message_counters(session, message, false); +} + +void increment_event_counters( + pcep_session *session, + pcep_session_counters_event_counter_ids counter_id) +{ + increment_counter(session->pcep_session_counters, + COUNTER_SUBGROUP_ID_EVENT, counter_id); +} diff --git a/pceplib/pcep_session_logic_internals.h b/pceplib/pcep_session_logic_internals.h new file mode 100644 index 0000000000..004459b918 --- /dev/null +++ b/pceplib/pcep_session_logic_internals.h @@ -0,0 +1,109 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Brady Johnson <brady@voltanet.io> + * + */ + + +/* + * Internal Session Logic declarations, not intended to be in the public API. + */ + +#ifndef SRC_PCEPSESSIONLOGICINTERNALS_H_ +#define SRC_PCEPSESSIONLOGICINTERNALS_H_ + + +#include <pthread.h> +#include <stdbool.h> + +#include "pcep_msg_tools.h" + +#include "pcep_utils_double_linked_list.h" +#include "pcep_utils_ordered_list.h" +#include "pcep_utils_queue.h" + + +typedef struct pcep_session_logic_handle_ { + pthread_t session_logic_thread; + pthread_mutex_t session_logic_mutex; + pthread_cond_t session_logic_cond_var; + bool session_logic_condition; + bool active; + + ordered_list_handle *session_list; + pthread_mutex_t session_list_mutex; + /* Internal timers and socket events */ + queue_handle *session_event_queue; + +} pcep_session_logic_handle; + + +/* Used internally for Session events: message received, timer expired, + * or socket closed */ +typedef struct pcep_session_event_ { + pcep_session *session; + int expired_timer_id; + double_linked_list *received_msg_list; + bool socket_closed; + +} pcep_session_event; + +/* Event Counters counter-id definitions */ +typedef enum pcep_session_counters_event_counter_ids { + PCEP_EVENT_COUNTER_ID_PCC_CONNECT = 0, + PCEP_EVENT_COUNTER_ID_PCE_CONNECT = 1, + PCEP_EVENT_COUNTER_ID_PCC_DISCONNECT = 2, + PCEP_EVENT_COUNTER_ID_PCE_DISCONNECT = 3, + PCEP_EVENT_COUNTER_ID_TIMER_KEEPALIVE = 4, + PCEP_EVENT_COUNTER_ID_TIMER_DEADTIMER = 5, + PCEP_EVENT_COUNTER_ID_TIMER_OPENKEEPWAIT = 6, + PCEP_EVENT_COUNTER_ID_TIMER_OPENKEEPALIVE = 7 + +} pcep_session_counters_event_counter_ids; + +/* functions implemented in pcep_session_logic_loop.c */ +void *session_logic_loop(void *data); +int session_logic_msg_ready_handler(void *data, int socket_fd); +void session_logic_message_sent_handler(void *data, int socket_fd); +void session_logic_conn_except_notifier(void *data, int socket_fd); +void session_logic_timer_expire_handler(void *data, int timer_id); + +void handle_timer_event(pcep_session_event *event); +void handle_socket_comm_event(pcep_session_event *event); +void session_send_message(pcep_session *session, struct pcep_message *message); + +/* defined in pcep_session_logic_states.c */ +void send_pcep_error(pcep_session *session, enum pcep_error_type error_type, + enum pcep_error_value error_value); +void enqueue_event(pcep_session *session, pcep_event_type event_type, + struct pcep_message *message); +void increment_unknown_message(pcep_session *session); + +/* defined in pcep_session_logic_counters.c */ +void create_session_counters(pcep_session *session); +void increment_event_counters( + pcep_session *session, + pcep_session_counters_event_counter_ids counter_id); +void increment_message_rx_counters(pcep_session *session, + struct pcep_message *message); + +/* defined in pcep_session_logic.c, also used in pcep_session_logic_states.c */ +struct pcep_message *create_pcep_open(pcep_session *session); + +#endif /* SRC_PCEPSESSIONLOGICINTERNALS_H_ */ diff --git a/pceplib/pcep_session_logic_loop.c b/pceplib/pcep_session_logic_loop.c new file mode 100644 index 0000000000..269aa1e07e --- /dev/null +++ b/pceplib/pcep_session_logic_loop.c @@ -0,0 +1,361 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Brady Johnson <brady@voltanet.io> + * + */ + +#include <pthread.h> +#include <stdbool.h> +#include <stdio.h> + +#include "pcep_session_logic.h" +#include "pcep_session_logic_internals.h" +#include "pcep_timers.h" +#include "pcep_utils_logging.h" +#include "pcep_utils_memory.h" + +/* global var needed for callback handlers */ +extern pcep_session_logic_handle *session_logic_handle_; + +/* internal util function to create session_event's */ +static pcep_session_event *create_session_event(pcep_session *session) +{ + pcep_session_event *event = + pceplib_malloc(PCEPLIB_INFRA, sizeof(pcep_session_event)); + event->session = session; + event->expired_timer_id = TIMER_ID_NOT_SET; + event->received_msg_list = NULL; + event->socket_closed = false; + + return event; +} + + +/* A function pointer to this function is passed to pcep_socket_comm + * for each pcep_session creation, so it will be called whenever + * messages are ready to be read. This function will be called + * by the socket_comm thread. + * This function will decode the read PCEP message and give it + * to the session_logic_loop so it can be handled by the session_logic + * state machine. */ +int session_logic_msg_ready_handler(void *data, int socket_fd) +{ + if (data == NULL) { + pcep_log(LOG_WARNING, + "%s: Cannot handle msg_ready with NULL data", + __func__); + return -1; + } + + if (session_logic_handle_->active == false) { + pcep_log( + LOG_WARNING, + "%s: Received a message ready notification while the session logic is not active", + __func__); + return -1; + } + + pcep_session *session = (pcep_session *)data; + + pthread_mutex_lock(&(session_logic_handle_->session_logic_mutex)); + session_logic_handle_->session_logic_condition = true; + + /* This event will ultimately be handled by handle_socket_comm_event() + * in pcep_session_logic_states.c */ + pcep_session_event *rcvd_msg_event = create_session_event(session); + + int msg_length = 0; + double_linked_list *msg_list = pcep_msg_read(socket_fd); + + if (msg_list == NULL) { + /* The socket was closed, or there was a socket read error */ + pcep_log(LOG_INFO, + "%s: PCEP connection closed for session [%d]", + __func__, session->session_id); + dll_destroy(msg_list); + rcvd_msg_event->socket_closed = true; + socket_comm_session_teardown(session->socket_comm_session); + pcep_session_cancel_timers(session); + session->socket_comm_session = NULL; + session->session_state = SESSION_STATE_INITIALIZED; + enqueue_event(session, PCE_CLOSED_SOCKET, NULL); + } 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 */ + struct pcep_message *msg = + ((struct pcep_message *)msg_list->head->data); + pcep_log( + LOG_INFO, + "%s: [%ld-%ld] session_logic_msg_ready_handler received message of type [%d] len [%d] on session [%d]", + __func__, time(NULL), pthread_self(), + msg->msg_header->type, msg->encoded_message_length, + session->session_id); + + rcvd_msg_event->received_msg_list = msg_list; + msg_length = msg->encoded_message_length; + } + + queue_enqueue(session_logic_handle_->session_event_queue, + rcvd_msg_event); + pthread_cond_signal(&(session_logic_handle_->session_logic_cond_var)); + pthread_mutex_unlock(&(session_logic_handle_->session_logic_mutex)); + + return msg_length; +} + + +/* A function pointer to this function was passed to pcep_socket_comm, + * so it will be called when a message is sent. This is useful since + * message sending is asynchronous, and there are times that actions + * need to be performed only after a message has been sent. */ +void session_logic_message_sent_handler(void *data, int socket_fd) +{ + (void)socket_fd; + + if (data == NULL) { + pcep_log(LOG_WARNING, + "%s: Cannot handle msg_sent with NULL data", __func__); + return; + } + + pcep_session *session = (pcep_session *)data; + if (session->destroy_session_after_write == true) { + /* Do not call destroy until all of the queued messages are + * written */ + if (session->socket_comm_session != NULL + && session->socket_comm_session->message_queue->num_entries + == 0) { + destroy_pcep_session(session); + } + } else { + /* Reset the keep alive timer for every message sent on + * the session, only if the session is not destroyed */ + if (session->timer_id_keep_alive == TIMER_ID_NOT_SET) { + pcep_log( + LOG_INFO, + "%s: [%ld-%ld] pcep_session_logic set keep alive timer [%d secs] for session [%d]", + __func__, time(NULL), pthread_self(), + session->pcc_config + .keep_alive_pce_negotiated_timer_seconds, + session->session_id); + session->timer_id_keep_alive = create_timer( + session->pcc_config + .keep_alive_pce_negotiated_timer_seconds, + session); + } else { + pcep_log( + LOG_INFO, + "%s: [%ld-%ld] pcep_session_logic reset keep alive timer [%d secs] for session [%d]", + __func__, time(NULL), pthread_self(), + session->pcc_config + .keep_alive_pce_negotiated_timer_seconds, + session->session_id); + reset_timer(session->timer_id_keep_alive); + } + } +} + + +/* A function pointer to this function was passed to pcep_socket_comm, + * so it will be called whenever the socket is closed. this function + * will be called by the socket_comm thread. */ +void session_logic_conn_except_notifier(void *data, int socket_fd) +{ + if (data == NULL) { + pcep_log(LOG_WARNING, + "%s: Cannot handle conn_except with NULL data", + __func__); + return; + } + + if (session_logic_handle_->active == false) { + pcep_log( + LOG_WARNING, + "%s: Received a connection exception notification while the session logic is not active", + __func__); + return; + } + + pcep_session *session = (pcep_session *)data; + pcep_log( + LOG_INFO, + "%s: [%ld-%ld] pcep_session_logic session_logic_conn_except_notifier socket closed [%d], session [%d]", + __func__, time(NULL), pthread_self(), socket_fd, + session->session_id); + + pthread_mutex_lock(&(session_logic_handle_->session_logic_mutex)); + pcep_session_event *socket_event = create_session_event(session); + socket_event->socket_closed = true; + queue_enqueue(session_logic_handle_->session_event_queue, socket_event); + 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)); +} + + +/* + * this method is the timer expire handler, and will only + * pass the event to the session_logic loop and notify it + * that there is a timer available. this function will be + * called by the timers thread. + */ +void session_logic_timer_expire_handler(void *data, int timer_id) +{ + if (data == NULL) { + pcep_log(LOG_WARNING, "%s: Cannot handle timer with NULL data", + __func__); + return; + } + + if (session_logic_handle_->active == false) { + pcep_log( + LOG_WARNING, + "%s: Received a timer expiration while the session logic is not active", + __func__); + return; + } + + pcep_log(LOG_INFO, "%s: [%ld-%ld] timer expired handler timer_id [%d]", + __func__, time(NULL), pthread_self(), timer_id); + pcep_session_event *expired_timer_event = + create_session_event((pcep_session *)data); + expired_timer_event->expired_timer_id = timer_id; + + pthread_mutex_lock(&(session_logic_handle_->session_logic_mutex)); + session_logic_handle_->session_logic_condition = true; + queue_enqueue(session_logic_handle_->session_event_queue, + expired_timer_event); + + pthread_cond_signal(&(session_logic_handle_->session_logic_cond_var)); + pthread_mutex_unlock(&(session_logic_handle_->session_logic_mutex)); +} + + +/* + * session_logic event loop + * this function is called upon thread creation from pcep_session_logic.c + */ +void *session_logic_loop(void *data) +{ + if (data == NULL) { + pcep_log(LOG_WARNING, + "%s: Cannot start session_logic_loop with NULL data", + __func__); + + return NULL; + } + + pcep_log(LOG_NOTICE, "%s: [%ld-%ld] Starting session_logic_loop thread", + __func__, time(NULL), pthread_self()); + + pcep_session_logic_handle *session_logic_handle = + (pcep_session_logic_handle *)data; + + while (session_logic_handle->active) { + /* Mutex locking for session_logic_loop condition variable */ + pthread_mutex_lock( + &(session_logic_handle->session_logic_mutex)); + + /* this internal loop helps avoid spurious interrupts */ + while (!session_logic_handle->session_logic_condition) { + pthread_cond_wait( + &(session_logic_handle->session_logic_cond_var), + &(session_logic_handle->session_logic_mutex)); + } + + pcep_session_event *event = queue_dequeue( + session_logic_handle->session_event_queue); + while (event != NULL) { + if (event->session == NULL) { + pcep_log( + LOG_INFO, + "%s: [%ld-%ld] Invalid session_logic_loop event [%s] with NULL session", + __func__, time(NULL), pthread_self(), + (event->expired_timer_id + != TIMER_ID_NOT_SET) + ? "timer" + : "message"); + pceplib_free(PCEPLIB_INFRA, event); + event = queue_dequeue( + session_logic_handle + ->session_event_queue); + continue; + } + + /* Check if the session still exists, and synchronize + * possible session destroy */ + pcep_log( + LOG_DEBUG, + "%s: session_logic_loop checking session_list sessionPtr %p", + __func__, event->session); + pthread_mutex_lock( + &(session_logic_handle->session_list_mutex)); + if (ordered_list_find( + session_logic_handle->session_list, + event->session) + == NULL) { + pcep_log( + LOG_INFO, + "%s: [%ld-%ld] In-flight event [%s] for destroyed session being discarded", + __func__, time(NULL), pthread_self(), + (event->expired_timer_id + != TIMER_ID_NOT_SET) + ? "timer" + : "message"); + pceplib_free(PCEPLIB_INFRA, event); + event = queue_dequeue( + session_logic_handle + ->session_event_queue); + pthread_mutex_unlock( + &(session_logic_handle_ + ->session_list_mutex)); + continue; + } + + if (event->expired_timer_id != TIMER_ID_NOT_SET) { + handle_timer_event(event); + } + + if (event->received_msg_list != NULL) { + handle_socket_comm_event(event); + } + + pceplib_free(PCEPLIB_INFRA, event); + event = queue_dequeue( + session_logic_handle->session_event_queue); + + pthread_mutex_unlock( + &(session_logic_handle_->session_list_mutex)); + } + + session_logic_handle->session_logic_condition = false; + pthread_mutex_unlock( + &(session_logic_handle->session_logic_mutex)); + } + + pcep_log(LOG_NOTICE, "%s: [%ld-%ld] Finished session_logic_loop thread", + __func__, time(NULL), pthread_self()); + + return NULL; +} diff --git a/pceplib/pcep_session_logic_states.c b/pceplib/pcep_session_logic_states.c new file mode 100644 index 0000000000..3beceefad0 --- /dev/null +++ b/pceplib/pcep_session_logic_states.c @@ -0,0 +1,1135 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Brady Johnson <brady@voltanet.io> + * + */ + +#include <pthread.h> +#include <stdbool.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> + +#include "pcep_msg_encoding.h" +#include "pcep_session_logic.h" +#include "pcep_session_logic_internals.h" +#include "pcep_timers.h" +#include "pcep_utils_logging.h" +#include "pcep_utils_memory.h" + +#define TIMER_OPEN_KEEP_ALIVE_SECONDS 1 + +/* Session Logic Handle managed in pcep_session_logic.c */ +extern pcep_event_queue *session_logic_event_queue_; +void send_keep_alive(pcep_session *session); +void send_pcep_error_with_object(pcep_session *session, + enum pcep_error_type error_type, + enum pcep_error_value error_value, + struct pcep_object_header *object); +void reset_dead_timer(pcep_session *session); +bool verify_pcep_open_object(pcep_session *session, + struct pcep_object_open *open_object); +void send_reconciled_pcep_open(pcep_session *session, + struct pcep_message *error_msg); +bool handle_pcep_update(pcep_session *session, struct pcep_message *upd_msg); +bool handle_pcep_initiate(pcep_session *session, struct pcep_message *init_msg); +bool check_and_send_open_keep_alive(pcep_session *session); +void log_pcc_pce_connection(pcep_session *session); +bool handle_pcep_open(pcep_session *session, struct pcep_message *open_msg); + +/* + * util functions called by the state handling below + */ + +void send_keep_alive(pcep_session *session) +{ + struct pcep_message *keep_alive_msg = pcep_msg_create_keepalive(); + + pcep_log( + LOG_INFO, + "%s: [%ld-%ld] pcep_session_logic send keep_alive message for session [%d]", + __func__, time(NULL), pthread_self(), session->session_id); + + session_send_message(session, keep_alive_msg); + + /* The keep alive timer will be (re)set once the message + * is sent in session_logic_message_sent_handler() */ +} + + +/* Send an error message with the corrected or offending object */ +void send_pcep_error_with_object(pcep_session *session, + enum pcep_error_type error_type, + enum pcep_error_value error_value, + struct pcep_object_header *object) +{ + double_linked_list *obj_list = dll_initialize(); + dll_append(obj_list, object); + struct pcep_message *error_msg = pcep_msg_create_error_with_objects( + error_type, error_value, obj_list); + + pcep_log( + LOG_INFO, + "%s: [%ld-%ld] pcep_session_logic send error message with object [%d][%d] for session [%d]", + __func__, time(NULL), pthread_self(), error_type, error_value, + session->session_id); + + session_send_message(session, error_msg); +} + + +void send_pcep_error(pcep_session *session, enum pcep_error_type error_type, + enum pcep_error_value error_value) +{ + struct pcep_message *error_msg = + pcep_msg_create_error(error_type, error_value); + + pcep_log( + LOG_INFO, + "%s: [%ld-%ld] pcep_session_logic send error message [%d][%d] for session [%d]", + __func__, time(NULL), pthread_self(), error_type, error_value, + session->session_id); + + session_send_message(session, error_msg); +} + + +void reset_dead_timer(pcep_session *session) +{ + /* Default to configured dead_timer if its not set yet or set to 0 by + * the PCE */ + int dead_timer_seconds = + (session->pcc_config.dead_timer_pce_negotiated_seconds == 0) + ? session->pcc_config.dead_timer_seconds + : session->pcc_config.dead_timer_pce_negotiated_seconds; + + if (session->timer_id_dead_timer == TIMER_ID_NOT_SET) { + session->timer_id_dead_timer = + create_timer(dead_timer_seconds, session); + pcep_log( + LOG_INFO, + "%s: [%ld-%ld] pcep_session_logic set dead timer [%d secs] id [%d] for session [%d]", + __func__, time(NULL), pthread_self(), + dead_timer_seconds, session->timer_id_dead_timer, + session->session_id); + } else { + pcep_log( + LOG_INFO, + "%s: [%ld-%ld] pcep_session_logic reset dead timer [%d secs] id [%d] for session [%d]", + __func__, time(NULL), pthread_self(), + dead_timer_seconds, session->timer_id_dead_timer, + session->session_id); + reset_timer(session->timer_id_dead_timer); + } +} + + +void enqueue_event(pcep_session *session, pcep_event_type event_type, + struct pcep_message *message) +{ + if (event_type == MESSAGE_RECEIVED && message == NULL) { + pcep_log( + LOG_WARNING, + "%s: enqueue_event cannot enqueue a NULL message session [%d]", + __func__, session->session_id); + return; + } + + pcep_event *event = pceplib_malloc(PCEPLIB_INFRA, sizeof(pcep_event)); + memset(event, 0, sizeof(pcep_event)); + + event->session = session; + event->event_type = event_type; + event->event_time = time(NULL); + event->message = message; + + pthread_mutex_lock(&session_logic_event_queue_->event_queue_mutex); + if (session_logic_event_queue_->event_callback != NULL) { + session_logic_event_queue_->event_callback( + session_logic_event_queue_->event_callback_data, event); + } else { + queue_enqueue(session_logic_event_queue_->event_queue, event); + } + pthread_mutex_unlock(&session_logic_event_queue_->event_queue_mutex); +} + +/* Verify the received PCEP Open object parameters are acceptable. If not, + * update the unacceptable value(s) with an acceptable value so it can be sent + * back to the sender. */ +bool verify_pcep_open_object(pcep_session *session, + struct pcep_object_open *open_object) +{ + int retval = true; + + if (open_object->open_keepalive + < session->pcc_config.min_keep_alive_seconds) { + pcep_log( + LOG_INFO, + "%s: Rejecting unsupported Open Keep Alive value [%d] min [%d]", + __func__, open_object->open_keepalive, + session->pcc_config.min_keep_alive_seconds); + open_object->open_keepalive = + session->pcc_config.min_keep_alive_seconds; + retval = false; + } else if (open_object->open_keepalive + > session->pcc_config.max_keep_alive_seconds) { + pcep_log( + LOG_INFO, + "%s: Rejecting unsupported Open Keep Alive value [%d] max [%d]", + __func__, open_object->open_keepalive, + session->pcc_config.max_keep_alive_seconds); + open_object->open_keepalive = + session->pcc_config.max_keep_alive_seconds; + retval = false; + } + + if (open_object->open_deadtimer + < session->pcc_config.min_dead_timer_seconds) { + pcep_log(LOG_INFO, + "%s: Rejecting unsupported Open Dead Timer value [%d]", + __func__, open_object->open_deadtimer); + open_object->open_deadtimer = + session->pcc_config.min_dead_timer_seconds; + retval = false; + } else if (open_object->open_deadtimer + > session->pcc_config.max_dead_timer_seconds) { + pcep_log(LOG_INFO, + "%s: Rejecting unsupported Open Dead Timer value [%d]", + __func__, open_object->open_deadtimer); + open_object->open_deadtimer = + session->pcc_config.max_dead_timer_seconds; + retval = false; + } + + /* Check for Open Object TLVs */ + if (pcep_object_has_tlvs((struct pcep_object_header *)open_object) + == false) { + /* There are no TLVs, all done */ + return retval; + } + + double_linked_list_node *tlv_node = open_object->header.tlv_list->head; + while (tlv_node != NULL) { + struct pcep_object_tlv_header *tlv = tlv_node->data; + tlv_node = tlv_node->next_node; + + /* Supported Open Object TLVs */ + switch (tlv->type) { + case PCEP_OBJ_TLV_TYPE_LSP_DB_VERSION: + case PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE_CAPABILITY: + case PCEP_OBJ_TLV_TYPE_SPEAKER_ENTITY_ID: + case PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY: + case PCEP_OBJ_TLV_TYPE_SR_PCE_CAPABILITY: + break; + + default: + /* TODO how to handle unrecognized TLV ?? */ + pcep_log( + LOG_INFO, + "%s: Unhandled OPEN Object TLV type: %d, length %d", + __func__, tlv->type, tlv->encoded_tlv_length); + break; + } + + /* Verify the STATEFUL-PCE-CAPABILITY TLV */ + if (tlv->type == PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY) { + struct pcep_object_tlv_stateful_pce_capability + *pce_cap_tlv = + (struct + pcep_object_tlv_stateful_pce_capability + *)tlv; + + /* If the U flag is set, then the PCE is + * capable of updating LSP parameters */ + if (pce_cap_tlv->flag_u_lsp_update_capability) { + if (session->pce_config + .support_stateful_pce_lsp_update + == false) { + /* Turn off the U bit, as it is not + * supported */ + pcep_log( + LOG_INFO, + "%s: Rejecting unsupported Open STATEFUL-PCE-CAPABILITY TLV U flag", + __func__); + pce_cap_tlv + ->flag_u_lsp_update_capability = + false; + retval = false; + } else { + session->stateful_pce = true; + pcep_log( + LOG_INFO, + "%s: Setting PCEP session [%d] STATEFUL to support LSP updates", + __func__, session->session_id); + } + } + /* TODO the rest of the flags are not implemented yet */ + else if (pce_cap_tlv->flag_s_include_db_version) { + pcep_log( + LOG_INFO, + "%s: Ignoring Open STATEFUL-PCE-CAPABILITY TLV S Include DB Version flag", + __func__); + } else if ( + pce_cap_tlv + ->flag_i_lsp_instantiation_capability) { + pcep_log( + LOG_INFO, + "%s: Ignoring Open STATEFUL-PCE-CAPABILITY TLV I LSP Instantiation Capability flag", + __func__); + } else if (pce_cap_tlv->flag_t_triggered_resync) { + pcep_log( + LOG_INFO, + "%s: Ignoring Open STATEFUL-PCE-CAPABILITY TLV T Triggered Resync flag", + __func__); + } else if (pce_cap_tlv->flag_d_delta_lsp_sync) { + pcep_log( + LOG_INFO, + "%s: Ignoring Open STATEFUL-PCE-CAPABILITY TLV D Delta LSP Sync flag", + __func__); + } else if (pce_cap_tlv->flag_f_triggered_initial_sync) { + pcep_log( + LOG_INFO, + "%s: Ignoring Open STATEFUL-PCE-CAPABILITY TLV F Triggered Initial Sync flag", + __func__); + } + } else if (tlv->type == PCEP_OBJ_TLV_TYPE_LSP_DB_VERSION) { + if (session->pce_config.support_include_db_version + == false) { + pcep_log( + LOG_INFO, + "%s: Rejecting unsupported Open LSP DB VERSION TLV", + __func__); + /* Remove this TLV from the list */ + dll_delete_node(open_object->header.tlv_list, + tlv_node); + retval = false; + } + } + } + + return retval; +} + + +bool handle_pcep_open(pcep_session *session, struct pcep_message *open_msg) +{ + /* Open Message validation and errors according to: + * https://tools.ietf.org/html/rfc5440#section-7.15 */ + + if (session->session_state != SESSION_STATE_PCEP_CONNECTING + && session->session_state != SESSION_STATE_INITIALIZED) { + pcep_log( + LOG_INFO, + "%s: Received unexpected OPEN, current session state [%d, replying with error]", + __func__, session->session_state); + send_pcep_error(session, + PCEP_ERRT_ATTEMPT_TO_ESTABLISH_2ND_PCEP_SESSION, + PCEP_ERRV_RECVD_INVALID_OPEN_MSG); + return false; + } + + if (session->pce_open_received == true + && session->pce_open_rejected == false) { + pcep_log(LOG_INFO, + "%s: Received duplicate OPEN, replying with error", + __func__); + send_pcep_error(session, + PCEP_ERRT_ATTEMPT_TO_ESTABLISH_2ND_PCEP_SESSION, + PCEP_ERRV_RECVD_INVALID_OPEN_MSG); + return false; + } + + struct pcep_object_open *open_object = + (struct pcep_object_open *)pcep_obj_get(open_msg->obj_list, + PCEP_OBJ_CLASS_OPEN); + if (open_object == NULL) { + pcep_log( + LOG_INFO, + "%s: Received OPEN message with no OPEN object, replying with error", + __func__); + send_pcep_error(session, PCEP_ERRT_SESSION_FAILURE, + PCEP_ERRV_RECVD_INVALID_OPEN_MSG); + return false; + } + + /* Check for additional Open Msg objects */ + if (open_msg->obj_list->num_entries > 1) { + pcep_log( + LOG_INFO, + "%s: Found additional unsupported objects in the Open message, replying with error", + __func__); + send_pcep_error(session, PCEP_ERRT_SESSION_FAILURE, + PCEP_ERRV_RECVD_INVALID_OPEN_MSG); + return false; + } + + session->pce_open_received = true; + + /* Verify the open object parameters and TLVs */ + if (verify_pcep_open_object(session, open_object) == false) { + enqueue_event(session, PCC_RCVD_INVALID_OPEN, NULL); + if (session->pce_open_rejected) { + /* The Open message was already rejected once, so + * according to the spec, send an error message and + * close the TCP connection. */ + pcep_log( + LOG_INFO, + "%s: Received 2 consecutive unsupported Open messages, closing the connection.", + __func__); + send_pcep_error( + session, PCEP_ERRT_SESSION_FAILURE, + PCEP_ERRV_RECVD_SECOND_OPEN_MSG_UNACCEPTABLE); + socket_comm_session_close_tcp_after_write( + session->socket_comm_session); + session->session_state = SESSION_STATE_INITIALIZED; + enqueue_event(session, PCC_CONNECTION_FAILURE, NULL); + } else { + session->pce_open_rejected = true; + /* Clone the object here, since the encapsulating + * message will be deleted in handle_socket_comm_event() + * most likely before this error message is sent */ + struct pcep_object_open *cloned_open_object = + pceplib_malloc(PCEPLIB_MESSAGES, + sizeof(struct pcep_object_open)); + memcpy(cloned_open_object, open_object, + sizeof(struct pcep_object_open)); + open_object->header.tlv_list = NULL; + cloned_open_object->header.encoded_object = NULL; + cloned_open_object->header.encoded_object_length = 0; + send_pcep_error_with_object( + session, PCEP_ERRT_SESSION_FAILURE, + PCEP_ERRV_UNACCEPTABLE_OPEN_MSG_NEG, + &cloned_open_object->header); + } + + return false; + } + + /* + * Open Message accepted + * Sending the keep-alive response will be managed the function caller + */ + + session->timer_id_open_keep_alive = + create_timer(TIMER_OPEN_KEEP_ALIVE_SECONDS, session); + session->pcc_config.dead_timer_pce_negotiated_seconds = + (int)open_object->open_deadtimer; + /* Cancel the timer so we can change the dead_timer value */ + cancel_timer(session->timer_id_dead_timer); + session->timer_id_dead_timer = TIMER_ID_NOT_SET; + reset_dead_timer(session); + + return true; +} + + +/* The original PCEP Open message sent to the PCE was rejected, + * try to reconcile the differences and re-send a new Open. */ +void send_reconciled_pcep_open(pcep_session *session, + struct pcep_message *error_msg) +{ + struct pcep_message *open_msg = create_pcep_open(session); + + struct pcep_object_open *error_open_obj = + (struct pcep_object_open *)pcep_obj_get(error_msg->obj_list, + PCEP_OBJ_CLASS_OPEN); + if (error_open_obj == NULL) { + /* Nothing to reconcile, send the same Open message again */ + pcep_log( + LOG_INFO, + "%s: No Open object received in Error, sending the same Open message", + __func__); + session_send_message(session, open_msg); + return; + } + + 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) { + if (error_open_obj->open_deadtimer + >= session->pce_config.min_dead_timer_seconds + && error_open_obj->open_deadtimer + <= session->pce_config.max_dead_timer_seconds) { + open_obj->open_deadtimer = + error_open_obj->open_deadtimer; + session->pcc_config.dead_timer_pce_negotiated_seconds = + error_open_obj->open_deadtimer; + pcep_log( + LOG_INFO, + "%s: Open deadtimer value [%d] rejected, using PCE value [%d]", + __func__, + session->pcc_config.dead_timer_seconds, + session->pcc_config + .dead_timer_pce_negotiated_seconds); + /* Reset the timer with the new value */ + cancel_timer(session->timer_id_dead_timer); + session->timer_id_dead_timer = TIMER_ID_NOT_SET; + reset_dead_timer(session); + } else { + pcep_log( + LOG_INFO, + "%s: Can not reconcile Open with suggested deadtimer [%d]", + __func__, error_open_obj->open_deadtimer); + } + } + + if (error_open_obj->open_keepalive + != session->pce_config.keep_alive_seconds) { + if (error_open_obj->open_keepalive + >= session->pce_config.min_keep_alive_seconds + && error_open_obj->open_keepalive + <= session->pce_config.max_keep_alive_seconds) { + open_obj->open_keepalive = + error_open_obj->open_keepalive; + session->pcc_config + .keep_alive_pce_negotiated_timer_seconds = + error_open_obj->open_keepalive; + pcep_log( + LOG_INFO, + "%s: Open keep alive value [%d] rejected, using PCE value [%d]", + __func__, + session->pcc_config.keep_alive_seconds, + session->pcc_config + .keep_alive_pce_negotiated_timer_seconds); + /* Cancel the timer, the timer will be set again with + * the new value when this open message is sent */ + cancel_timer(session->timer_id_keep_alive); + session->timer_id_keep_alive = TIMER_ID_NOT_SET; + } else { + pcep_log( + LOG_INFO, + "%s: Can not reconcile Open with suggested keepalive [%d]", + __func__, error_open_obj->open_keepalive); + } + } + + /* TODO reconcile the TLVs */ + + session_send_message(session, open_msg); + reset_timer(session->timer_id_open_keep_alive); +} + + +bool handle_pcep_update(pcep_session *session, struct pcep_message *upd_msg) +{ + /* Update Message validation and errors according to: + * https://tools.ietf.org/html/rfc8231#section-6.2 */ + + if (upd_msg->obj_list == NULL) { + pcep_log(LOG_INFO, + "%s: Invalid PcUpd message: Message has no objects", + __func__); + send_pcep_error(session, PCEP_ERRT_MANDATORY_OBJECT_MISSING, + PCEP_ERRV_SRP_OBJECT_MISSING); + return false; + } + + /* Verify the mandatory objects are present */ + struct pcep_object_header *obj = + pcep_obj_get(upd_msg->obj_list, PCEP_OBJ_CLASS_SRP); + if (obj == NULL) { + pcep_log(LOG_INFO, + "%s: Invalid PcUpd message: Missing SRP object", + __func__); + send_pcep_error(session, PCEP_ERRT_MANDATORY_OBJECT_MISSING, + PCEP_ERRV_SRP_OBJECT_MISSING); + return false; + } + + obj = pcep_obj_get(upd_msg->obj_list, PCEP_OBJ_CLASS_LSP); + if (obj == NULL) { + pcep_log(LOG_INFO, + "%s: Invalid PcUpd message: Missing LSP object", + __func__); + send_pcep_error(session, PCEP_ERRT_MANDATORY_OBJECT_MISSING, + PCEP_ERRV_LSP_OBJECT_MISSING); + return false; + } + + obj = pcep_obj_get(upd_msg->obj_list, PCEP_OBJ_CLASS_ERO); + if (obj == NULL) { + pcep_log(LOG_INFO, + "%s: Invalid PcUpd message: Missing ERO object", + __func__); + send_pcep_error(session, PCEP_ERRT_MANDATORY_OBJECT_MISSING, + PCEP_ERRV_ERO_OBJECT_MISSING); + return false; + } + + /* Verify the objects are are in the correct order */ + double_linked_list_node *node = upd_msg->obj_list->head; + struct pcep_object_srp *srp_object = + (struct pcep_object_srp *)node->data; + if (srp_object->header.object_class != PCEP_OBJ_CLASS_SRP) { + pcep_log( + LOG_INFO, + "%s: Invalid PcUpd message: First object must be an SRP, found [%d]", + __func__, srp_object->header.object_class); + send_pcep_error(session, PCEP_ERRT_MANDATORY_OBJECT_MISSING, + PCEP_ERRV_SRP_OBJECT_MISSING); + return false; + } + + node = node->next_node; + struct pcep_object_lsp *lsp_object = + (struct pcep_object_lsp *)node->data; + if (lsp_object->header.object_class != PCEP_OBJ_CLASS_LSP) { + pcep_log( + LOG_INFO, + "%s: Invalid PcUpd message: Second object must be an LSP, found [%d]", + __func__, lsp_object->header.object_class); + send_pcep_error(session, PCEP_ERRT_MANDATORY_OBJECT_MISSING, + PCEP_ERRV_LSP_OBJECT_MISSING); + return false; + } + + node = node->next_node; + struct pcep_object_ro *ero_object = node->data; + if (ero_object->header.object_class != PCEP_OBJ_CLASS_ERO) { + pcep_log( + LOG_INFO, + "%s: Invalid PcUpd message: Third object must be an ERO, found [%d]", + __func__, ero_object->header.object_class); + send_pcep_error(session, PCEP_ERRT_MANDATORY_OBJECT_MISSING, + PCEP_ERRV_ERO_OBJECT_MISSING); + return false; + } + + return true; +} + +bool handle_pcep_initiate(pcep_session *session, struct pcep_message *init_msg) +{ + /* Instantiate Message validation and errors according to: + * https://tools.ietf.org/html/rfc8281#section-5 */ + + if (init_msg->obj_list == NULL) { + pcep_log( + LOG_INFO, + "%s: Invalid PcInitiate message: Message has no objects", + __func__); + send_pcep_error(session, PCEP_ERRT_MANDATORY_OBJECT_MISSING, + PCEP_ERRV_SRP_OBJECT_MISSING); + return false; + } + + /* Verify the mandatory objects are present */ + struct pcep_object_header *obj = + pcep_obj_get(init_msg->obj_list, PCEP_OBJ_CLASS_SRP); + if (obj == NULL) { + pcep_log(LOG_INFO, + "%s: Invalid PcInitiate message: Missing SRP object", + __func__); + send_pcep_error(session, PCEP_ERRT_MANDATORY_OBJECT_MISSING, + PCEP_ERRV_SRP_OBJECT_MISSING); + return false; + } + + obj = pcep_obj_get(init_msg->obj_list, PCEP_OBJ_CLASS_LSP); + if (obj == NULL) { + pcep_log(LOG_INFO, + "%s: Invalid PcInitiate message: Missing LSP object", + __func__); + send_pcep_error(session, PCEP_ERRT_MANDATORY_OBJECT_MISSING, + PCEP_ERRV_LSP_OBJECT_MISSING); + return false; + } + + /* Verify the objects are are in the correct order */ + double_linked_list_node *node = init_msg->obj_list->head; + struct pcep_object_srp *srp_object = + (struct pcep_object_srp *)node->data; + if (srp_object->header.object_class != PCEP_OBJ_CLASS_SRP) { + pcep_log( + LOG_INFO, + "%s: Invalid PcInitiate message: First object must be an SRP, found [%d]", + __func__, srp_object->header.object_class); + send_pcep_error(session, PCEP_ERRT_MANDATORY_OBJECT_MISSING, + PCEP_ERRV_SRP_OBJECT_MISSING); + return false; + } + + node = node->next_node; + struct pcep_object_lsp *lsp_object = + (struct pcep_object_lsp *)node->data; + if (lsp_object->header.object_class != PCEP_OBJ_CLASS_LSP) { + pcep_log( + LOG_INFO, + "%s: Invalid PcInitiate message: Second object must be an LSP, found [%d]", + __func__, lsp_object->header.object_class); + send_pcep_error(session, PCEP_ERRT_MANDATORY_OBJECT_MISSING, + PCEP_ERRV_LSP_OBJECT_MISSING); + return false; + } + + /* There may be more optional objects */ + return true; +} + +void increment_unknown_message(pcep_session *session) +{ + /* https://tools.ietf.org/html/rfc5440#section-6.9 + * If a PCC/PCE receives unrecognized messages at a rate equal or + * greater than MAX-UNKNOWN-MESSAGES unknown message requests per + * minute, the PCC/PCE MUST send a PCEP CLOSE message */ + + time_t *unknown_message_time = + pceplib_malloc(PCEPLIB_INFRA, sizeof(time_t)); + *unknown_message_time = time(NULL); + time_t expire_time = *unknown_message_time + 60; + queue_enqueue(session->num_unknown_messages_time_queue, + unknown_message_time); + + /* Purge any entries older than 1 minute. The oldest entries are at the + * queue head */ + queue_node *time_node = session->num_unknown_messages_time_queue->head; + while (time_node != NULL) { + if (*((time_t *)time_node->data) > expire_time) { + pceplib_free( + PCEPLIB_INFRA, + queue_dequeue( + session->num_unknown_messages_time_queue)); + time_node = + session->num_unknown_messages_time_queue->head; + } else { + time_node = NULL; + } + } + + if ((int)session->num_unknown_messages_time_queue->num_entries + >= session->pcc_config.max_unknown_messages) { + pcep_log( + LOG_INFO, + "%s: [%ld-%ld] Max unknown messages reached [%d] closing session [%d]", + __func__, time(NULL), pthread_self(), + session->pcc_config.max_unknown_messages, + session->session_id); + + close_pcep_session_with_reason(session, + PCEP_CLOSE_REASON_UNREC_MSG); + enqueue_event(session, PCC_RCVD_MAX_UNKOWN_MSGS, NULL); + } +} + +bool check_and_send_open_keep_alive(pcep_session *session) +{ + if (session->pce_open_received == true + && session->pce_open_rejected == false + && session->pce_open_keep_alive_sent == false) { + /* Send the PCE Open keep-alive response if it hasnt been sent + * yet */ + cancel_timer(session->timer_id_open_keep_alive); + session->timer_id_open_keep_alive = TIMER_ID_NOT_SET; + send_keep_alive(session); + session->pce_open_keep_alive_sent = true; + + return true; + } + + return false; +} + +void log_pcc_pce_connection(pcep_session *session) +{ + if (session->socket_comm_session == NULL) { + /* This only happens in UT */ + return; + } + + char src_ip_buf[40] = {0}, dst_ip_buf[40] = {0}; + uint16_t src_port, dst_port; + + if (session->socket_comm_session->is_ipv6) { + inet_ntop(AF_INET6, + &session->socket_comm_session->src_sock_addr + .src_sock_addr_ipv6.sin6_addr, + src_ip_buf, sizeof(src_ip_buf)); + inet_ntop(AF_INET6, + &session->socket_comm_session->dest_sock_addr + .dest_sock_addr_ipv6.sin6_addr, + dst_ip_buf, sizeof(dst_ip_buf)); + src_port = htons(session->socket_comm_session->src_sock_addr + .src_sock_addr_ipv6.sin6_port); + dst_port = htons(session->socket_comm_session->dest_sock_addr + .dest_sock_addr_ipv6.sin6_port); + } else { + inet_ntop(AF_INET, + &session->socket_comm_session->src_sock_addr + .src_sock_addr_ipv4.sin_addr, + src_ip_buf, sizeof(src_ip_buf)); + inet_ntop(AF_INET, + &session->socket_comm_session->dest_sock_addr + .dest_sock_addr_ipv4.sin_addr, + dst_ip_buf, sizeof(dst_ip_buf)); + src_port = htons(session->socket_comm_session->src_sock_addr + .src_sock_addr_ipv4.sin_port); + dst_port = htons(session->socket_comm_session->dest_sock_addr + .dest_sock_addr_ipv4.sin_port); + } + + pcep_log( + LOG_INFO, + "%s: [%ld-%ld] Successful PCC [%s:%d] connection to PCE [%s:%d] session [%d] fd [%d]", + __func__, time(NULL), pthread_self(), src_ip_buf, src_port, + dst_ip_buf, dst_port, session->session_id, + session->socket_comm_session->socket_fd); +} + +/* + * these functions are called by session_logic_loop() from + * pcep_session_logic_loop.c these functions are executed in the + * session_logic_loop thread, and the mutex is locked before calling these + * functions, so they are thread safe. + */ + +/* state machine handling for expired timers */ +void handle_timer_event(pcep_session_event *event) +{ + if (event == NULL) { + pcep_log(LOG_INFO, "%s: handle_timer_event NULL event", + __func__); + return; + } + + pcep_session *session = event->session; + + pcep_log( + LOG_INFO, + "%s: [%ld-%ld] pcep_session_logic handle_timer_event: session [%d] event timer_id [%d] session timers [OKW, OKA, DT, KA] [%d, %d, %d, %d]", + __func__, time(NULL), pthread_self(), session->session_id, + event->expired_timer_id, session->timer_id_open_keep_wait, + session->timer_id_open_keep_alive, session->timer_id_dead_timer, + session->timer_id_keep_alive); + + /* + * these timer expirations are independent of the session state + */ + if (event->expired_timer_id == session->timer_id_dead_timer) { + session->timer_id_dead_timer = TIMER_ID_NOT_SET; + increment_event_counters(session, + PCEP_EVENT_COUNTER_ID_TIMER_DEADTIMER); + close_pcep_session_with_reason(session, + PCEP_CLOSE_REASON_DEADTIMER); + enqueue_event(session, PCE_DEAD_TIMER_EXPIRED, NULL); + return; + } else if (event->expired_timer_id == session->timer_id_keep_alive) { + session->timer_id_keep_alive = TIMER_ID_NOT_SET; + increment_event_counters(session, + PCEP_EVENT_COUNTER_ID_TIMER_KEEPALIVE); + send_keep_alive(session); + return; + } + + /* + * handle timers that depend on the session state + */ + switch (session->session_state) { + case SESSION_STATE_PCEP_CONNECTING: + if (event->expired_timer_id + == session->timer_id_open_keep_wait) { + /* close the TCP session */ + pcep_log( + LOG_INFO, + "%s: handle_timer_event open_keep_wait timer expired for session [%d]", + __func__, session->session_id); + increment_event_counters( + session, + PCEP_EVENT_COUNTER_ID_TIMER_OPENKEEPWAIT); + socket_comm_session_close_tcp_after_write( + session->socket_comm_session); + session->session_state = SESSION_STATE_INITIALIZED; + session->timer_id_open_keep_wait = TIMER_ID_NOT_SET; + enqueue_event(session, PCE_OPEN_KEEP_WAIT_TIMER_EXPIRED, + NULL); + } + + if (event->expired_timer_id + == session->timer_id_open_keep_alive) { + increment_event_counters( + session, + PCEP_EVENT_COUNTER_ID_TIMER_OPENKEEPALIVE); + session->timer_id_open_keep_alive = TIMER_ID_NOT_SET; + if (check_and_send_open_keep_alive(session) == true) { + if (session->pcc_open_accepted == true + && session->session_state + != SESSION_STATE_PCEP_CONNECTED) { + log_pcc_pce_connection(session); + session->session_state = + SESSION_STATE_PCEP_CONNECTED; + increment_event_counters( + session, + PCEP_EVENT_COUNTER_ID_PCE_CONNECT); + enqueue_event(session, + PCC_CONNECTED_TO_PCE, + NULL); + } + } + return; + } + break; + + case SESSION_STATE_INITIALIZED: + case SESSION_STATE_PCEP_CONNECTED: + default: + pcep_log( + LOG_INFO, + "%s: handle_timer_event unrecognized state transition, timer_id [%d] state [%d] session [%d]", + __func__, event->expired_timer_id, + session->session_state, session->session_id); + break; + } +} + +/* State machine handling for received messages. + * This event was created in session_logic_msg_ready_handler() in + * pcep_session_logic_loop.c */ +void handle_socket_comm_event(pcep_session_event *event) +{ + if (event == NULL) { + pcep_log(LOG_INFO, "%s: handle_socket_comm_event NULL event", + __func__); + return; + } + + pcep_session *session = event->session; + + pcep_log( + LOG_INFO, + "%s: [%ld-%ld] pcep_session_logic handle_socket_comm_event: session [%d] num messages [%d] socket_closed [%d]", + __func__, time(NULL), pthread_self(), session->session_id, + (event->received_msg_list == NULL + ? -1 + : (int)event->received_msg_list->num_entries), + event->socket_closed); + + /* + * independent of the session state + */ + if (event->socket_closed) { + pcep_log( + LOG_INFO, + "%s: handle_socket_comm_event socket closed for session [%d]", + __func__, session->session_id); + socket_comm_session_close_tcp(session->socket_comm_session); + enqueue_event(session, PCE_CLOSED_SOCKET, NULL); + if (session->session_state == SESSION_STATE_PCEP_CONNECTING) { + enqueue_event(session, PCC_CONNECTION_FAILURE, NULL); + } + session->session_state = SESSION_STATE_INITIALIZED; + increment_event_counters(session, + PCEP_EVENT_COUNTER_ID_PCE_DISCONNECT); + return; + } + + reset_dead_timer(session); + + if (event->received_msg_list == NULL) { + return; + } + + /* Message received on socket */ + double_linked_list_node *msg_node; + for (msg_node = event->received_msg_list->head; msg_node != NULL; + msg_node = msg_node->next_node) { + bool message_enqueued = false; + struct pcep_message *msg = + (struct pcep_message *)msg_node->data; + pcep_log(LOG_INFO, "%s: \t %s message", __func__, + get_message_type_str(msg->msg_header->type)); + + increment_message_rx_counters(session, msg); + + switch (msg->msg_header->type) { + case PCEP_TYPE_OPEN: + /* handle_pcep_open() checks session state, and for + * duplicate erroneous open messages, and replies with + * error messages as needed. It also sets + * pce_open_received. */ + if (handle_pcep_open(session, msg) == true) { + /* PCE Open Message Accepted */ + enqueue_event(session, MESSAGE_RECEIVED, msg); + message_enqueued = true; + session->pce_open_accepted = true; + session->pce_open_rejected = false; + if (session->pcc_open_accepted) { + /* If both the PCC and PCE Opens are + * accepted, then the session is + * connected */ + + check_and_send_open_keep_alive(session); + log_pcc_pce_connection(session); + session->session_state = + SESSION_STATE_PCEP_CONNECTED; + increment_event_counters( + session, + PCEP_EVENT_COUNTER_ID_PCE_CONNECT); + enqueue_event(session, + PCC_CONNECTED_TO_PCE, + NULL); + } + } + break; + + case PCEP_TYPE_KEEPALIVE: + if (session->session_state + == SESSION_STATE_PCEP_CONNECTING) { + /* PCC Open Message Accepted */ + cancel_timer(session->timer_id_open_keep_wait); + session->timer_id_open_keep_wait = + TIMER_ID_NOT_SET; + session->pcc_open_accepted = true; + session->pcc_open_rejected = false; + check_and_send_open_keep_alive(session); + + if (session->pce_open_accepted) { + /* If both the PCC and PCE Opens are + * accepted, then the session is + * connected */ + log_pcc_pce_connection(session); + session->session_state = + SESSION_STATE_PCEP_CONNECTED; + increment_event_counters( + session, + PCEP_EVENT_COUNTER_ID_PCC_CONNECT); + enqueue_event(session, + PCC_CONNECTED_TO_PCE, + NULL); + } + } + /* The dead_timer was already reset above, so nothing + * extra to do here */ + break; + + case PCEP_TYPE_PCREP: + enqueue_event(session, MESSAGE_RECEIVED, msg); + message_enqueued = true; + break; + + case PCEP_TYPE_CLOSE: + session->session_state = SESSION_STATE_INITIALIZED; + socket_comm_session_close_tcp( + session->socket_comm_session); + /* TODO should we also enqueue the message, so they can + * see the reasons?? */ + enqueue_event(session, PCE_SENT_PCEP_CLOSE, NULL); + /* TODO could this duplicate the disconnect counter with + * socket close ?? */ + increment_event_counters( + session, PCEP_EVENT_COUNTER_ID_PCE_DISCONNECT); + break; + + case PCEP_TYPE_PCREQ: + /* The PCC does not support receiving PcReq messages */ + send_pcep_error(session, + PCEP_ERRT_CAPABILITY_NOT_SUPPORTED, + PCEP_ERRV_UNASSIGNED); + break; + + case PCEP_TYPE_REPORT: + /* The PCC does not support receiving Report messages */ + send_pcep_error(session, + PCEP_ERRT_CAPABILITY_NOT_SUPPORTED, + PCEP_ERRV_UNASSIGNED); + break; + + case PCEP_TYPE_UPDATE: + /* Should reply with a PcRpt */ + if (handle_pcep_update(session, msg) == true) { + enqueue_event(session, MESSAGE_RECEIVED, msg); + message_enqueued = true; + } + break; + + case PCEP_TYPE_INITIATE: + /* Should reply with a PcRpt */ + if (handle_pcep_initiate(session, msg) == true) { + enqueue_event(session, MESSAGE_RECEIVED, msg); + message_enqueued = true; + } + break; + + case PCEP_TYPE_PCNOTF: + enqueue_event(session, MESSAGE_RECEIVED, msg); + message_enqueued = true; + break; + + case PCEP_TYPE_ERROR: + if (msg->obj_list != NULL + && msg->obj_list->num_entries > 0) { + struct pcep_object_header *obj_hdr = + pcep_obj_get(msg->obj_list, + PCEP_OBJ_CLASS_ERROR); + if (obj_hdr != NULL) { + struct pcep_object_error *error_obj = + (struct pcep_object_error *) + obj_hdr; + pcep_log( + LOG_DEBUG, + "%s: Error object [type, value] = [%s, %s]", + __func__, + get_error_type_str( + error_obj->error_type), + get_error_value_str( + error_obj->error_type, + error_obj + ->error_value)); + } + } + + if (session->session_state + == SESSION_STATE_PCEP_CONNECTING) { + /* A PCC_CONNECTION_FAILURE event will be sent + * when the socket is closed, if the state is + * SESSION_STATE_PCEP_CONNECTING, in case the + * PCE allows more than 2 failed open messages. + */ + pcep_log(LOG_INFO, + "%s: PCC Open message rejected by PCE", + __func__); + session->pcc_open_rejected = true; + send_reconciled_pcep_open(session, msg); + enqueue_event(session, PCC_SENT_INVALID_OPEN, + NULL); + } + enqueue_event(session, MESSAGE_RECEIVED, msg); + message_enqueued = true; + break; + + default: + pcep_log(LOG_INFO, "%s: \t UnSupported message", + __func__); + send_pcep_error(session, + PCEP_ERRT_CAPABILITY_NOT_SUPPORTED, + PCEP_ERRV_UNASSIGNED); + increment_unknown_message(session); + break; + } + + /* if the message was enqueued, dont free it yet */ + if (message_enqueued == false) { + pcep_msg_free_message(msg); + } + } + dll_destroy(event->received_msg_list); +} diff --git a/pceplib/pcep_socket_comm.c b/pceplib/pcep_socket_comm.c new file mode 100644 index 0000000000..e22eb6e675 --- /dev/null +++ b/pceplib/pcep_socket_comm.c @@ -0,0 +1,781 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Brady Johnson <brady@voltanet.io> + * + */ + + +/* + * Implementation of public API functions. + */ + +#include <zebra.h> + +#include <errno.h> +#include <fcntl.h> +#include <netdb.h> // gethostbyname +#include <stdbool.h> +#include <string.h> +#include <unistd.h> // close + +#include <arpa/inet.h> // sockets etc. +#include <sys/types.h> // sockets etc. +#include <sys/socket.h> // sockets etc. + +#include "pcep.h" +#include "pcep_socket_comm.h" +#include "pcep_socket_comm_internals.h" +#include "pcep_utils_logging.h" +#include "pcep_utils_memory.h" +#include "pcep_utils_ordered_list.h" +#include "pcep_utils_queue.h" + +bool initialize_socket_comm_pre(void); +bool socket_comm_session_initialize_post( + pcep_socket_comm_session *socket_comm_session); + +pcep_socket_comm_handle *socket_comm_handle_ = NULL; + + +/* simple compare method callback used by pcep_utils_ordered_list + * for ordered list insertion. */ +int socket_fd_node_compare(void *list_entry, void *new_entry) +{ + return ((pcep_socket_comm_session *)new_entry)->socket_fd + - ((pcep_socket_comm_session *)list_entry)->socket_fd; +} + + +bool initialize_socket_comm_pre() +{ + socket_comm_handle_ = + pceplib_malloc(PCEPLIB_INFRA, sizeof(pcep_socket_comm_handle)); + memset(socket_comm_handle_, 0, sizeof(pcep_socket_comm_handle)); + + socket_comm_handle_->active = true; + socket_comm_handle_->num_active_sessions = 0; + socket_comm_handle_->read_list = + ordered_list_initialize(socket_fd_node_compare); + socket_comm_handle_->write_list = + ordered_list_initialize(socket_fd_node_compare); + socket_comm_handle_->session_list = + ordered_list_initialize(pointer_compare_function); + FD_ZERO(&socket_comm_handle_->except_master_set); + FD_ZERO(&socket_comm_handle_->read_master_set); + FD_ZERO(&socket_comm_handle_->write_master_set); + + if (pthread_mutex_init(&(socket_comm_handle_->socket_comm_mutex), NULL) + != 0) { + pcep_log(LOG_ERR, "%s: Cannot initialize socket_comm mutex.", + __func__); + pceplib_free(PCEPLIB_INFRA, socket_comm_handle_); + socket_comm_handle_ = NULL; + + return false; + } + + return true; +} + +bool initialize_socket_comm_external_infra( + void *external_infra_data, ext_socket_read socket_read_cb, + ext_socket_write socket_write_cb, + ext_socket_pthread_create_callback thread_create_func) +{ + if (socket_comm_handle_ != NULL) { + /* already initialized */ + return true; + } + + if (initialize_socket_comm_pre() == false) { + return false; + } + + /* Notice: If the thread_create_func is set, then both the + * socket_read_cb and the socket_write_cb SHOULD be NULL. */ + if (thread_create_func != NULL) { + if (thread_create_func( + &(socket_comm_handle_->socket_comm_thread), NULL, + socket_comm_loop, socket_comm_handle_, + "pceplib_timers")) { + pcep_log( + LOG_ERR, + "%s: Cannot initialize external socket_comm thread.", + __func__); + return false; + } + } + + socket_comm_handle_->external_infra_data = external_infra_data; + socket_comm_handle_->socket_write_func = socket_write_cb; + socket_comm_handle_->socket_read_func = socket_read_cb; + + return true; +} + +bool initialize_socket_comm_loop() +{ + if (socket_comm_handle_ != NULL) { + /* already initialized */ + return true; + } + + if (initialize_socket_comm_pre() == false) { + return false; + } + + /* Launch socket comm loop pthread */ + if (pthread_create(&(socket_comm_handle_->socket_comm_thread), NULL, + socket_comm_loop, socket_comm_handle_)) { + pcep_log(LOG_ERR, "%s: Cannot initialize socket_comm thread.", + __func__); + return false; + } + + return true; +} + + +bool destroy_socket_comm_loop() +{ + socket_comm_handle_->active = false; + + pthread_join(socket_comm_handle_->socket_comm_thread, NULL); + ordered_list_destroy(socket_comm_handle_->read_list); + ordered_list_destroy(socket_comm_handle_->write_list); + ordered_list_destroy(socket_comm_handle_->session_list); + pthread_mutex_destroy(&(socket_comm_handle_->socket_comm_mutex)); + + pceplib_free(PCEPLIB_INFRA, socket_comm_handle_); + socket_comm_handle_ = NULL; + + return true; +} + +/* Internal common init function */ +static pcep_socket_comm_session *socket_comm_session_initialize_pre( + message_received_handler message_handler, + message_ready_to_read_handler message_ready_handler, + message_sent_notifier msg_sent_notifier, + connection_except_notifier notifier, uint32_t connect_timeout_millis, + const char *tcp_authentication_str, bool is_tcp_auth_md5, + void *session_data) +{ + /* check that not both message handlers were set */ + if (message_handler != NULL && message_ready_handler != NULL) { + pcep_log( + LOG_WARNING, + "%s: Only one of <message_received_handler | message_ready_to_read_handler> can be set.", + __func__); + return NULL; + } + + /* check that at least one message handler was set */ + if (message_handler == NULL && message_ready_handler == NULL) { + pcep_log( + LOG_WARNING, + "%s: At least one of <message_received_handler | message_ready_to_read_handler> must be set.", + __func__); + return NULL; + } + + if (!initialize_socket_comm_loop()) { + pcep_log(LOG_WARNING, + "%s: ERROR: cannot initialize socket_comm_loop.", + __func__); + + return NULL; + } + + /* initialize everything for a pcep_session socket_comm */ + + pcep_socket_comm_session *socket_comm_session = + pceplib_malloc(PCEPLIB_INFRA, sizeof(pcep_socket_comm_session)); + memset(socket_comm_session, 0, sizeof(pcep_socket_comm_session)); + + socket_comm_handle_->num_active_sessions++; + socket_comm_session->close_after_write = false; + socket_comm_session->session_data = session_data; + socket_comm_session->message_handler = message_handler; + socket_comm_session->message_ready_to_read_handler = + message_ready_handler; + socket_comm_session->message_sent_handler = msg_sent_notifier; + socket_comm_session->conn_except_notifier = notifier; + socket_comm_session->message_queue = queue_initialize(); + socket_comm_session->connect_timeout_millis = connect_timeout_millis; + socket_comm_session->external_socket_data = NULL; + if (tcp_authentication_str != NULL) { + socket_comm_session->is_tcp_auth_md5 = is_tcp_auth_md5; + strlcpy(socket_comm_session->tcp_authentication_str, + tcp_authentication_str, + sizeof(socket_comm_session->tcp_authentication_str)); + } + + return socket_comm_session; +} + +/* Internal common init function */ +bool socket_comm_session_initialize_post( + pcep_socket_comm_session *socket_comm_session) +{ + /* If we dont use SO_REUSEADDR, the socket will take 2 TIME_WAIT + * periods before being closed in the kernel if bind() was called */ + int reuse_addr = 1; + if (setsockopt(socket_comm_session->socket_fd, SOL_SOCKET, SO_REUSEADDR, + &reuse_addr, sizeof(int)) + < 0) { + pcep_log( + LOG_WARNING, + "%s: Error in setsockopt() SO_REUSEADDR errno [%d %s].", + __func__, errno, strerror(errno)); + socket_comm_session_teardown(socket_comm_session); + + return false; + } + + struct sockaddr *src_sock_addr = + (socket_comm_session->is_ipv6 + ? (struct sockaddr *)&( + socket_comm_session->src_sock_addr + .src_sock_addr_ipv6) + : (struct sockaddr *)&( + socket_comm_session->src_sock_addr + .src_sock_addr_ipv4)); + int addr_len = (socket_comm_session->is_ipv6 + ? sizeof(socket_comm_session->src_sock_addr + .src_sock_addr_ipv6) + : sizeof(socket_comm_session->src_sock_addr + .src_sock_addr_ipv4)); + if (bind(socket_comm_session->socket_fd, src_sock_addr, addr_len) + == -1) { + pcep_log(LOG_WARNING, + "%s: Cannot bind address to socket errno [%d %s].", + __func__, errno, strerror(errno)); + socket_comm_session_teardown(socket_comm_session); + + return false; + } + + /* Register the session as active with the Socket Comm Loop */ + pthread_mutex_lock(&(socket_comm_handle_->socket_comm_mutex)); + ordered_list_add_node(socket_comm_handle_->session_list, + socket_comm_session); + pthread_mutex_unlock(&(socket_comm_handle_->socket_comm_mutex)); + + /* dont connect to the destination yet, since the PCE will have a timer + * for max time between TCP connect and PCEP open. we'll connect later + * when we send the PCEP open. */ + + return true; +} + + +pcep_socket_comm_session *socket_comm_session_initialize( + message_received_handler message_handler, + message_ready_to_read_handler message_ready_handler, + message_sent_notifier msg_sent_notifier, + connection_except_notifier notifier, struct in_addr *dest_ip, + short dest_port, uint32_t connect_timeout_millis, + const char *tcp_authentication_str, bool is_tcp_auth_md5, + void *session_data) +{ + return socket_comm_session_initialize_with_src( + message_handler, message_ready_handler, msg_sent_notifier, + notifier, NULL, 0, dest_ip, dest_port, connect_timeout_millis, + tcp_authentication_str, is_tcp_auth_md5, session_data); +} + +pcep_socket_comm_session *socket_comm_session_initialize_ipv6( + message_received_handler message_handler, + message_ready_to_read_handler message_ready_handler, + message_sent_notifier msg_sent_notifier, + connection_except_notifier notifier, struct in6_addr *dest_ip, + short dest_port, uint32_t connect_timeout_millis, + const char *tcp_authentication_str, bool is_tcp_auth_md5, + void *session_data) +{ + return socket_comm_session_initialize_with_src_ipv6( + message_handler, message_ready_handler, msg_sent_notifier, + notifier, NULL, 0, dest_ip, dest_port, connect_timeout_millis, + tcp_authentication_str, is_tcp_auth_md5, session_data); +} + + +pcep_socket_comm_session *socket_comm_session_initialize_with_src( + message_received_handler message_handler, + message_ready_to_read_handler message_ready_handler, + message_sent_notifier msg_sent_notifier, + connection_except_notifier notifier, struct in_addr *src_ip, + short src_port, struct in_addr *dest_ip, short dest_port, + uint32_t connect_timeout_millis, const char *tcp_authentication_str, + bool is_tcp_auth_md5, void *session_data) +{ + if (dest_ip == NULL) { + pcep_log(LOG_WARNING, "%s: dest_ipv4 is NULL", __func__); + return NULL; + } + + pcep_socket_comm_session *socket_comm_session = + socket_comm_session_initialize_pre( + message_handler, message_ready_handler, + msg_sent_notifier, notifier, connect_timeout_millis, + tcp_authentication_str, is_tcp_auth_md5, session_data); + if (socket_comm_session == NULL) { + return NULL; + } + + socket_comm_session->socket_fd = + socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + if (socket_comm_session->socket_fd == -1) { + pcep_log(LOG_WARNING, + "%s: Cannot create ipv4 socket errno [%d %s].", + __func__, errno, strerror(errno)); + socket_comm_session_teardown( + socket_comm_session); // socket_comm_session freed + // inside fn so NOLINT next. + + return NULL; // NOLINT(clang-analyzer-unix.Malloc) + } + + socket_comm_session->is_ipv6 = false; + socket_comm_session->dest_sock_addr.dest_sock_addr_ipv4.sin_family = + AF_INET; + socket_comm_session->src_sock_addr.src_sock_addr_ipv4.sin_family = + AF_INET; + socket_comm_session->dest_sock_addr.dest_sock_addr_ipv4.sin_port = + htons(dest_port); + socket_comm_session->src_sock_addr.src_sock_addr_ipv4.sin_port = + htons(src_port); + socket_comm_session->dest_sock_addr.dest_sock_addr_ipv4.sin_addr + .s_addr = dest_ip->s_addr; + if (src_ip != NULL) { + socket_comm_session->src_sock_addr.src_sock_addr_ipv4.sin_addr + .s_addr = src_ip->s_addr; + } else { + socket_comm_session->src_sock_addr.src_sock_addr_ipv4.sin_addr + .s_addr = INADDR_ANY; + } + + if (socket_comm_session_initialize_post(socket_comm_session) == false) { + return NULL; + } + + return socket_comm_session; +} + +pcep_socket_comm_session *socket_comm_session_initialize_with_src_ipv6( + message_received_handler message_handler, + message_ready_to_read_handler message_ready_handler, + message_sent_notifier msg_sent_notifier, + connection_except_notifier notifier, struct in6_addr *src_ip, + short src_port, struct in6_addr *dest_ip, short dest_port, + uint32_t connect_timeout_millis, const char *tcp_authentication_str, + bool is_tcp_auth_md5, void *session_data) +{ + if (dest_ip == NULL) { + pcep_log(LOG_WARNING, "%s: dest_ipv6 is NULL", __func__); + return NULL; + } + + pcep_socket_comm_session *socket_comm_session = + socket_comm_session_initialize_pre( + message_handler, message_ready_handler, + msg_sent_notifier, notifier, connect_timeout_millis, + tcp_authentication_str, is_tcp_auth_md5, session_data); + if (socket_comm_session == NULL) { + return NULL; + } + + socket_comm_session->socket_fd = + socket(PF_INET6, SOCK_STREAM, IPPROTO_TCP); + if (socket_comm_session->socket_fd == -1) { + pcep_log(LOG_WARNING, + "%s: Cannot create ipv6 socket errno [%d %s].", + __func__, errno, strerror(errno)); + socket_comm_session_teardown( + socket_comm_session); // socket_comm_session freed + // inside fn so NOLINT next. + + return NULL; // NOLINT(clang-analyzer-unix.Malloc) + } + + socket_comm_session->is_ipv6 = true; + socket_comm_session->dest_sock_addr.dest_sock_addr_ipv6.sin6_family = + AF_INET6; + socket_comm_session->src_sock_addr.src_sock_addr_ipv6.sin6_family = + AF_INET6; + socket_comm_session->dest_sock_addr.dest_sock_addr_ipv6.sin6_port = + htons(dest_port); + socket_comm_session->src_sock_addr.src_sock_addr_ipv6.sin6_port = + htons(src_port); + memcpy(&socket_comm_session->dest_sock_addr.dest_sock_addr_ipv6 + .sin6_addr, + dest_ip, sizeof(struct in6_addr)); + if (src_ip != NULL) { + memcpy(&socket_comm_session->src_sock_addr.src_sock_addr_ipv6 + .sin6_addr, + src_ip, sizeof(struct in6_addr)); + } else { + socket_comm_session->src_sock_addr.src_sock_addr_ipv6 + .sin6_addr = in6addr_any; + } + + if (socket_comm_session_initialize_post(socket_comm_session) == false) { + return NULL; + } + + return socket_comm_session; +} + + +bool socket_comm_session_connect_tcp( + pcep_socket_comm_session *socket_comm_session) +{ + if (socket_comm_session == NULL) { + pcep_log( + LOG_WARNING, + "%s: socket_comm_session_connect_tcp NULL socket_comm_session.", + __func__); + return NULL; + } + + /* Set the socket to non-blocking, so connect() does not block */ + int fcntl_arg; + if ((fcntl_arg = fcntl(socket_comm_session->socket_fd, F_GETFL, NULL)) + < 0) { + pcep_log(LOG_WARNING, "%s: Error fcntl(..., F_GETFL) [%d %s]", + __func__, errno, strerror(errno)); + return false; + } + + fcntl_arg |= O_NONBLOCK; + if (fcntl(socket_comm_session->socket_fd, F_SETFL, fcntl_arg) < 0) { + pcep_log(LOG_WARNING, "%s: Error fcntl(..., F_SETFL) [%d %s]", + __func__, errno, strerror(errno)); + return false; + } + +#if HAVE_DECL_TCP_MD5SIG + /* TCP authentication, currently only TCP MD5 RFC2385 is supported */ + if (socket_comm_session->tcp_authentication_str[0] != '\0') { +#if defined(linux) || defined(GNU_LINUX) + struct tcp_md5sig sig; + memset(&sig, 0, sizeof(sig)); + if (socket_comm_session->is_ipv6) { + memcpy(&sig.tcpm_addr, + &socket_comm_session->dest_sock_addr + .dest_sock_addr_ipv6, + sizeof(struct sockaddr_in6)); + } else { + memcpy(&sig.tcpm_addr, + &socket_comm_session->dest_sock_addr + .dest_sock_addr_ipv4, + sizeof(struct sockaddr_in)); + } + sig.tcpm_keylen = + strlen(socket_comm_session->tcp_authentication_str); + memcpy(sig.tcpm_key, + socket_comm_session->tcp_authentication_str, + sig.tcpm_keylen); +#else + int sig = 1; +#endif + if (setsockopt(socket_comm_session->socket_fd, IPPROTO_TCP, + TCP_MD5SIG, &sig, sizeof(sig)) + == -1) { + pcep_log(LOG_ERR, "%s: Failed to setsockopt(): [%d %s]", + __func__, errno, strerror(errno)); + return false; + } + } +#endif + + int connect_result = 0; + if (socket_comm_session->is_ipv6) { + connect_result = connect( + socket_comm_session->socket_fd, + (struct sockaddr *)&(socket_comm_session->dest_sock_addr + .dest_sock_addr_ipv6), + sizeof(socket_comm_session->dest_sock_addr + .dest_sock_addr_ipv6)); + } else { + connect_result = connect( + socket_comm_session->socket_fd, + (struct sockaddr *)&(socket_comm_session->dest_sock_addr + .dest_sock_addr_ipv4), + sizeof(socket_comm_session->dest_sock_addr + .dest_sock_addr_ipv4)); + } + + if (connect_result < 0) { + if (errno == EINPROGRESS) { + /* Calculate the configured timeout in seconds and + * microseconds */ + struct timeval tv; + if (socket_comm_session->connect_timeout_millis + > 1000) { + tv.tv_sec = socket_comm_session + ->connect_timeout_millis + / 1000; + tv.tv_usec = (socket_comm_session + ->connect_timeout_millis + - (tv.tv_sec * 1000)) + * 1000; + } else { + tv.tv_sec = 0; + tv.tv_usec = socket_comm_session + ->connect_timeout_millis + * 1000; + } + + /* Use select to wait a max timeout for connect + * https://stackoverflow.com/questions/2597608/c-socket-connection-timeout + */ + fd_set fdset; + FD_ZERO(&fdset); + FD_SET(socket_comm_session->socket_fd, &fdset); + if (select(socket_comm_session->socket_fd + 1, NULL, + &fdset, NULL, &tv) + > 0) { + int so_error; + socklen_t len = sizeof(so_error); + getsockopt(socket_comm_session->socket_fd, + SOL_SOCKET, SO_ERROR, &so_error, + &len); + if (so_error) { + pcep_log( + LOG_WARNING, + "%s: TCP connect failed on socket_fd [%d].", + __func__, + socket_comm_session->socket_fd); + return false; + } + } else { + pcep_log( + LOG_WARNING, + "%s: TCP connect timed-out on socket_fd [%d].", + __func__, + socket_comm_session->socket_fd); + return false; + } + } else { + pcep_log( + LOG_WARNING, + "%s: TCP connect, error connecting on socket_fd [%d] errno [%d %s]", + __func__, socket_comm_session->socket_fd, errno, + strerror(errno)); + return false; + } + } + + pthread_mutex_lock(&(socket_comm_handle_->socket_comm_mutex)); + /* once the TCP connection is open, we should be ready to read at any + * time */ + ordered_list_add_node(socket_comm_handle_->read_list, + socket_comm_session); + + if (socket_comm_handle_->socket_read_func != NULL) { + socket_comm_handle_->socket_read_func( + socket_comm_handle_->external_infra_data, + &socket_comm_session->external_socket_data, + socket_comm_session->socket_fd, socket_comm_handle_); + } + pthread_mutex_unlock(&(socket_comm_handle_->socket_comm_mutex)); + + return true; +} + + +bool socket_comm_session_close_tcp( + pcep_socket_comm_session *socket_comm_session) +{ + if (socket_comm_session == NULL) { + pcep_log( + LOG_WARNING, + "%s: socket_comm_session_close_tcp NULL socket_comm_session.", + __func__); + return false; + } + + pcep_log(LOG_DEBUG, + "%s: socket_comm_session_close_tcp close() socket fd [%d]", + __func__, socket_comm_session->socket_fd); + + pthread_mutex_lock(&(socket_comm_handle_->socket_comm_mutex)); + ordered_list_remove_first_node_equals(socket_comm_handle_->read_list, + socket_comm_session); + ordered_list_remove_first_node_equals(socket_comm_handle_->write_list, + socket_comm_session); + // TODO should it be close() or shutdown()?? + close(socket_comm_session->socket_fd); + socket_comm_session->socket_fd = -1; + pthread_mutex_unlock(&(socket_comm_handle_->socket_comm_mutex)); + + return true; +} + + +bool socket_comm_session_close_tcp_after_write( + pcep_socket_comm_session *socket_comm_session) +{ + if (socket_comm_session == NULL) { + pcep_log( + LOG_WARNING, + "%s: socket_comm_session_close_tcp_after_write NULL socket_comm_session.", + __func__); + return false; + } + + pthread_mutex_lock(&(socket_comm_handle_->socket_comm_mutex)); + socket_comm_session->close_after_write = true; + pthread_mutex_unlock(&(socket_comm_handle_->socket_comm_mutex)); + + return true; +} + + +bool socket_comm_session_teardown(pcep_socket_comm_session *socket_comm_session) +{ + if (socket_comm_handle_ == NULL) { + pcep_log(LOG_WARNING, + "%s: Cannot teardown NULL socket_comm_handle", + __func__); + return false; + } + + if (socket_comm_session == NULL) { + pcep_log(LOG_WARNING, "%s: Cannot teardown NULL session", + __func__); + return false; + } + + if (comm_session_exists_locking(socket_comm_handle_, + socket_comm_session) + == false) { + pcep_log(LOG_WARNING, + "%s: Cannot teardown session that does not exist", + __func__); + return false; + } + + if (socket_comm_session->socket_fd >= 0) { + shutdown(socket_comm_session->socket_fd, SHUT_RDWR); + close(socket_comm_session->socket_fd); + } + + pthread_mutex_lock(&(socket_comm_handle_->socket_comm_mutex)); + queue_destroy(socket_comm_session->message_queue); + ordered_list_remove_first_node_equals(socket_comm_handle_->session_list, + socket_comm_session); + ordered_list_remove_first_node_equals(socket_comm_handle_->read_list, + socket_comm_session); + ordered_list_remove_first_node_equals(socket_comm_handle_->write_list, + socket_comm_session); + socket_comm_handle_->num_active_sessions--; + pthread_mutex_unlock(&(socket_comm_handle_->socket_comm_mutex)); + + pcep_log( + LOG_INFO, + "%s: [%ld-%ld] socket_comm_session fd [%d] destroyed, [%d] sessions remaining", + __func__, time(NULL), pthread_self(), + socket_comm_session->socket_fd, + socket_comm_handle_->num_active_sessions); + + pceplib_free(PCEPLIB_INFRA, socket_comm_session); + + /* It would be nice to call destroy_socket_comm_loop() here if + * socket_comm_handle_->num_active_sessions == 0, but this function + * will usually be called from the message_sent_notifier callback, + * which gets called in the middle of the socket_comm_loop, and that + * is dangerous, so destroy_socket_comm_loop() must be called upon + * application exit. */ + + return true; +} + + +void socket_comm_session_send_message( + pcep_socket_comm_session *socket_comm_session, + const char *encoded_message, unsigned int msg_length, + bool free_after_send) +{ + if (socket_comm_session == NULL) { + pcep_log( + LOG_WARNING, + "%s: socket_comm_session_send_message NULL socket_comm_session.", + __func__); + return; + } + + pcep_socket_comm_queued_message *queued_message = pceplib_malloc( + PCEPLIB_MESSAGES, sizeof(pcep_socket_comm_queued_message)); + queued_message->encoded_message = encoded_message; + queued_message->msg_length = msg_length; + queued_message->free_after_send = free_after_send; + + pthread_mutex_lock(&(socket_comm_handle_->socket_comm_mutex)); + + /* Do not proceed if the socket_comm_session has been deleted */ + if (ordered_list_find(socket_comm_handle_->session_list, + socket_comm_session) + == NULL) { + /* Should never get here, only if the session was deleted and + * someone still tries to write on it */ + pcep_log( + LOG_WARNING, + "%s: Cannot write a message on a deleted socket comm session, discarding message", + __func__); + pthread_mutex_unlock(&(socket_comm_handle_->socket_comm_mutex)); + pceplib_free(PCEPLIB_MESSAGES, queued_message); + + return; + } + + /* Do not proceed if the socket has been closed */ + if (socket_comm_session->socket_fd < 0) { + /* Should never get here, only if the session was deleted and + * someone still tries to write on it */ + pcep_log( + LOG_WARNING, + "%s: Cannot write a message on a closed socket, discarding message", + __func__); + pthread_mutex_unlock(&(socket_comm_handle_->socket_comm_mutex)); + pceplib_free(PCEPLIB_MESSAGES, queued_message); + + return; + } + + queue_enqueue(socket_comm_session->message_queue, queued_message); + + /* Add it to the write list only if its not already there */ + if (ordered_list_find(socket_comm_handle_->write_list, + socket_comm_session) + == NULL) { + ordered_list_add_node(socket_comm_handle_->write_list, + socket_comm_session); + } + + if (socket_comm_handle_->socket_write_func != NULL) { + socket_comm_handle_->socket_write_func( + socket_comm_handle_->external_infra_data, + &socket_comm_session->external_socket_data, + socket_comm_session->socket_fd, socket_comm_handle_); + } + pthread_mutex_unlock(&(socket_comm_handle_->socket_comm_mutex)); +} diff --git a/pceplib/pcep_socket_comm.h b/pceplib/pcep_socket_comm.h new file mode 100644 index 0000000000..797ffda860 --- /dev/null +++ b/pceplib/pcep_socket_comm.h @@ -0,0 +1,198 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Brady Johnson <brady@voltanet.io> + * + */ + + +/* + * Declaration of public API functions. + */ + +#ifndef INCLUDE_PCEPSOCKETCOMM_H_ +#define INCLUDE_PCEPSOCKETCOMM_H_ + +#include "pcep.h" +#include <arpa/inet.h> // sockaddr_in +#include <netinet/tcp.h> +#include <stdbool.h> + +#include "pcep_utils_queue.h" + +#define MAX_RECVD_MSG_SIZE 2048 + +/* + * A socket_comm_session can be initialized with 1 of 2 types of mutually + * exclusive message callbacks: + * - message_received_handler : the socket_comm library reads the message and + * calls the callback with the message_data and message_length. this callback + * should be used for smaller/simpler messages. + * - message_ready_to_read_handler : the socket_comm library will call this + * callback when a message is ready to be read on a socket_fd. this callback + * should be used if the + */ + +/* message received handler that receives the message data and message length */ +typedef void (*message_received_handler)(void *session_data, + const char *message_data, + unsigned int message_length); +/* message ready received handler that should read the message on socket_fd + * and return the number of bytes read */ +typedef int (*message_ready_to_read_handler)(void *session_data, int socket_fd); +/* callback handler called when a messages is sent */ +typedef void (*message_sent_notifier)(void *session_data, int socket_fd); +/* callback handler called when the socket is closed */ +typedef void (*connection_except_notifier)(void *session_data, int socket_fd); + +/* Function pointers when an external socket infrastructure is used */ +typedef int (*ext_socket_write)(void *infra_data, void **infra_socket_data, + int fd, void *data); +typedef int (*ext_socket_read)(void *infra_data, void **infra_socket_data, + int fd, void *data); +typedef int (*ext_socket_pthread_create_callback)( + pthread_t *pthread_id, const pthread_attr_t *attr, + void *(*start_routine)(void *), void *data, const char *thread_name); + +typedef struct pcep_socket_comm_session_ { + message_received_handler message_handler; + message_ready_to_read_handler message_ready_to_read_handler; + message_sent_notifier message_sent_handler; + connection_except_notifier conn_except_notifier; + union src_sock_addr { + struct sockaddr_in src_sock_addr_ipv4; + struct sockaddr_in6 src_sock_addr_ipv6; + } src_sock_addr; + union dest_sock_addr { + struct sockaddr_in dest_sock_addr_ipv4; + struct sockaddr_in6 dest_sock_addr_ipv6; + } dest_sock_addr; + bool is_ipv6; + uint32_t connect_timeout_millis; + int socket_fd; + void *session_data; + queue_handle *message_queue; + char received_message[MAX_RECVD_MSG_SIZE]; + int received_bytes; + bool close_after_write; + void *external_socket_data; /* used for external socket infra */ + char tcp_authentication_str[TCP_MD5SIG_MAXKEYLEN + + 1]; /* should be used with is_tcp_auth_md5 + flag */ + bool is_tcp_auth_md5; /* flag to distinguish between rfc 2385 (md5) and + rfc 5925 (tcp-ao) */ + +} pcep_socket_comm_session; + + +/* Need to document that when the msg_rcv_handler is called, the data needs + * to be handled in the same function call, else it may be overwritten by + * the next read from this socket */ + + +/* Initialize the Socket Comm infrastructure, with either an internal pthread + * or with an external infrastructure. + * If an internal pthread infrastructure is to be used, then it is not necessary + * to explicitly call initialize_socket_comm_loop() as it will be called + * internally when a socket comm session is initialized. */ + +/* Initialize the Socket Comm infrastructure with an internal pthread */ +bool initialize_socket_comm_loop(void); +/* Initialize the Socket Comm infrastructure with an external infrastructure. + * Notice: If the thread_create_func is set, then both the socket_read_cb + * and the socket_write_cb SHOULD be NULL. */ +bool initialize_socket_comm_external_infra( + void *external_infra_data, ext_socket_read socket_read_cb, + ext_socket_write socket_write_cb, + ext_socket_pthread_create_callback thread_create_func); + +/* The msg_rcv_handler and msg_ready_handler are mutually exclusive, and only + * one can be set (as explained above), else NULL will be returned. */ +pcep_socket_comm_session * +socket_comm_session_initialize(message_received_handler msg_rcv_handler, + message_ready_to_read_handler msg_ready_handler, + message_sent_notifier msg_sent_notifier, + connection_except_notifier notifier, + struct in_addr *dst_ip, short dst_port, + uint32_t connect_timeout_millis, + const char *tcp_authentication_str, + bool is_tcp_auth_md5, void *session_data); + +pcep_socket_comm_session *socket_comm_session_initialize_ipv6( + message_received_handler msg_rcv_handler, + message_ready_to_read_handler msg_ready_handler, + message_sent_notifier msg_sent_notifier, + connection_except_notifier notifier, struct in6_addr *dst_ip, + short dst_port, uint32_t connect_timeout_millis, + const char *tcp_authentication_str, bool is_tcp_auth_md5, + void *session_data); + +pcep_socket_comm_session *socket_comm_session_initialize_with_src( + message_received_handler msg_rcv_handler, + message_ready_to_read_handler msg_ready_handler, + message_sent_notifier msg_sent_notifier, + connection_except_notifier notifier, struct in_addr *src_ip, + short src_port, struct in_addr *dst_ip, short dst_port, + uint32_t connect_timeout_millis, const char *tcp_authentication_str, + bool is_tcp_auth_md5, void *session_data); + +pcep_socket_comm_session *socket_comm_session_initialize_with_src_ipv6( + message_received_handler msg_rcv_handler, + message_ready_to_read_handler msg_ready_handler, + message_sent_notifier msg_sent_notifier, + connection_except_notifier notifier, struct in6_addr *src_ip, + short src_port, struct in6_addr *dst_ip, short dst_port, + uint32_t connect_timeout_millis, const char *tcp_authentication_str, + bool is_tcp_auth_md5, void *session_data); + +bool socket_comm_session_teardown( + pcep_socket_comm_session *socket_comm_session); + +bool socket_comm_session_connect_tcp( + pcep_socket_comm_session *socket_comm_session); + +/* Immediately close the TCP connection, irregardless if there are pending + * messages to be sent. */ +bool socket_comm_session_close_tcp( + pcep_socket_comm_session *socket_comm_session); + +/* Sets a flag to close the TCP connection either after all the pending messages + * are written, or if there are no pending messages, the next time the socket is + * checked to be writeable. */ +bool socket_comm_session_close_tcp_after_write( + pcep_socket_comm_session *socket_comm_session); + +void socket_comm_session_send_message( + pcep_socket_comm_session *socket_comm_session, + const char *encoded_message, unsigned int msg_length, + bool free_after_send); + +/* If an external Socket infra like FRR is used, then these functions will + * be called when a socket is ready to read/write in the external infra. + * Implemented in pcep_socket_comm_loop.c */ +int pceplib_external_socket_read(int fd, void *payload); +int pceplib_external_socket_write(int fd, void *payload); + +/* the socket comm loop is started internally by + * socket_comm_session_initialize() + * but needs to be explicitly stopped with this call. */ +bool destroy_socket_comm_loop(void); + +int socket_fd_node_compare(void *list_entry, void *new_entry); + +#endif /* INCLUDE_PCEPSOCKETCOMM_H_ */ diff --git a/pceplib/pcep_socket_comm_internals.h b/pceplib/pcep_socket_comm_internals.h new file mode 100644 index 0000000000..4445a14fac --- /dev/null +++ b/pceplib/pcep_socket_comm_internals.h @@ -0,0 +1,69 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Brady Johnson <brady@voltanet.io> + * + */ + + +#ifndef SRC_PCEPSOCKETCOMMINTERNALS_H_ +#define SRC_PCEPSOCKETCOMMINTERNALS_H_ + +#include <pthread.h> +#include <stdbool.h> + +#include "pcep_utils_ordered_list.h" +#include "pcep_socket_comm.h" + + +typedef struct pcep_socket_comm_handle_ { + bool active; + pthread_t socket_comm_thread; + pthread_mutex_t socket_comm_mutex; + fd_set read_master_set; + fd_set write_master_set; + fd_set except_master_set; + /* ordered_list of socket_descriptors to read from */ + ordered_list_handle *read_list; + /* ordered_list of socket_descriptors to write to */ + ordered_list_handle *write_list; + ordered_list_handle *session_list; + int num_active_sessions; + void *external_infra_data; + ext_socket_write socket_write_func; + ext_socket_read socket_read_func; + +} pcep_socket_comm_handle; + + +typedef struct pcep_socket_comm_queued_message_ { + const char *encoded_message; + int msg_length; + bool free_after_send; + +} pcep_socket_comm_queued_message; + + +/* Functions implemented in pcep_socket_comm_loop.c */ +void *socket_comm_loop(void *data); +bool comm_session_exists(pcep_socket_comm_handle *socket_comm_handle, + pcep_socket_comm_session *socket_comm_session); +bool comm_session_exists_locking(pcep_socket_comm_handle *socket_comm_handle, + pcep_socket_comm_session *socket_comm_session); + +#endif /* SRC_PCEPSOCKETCOMMINTERNALS_H_ */ diff --git a/pceplib/pcep_socket_comm_loop.c b/pceplib/pcep_socket_comm_loop.c new file mode 100644 index 0000000000..d58409c4f3 --- /dev/null +++ b/pceplib/pcep_socket_comm_loop.c @@ -0,0 +1,493 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Brady Johnson <brady@voltanet.io> + * + */ + + +#include <errno.h> +#include <stdbool.h> +#include <stddef.h> +#include <string.h> +#include <unistd.h> +#include <assert.h> + +#include "pcep_socket_comm_internals.h" +#include "pcep_socket_comm_loop.h" +#include "pcep_utils_logging.h" +#include "pcep_utils_ordered_list.h" +#include "pcep_utils_logging.h" +#include "pcep_utils_memory.h" + +void write_message(int socket_fd, const char *message, unsigned int msg_length); +unsigned int read_message(int socket_fd, char *received_message, + unsigned int max_message_size); +int build_fd_sets(pcep_socket_comm_handle *socket_comm_handle); +void handle_writes(pcep_socket_comm_handle *socket_comm_handle); +void handle_excepts(pcep_socket_comm_handle *socket_comm_handle); + +bool comm_session_exists(pcep_socket_comm_handle *socket_comm_handle, + pcep_socket_comm_session *socket_comm_session) +{ + if (socket_comm_handle == NULL) { + return false; + } + + return (ordered_list_find(socket_comm_handle->session_list, + socket_comm_session) + != NULL); +} + + +bool comm_session_exists_locking(pcep_socket_comm_handle *socket_comm_handle, + pcep_socket_comm_session *socket_comm_session) +{ + if (socket_comm_handle == NULL) { + return false; + } + + pthread_mutex_lock(&(socket_comm_handle->socket_comm_mutex)); + bool exists = + comm_session_exists(socket_comm_handle, socket_comm_session); + pthread_mutex_unlock(&(socket_comm_handle->socket_comm_mutex)); + + return exists; +} + + +void write_message(int socket_fd, const char *message, unsigned int msg_length) +{ + ssize_t bytes_sent = 0; + unsigned int total_bytes_sent = 0; + + while ((uint32_t)bytes_sent < msg_length) { + bytes_sent = write(socket_fd, message + total_bytes_sent, + msg_length); + + pcep_log( + LOG_INFO, + "%s: [%ld-%ld] socket_comm writing on socket fd [%d] msg_lenth [%u] bytes sent [%d]", + __func__, time(NULL), pthread_self(), socket_fd, + msg_length, bytes_sent); + + if (bytes_sent < 0) { + if (errno != EAGAIN && errno != EWOULDBLOCK) { + pcep_log(LOG_WARNING, "%s: send() failure", + __func__); + + return; + } + } else { + total_bytes_sent += bytes_sent; + } + } +} + + +unsigned int read_message(int socket_fd, char *received_message, + unsigned int max_message_size) +{ + /* TODO what if bytes_read == max_message_size? there could be more to + * read */ + unsigned int bytes_read = + read(socket_fd, received_message, max_message_size); + pcep_log( + LOG_INFO, + "%s: [%ld-%ld] socket_comm read message bytes_read [%u] on socket fd [%d]", + __func__, time(NULL), pthread_self(), bytes_read, socket_fd); + + return bytes_read; +} + + +int build_fd_sets(pcep_socket_comm_handle *socket_comm_handle) +{ + int max_fd = 0; + + pthread_mutex_lock(&(socket_comm_handle->socket_comm_mutex)); + + FD_ZERO(&socket_comm_handle->except_master_set); + FD_ZERO(&socket_comm_handle->read_master_set); + ordered_list_node *node = socket_comm_handle->read_list->head; + pcep_socket_comm_session *comm_session; + while (node != NULL) { + 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 + ready_toRead + [%d]", __func__, time(NULL), comm_session->socket_fd);*/ + FD_SET(comm_session->socket_fd, + &socket_comm_handle->read_master_set); + FD_SET(comm_session->socket_fd, + &socket_comm_handle->except_master_set); + node = node->next_node; + } + + FD_ZERO(&socket_comm_handle->write_master_set); + node = socket_comm_handle->write_list->head; + while (node != NULL) { + 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 + ready_toWrite [%d]", __func__, time(NULL), + comm_session->socket_fd);*/ + FD_SET(comm_session->socket_fd, + &socket_comm_handle->write_master_set); + FD_SET(comm_session->socket_fd, + &socket_comm_handle->except_master_set); + node = node->next_node; + } + + pthread_mutex_unlock(&(socket_comm_handle->socket_comm_mutex)); + + return max_fd + 1; +} + + +void handle_reads(pcep_socket_comm_handle *socket_comm_handle) +{ + + /* + * iterate all the socket_fd's in the read_list. it may be that not + * all of them have something to read. dont remove the socket_fd + * from the read_list since messages could come at any time. + */ + + /* Notice: Only locking the mutex when accessing the read_list, + * since the read callbacks may end up calling back into the socket + * comm module to write messages which could be a deadlock. */ + pthread_mutex_lock(&(socket_comm_handle->socket_comm_mutex)); + ordered_list_node *node = socket_comm_handle->read_list->head; + pthread_mutex_unlock(&(socket_comm_handle->socket_comm_mutex)); + + while (node != NULL) { + pcep_socket_comm_session *comm_session = + (pcep_socket_comm_session *)node->data; + + pthread_mutex_lock(&(socket_comm_handle->socket_comm_mutex)); + node = node->next_node; + if (!comm_session_exists(socket_comm_handle, comm_session)) { + /* This comm_session has been deleted, move on to the + * next one */ + pthread_mutex_unlock( + &(socket_comm_handle->socket_comm_mutex)); + continue; + } + + int is_set = FD_ISSET(comm_session->socket_fd, + &(socket_comm_handle->read_master_set)); + /* Upon read failure, the comm_session might be free'd, so we + * cant store the received_bytes in the comm_session, until we + * know the read was successful. */ + int received_bytes = 0; + pthread_mutex_unlock(&(socket_comm_handle->socket_comm_mutex)); + + if (is_set) { + FD_CLR(comm_session->socket_fd, + &(socket_comm_handle->read_master_set)); + + /* either read the message locally, or call the + * message_ready_handler to read it */ + if (comm_session->message_handler != NULL) { + received_bytes = read_message( + comm_session->socket_fd, + comm_session->received_message, + MAX_RECVD_MSG_SIZE); + if (received_bytes > 0) { + /* Send the received message to the + * handler */ + comm_session->received_bytes = + received_bytes; + comm_session->message_handler( + comm_session->session_data, + comm_session->received_message, + comm_session->received_bytes); + } + } else { + /* Tell the handler a message is ready to be + * read. The comm_session may be destroyed in + * this call, if + * there is an error reading or if the socket is + * closed. */ + received_bytes = + comm_session + ->message_ready_to_read_handler( + comm_session + ->session_data, + comm_session + ->socket_fd); + } + + /* handle the read results */ + if (received_bytes == 0) { + if (comm_session_exists_locking( + socket_comm_handle, comm_session)) { + comm_session->received_bytes = 0; + /* the socket was closed */ + /* TODO should we define a socket except + * enum? or will the only time we call + * this is when the socket is closed?? + */ + if (comm_session->conn_except_notifier + != NULL) { + comm_session->conn_except_notifier( + comm_session + ->session_data, + comm_session + ->socket_fd); + } + + /* stop reading from the socket if its + * closed */ + pthread_mutex_lock( + &(socket_comm_handle + ->socket_comm_mutex)); + ordered_list_remove_first_node_equals( + socket_comm_handle->read_list, + comm_session); + pthread_mutex_unlock( + &(socket_comm_handle + ->socket_comm_mutex)); + } + } else if (received_bytes < 0) { + /* TODO should we call conn_except_notifier() + * here ? */ + pcep_log( + LOG_WARNING, + "%s: Error on socket fd [%d] : errno [%d][%s]", + __func__, comm_session->socket_fd, + errno, strerror(errno)); + } else { + comm_session->received_bytes = received_bytes; + } + } + } +} + + +void handle_writes(pcep_socket_comm_handle *socket_comm_handle) +{ + pthread_mutex_lock(&(socket_comm_handle->socket_comm_mutex)); + + /* + * iterate all the socket_fd's in the write_list. it may be that not + * all of them are ready to be written to. only remove the socket_fd + * from the list if it is ready to be written to. + */ + + ordered_list_node *node = socket_comm_handle->write_list->head; + pcep_socket_comm_session *comm_session; + bool msg_written; + while (node != NULL) { + comm_session = (pcep_socket_comm_session *)node->data; + node = node->next_node; + msg_written = false; + + if (!comm_session_exists(socket_comm_handle, comm_session)) { + /* This comm_session has been deleted, move on to the + * next one */ + continue; + } + + if (FD_ISSET(comm_session->socket_fd, + &(socket_comm_handle->write_master_set))) { + /* only remove the entry from the list, if it is written + * to */ + ordered_list_remove_first_node_equals( + socket_comm_handle->write_list, comm_session); + FD_CLR(comm_session->socket_fd, + &(socket_comm_handle->write_master_set)); + + /* dequeue all the comm_session messages and send them + */ + pcep_socket_comm_queued_message *queued_message = + queue_dequeue(comm_session->message_queue); + while (queued_message != NULL) { + msg_written = true; + write_message(comm_session->socket_fd, + queued_message->encoded_message, + queued_message->msg_length); + if (queued_message->free_after_send) { + pceplib_free(PCEPLIB_MESSAGES, + (void *)queued_message + ->encoded_message); + } + pceplib_free(PCEPLIB_MESSAGES, queued_message); + queued_message = queue_dequeue( + comm_session->message_queue); + } + } + + /* check if the socket should be closed after writing */ + if (comm_session->close_after_write == true) { + if (comm_session->message_queue->num_entries == 0) { + /* TODO check to make sure modifying the + * write_list while iterating it doesnt cause + * problems. */ + pcep_log( + LOG_DEBUG, + "%s: handle_writes close() socket fd [%d]", + __func__, comm_session->socket_fd); + ordered_list_remove_first_node_equals( + socket_comm_handle->read_list, + comm_session); + ordered_list_remove_first_node_equals( + socket_comm_handle->write_list, + comm_session); + close(comm_session->socket_fd); + comm_session->socket_fd = -1; + } + } + + if (comm_session->message_sent_handler != NULL + && msg_written == true) { + /* Unlocking to allow the message_sent_handler to + * make calls like destroy_socket_comm_session */ + pthread_mutex_unlock( + &(socket_comm_handle->socket_comm_mutex)); + comm_session->message_sent_handler( + comm_session->session_data, + comm_session->socket_fd); + pthread_mutex_lock( + &(socket_comm_handle->socket_comm_mutex)); + } + } + + pthread_mutex_unlock(&(socket_comm_handle->socket_comm_mutex)); +} + + +void handle_excepts(pcep_socket_comm_handle *socket_comm_handle) +{ + /* TODO finish this */ + (void)socket_comm_handle; +} + + +/* pcep_socket_comm::initialize_socket_comm_loop() will create a thread and + * invoke this method */ +void *socket_comm_loop(void *data) +{ + if (data == NULL) { + pcep_log( + LOG_WARNING, + "%s: Cannot start socket_comm_loop with NULL pcep_socketcomm_handle", + __func__); + return NULL; + } + + pcep_log(LOG_NOTICE, "%s: [%ld-%ld] Starting socket_comm_loop thread", + __func__, time(NULL), pthread_self()); + + pcep_socket_comm_handle *socket_comm_handle = + (pcep_socket_comm_handle *)data; + struct timeval timer; + int max_fd; + + while (socket_comm_handle->active) { + /* check the FD's every 1/4 sec, 250 milliseconds */ + timer.tv_sec = 0; + timer.tv_usec = 250000; + max_fd = build_fd_sets(socket_comm_handle); + + if (select(max_fd, &(socket_comm_handle->read_master_set), + &(socket_comm_handle->write_master_set), + &(socket_comm_handle->except_master_set), &timer) + < 0) { + /* TODO handle the error */ + pcep_log( + LOG_WARNING, + "%s: ERROR socket_comm_loop on select : errno [%d][%s]", + __func__, errno, strerror(errno)); + } + + handle_reads(socket_comm_handle); + handle_writes(socket_comm_handle); + handle_excepts(socket_comm_handle); + } + + pcep_log(LOG_NOTICE, "%s: [%ld-%ld] Finished socket_comm_loop thread", + __func__, time(NULL), pthread_self()); + + return NULL; +} + +int pceplib_external_socket_read(int fd, void *payload) +{ + pcep_socket_comm_handle *socket_comm_handle = + (pcep_socket_comm_handle *)payload; + if (socket_comm_handle == NULL) { + return -1; + } + + pthread_mutex_lock(&(socket_comm_handle->socket_comm_mutex)); + FD_SET(fd, &(socket_comm_handle->read_master_set)); + pthread_mutex_unlock(&(socket_comm_handle->socket_comm_mutex)); + + handle_reads(socket_comm_handle); + + /* Get the socket_comm_session */ + pcep_socket_comm_session find_session = {.socket_fd = fd}; + pthread_mutex_lock(&(socket_comm_handle->socket_comm_mutex)); + ordered_list_node *node = + ordered_list_find(socket_comm_handle->read_list, &find_session); + + /* read again */ + if (node != NULL) { + socket_comm_handle->socket_read_func( + socket_comm_handle->external_infra_data, + &((pcep_socket_comm_session *)node) + ->external_socket_data, + fd, socket_comm_handle); + } + pthread_mutex_unlock(&(socket_comm_handle->socket_comm_mutex)); + + return 0; +} + +int pceplib_external_socket_write(int fd, void *payload) +{ + pcep_socket_comm_handle *socket_comm_handle = + (pcep_socket_comm_handle *)payload; + if (socket_comm_handle == NULL) { + return -1; + } + + pthread_mutex_lock(&(socket_comm_handle->socket_comm_mutex)); + FD_SET(fd, &(socket_comm_handle->write_master_set)); + pthread_mutex_unlock(&(socket_comm_handle->socket_comm_mutex)); + + handle_writes(socket_comm_handle); + + /* TODO do we need to cancel this FD from writing?? */ + + return 0; +} diff --git a/pceplib/pcep_socket_comm_loop.h b/pceplib/pcep_socket_comm_loop.h new file mode 100644 index 0000000000..3ca2c037fa --- /dev/null +++ b/pceplib/pcep_socket_comm_loop.h @@ -0,0 +1,32 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Javier Garcia <javier.garcia@voltanet.io> + * + */ + +/* + * Timer definitions to be used internally by the pcep_timers library. + */ + +#ifndef PCEPSOCKETCOMMLOOP_H_ +#define PCEPSOCKETCOMMLOOP_H_ + +void handle_reads(pcep_socket_comm_handle *socket_comm_handle); + +#endif /* PCEPTIMERINTERNALS_H_ */ diff --git a/pceplib/pcep_socket_comm_mock.c b/pceplib/pcep_socket_comm_mock.c new file mode 100644 index 0000000000..069d0cf998 --- /dev/null +++ b/pceplib/pcep_socket_comm_mock.c @@ -0,0 +1,363 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Brady Johnson <brady@voltanet.io> + * + */ + + +/* + * This module is built into a separate library, and is used by several + * other modules for unit testing, so that real sockets dont have to be + * created. + */ + +#include <netinet/in.h> +#include <stdbool.h> +#include <stdlib.h> +#include <string.h> + +#include <CUnit/CUnit.h> + +#include "pcep_socket_comm.h" +#include "pcep_socket_comm_mock.h" +#include "pcep_utils_queue.h" + +/* reset_mock_socket_comm_info() should be used before each test */ +mock_socket_comm_info mock_socket_metadata; + +void setup_mock_socket_comm_info(void) +{ + mock_socket_metadata.socket_comm_session_initialize_times_called = 0; + mock_socket_metadata.socket_comm_session_initialize_src_times_called = + 0; + mock_socket_metadata.socket_comm_session_teardown_times_called = 0; + mock_socket_metadata.socket_comm_session_connect_tcp_times_called = 0; + mock_socket_metadata.socket_comm_session_send_message_times_called = 0; + mock_socket_metadata + .socket_comm_session_close_tcp_after_write_times_called = 0; + mock_socket_metadata.socket_comm_session_close_tcp_times_called = 0; + mock_socket_metadata.destroy_socket_comm_loop_times_called = 0; + mock_socket_metadata.send_message_save_message = false; + mock_socket_metadata.sent_message_list = dll_initialize(); +} + +void teardown_mock_socket_comm_info(void) +{ + dll_destroy(mock_socket_metadata.sent_message_list); +} + +void reset_mock_socket_comm_info(void) +{ + teardown_mock_socket_comm_info(); + setup_mock_socket_comm_info(); +} + +mock_socket_comm_info *get_mock_socket_comm_info(void) +{ + return &mock_socket_metadata; +} + +void verify_socket_comm_times_called(int initialized, int teardown, int connect, + int send_message, + int close_tcp_after_write, int close_tcp, + int destroy) +{ + CU_ASSERT_EQUAL(initialized, + mock_socket_metadata + .socket_comm_session_initialize_times_called); + CU_ASSERT_EQUAL( + teardown, + mock_socket_metadata.socket_comm_session_teardown_times_called); + CU_ASSERT_EQUAL(connect, + mock_socket_metadata + .socket_comm_session_connect_tcp_times_called); + CU_ASSERT_EQUAL(send_message, + mock_socket_metadata + .socket_comm_session_send_message_times_called); + CU_ASSERT_EQUAL( + close_tcp_after_write, + mock_socket_metadata + .socket_comm_session_close_tcp_after_write_times_called); + CU_ASSERT_EQUAL(close_tcp, + mock_socket_metadata + .socket_comm_session_close_tcp_times_called); + CU_ASSERT_EQUAL( + destroy, + mock_socket_metadata.destroy_socket_comm_loop_times_called); +} + + +/* + * Mock the socket_comm functions used by session_logic for Unit Testing + */ + +bool initialize_socket_comm_external_infra( + void *external_infra_data, ext_socket_read socket_read_cb, + ext_socket_write socket_write_cb, + ext_socket_pthread_create_callback thread_create_func) +{ + (void)external_infra_data; + (void)socket_read_cb; + (void)socket_write_cb; + (void)thread_create_func; + + mock_socket_metadata + .socket_comm_initialize_external_infra_times_called++; + + return true; +} + +bool destroy_socket_comm_loop() +{ + mock_socket_metadata.destroy_socket_comm_loop_times_called++; + + return false; +} + +pcep_socket_comm_session * +socket_comm_session_initialize(message_received_handler msg_rcv_handler, + message_ready_to_read_handler msg_ready_handler, + message_sent_notifier msg_sent_notifier, + connection_except_notifier notifier, + struct in_addr *dst_ip, short dst_port, + uint32_t connect_timeout_millis, + const char *tcp_authentication_str, + bool is_tcp_auth_md5, void *session_data) +{ + (void)msg_sent_notifier; + (void)tcp_authentication_str; + (void)is_tcp_auth_md5; + + mock_socket_metadata.socket_comm_session_initialize_times_called++; + + pcep_socket_comm_session *comm_session = + malloc(sizeof(pcep_socket_comm_session)); + memset(comm_session, 0, sizeof(pcep_socket_comm_session)); + + comm_session->message_handler = msg_rcv_handler; + comm_session->message_ready_to_read_handler = msg_ready_handler; + comm_session->conn_except_notifier = notifier; + comm_session->message_queue = queue_initialize(); + comm_session->session_data = session_data; + comm_session->close_after_write = false; + comm_session->connect_timeout_millis = connect_timeout_millis; + comm_session->is_ipv6 = false; + comm_session->dest_sock_addr.dest_sock_addr_ipv4.sin_family = AF_INET; + comm_session->dest_sock_addr.dest_sock_addr_ipv4.sin_port = + htons(dst_port); + comm_session->dest_sock_addr.dest_sock_addr_ipv4.sin_addr.s_addr = + dst_ip->s_addr; + + return comm_session; +} + +pcep_socket_comm_session *socket_comm_session_initialize_ipv6( + message_received_handler msg_rcv_handler, + message_ready_to_read_handler msg_ready_handler, + message_sent_notifier msg_sent_notifier, + connection_except_notifier notifier, struct in6_addr *dst_ip, + short dst_port, uint32_t connect_timeout_millis, + const char *tcp_authentication_str, bool is_tcp_auth_md5, + void *session_data) +{ + (void)msg_sent_notifier; + (void)tcp_authentication_str; + (void)is_tcp_auth_md5; + + mock_socket_metadata.socket_comm_session_initialize_times_called++; + + pcep_socket_comm_session *comm_session = + malloc(sizeof(pcep_socket_comm_session)); + memset(comm_session, 0, sizeof(pcep_socket_comm_session)); + + comm_session->message_handler = msg_rcv_handler; + comm_session->message_ready_to_read_handler = msg_ready_handler; + comm_session->conn_except_notifier = notifier; + comm_session->message_queue = queue_initialize(); + comm_session->session_data = session_data; + comm_session->close_after_write = false; + comm_session->connect_timeout_millis = connect_timeout_millis; + comm_session->is_ipv6 = true; + comm_session->dest_sock_addr.dest_sock_addr_ipv6.sin6_family = AF_INET6; + comm_session->dest_sock_addr.dest_sock_addr_ipv6.sin6_port = + htons(dst_port); + memcpy(&comm_session->dest_sock_addr.dest_sock_addr_ipv6.sin6_addr, + dst_ip, sizeof(struct in6_addr)); + + return comm_session; +} + +pcep_socket_comm_session *socket_comm_session_initialize_with_src( + message_received_handler msg_rcv_handler, + message_ready_to_read_handler msg_ready_handler, + message_sent_notifier msg_sent_notifier, + connection_except_notifier notifier, struct in_addr *src_ip, + short src_port, struct in_addr *dst_ip, short dst_port, + uint32_t connect_timeout_millis, const char *tcp_authentication_str, + bool is_tcp_auth_md5, void *session_data) +{ + (void)msg_sent_notifier; + (void)tcp_authentication_str; + (void)is_tcp_auth_md5; + + mock_socket_metadata.socket_comm_session_initialize_src_times_called++; + + pcep_socket_comm_session *comm_session = + malloc(sizeof(pcep_socket_comm_session)); + memset(comm_session, 0, sizeof(pcep_socket_comm_session)); + + comm_session->message_handler = msg_rcv_handler; + comm_session->message_ready_to_read_handler = msg_ready_handler; + comm_session->conn_except_notifier = notifier; + comm_session->message_queue = queue_initialize(); + comm_session->session_data = session_data; + comm_session->close_after_write = false; + comm_session->connect_timeout_millis = connect_timeout_millis; + comm_session->is_ipv6 = false; + comm_session->src_sock_addr.src_sock_addr_ipv4.sin_family = AF_INET; + comm_session->src_sock_addr.src_sock_addr_ipv4.sin_port = + htons(src_port); + comm_session->src_sock_addr.src_sock_addr_ipv4.sin_addr.s_addr = + ((src_ip == NULL) ? INADDR_ANY : src_ip->s_addr); + comm_session->dest_sock_addr.dest_sock_addr_ipv4.sin_family = AF_INET; + comm_session->dest_sock_addr.dest_sock_addr_ipv4.sin_port = + htons(dst_port); + comm_session->dest_sock_addr.dest_sock_addr_ipv4.sin_addr.s_addr = + dst_ip->s_addr; + + return comm_session; +} + +pcep_socket_comm_session *socket_comm_session_initialize_with_src_ipv6( + message_received_handler msg_rcv_handler, + message_ready_to_read_handler msg_ready_handler, + message_sent_notifier msg_sent_notifier, + connection_except_notifier notifier, struct in6_addr *src_ip, + short src_port, struct in6_addr *dst_ip, short dst_port, + uint32_t connect_timeout_millis, const char *tcp_authentication_str, + bool is_tcp_auth_md5, void *session_data) +{ + (void)msg_sent_notifier; + (void)tcp_authentication_str; + (void)is_tcp_auth_md5; + + mock_socket_metadata.socket_comm_session_initialize_src_times_called++; + + pcep_socket_comm_session *comm_session = + malloc(sizeof(pcep_socket_comm_session)); + memset(comm_session, 0, sizeof(pcep_socket_comm_session)); + + comm_session->message_handler = msg_rcv_handler; + comm_session->message_ready_to_read_handler = msg_ready_handler; + comm_session->conn_except_notifier = notifier; + comm_session->message_queue = queue_initialize(); + comm_session->session_data = session_data; + comm_session->close_after_write = false; + comm_session->connect_timeout_millis = connect_timeout_millis; + comm_session->is_ipv6 = true; + comm_session->src_sock_addr.src_sock_addr_ipv6.sin6_family = AF_INET6; + comm_session->src_sock_addr.src_sock_addr_ipv6.sin6_port = + htons(src_port); + if (src_ip == NULL) { + comm_session->src_sock_addr.src_sock_addr_ipv6.sin6_addr = + in6addr_any; + } else { + memcpy(&comm_session->src_sock_addr.src_sock_addr_ipv6 + .sin6_addr, + src_ip, sizeof(struct in6_addr)); + } + comm_session->dest_sock_addr.dest_sock_addr_ipv6.sin6_family = AF_INET6; + comm_session->dest_sock_addr.dest_sock_addr_ipv6.sin6_port = + htons(dst_port); + memcpy(&comm_session->dest_sock_addr.dest_sock_addr_ipv6.sin6_addr, + dst_ip, sizeof(struct in6_addr)); + + return comm_session; +} + +bool socket_comm_session_teardown(pcep_socket_comm_session *socket_comm_session) +{ + mock_socket_metadata.socket_comm_session_teardown_times_called++; + + if (socket_comm_session != NULL) { + queue_destroy(socket_comm_session->message_queue); + free(socket_comm_session); + } + + return true; +} + + +bool socket_comm_session_connect_tcp( + pcep_socket_comm_session *socket_comm_session) +{ + (void)socket_comm_session; + + mock_socket_metadata.socket_comm_session_connect_tcp_times_called++; + + return true; +} + + +void socket_comm_session_send_message( + pcep_socket_comm_session *socket_comm_session, + const char *encoded_message, unsigned int msg_length, + bool delete_after_send) +{ + (void)socket_comm_session; + (void)msg_length; + + mock_socket_metadata.socket_comm_session_send_message_times_called++; + + if (mock_socket_metadata.send_message_save_message == true) { + /* the caller/test case is responsible for freeing the message + */ + dll_append(mock_socket_metadata.sent_message_list, + (char *)encoded_message); + } else { + if (delete_after_send == true) { + free((void *)encoded_message); + } + } + + return; +} + + +bool socket_comm_session_close_tcp_after_write( + pcep_socket_comm_session *socket_comm_session) +{ + (void)socket_comm_session; + + mock_socket_metadata + .socket_comm_session_close_tcp_after_write_times_called++; + + return true; +} + + +bool socket_comm_session_close_tcp( + pcep_socket_comm_session *socket_comm_session) +{ + (void)socket_comm_session; + + mock_socket_metadata.socket_comm_session_close_tcp_times_called++; + + return true; +} diff --git a/pceplib/pcep_socket_comm_mock.h b/pceplib/pcep_socket_comm_mock.h new file mode 100644 index 0000000000..ca0e38b803 --- /dev/null +++ b/pceplib/pcep_socket_comm_mock.h @@ -0,0 +1,67 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Brady Johnson <brady@voltanet.io> + * + */ + +/* + * This module is built into a separate library, and is used by several + * other modules for unit testing, so that real sockets dont have to be + * created. + */ + +#ifndef PCEP_SOCKET_COMM_MOCK_SOCKET_COMM_H_ +#define PCEP_SOCKET_COMM_MOCK_SOCKET_COMM_H_ + +#include <stdbool.h> + +#include "pcep_utils_double_linked_list.h" + +typedef struct mock_socket_comm_info_ { + int socket_comm_initialize_external_infra_times_called; + int socket_comm_session_initialize_times_called; + int socket_comm_session_initialize_src_times_called; + int socket_comm_session_teardown_times_called; + int socket_comm_session_connect_tcp_times_called; + int socket_comm_session_send_message_times_called; + int socket_comm_session_close_tcp_after_write_times_called; + int socket_comm_session_close_tcp_times_called; + int destroy_socket_comm_loop_times_called; + + /* TODO later if necessary, we can add return values for + * those functions that return something */ + + /* Used to access messages sent with socket_comm_session_send_message() + */ + bool send_message_save_message; + double_linked_list *sent_message_list; + +} mock_socket_comm_info; + +void setup_mock_socket_comm_info(void); +void teardown_mock_socket_comm_info(void); +void reset_mock_socket_comm_info(void); +bool destroy_socket_comm_loop(void); + +mock_socket_comm_info *get_mock_socket_comm_info(void); +void verify_socket_comm_times_called(int initialized, int teardown, int connect, + int send_message, int close_after_write, + int close, int destroy); + +#endif /* PCEP_SOCKET_COMM_MOCK_SOCKET_COMM_H_ */ diff --git a/pceplib/pcep_timer_internals.h b/pceplib/pcep_timer_internals.h new file mode 100644 index 0000000000..8221c78baa --- /dev/null +++ b/pceplib/pcep_timer_internals.h @@ -0,0 +1,76 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Brady Johnson <brady@voltanet.io> + * + */ + +/* + * Timer definitions to be used internally by the pcep_timers library. + */ + +#ifndef PCEPTIMERINTERNALS_H_ +#define PCEPTIMERINTERNALS_H_ + +#include <stdint.h> +#include <pthread.h> + +#include "pcep_utils_ordered_list.h" + +/* Function pointer to be called when timers expire. + * Parameters: + * void *data - passed into create_timer + * int timer_id - the timer_id returned by create_timer + */ +typedef void (*timer_expire_handler)(void *, int); + +/* Function pointer when an external timer infrastructure is used */ +typedef void (*ext_timer_create)(void *infra_data, void **timer, int seconds, + void *data); +typedef void (*ext_timer_cancel)(void **timer); +typedef int (*ext_pthread_create_callback)(pthread_t *pthread_id, + const pthread_attr_t *attr, + void *(*start_routine)(void *), + void *data, const char *thread_name); + +typedef struct pcep_timer_ { + time_t expire_time; + uint16_t sleep_seconds; + int timer_id; + void *data; + void *external_timer; + +} pcep_timer; + +typedef struct pcep_timers_context_ { + ordered_list_handle *timer_list; + bool active; + timer_expire_handler expire_handler; + pthread_t event_loop_thread; + pthread_mutex_t timer_list_lock; + void *external_timer_infra_data; + ext_timer_create timer_create_func; + ext_timer_cancel timer_cancel_func; + +} pcep_timers_context; + +/* functions implemented in pcep_timers_loop.c */ +void *event_loop(void *context); + + +#endif /* PCEPTIMERINTERNALS_H_ */ diff --git a/pceplib/pcep_timers.c b/pceplib/pcep_timers.c new file mode 100644 index 0000000000..e9d9d4b21d --- /dev/null +++ b/pceplib/pcep_timers.c @@ -0,0 +1,482 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Brady Johnson <brady@voltanet.io> + * + */ + + +/* + * Implementation of public API timer functions. + */ + +#include <limits.h> +#include <pthread.h> +#include <stddef.h> +#include <stdbool.h> +#include <string.h> + +#include "pcep_timers.h" +#include "pcep_utils_logging.h" +#include "pcep_utils_memory.h" +#include "pcep_utils_ordered_list.h" + +static pcep_timers_context *timers_context_ = NULL; +static int timer_id_ = 0; + + +/* simple compare method callback used by pcep_utils_ordered_list + * for ordered list insertion. */ +int timer_list_node_compare(void *list_entry, void *new_entry) +{ + /* return: + * < 0 if new_entry < list_entry + * == 0 if new_entry == list_entry (new_entry will be inserted after + * list_entry) > 0 if new_entry > list_entry */ + return ((pcep_timer *)new_entry)->expire_time + - ((pcep_timer *)list_entry)->expire_time; +} + + +/* simple compare method callback used by pcep_utils_ordered_list + * ordered_list_remove_first_node_equals2 to remove a timer based on + * its timer_id. */ +int timer_list_node_timer_id_compare(void *list_entry, void *new_entry) +{ + return ((pcep_timer *)new_entry)->timer_id + - ((pcep_timer *)list_entry)->timer_id; +} + +/* simple compare method callback used by pcep_utils_ordered_list + * ordered_list_remove_first_node_equals2 to remove a timer based on + * its address. */ +int timer_list_node_timer_ptr_compare(void *list_entry, void *new_entry) +{ + return ((char *)new_entry - (char *)list_entry); +} + +/* internal util method */ +static pcep_timers_context *create_timers_context_() +{ + if (timers_context_ == NULL) { + timers_context_ = pceplib_malloc(PCEPLIB_INFRA, + sizeof(pcep_timers_context)); + memset(timers_context_, 0, sizeof(pcep_timers_context)); + timers_context_->active = false; + } + + return timers_context_; +} + + +/* Internal util function */ +static bool initialize_timers_common(timer_expire_handler expire_handler) +{ + if (expire_handler == NULL) { + /* Cannot have a NULL handler function */ + return false; + } + + timers_context_ = create_timers_context_(); + + if (timers_context_->active == true) { + /* already initialized */ + return false; + } + + timers_context_->active = true; + timers_context_->timer_list = + ordered_list_initialize(timer_list_node_compare); + timers_context_->expire_handler = expire_handler; + + if (pthread_mutex_init(&(timers_context_->timer_list_lock), NULL) + != 0) { + pcep_log( + LOG_ERR, + "%s: ERROR initializing timers, cannot initialize the mutex", + __func__); + return false; + } + + return true; +} + +bool initialize_timers(timer_expire_handler expire_handler) +{ + if (initialize_timers_common(expire_handler) == false) { + return false; + } + + if (pthread_create(&(timers_context_->event_loop_thread), NULL, + event_loop, timers_context_)) { + pcep_log( + LOG_ERR, + "%s: ERROR initializing timers, cannot initialize the thread", + __func__); + return false; + } + + return true; +} + +bool initialize_timers_external_infra( + timer_expire_handler expire_handler, void *external_timer_infra_data, + ext_timer_create timer_create_func, ext_timer_cancel timer_cancel_func, + ext_pthread_create_callback thread_create_func) +{ + if (initialize_timers_common(expire_handler) == false) { + return false; + } + + if (thread_create_func != NULL) { + if (thread_create_func(&(timers_context_->event_loop_thread), + NULL, event_loop, timers_context_, + "pceplib_timers")) { + pcep_log( + LOG_ERR, + "%s: Cannot initialize external timers thread.", + __func__); + return false; + } + } else { + if (pthread_create(&(timers_context_->event_loop_thread), NULL, + event_loop, timers_context_)) { + pcep_log( + LOG_ERR, + "%s: ERROR initializing timers, cannot initialize the thread", + __func__); + return false; + } + } + + timers_context_->external_timer_infra_data = external_timer_infra_data; + timers_context_->timer_create_func = timer_create_func; + timers_context_->timer_cancel_func = timer_cancel_func; + + return true; +} + +/* + * This function is only used to tear_down the timer data. + * Only the timer data is deleted, not the list itself, + * which is deleted by ordered_list_destroy(). + */ +void free_all_timers(pcep_timers_context *timers_context) +{ + pthread_mutex_lock(&timers_context->timer_list_lock); + + ordered_list_node *timer_node = timers_context->timer_list->head; + + while (timer_node != NULL) { + if (timer_node->data != NULL) { + pceplib_free(PCEPLIB_INFRA, timer_node->data); + } + timer_node = timer_node->next_node; + } + + pthread_mutex_unlock(&timers_context->timer_list_lock); +} + + +bool teardown_timers() +{ + if (timers_context_ == NULL) { + pcep_log( + LOG_WARNING, + "%s: Trying to teardown the timers, but they are not initialized", + __func__); + return false; + } + + if (timers_context_->active == false) { + pcep_log( + LOG_WARNING, + "%s: Trying to teardown the timers, but they are not active", + __func__); + return false; + } + + timers_context_->active = false; + if (timers_context_->event_loop_thread != 0) { + /* TODO this does not build + * Instead of calling pthread_join() which could block if the + thread + * is blocked, try joining for at most 1 second. + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + ts.tv_sec += 1; + int retval = + pthread_timedjoin_np(timers_context_->event_loop_thread, NULL, + &ts); if (retval != 0) + { + pcep_log(LOG_WARNING, "%s: thread did not stop after 1 + second waiting on it.", __func__); + } + */ + pthread_join(timers_context_->event_loop_thread, NULL); + } + + free_all_timers(timers_context_); + ordered_list_destroy(timers_context_->timer_list); + + if (pthread_mutex_destroy(&(timers_context_->timer_list_lock)) != 0) { + pcep_log( + LOG_WARNING, + "%s: Trying to teardown the timers, cannot destroy the mutex", + __func__); + } + + pceplib_free(PCEPLIB_INFRA, timers_context_); + timers_context_ = NULL; + + return true; +} + + +int get_next_timer_id() +{ + if (timer_id_ == INT_MAX) { + timer_id_ = 0; + } + + return timer_id_++; +} + +int create_timer(uint16_t sleep_seconds, void *data) +{ + if (timers_context_ == NULL) { + pcep_log( + LOG_WARNING, + "%s: Trying to create a timer: the timers have not been initialized", + __func__); + return -1; + } + + pcep_timer *timer = pceplib_malloc(PCEPLIB_INFRA, sizeof(pcep_timer)); + memset(timer, 0, sizeof(pcep_timer)); + timer->data = data; + timer->sleep_seconds = sleep_seconds; + timer->expire_time = time(NULL) + sleep_seconds; + + pthread_mutex_lock(&timers_context_->timer_list_lock); + timer->timer_id = get_next_timer_id(); + + /* implemented in pcep_utils_ordered_list.c */ + if (ordered_list_add_node(timers_context_->timer_list, timer) == NULL) { + pceplib_free(PCEPLIB_INFRA, timer); + pthread_mutex_unlock(&timers_context_->timer_list_lock); + pcep_log( + LOG_WARNING, + "%s: Trying to create a timer, cannot add the timer to the timer list", + __func__); + + return -1; + } + + pthread_mutex_unlock(&timers_context_->timer_list_lock); + + if (timers_context_->timer_create_func) { + timers_context_->timer_create_func( + timers_context_->external_timer_infra_data, + &timer->external_timer, sleep_seconds, timer); + } + + return timer->timer_id; +} + + +bool cancel_timer(int timer_id) +{ + static pcep_timer compare_timer; + + if (timers_context_ == NULL) { + pcep_log( + LOG_WARNING, + "%s: Trying to cancel a timer: the timers have not been initialized", + __func__); + return false; + } + + pthread_mutex_lock(&timers_context_->timer_list_lock); + + compare_timer.timer_id = timer_id; + pcep_timer *timer_toRemove = ordered_list_remove_first_node_equals2( + timers_context_->timer_list, &compare_timer, + timer_list_node_timer_id_compare); + if (timer_toRemove == NULL) { + pthread_mutex_unlock(&timers_context_->timer_list_lock); + pcep_log( + LOG_WARNING, + "%s: Trying to cancel a timer [%d] that does not exist", + __func__, timer_id); + return false; + } + + pthread_mutex_unlock(&timers_context_->timer_list_lock); + + if (timers_context_->timer_cancel_func) { + timers_context_->timer_cancel_func( + &timer_toRemove->external_timer); + } + + pceplib_free(PCEPLIB_INFRA, timer_toRemove); + + return true; +} + + +bool reset_timer(int timer_id) +{ + static pcep_timer compare_timer; + + if (timers_context_ == NULL) { + pcep_log( + LOG_WARNING, + "%s: Trying to reset a timer: the timers have not been initialized", + __func__); + + return false; + } + + pthread_mutex_lock(&timers_context_->timer_list_lock); + + compare_timer.timer_id = timer_id; + ordered_list_node *timer_to_reset_node = + ordered_list_find2(timers_context_->timer_list, &compare_timer, + timer_list_node_timer_id_compare); + if (timer_to_reset_node == NULL) { + pthread_mutex_unlock(&timers_context_->timer_list_lock); + pcep_log(LOG_WARNING, + "%s: Trying to reset a timer node that does not exist", + __func__); + + return false; + } + + pcep_timer *timer_to_reset = timer_to_reset_node->data; + if (timer_to_reset == NULL) { + pthread_mutex_unlock(&timers_context_->timer_list_lock); + pcep_log(LOG_WARNING, + "%s: Trying to reset a timer that does not exist", + __func__); + + return false; + } + + /* First check if the timer to reset already has the same expire time, + * which means multiple reset_timer() calls were made on the same timer + * in the same second */ + time_t expire_time = time(NULL) + timer_to_reset->sleep_seconds; + if (timer_to_reset->expire_time == expire_time) { + pthread_mutex_unlock(&timers_context_->timer_list_lock); + return true; + } + + ordered_list_remove_node2(timers_context_->timer_list, + timer_to_reset_node); + + timer_to_reset->expire_time = expire_time; + if (ordered_list_add_node(timers_context_->timer_list, timer_to_reset) + == NULL) { + pceplib_free(PCEPLIB_INFRA, timer_to_reset); + pthread_mutex_unlock(&timers_context_->timer_list_lock); + pcep_log( + LOG_WARNING, + "%s: Trying to reset a timer, cannot add the timer to the timer list", + __func__); + + return false; + } + + pthread_mutex_unlock(&timers_context_->timer_list_lock); + + if (timers_context_->timer_cancel_func) { + /* Keeping this log for now, since in older versions of FRR the + * timer cancellation was blocking. This allows us to see how + * long the it takes.*/ + pcep_log(LOG_DEBUG, "%s: Reseting timer [%d] with callback", + __func__, timer_to_reset->timer_id); + timers_context_->timer_cancel_func( + &timer_to_reset->external_timer); + timer_to_reset->external_timer = NULL; + } + + if (timers_context_->timer_create_func) { + timers_context_->timer_create_func( + timers_context_->external_timer_infra_data, + &timer_to_reset->external_timer, + timer_to_reset->sleep_seconds, timer_to_reset); + /* Keeping this log for now, since in older versions of FRR the + * timer cancellation was blocking. This allows us to see how + * long the it takes.*/ + pcep_log(LOG_DEBUG, "%s: Reset timer [%d] with callback", + __func__, timer_to_reset->timer_id); + } + + return true; +} + + +void pceplib_external_timer_expire_handler(void *data) +{ + if (timers_context_ == NULL) { + pcep_log( + LOG_WARNING, + "%s: External timer expired but timers_context is not initialized", + __func__); + return; + } + + if (timers_context_->expire_handler == NULL) { + pcep_log( + LOG_WARNING, + "%s: External timer expired but expire_handler is not initialized", + __func__); + return; + } + + if (data == NULL) { + pcep_log(LOG_WARNING, + "%s: External timer expired with NULL data", __func__); + return; + } + + 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); + pthread_mutex_unlock(&timers_context_->timer_list_lock); + + /* Cannot continue if the timer does not exist */ + if (timer_node == NULL) { + pcep_log( + LOG_WARNING, + "%s: pceplib_external_timer_expire_handler timer [%p] id [%d] does not exist", + __func__, timer, timer->timer_id); + return; + } + + 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/pcep_timers.h b/pceplib/pcep_timers.h new file mode 100644 index 0000000000..b2cc6ec546 --- /dev/null +++ b/pceplib/pcep_timers.h @@ -0,0 +1,92 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Brady Johnson <brady@voltanet.io> + * + */ + + +/* + * Public API for pcep_timers + */ + +#ifndef PCEPTIMERS_H_ +#define PCEPTIMERS_H_ + +#include <pthread.h> +#include <stdbool.h> + +#include "pcep_timer_internals.h" + +#define TIMER_ID_NOT_SET -1 + +/* + * Initialize the timers module. + * The timer_expire_handler function pointer will be called each time a timer + * expires. Return true for successful initialization, false otherwise. + */ +bool initialize_timers(timer_expire_handler expire_handler); + +/* + * Initialize the timers module with an external back-end infrastructure, like + * FRR. + */ +bool initialize_timers_external_infra( + timer_expire_handler expire_handler, void *external_timer_infra_data, + ext_timer_create timer_create_func, ext_timer_cancel timer_cancel_func, + ext_pthread_create_callback thread_create_func); + +/* + * Teardown the timers module. + */ +bool teardown_timers(void); + +/* + * Create a new timer for "sleep_seconds" seconds. + * If the timer expires before being cancelled, the timer_expire_handler + * passed to initialize_timers() will be called with the pointer to "data". + * Returns a timer_id <= 0 that can be used to cancel_timer. + * Returns < 0 on error. + */ +int create_timer(uint16_t sleep_seconds, void *data); + +/* + * Cancel a timer created with create_timer(). + * Returns true if the timer was found and cancelled, false otherwise. + */ +bool cancel_timer(int timer_id); + +/* + * Reset an previously created timer, maintaining the same timer_id. + * Returns true if the timer was found and reset, false otherwise. + */ +bool reset_timer(int timer_id); + +/* + * If an external timer infra like FRR is used, then this function + * will be called when the timers expire in the external infra. + */ +void pceplib_external_timer_expire_handler(void *data); + +int timer_list_node_compare(void *list_entry, void *new_entry); +int timer_list_node_timer_id_compare(void *list_entry, void *new_entry); +int timer_list_node_timer_ptr_compare(void *list_entry, void *new_entry); +void free_all_timers(pcep_timers_context *timers_context); +int get_next_timer_id(void); + +#endif /* PCEPTIMERS_H_ */ diff --git a/pceplib/pcep_timers_event_loop.c b/pceplib/pcep_timers_event_loop.c new file mode 100644 index 0000000000..932a53eb2a --- /dev/null +++ b/pceplib/pcep_timers_event_loop.c @@ -0,0 +1,106 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Brady Johnson <brady@voltanet.io> + * + */ + + +#include <errno.h> +#include <stddef.h> +#include <stdbool.h> +#include <stdio.h> +#include <sys/select.h> + +#include "pcep_timers_event_loop.h" +#include "pcep_timer_internals.h" +#include "pcep_utils_ordered_list.h" +#include "pcep_utils_logging.h" +#include "pcep_utils_memory.h" + +/* For each expired timer: remove the timer from the list, call the + * expire_handler, and free the timer. */ +void walk_and_process_timers(pcep_timers_context *timers_context) +{ + pthread_mutex_lock(&timers_context->timer_list_lock); + + bool keep_walking = true; + ordered_list_node *timer_node = timers_context->timer_list->head; + time_t now = time(NULL); + pcep_timer *timer_data; + + /* the timers are sorted by expire_time, so we will only + * remove the top node each time through the loop */ + while (timer_node != NULL && keep_walking) { + timer_data = (pcep_timer *)timer_node->data; + if (timer_data->expire_time <= now) { + timer_node = timer_node->next_node; + ordered_list_remove_first_node( + timers_context->timer_list); + /* call the timer expired handler */ + timers_context->expire_handler(timer_data->data, + timer_data->timer_id); + pceplib_free(PCEPLIB_INFRA, timer_data); + } else { + keep_walking = false; + } + } + + pthread_mutex_unlock(&timers_context->timer_list_lock); +} + + +/* pcep_timers::initialize() will create a thread and invoke this method */ +void *event_loop(void *context) +{ + if (context == NULL) { + pcep_log( + LOG_WARNING, + "%s: pcep_timers_event_loop cannot start event_loop with NULL data", + __func__); + return NULL; + } + + pcep_log(LOG_NOTICE, "%s: [%ld-%ld] Starting timers_event_loop thread", + __func__, time(NULL), pthread_self()); + + pcep_timers_context *timers_context = (pcep_timers_context *)context; + struct timeval timer; + int retval; + + while (timers_context->active) { + /* check the timers every half second */ + timer.tv_sec = 0; + timer.tv_usec = 500000; + + do { + /* if the select() call gets interrupted, select() will + * set the remaining time in timer, so we need to call + * it again. + */ + retval = select(0, NULL, NULL, NULL, &timer); + } while (retval != 0 && errno == EINTR); + + walk_and_process_timers(timers_context); + } + + pcep_log(LOG_WARNING, "%s: [%ld-%ld] Finished timers_event_loop thread", + __func__, time(NULL), pthread_self()); + + return NULL; +} diff --git a/pceplib/pcep_timers_event_loop.h b/pceplib/pcep_timers_event_loop.h new file mode 100644 index 0000000000..c4a7264da3 --- /dev/null +++ b/pceplib/pcep_timers_event_loop.h @@ -0,0 +1,34 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Javier Garcia <javier.garcia@voltanet.io> + * + */ + +/* + * Timer definitions to be used internally by the pcep_timers library. + */ + +#ifndef PCEP_TIMERS_EVENT_LOOP_H_ +#define PCEP_TIMERS_EVENT_LOOP_H_ + +#include "pcep_timer_internals.h" + +void walk_and_process_timers(pcep_timers_context *timers_context); + +#endif diff --git a/pceplib/pcep_utils_counters.c b/pceplib/pcep_utils_counters.c new file mode 100644 index 0000000000..d8078f683f --- /dev/null +++ b/pceplib/pcep_utils_counters.c @@ -0,0 +1,475 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Brady Johnson <brady@voltanet.io> + * + */ + + +/* + * Implementation of PCEP Counters. + */ + +#include <zebra.h> + +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#include "pcep_utils_counters.h" +#include "pcep_utils_logging.h" +#include "pcep_utils_memory.h" + +struct counters_group *create_counters_group(const char *group_name, + uint16_t max_subgroups) +{ + if (group_name == NULL) { + pcep_log( + LOG_INFO, + "%s: Cannot create counters group: group_name is NULL.", + __func__); + return NULL; + } + + if (max_subgroups > MAX_COUNTER_GROUPS) { + pcep_log( + LOG_INFO, + "%s: Cannot create counters group: max_subgroups [%d] is larger than max the [%d].", + __func__, max_subgroups, MAX_COUNTER_GROUPS); + return NULL; + } + + struct counters_group *group = + pceplib_malloc(PCEPLIB_INFRA, sizeof(struct counters_group)); + memset(group, 0, sizeof(struct counters_group)); + group->subgroups = + pceplib_malloc(PCEPLIB_INFRA, sizeof(struct counters_subgroup *) + * (max_subgroups + 1)); + memset(group->subgroups, 0, + sizeof(struct counters_subgroup *) * (max_subgroups + 1)); + + strlcpy(group->counters_group_name, group_name, + sizeof(group->counters_group_name)); + group->max_subgroups = max_subgroups; + group->start_time = time(NULL); + + return group; +} + +struct counters_subgroup *create_counters_subgroup(const char *subgroup_name, + uint16_t subgroup_id, + uint16_t max_counters) +{ + if (subgroup_name == NULL) { + pcep_log( + LOG_INFO, + "%s: Cannot create counters subgroup: subgroup_name is NULL.", + __func__); + return NULL; + } + + if (max_counters > MAX_COUNTERS) { + pcep_log( + LOG_INFO, + "%s: Cannot create counters subgroup: max_counters [%d] is larger than the max [%d].", + __func__, max_counters, MAX_COUNTERS); + return NULL; + } + + if (subgroup_id > MAX_COUNTER_GROUPS) { + pcep_log( + LOG_INFO, + "%s: Cannot create counters subgroup: subgroup_id [%d] is larger than max the [%d].", + __func__, subgroup_id, MAX_COUNTER_GROUPS); + return NULL; + } + + struct counters_subgroup *subgroup = + pceplib_malloc(PCEPLIB_INFRA, sizeof(struct counters_subgroup)); + memset(subgroup, 0, sizeof(struct counters_subgroup)); + subgroup->counters = pceplib_malloc( + PCEPLIB_INFRA, sizeof(struct counter *) * (max_counters + 1)); + memset(subgroup->counters, 0, + sizeof(struct counter *) * (max_counters + 1)); + + strlcpy(subgroup->counters_subgroup_name, subgroup_name, + sizeof(subgroup->counters_subgroup_name)); + subgroup->subgroup_id = subgroup_id; + subgroup->max_counters = max_counters; + + return subgroup; +} + +struct counters_subgroup * +clone_counters_subgroup(struct counters_subgroup *subgroup, + const char *subgroup_name, uint16_t subgroup_id) +{ + if (subgroup == NULL) { + pcep_log( + LOG_INFO, + "%s: Cannot clone counters subgroup: input counters_subgroup is NULL.", + __func__); + return NULL; + } + + if (subgroup_name == NULL) { + pcep_log( + LOG_INFO, + "%s: Cannot clone counters subgroup: subgroup_name is NULL.", + __func__); + return NULL; + } + + if (subgroup_id > MAX_COUNTER_GROUPS) { + pcep_log( + LOG_INFO, + "%s: Cannot clone counters subgroup: subgroup_id [%d] is larger than max the [%d].", + __func__, subgroup_id, MAX_COUNTER_GROUPS); + return NULL; + } + + struct counters_subgroup *cloned_subgroup = create_counters_subgroup( + subgroup_name, subgroup_id, subgroup->max_counters); + int i = 0; + for (; i <= subgroup->max_counters; i++) { + struct counter *counter = subgroup->counters[i]; + if (counter != NULL) { + create_subgroup_counter(cloned_subgroup, + counter->counter_id, + counter->counter_name); + } + } + + return cloned_subgroup; +} + +bool add_counters_subgroup(struct counters_group *group, + struct counters_subgroup *subgroup) +{ + if (group == NULL) { + pcep_log( + LOG_INFO, + "%s: Cannot add counters subgroup: counters_group is NULL.", + __func__); + return false; + } + + if (subgroup == NULL) { + pcep_log( + LOG_INFO, + "%s: Cannot add counters subgroup: counters_subgroup is NULL.", + __func__); + return false; + } + + if (subgroup->subgroup_id >= group->max_subgroups) { + pcep_log( + LOG_INFO, + "%s: Cannot add counters subgroup: counters_subgroup id [%d] is larger than the group max_subgroups [%d].", + __func__, subgroup->subgroup_id, group->max_subgroups); + return false; + } + + group->num_subgroups++; + group->subgroups[subgroup->subgroup_id] = subgroup; + + return true; +} + +bool create_subgroup_counter(struct counters_subgroup *subgroup, + uint32_t counter_id, const char *counter_name) +{ + if (subgroup == NULL) { + pcep_log( + LOG_INFO, + "%s: Cannot create subgroup counter: counters_subgroup is NULL.", + __func__); + return false; + } + + if (counter_id >= subgroup->max_counters) { + pcep_log( + LOG_INFO, + "%s: Cannot create subgroup counter: counter_id [%d] is larger than the subgroup max_counters [%d].", + __func__, counter_id, subgroup->max_counters); + return false; + } + + if (counter_name == NULL) { + pcep_log( + LOG_INFO, + "%s: Cannot create subgroup counter: counter_name is NULL.", + __func__); + return NULL; + } + + struct counter *counter = + pceplib_malloc(PCEPLIB_INFRA, sizeof(struct counter)); + memset(counter, 0, sizeof(struct counter)); + counter->counter_id = counter_id; + strlcpy(counter->counter_name, counter_name, + sizeof(counter->counter_name)); + + subgroup->num_counters++; + subgroup->counters[counter->counter_id] = counter; + + return true; +} + +bool delete_counters_group(struct counters_group *group) +{ + if (group == NULL) { + pcep_log( + LOG_INFO, + "%s: Cannot delete group counters: counters_group is NULL.", + __func__); + return false; + } + + int i = 0; + for (; i <= group->max_subgroups; i++) { + struct counters_subgroup *subgroup = group->subgroups[i]; + if (subgroup != NULL) { + delete_counters_subgroup(subgroup); + } + } + + pceplib_free(PCEPLIB_INFRA, group->subgroups); + pceplib_free(PCEPLIB_INFRA, group); + + return true; +} + +bool delete_counters_subgroup(struct counters_subgroup *subgroup) +{ + if (subgroup == NULL || subgroup->counters == NULL) { + pcep_log( + LOG_INFO, + "%s: Cannot delete subgroup counters: counters_subgroup is NULL.", + __func__); + return false; + } + + int i = 0; + for (; i <= subgroup->max_counters; i++) { + struct counter *counter = subgroup->counters[i]; + if (counter != NULL) { + pceplib_free(PCEPLIB_INFRA, counter); + } + } + + pceplib_free(PCEPLIB_INFRA, subgroup->counters); + pceplib_free(PCEPLIB_INFRA, subgroup); + + return true; +} + +bool reset_group_counters(struct counters_group *group) +{ + if (group == NULL) { + pcep_log( + LOG_INFO, + "%s: Cannot reset group counters: counters_group is NULL.", + __func__); + return false; + } + + int i = 0; + for (; i <= group->max_subgroups; i++) { + struct counters_subgroup *subgroup = group->subgroups[i]; + if (subgroup != NULL) { + reset_subgroup_counters(subgroup); + } + } + + group->start_time = time(NULL); + + return true; +} + +bool reset_subgroup_counters(struct counters_subgroup *subgroup) +{ + if (subgroup == NULL) { + pcep_log( + LOG_INFO, + "%s: Cannot reset subgroup counters: counters_subgroup is NULL.", + __func__); + return false; + } + + int i = 0; + for (; i <= subgroup->max_counters; i++) { + struct counter *counter = subgroup->counters[i]; + if (counter != NULL) { + counter->counter_value = 0; + } + } + + return true; +} + +bool increment_counter(struct counters_group *group, uint16_t subgroup_id, + uint16_t counter_id) +{ + if (group == NULL) { + pcep_log( + LOG_INFO, + "%s: Cannot increment counter: counters_group is NULL.", + __func__); + return false; + } + + if (subgroup_id >= group->max_subgroups) { + pcep_log( + LOG_DEBUG, + "%s: Cannot increment counter: subgroup_id [%d] is larger than the group max_subgroups [%d].", + __func__, subgroup_id, group->max_subgroups); + return false; + } + + struct counters_subgroup *subgroup = group->subgroups[subgroup_id]; + if (subgroup == NULL) { + pcep_log( + LOG_INFO, + "%s: Cannot increment counter: counters_subgroup in counters_group is NULL.", + __func__); + return false; + } + + return increment_subgroup_counter(subgroup, counter_id); +} + +bool increment_subgroup_counter(struct counters_subgroup *subgroup, + uint16_t counter_id) +{ + if (subgroup == NULL) { + pcep_log( + LOG_INFO, + "%s: Cannot increment counter: counters_subgroup is NULL.", + __func__); + return false; + } + + if (counter_id >= subgroup->max_counters) { + pcep_log( + LOG_DEBUG, + "%s: Cannot increment counter: counter_id [%d] is larger than the subgroup max_counters [%d].", + __func__, counter_id, subgroup->max_counters); + return false; + } + + if (subgroup->counters[counter_id] == NULL) { + pcep_log( + LOG_INFO, + "%s: Cannot increment counter: No counter exists for counter_id [%d].", + __func__, counter_id); + return false; + } + + subgroup->counters[counter_id]->counter_value++; + + return true; +} + +bool dump_counters_group_to_log(struct counters_group *group) +{ + if (group == NULL) { + pcep_log( + LOG_INFO, + "%s: Cannot dump group counters to log: counters_group is NULL.", + __func__); + return false; + } + + time_t now = time(NULL); + pcep_log( + LOG_INFO, + "%s: PCEP Counters group:\n %s \n Sub-Groups [%d] \n Active for [%d seconds]", + __func__, group->counters_group_name, group->num_subgroups, + (now - group->start_time)); + + int i = 0; + for (; i <= group->max_subgroups; i++) { + struct counters_subgroup *subgroup = group->subgroups[i]; + if (subgroup != NULL) { + dump_counters_subgroup_to_log(subgroup); + } + } + + return true; +} + +bool dump_counters_subgroup_to_log(struct counters_subgroup *subgroup) +{ + if (subgroup == NULL) { + pcep_log( + LOG_INFO, + "%s: Cannot dump subgroup counters to log: counters_subgroup is NULL.", + __func__); + return false; + } + + pcep_log(LOG_INFO, + "%s: \tPCEP Counters sub-group [%s] with [%d] counters", + __func__, subgroup->counters_subgroup_name, + subgroup->num_counters); + + int i = 0; + for (; i <= subgroup->max_counters; i++) { + struct counter *counter = subgroup->counters[i]; + if (counter != NULL) { + pcep_log(LOG_INFO, "%s: \t\t%s %d", __func__, + counter->counter_name, counter->counter_value); + } + } + + return true; +} + +struct counters_subgroup *find_subgroup(const struct counters_group *group, + uint16_t subgroup_id) +{ + int i = 0; + for (; i <= group->max_subgroups; i++) { + struct counters_subgroup *subgroup = group->subgroups[i]; + if (subgroup != NULL) { + if (subgroup->subgroup_id == subgroup_id) { + return subgroup; + } + } + } + + return NULL; +} + +uint32_t subgroup_counters_total(struct counters_subgroup *subgroup) +{ + if (subgroup == NULL) { + return 0; + } + uint32_t counter_total = 0; + int i = 0; + for (; i <= subgroup->max_counters; i++) { + struct counter *counter = subgroup->counters[i]; + if (counter != NULL) { + counter_total += counter->counter_value; + } + } + + return counter_total; +} diff --git a/pceplib/pcep_utils_counters.h b/pceplib/pcep_utils_counters.h new file mode 100644 index 0000000000..240e9758b7 --- /dev/null +++ b/pceplib/pcep_utils_counters.h @@ -0,0 +1,232 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Brady Johnson <brady@voltanet.io> + * + */ + + +/* + * Definitions of PCEP Counters. + */ + +#ifndef PCEP_UTILS_INCLUDE_PCEP_UTILS_COUNTERS_H_ +#define PCEP_UTILS_INCLUDE_PCEP_UTILS_COUNTERS_H_ + +#include <stdbool.h> +#include <stdint.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Example Counter group with sub-groups and counters + * + * pcep_counters { + * counters_group_rx { + * message_open; + * message_keepalive; + * message_pcreq; + * } + * counters_group_tx { + * message_open; + * message_keepalive; + * message_pcreq; + * } + * counters_group_events { + * pcc_connect; + * pce_connect; + * pcc_disconnect; + * pce_disconnect; + * } + * } + * + * To create the above structure of groups, sub-groups, and counters, do the + * following: + * + * struct counters_subgroup *rx_subgroup = create_counters_subgroup("rx + * counters", 3); struct counters_subgroup *tx_subgroup = + * create_counters_subgroup("tx counters", 3); struct counters_subgroup + * *events_subgroup = create_counters_subgroup("events counters", 4); + * + * Use message_id: PCEP_TYPE_OPEN=1 + * create_subgroup_counter(rx_subgroup, 1, "Message Open"); + * create_subgroup_counter(rx_subgroup, 2, "Message KeepAlive"); + * create_subgroup_counter(rx_subgroup, 3, "Message PcReq"); + * + * create_subgroup_counter(tx_subgroup, 1, "Message Open"); + * create_subgroup_counter(tx_subgroup, 2, "Message KeepAlive"); + * create_subgroup_counter(tx_subgroup, 3, "Message PcReq"); + * + * create_subgroup_counter(events_subgroup, 1, "PCC Connect"); + * create_subgroup_counter(events_subgroup, 2, "PCE Connect"); + * create_subgroup_counter(events_subgroup, 3, "PCC Disconnect"); + * create_subgroup_counter(events_subgroup, 4, "PCE Disconnect"); + * + * struct counters_group *cntrs_group = create_counters_group("PCEP Counters", + * 3); add_counters_subgroup(cntrs_group, rx_subgroup); + * add_counters_subgroup(cntrs_group, tx_subgroup); + * add_counters_subgroup(cntrs_group, events_subgroup); + */ + +#define MAX_COUNTER_STR_LENGTH 128 +#define MAX_COUNTER_GROUPS 500 +#define MAX_COUNTERS 500 + +struct counter { + uint16_t counter_id; + char counter_name[MAX_COUNTER_STR_LENGTH]; + uint32_t counter_value; +}; + +struct counters_subgroup { + char counters_subgroup_name[MAX_COUNTER_STR_LENGTH]; + uint16_t subgroup_id; + uint16_t num_counters; + uint16_t max_counters; + /* Array of (struct counter *) allocated when the subgroup is created. + * The array is indexed by the struct counter->counter_id */ + struct counter **counters; +}; + +struct counters_group { + char counters_group_name[MAX_COUNTER_STR_LENGTH]; + uint16_t num_subgroups; + uint16_t max_subgroups; + time_t start_time; + /* Array of (struct counters_subgroup *) allocated when the group is + * created. The subgroup is indexed by the (struct counters_subgroup + * *)->subgroup_id */ + struct counters_subgroup **subgroups; +}; + +/* + * Create a counters group with the given group_name and number of subgroups. + * Subgroup_ids are 0-based, so take that into account when setting + * max_subgroups. Return true on success or false if group_name is NULL or + * max_subgroups >= MAX_COUNTER_GROUPS. + */ +struct counters_group *create_counters_group(const char *group_name, + uint16_t max_subgroups); + +/* + * Create a counters subgroup with the given subgroup_name, subgroup_id and + * number of counters. The subgroup_id is 0-based. counter_ids are 0-based, so + * take that into account when setting max_counters. Return true on success or + * false if subgroup_name is NULL, subgroup_id >= MAX_COUNTER_GROUPS, or + * max_counters >= MAX_COUNTERS. + */ +struct counters_subgroup *create_counters_subgroup(const char *subgroup_name, + uint16_t subgroup_id, + uint16_t max_counters); + +/* + * Add a counter_subgroup to a counter_group. + * Return true on success or false if group is NULL or if subgroup is NULL. + */ +bool add_counters_subgroup(struct counters_group *group, + struct counters_subgroup *subgroup); + +/* + * Clone a subgroup and set a new name and subgroup_id for the new subgroup. + * This is useful for RX and TX counters: just create the RX counters and clone + * it for the TX counters. + */ +struct counters_subgroup * +clone_counters_subgroup(struct counters_subgroup *subgroup, + const char *subgroup_name, uint16_t subgroup_id); + +/* + * Create a counter in a subgroup with the given counter_id and counter_name. + * The counter_id is 0-based. + * Return true on success or false if subgroup is NULL, counter_id >= + * MAX_COUNTERS, or if counter_name is NULL. + */ +bool create_subgroup_counter(struct counters_subgroup *subgroup, + uint32_t counter_id, const char *counter_name); + +/* + * Delete the counters_group and recursively delete all subgroups and their + * counters. Return true on success or false if group is NULL. + */ +bool delete_counters_group(struct counters_group *group); + +/* + * Delete the counters_subgroup and all its counters counters. + * Return true on success or false if subgroup is NULL. + */ +bool delete_counters_subgroup(struct counters_subgroup *subgroup); + +/* + * Reset all the counters in all sub-groups contained in this group. + * Return true on success or false if group is NULL. + */ +bool reset_group_counters(struct counters_group *group); + +/* + * Reset all the counters in this subgroup. + * Return true on success or false if subgroup is NULL. + */ +bool reset_subgroup_counters(struct counters_subgroup *subgroup); + +/* + * Increment a counter given a counter_group, subgroup_id, and counter_id. + * Return true on success or false if group is NULL, subgroup_id >= + * MAX_COUNTER_GROUPS, or counter_id >= MAX_COUNTERS. + */ +bool increment_counter(struct counters_group *group, uint16_t subgroup_id, + uint16_t counter_id); + +/* + * Increment a counter given the counter_subgroup and counter_id. + * Return true on success or false if subgroup is NULL or counter_id >= + * MAX_COUNTERS. + */ +bool increment_subgroup_counter(struct counters_subgroup *subgroup, + uint16_t counter_id); + +/* + * Dump the counter_group info and all its counter_subgroups. + * Return true on success or false if group is NULL. + */ +bool dump_counters_group_to_log(struct counters_group *group); + +/* + * Dump all the counters in a counter_subgroup. + * Return true on success or false if subgroup is NULL. + */ +bool dump_counters_subgroup_to_log(struct counters_subgroup *subgroup); + +/* + * Search for a counters_subgroup by subgroup_id in a counters_group + * and return it, if found, else return NULL. + */ +struct counters_subgroup *find_subgroup(const struct counters_group *group, + uint16_t subgroup_id); + +/* + * Given a counters_subgroup, return the sum of all the counters. + */ +uint32_t subgroup_counters_total(struct counters_subgroup *subgroup); + +#ifdef __cplusplus +} +#endif + +#endif /* PCEP_UTILS_INCLUDE_PCEP_UTILS_COUNTERS_H_ */ diff --git a/pceplib/pcep_utils_double_linked_list.c b/pceplib/pcep_utils_double_linked_list.c new file mode 100644 index 0000000000..acdcee0598 --- /dev/null +++ b/pceplib/pcep_utils_double_linked_list.c @@ -0,0 +1,262 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Brady Johnson <brady@voltanet.io> + * + */ + +#include <stddef.h> +#include <string.h> + +#include "pcep_utils_double_linked_list.h" +#include "pcep_utils_logging.h" +#include "pcep_utils_memory.h" + +double_linked_list *dll_initialize() +{ + double_linked_list *handle = + pceplib_malloc(PCEPLIB_INFRA, sizeof(double_linked_list)); + if (handle != NULL) { + memset(handle, 0, sizeof(double_linked_list)); + handle->num_entries = 0; + handle->head = NULL; + handle->tail = NULL; + } else { + pcep_log(LOG_WARNING, + "%s: dll_initialize cannot allocate memory for handle", + __func__); + return NULL; + } + + return handle; +} + + +void dll_destroy(double_linked_list *handle) +{ + if (handle == NULL) { + pcep_log(LOG_WARNING, + "%s: dll_destroy cannot destroy NULL handle", + __func__); + return; + } + + double_linked_list_node *node = handle->head; + while (node != NULL) { + double_linked_list_node *node_to_delete = node; + node = node->next_node; + pceplib_free(PCEPLIB_INFRA, node_to_delete); + } + + pceplib_free(PCEPLIB_INFRA, handle); +} + + +void dll_destroy_with_data_memtype(double_linked_list *handle, + void *data_memory_type) +{ + if (handle == NULL) { + pcep_log(LOG_WARNING, + "%s: dll_destroy_with_data cannot destroy NULL handle", + __func__); + return; + } + + double_linked_list_node *node = handle->head; + while (node != NULL) { + double_linked_list_node *node_to_delete = node; + pceplib_free(data_memory_type, node->data); + node = node->next_node; + pceplib_free(PCEPLIB_INFRA, node_to_delete); + } + + pceplib_free(PCEPLIB_INFRA, handle); +} + + +void dll_destroy_with_data(double_linked_list *handle) +{ + /* Default to destroying the data with the INFRA mem type */ + dll_destroy_with_data_memtype(handle, PCEPLIB_INFRA); +} + + +/* Creates a node and adds it as the first item in the list */ +double_linked_list_node *dll_prepend(double_linked_list *handle, void *data) +{ + if (handle == NULL) { + pcep_log(LOG_WARNING, "%s: dll_prepend_data NULL handle", + __func__); + return NULL; + } + + /* Create the new node */ + double_linked_list_node *new_node = + pceplib_malloc(PCEPLIB_INFRA, sizeof(double_linked_list_node)); + memset(new_node, 0, sizeof(double_linked_list_node)); + new_node->data = data; + + if (handle->head == NULL) { + handle->head = new_node; + handle->tail = new_node; + } else { + new_node->next_node = handle->head; + handle->head->prev_node = new_node; + handle->head = new_node; + } + + (handle->num_entries)++; + + return new_node; +} + + +/* Creates a node and adds it as the last item in the list */ +double_linked_list_node *dll_append(double_linked_list *handle, void *data) +{ + if (handle == NULL) { + pcep_log(LOG_WARNING, "%s: dll_append_data NULL handle", + __func__); + return NULL; + } + + /* Create the new node */ + double_linked_list_node *new_node = + pceplib_malloc(PCEPLIB_INFRA, sizeof(double_linked_list_node)); + memset(new_node, 0, sizeof(double_linked_list_node)); + new_node->data = data; + + if (handle->head == NULL) { + handle->head = new_node; + handle->tail = new_node; + } else { + new_node->prev_node = handle->tail; + handle->tail->next_node = new_node; + handle->tail = new_node; + } + + (handle->num_entries)++; + + return new_node; +} + + +/* Delete the first node in the list, and return the data */ +void *dll_delete_first_node(double_linked_list *handle) +{ + if (handle == NULL) { + pcep_log(LOG_WARNING, "%s: dll_delete_first_node NULL handle", + __func__); + return NULL; + } + + if (handle->head == NULL) { + return NULL; + } + + double_linked_list_node *delete_node = handle->head; + void *data = delete_node->data; + + if (delete_node->next_node == NULL) { + /* Its the last node in the list */ + handle->head = NULL; + handle->tail = NULL; + } else { + handle->head = delete_node->next_node; + handle->head->prev_node = NULL; + } + + pceplib_free(PCEPLIB_INFRA, delete_node); + (handle->num_entries)--; + + return data; +} + + +/* Delete the last node in the list, and return the data */ +void *dll_delete_last_node(double_linked_list *handle) +{ + if (handle == NULL) { + pcep_log(LOG_WARNING, "%s: dll_delete_last_node NULL handle", + __func__); + return NULL; + } + + if (handle->head == NULL) { + return NULL; + } + + double_linked_list_node *delete_node = handle->tail; + void *data = delete_node->data; + + if (delete_node->prev_node == NULL) { + /* Its the last node in the list */ + handle->head = NULL; + handle->tail = NULL; + } else { + handle->tail = delete_node->prev_node; + handle->tail->next_node = NULL; + } + + pceplib_free(PCEPLIB_INFRA, delete_node); + (handle->num_entries)--; + + return data; +} + + +/* Delete the designated node in the list, and return the data */ +void *dll_delete_node(double_linked_list *handle, double_linked_list_node *node) +{ + if (handle == NULL) { + pcep_log(LOG_WARNING, "%s: dll_delete_node NULL handle", + __func__); + return NULL; + } + + if (node == NULL) { + return NULL; + } + + if (handle->head == NULL) { + return NULL; + } + + void *data = node->data; + + if (handle->head == handle->tail) { + /* Its the last node in the list */ + handle->head = NULL; + handle->tail = NULL; + } else if (handle->head == node) { + handle->head = node->next_node; + handle->head->prev_node = NULL; + } else if (handle->tail == node) { + handle->tail = node->prev_node; + handle->tail->next_node = NULL; + } else { + /* Its somewhere in the middle of the list */ + node->next_node->prev_node = node->prev_node; + node->prev_node->next_node = node->next_node; + } + + pceplib_free(PCEPLIB_INFRA, node); + (handle->num_entries)--; + + return data; +} diff --git a/pceplib/pcep_utils_double_linked_list.h b/pceplib/pcep_utils_double_linked_list.h new file mode 100644 index 0000000000..4fe01726ad --- /dev/null +++ b/pceplib/pcep_utils_double_linked_list.h @@ -0,0 +1,72 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Brady Johnson <brady@voltanet.io> + * + */ + + +#ifndef PCEP_UTILS_INCLUDE_PCEP_UTILS_DOUBLE_LINKED_LIST_H_ +#define PCEP_UTILS_INCLUDE_PCEP_UTILS_DOUBLE_LINKED_LIST_H_ + +typedef struct double_linked_list_node_ { + struct double_linked_list_node_ *prev_node; + struct double_linked_list_node_ *next_node; + void *data; + +} double_linked_list_node; + + +typedef struct double_linked_list_ { + double_linked_list_node *head; + double_linked_list_node *tail; + unsigned int num_entries; + +} double_linked_list; + + +/* Initialize a double linked list */ +double_linked_list *dll_initialize(void); + +/* Destroy a double linked list, by freeing the handle and nodes, + * user data will not be freed, and may be leaked if not handled + * externally. */ +void dll_destroy(double_linked_list *handle); +/* Destroy a double linked list, by freeing the handle and nodes, + * and the user data. */ +void dll_destroy_with_data(double_linked_list *handle); +void dll_destroy_with_data_memtype(double_linked_list *handle, + void *data_memory_type); + +/* Creates a node and adds it as the first item in the list */ +double_linked_list_node *dll_prepend(double_linked_list *handle, void *data); + +/* Creates a node and adds it as the last item in the list */ +double_linked_list_node *dll_append(double_linked_list *handle, void *data); + +/* Delete the first node in the list, and return the data */ +void *dll_delete_first_node(double_linked_list *handle); + +/* Delete the last node in the list, and return the data */ +void *dll_delete_last_node(double_linked_list *handle); + +/* Delete the designated node in the list, and return the data */ +void *dll_delete_node(double_linked_list *handle, + double_linked_list_node *node); + +#endif /* PCEP_UTILS_INCLUDE_PCEP_UTILS_DOUBLE_LINKED_LIST_H_ */ diff --git a/pceplib/pcep_utils_logging.c b/pceplib/pcep_utils_logging.c new file mode 100644 index 0000000000..65e1abbc03 --- /dev/null +++ b/pceplib/pcep_utils_logging.c @@ -0,0 +1,82 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Brady Johnson <brady@voltanet.io> + * + */ + + +#include <stdarg.h> +#include <stdio.h> +#include "pcep_utils_logging.h" + +/* Forward declaration */ +int pcep_stdout_logger(int priority, const char *format, va_list args); + +static pcep_logger_func logger_func = pcep_stdout_logger; +static int logging_level_ = LOG_INFO; + +void register_logger(pcep_logger_func logger) +{ + logger_func = logger; +} + +void set_logging_level(int level) +{ + logging_level_ = level; +} + +int get_logging_level() +{ + return logging_level_; +} + +void pcep_log(int priority, const char *format, ...) +{ + va_list va; + va_start(va, format); + logger_func(priority, format, va); + va_end(va); +} + +void pcep_log_hexbytes(int priority, const char *message, const uint8_t *bytes, + uint8_t bytes_len) +{ + char byte_str[2048] = {0}; + int i = 0; + + snprintf(byte_str, 2048, "%s ", message); + for (; i < bytes_len; i++) { + snprintf(byte_str, 2048, "%02x ", bytes[i]); + } + snprintf(byte_str, 2048, "\n"); + + pcep_log(priority, "%s", byte_str); +} + +/* Defined with a return type to match the FRR logging signature. + * Assuming glibc printf() is thread-safe. */ +int pcep_stdout_logger(int priority, const char *format, va_list args) +{ + if (priority <= logging_level_) { + vprintf(format, args); + printf("\n"); + } + + return 0; +} diff --git a/pceplib/pcep_utils_logging.h b/pceplib/pcep_utils_logging.h new file mode 100644 index 0000000000..24ea495bd8 --- /dev/null +++ b/pceplib/pcep_utils_logging.h @@ -0,0 +1,66 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Brady Johnson <brady@voltanet.io> + * + */ + + +#ifndef PCEP_UTILS_INCLUDE_PCEP_UTILS_LOGGING_H_ +#define PCEP_UTILS_INCLUDE_PCEP_UTILS_LOGGING_H_ + +#include <syslog.h> /* Logging levels */ +#include <stdarg.h> /* va_list */ +#include <stdint.h> /* uint8_t */ + +/* + * The logging defined here i intended to provide the infrastructure to + * be able to plug-in an external logger, primarily the FRR logger. There + * will be a default internal logger implemented that will write to stdout, + * but any other advanced logging features should be implemented externally. + */ + +/* Only the following logging levels from syslog.h should be used: + * + * LOG_DEBUG - For all messages that are enabled by optional debugging + * features, typically preceded by "if (IS...DEBUG...)" + * LOG_INFO - Information that may be of interest, but + * everything seems to be working properly. + * LOG_NOTICE - Only for message pertaining to daemon startup or shutdown. + * LOG_WARNING - Warning conditions: unexpected events, but the daemon + * believes it can continue to operate correctly. + * LOG_ERR - Error situations indicating malfunctions. + * Probably requires attention. + */ + + +/* The signature of this logger function is the same as the FRR logger */ +typedef int (*pcep_logger_func)(int, const char *, va_list); +void register_logger(pcep_logger_func logger); + +/* These functions only take affect when using the internal stdout logger */ +void set_logging_level(int level); +int get_logging_level(void); + +/* Log messages either to a previously registered + * logger or to the internal default stdout logger. */ +void pcep_log(int priority, const char *format, ...); +void pcep_log_hexbytes(int priority, const char *message, const uint8_t *bytes, + uint8_t bytes_len); + +#endif /* PCEP_UTILS_INCLUDE_PCEP_UTILS_LOGGING_H_ */ diff --git a/pceplib/pcep_utils_memory.c b/pceplib/pcep_utils_memory.c new file mode 100644 index 0000000000..7362e3433b --- /dev/null +++ b/pceplib/pcep_utils_memory.c @@ -0,0 +1,220 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Brady Johnson <brady@voltanet.io> + * + */ + +#include <stdlib.h> +#include <string.h> + +#include "pcep_utils_logging.h" +#include "pcep_utils_memory.h" + +/* Set default values for memory function pointers */ +static pceplib_malloc_func mfunc = NULL; +static pceplib_calloc_func cfunc = NULL; +static pceplib_realloc_func rfunc = NULL; +static pceplib_strdup_func sfunc = NULL; +static pceplib_free_func ffunc = NULL; + +/* Internal memory types */ +struct pceplib_memory_type pceplib_infra_mt = { + .memory_type_name = "PCEPlib Infrastructure memory", + .total_bytes_allocated = 0, + .num_allocates = 0, + .total_bytes_freed = 0, + .num_frees = 0}; +struct pceplib_memory_type pceplib_messages_mt = { + .memory_type_name = "PCEPlib Messages memory", + .total_bytes_allocated = 0, + .num_allocates = 0, + .total_bytes_freed = 0, + .num_frees = 0}; + +/* The memory type pointers default to the internal memory types */ +void *PCEPLIB_INFRA = &pceplib_infra_mt; +void *PCEPLIB_MESSAGES = &pceplib_messages_mt; + +/* Initialize memory function pointers and memory type pointers */ +bool pceplib_memory_initialize(void *pceplib_infra_mt, + void *pceplib_messages_mt, + pceplib_malloc_func mf, pceplib_calloc_func cf, + pceplib_realloc_func rf, pceplib_strdup_func sf, + pceplib_free_func ff) +{ + PCEPLIB_INFRA = (pceplib_infra_mt ? pceplib_infra_mt : PCEPLIB_INFRA); + PCEPLIB_MESSAGES = + (pceplib_messages_mt ? pceplib_messages_mt : PCEPLIB_MESSAGES); + + mfunc = (mf ? mf : mfunc); + cfunc = (cf ? cf : cfunc); + rfunc = (rf ? rf : rfunc); + sfunc = (sf ? sf : sfunc); + ffunc = (ff ? ff : ffunc); + + return true; +} + +void pceplib_memory_reset() +{ + pceplib_infra_mt.total_bytes_allocated = 0; + pceplib_infra_mt.num_allocates = 0; + pceplib_infra_mt.total_bytes_freed = 0; + pceplib_infra_mt.num_frees = 0; + + pceplib_messages_mt.total_bytes_allocated = 0; + pceplib_messages_mt.num_allocates = 0; + pceplib_messages_mt.total_bytes_freed = 0; + pceplib_messages_mt.num_frees = 0; +} + +void pceplib_memory_dump() +{ + if (PCEPLIB_INFRA) { + pcep_log( + LOG_INFO, + "%s: Memory Type [%s] Total [allocs, alloc bytes, frees] [%d, %d, %d]", + __func__, + ((struct pceplib_memory_type *)PCEPLIB_INFRA) + ->memory_type_name, + ((struct pceplib_memory_type *)PCEPLIB_INFRA) + ->num_allocates, + ((struct pceplib_memory_type *)PCEPLIB_INFRA) + ->total_bytes_allocated, + ((struct pceplib_memory_type *)PCEPLIB_INFRA) + ->num_frees); + } + + if (PCEPLIB_MESSAGES) { + pcep_log( + LOG_INFO, + "%s: Memory Type [%s] Total [allocs, alloc bytes, frees] [%d, %d, %d]", + __func__, + ((struct pceplib_memory_type *)PCEPLIB_MESSAGES) + ->memory_type_name, + ((struct pceplib_memory_type *)PCEPLIB_MESSAGES) + ->num_allocates, + ((struct pceplib_memory_type *)PCEPLIB_MESSAGES) + ->total_bytes_allocated, + ((struct pceplib_memory_type *)PCEPLIB_MESSAGES) + ->num_frees); + } +} + +/* PCEPlib memory functions: + * They either call the supplied function pointers, or use the internal + * implementations, which just increment simple counters and call the + * C stdlib memory implementations. */ + +void *pceplib_malloc(void *mem_type, size_t size) +{ + if (mfunc == NULL) { + if (mem_type != NULL) { + ((struct pceplib_memory_type *)mem_type) + ->total_bytes_allocated += size; + ((struct pceplib_memory_type *)mem_type) + ->num_allocates++; + } + + return malloc(size); + } else { + return mfunc(mem_type, size); + } +} + +void *pceplib_calloc(void *mem_type, size_t size) +{ + if (cfunc == NULL) { + if (mem_type != NULL) { + ((struct pceplib_memory_type *)mem_type) + ->total_bytes_allocated += size; + ((struct pceplib_memory_type *)mem_type) + ->num_allocates++; + } + + return calloc(1, size); + } else { + return cfunc(mem_type, size); + } +} + +void *pceplib_realloc(void *mem_type, void *ptr, size_t size) +{ + if (rfunc == NULL) { + if (mem_type != NULL) { + /* TODO should add previous allocated bytes to + * total_bytes_freed */ + ((struct pceplib_memory_type *)mem_type) + ->total_bytes_allocated += size; + ((struct pceplib_memory_type *)mem_type) + ->num_allocates++; + } + + return realloc(ptr, size); + } else { + return rfunc(mem_type, ptr, size); + } +} + +void *pceplib_strdup(void *mem_type, const char *str) +{ + if (sfunc == NULL) { + if (mem_type != NULL) { + ((struct pceplib_memory_type *)mem_type) + ->total_bytes_allocated += strlen(str); + ((struct pceplib_memory_type *)mem_type) + ->num_allocates++; + } + + return strdup(str); + } else { + return sfunc(mem_type, str); + } +} + +void pceplib_free(void *mem_type, void *ptr) +{ + if (ffunc == NULL) { + if (mem_type != NULL) { + /* TODO in order to increment total_bytes_freed, we need + * to keep track of the bytes allocated per pointer. + * Currently not implemented. */ + ((struct pceplib_memory_type *)mem_type)->num_frees++; + if (((struct pceplib_memory_type *)mem_type) + ->num_allocates + < ((struct pceplib_memory_type *)mem_type) + ->num_frees) { + pcep_log( + LOG_ERR, + "%s: pceplib_free MT N_Alloc < N_Free: MemType [%s] NumAllocates [%d] NumFrees [%d]", + __func__, + ((struct pceplib_memory_type *)mem_type) + ->memory_type_name, + ((struct pceplib_memory_type *)mem_type) + ->num_allocates, + ((struct pceplib_memory_type *)mem_type) + ->num_frees); + } + } + + return free(ptr); + } else { + return ffunc(mem_type, ptr); + } +} diff --git a/pceplib/pcep_utils_memory.h b/pceplib/pcep_utils_memory.h new file mode 100644 index 0000000000..4624a91a1c --- /dev/null +++ b/pceplib/pcep_utils_memory.h @@ -0,0 +1,89 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Brady Johnson <brady@voltanet.io> + * + */ + +#ifndef PCEP_UTILS_INCLUDE_PCEP_UTILS_MEMORY_H_ +#define PCEP_UTILS_INCLUDE_PCEP_UTILS_MEMORY_H_ + +#include <stdbool.h> +#include <stddef.h> +#include <stdint.h> + +/* This module is intended to be used primarily with FRR's memory module, + * which has memory groups and memory types, although any memory infrastructure + * can be used that has memory types or the memory types in this module can be + * set to NULL. The PCEPlib can be used stand-alone, in which case the simple + * internal memory type system will be used. + */ + +/* These memory function pointers are modeled after the memory functions + * in frr/lib/memory.h */ +typedef void *(*pceplib_malloc_func)(void *mem_type, size_t size); +typedef void *(*pceplib_calloc_func)(void *mem_type, size_t size); +typedef void *(*pceplib_realloc_func)(void *mem_type, void *ptr, size_t size); +typedef void *(*pceplib_strdup_func)(void *mem_type, const char *str); +typedef void (*pceplib_free_func)(void *mem_type, void *ptr); + +/* Either an internal pceplib_memory_type pointer + * or could be an FRR memory type pointer */ +extern void *PCEPLIB_INFRA; +extern void *PCEPLIB_MESSAGES; + +/* Internal PCEPlib memory type */ +struct pceplib_memory_type { + char memory_type_name[64]; + uint32_t total_bytes_allocated; + uint32_t num_allocates; + uint32_t total_bytes_freed; /* currently not used */ + uint32_t num_frees; +}; + +/* Initialize this module by passing in the 2 memory types used in the PCEPlib + * and by passing in the different memory allocation/free function pointers. + * Any of these parameters can be NULL, in which case an internal implementation + * will be used. + */ +bool pceplib_memory_initialize(void *pceplib_infra_mt, + void *pceplib_messages_mt, + pceplib_malloc_func mfunc, + pceplib_calloc_func cfunc, + pceplib_realloc_func rfunc, + pceplib_strdup_func sfunc, + pceplib_free_func ffunc); + +/* Reset the internal allocation/free counters. Used mainly for internal + * testing. */ +void pceplib_memory_reset(void); +void pceplib_memory_dump(void); + +/* Memory functions to be used throughout the PCEPlib. Internally, these + * functions will either used the function pointers passed in via + * pceplib_memory_initialize() or a simple internal implementation. The + * internal implementations just increment the internal memory type + * counters and call the C stdlib memory functions. + */ +void *pceplib_malloc(void *mem_type, size_t size); +void *pceplib_calloc(void *mem_type, size_t size); +void *pceplib_realloc(void *mem_type, void *ptr, size_t size); +void *pceplib_strdup(void *mem_type, const char *str); +void pceplib_free(void *mem_type, void *ptr); + +#endif /* PCEP_UTILS_INCLUDE_PCEP_UTILS_MEMORY_H_ */ diff --git a/pceplib/pcep_utils_ordered_list.c b/pceplib/pcep_utils_ordered_list.c new file mode 100644 index 0000000000..f5c7f70240 --- /dev/null +++ b/pceplib/pcep_utils_ordered_list.c @@ -0,0 +1,322 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Brady Johnson <brady@voltanet.io> + * + */ + + +#include <stdio.h> +#include <string.h> + +#include "pcep_utils_logging.h" +#include "pcep_utils_memory.h" +#include "pcep_utils_ordered_list.h" + +/* Compare function that simply compares pointers. + * return: + * < 0 if new_entry < list_entry + * == 0 if new_entry == list_entry (new_entry will be inserted after + * list_entry) > 0 if new_entry > list_entry + */ +int pointer_compare_function(void *list_entry, void *new_entry) +{ + return (char *)new_entry - (char *)list_entry; +} + +ordered_list_handle *ordered_list_initialize(ordered_compare_function func_ptr) +{ + ordered_list_handle *handle = + pceplib_malloc(PCEPLIB_INFRA, sizeof(ordered_list_handle)); + memset(handle, 0, sizeof(ordered_list_handle)); + handle->head = NULL; + handle->num_entries = 0; + handle->compare_function = func_ptr; + + return handle; +} + + +/* free all the ordered_list_node resources and the ordered_list_handle. + * it is assumed that the user is responsible fore freeing the data + * pointed to by the nodes. + */ +void ordered_list_destroy(ordered_list_handle *handle) +{ + if (handle == NULL) { + return; + } + + ordered_list_node *node = handle->head; + ordered_list_node *next; + + while (node != NULL) { + next = node->next_node; + pceplib_free(PCEPLIB_INFRA, node); + node = next; + } + + pceplib_free(PCEPLIB_INFRA, handle); +} + + +ordered_list_node *ordered_list_add_node(ordered_list_handle *handle, + void *data) +{ + if (handle == NULL) { + pcep_log( + LOG_WARNING, + "%s: ordered_list_add_node, the list has not been initialized", + __func__); + return NULL; + } + handle->num_entries++; + + ordered_list_node *new_node = + pceplib_malloc(PCEPLIB_INFRA, sizeof(ordered_list_node)); + memset(new_node, 0, sizeof(ordered_list_node)); + new_node->data = data; + new_node->next_node = NULL; + + /* check if its an empty list */ + if (handle->head == NULL) { + handle->head = new_node; + + return new_node; + } + + ordered_list_node *prev_node = handle->head; + ordered_list_node *node = prev_node; + int compare_result; + + while (node != NULL) { + compare_result = handle->compare_function(node->data, data); + if (compare_result < 0) { + /* insert the node */ + new_node->next_node = node; + if (handle->head == node) { + /* add it at the beginning of the list */ + handle->head = new_node; + } else { + prev_node->next_node = new_node; + } + + return new_node; + } + + /* keep searching with the next node in the list */ + prev_node = node; + node = node->next_node; + } + + /* at the end of the list, add it here */ + prev_node->next_node = new_node; + + return new_node; +} + + +ordered_list_node *ordered_list_find2(ordered_list_handle *handle, void *data, + ordered_compare_function compare_func) +{ + if (handle == NULL) { + pcep_log( + LOG_WARNING, + "%s: ordered_list_find2, the list has not been initialized", + __func__); + return NULL; + } + + ordered_list_node *node = handle->head; + int compare_result; + + while (node != NULL) { + compare_result = compare_func(node->data, data); + if (compare_result == 0) { + return node; + } else { + node = node->next_node; + } + } + + return NULL; +} + + +ordered_list_node *ordered_list_find(ordered_list_handle *handle, void *data) +{ + if (handle == NULL) { + pcep_log( + LOG_WARNING, + "%s: ordered_list_find, the list has not been initialized", + __func__); + return NULL; + } + + return ordered_list_find2(handle, data, handle->compare_function); +} + + +void *ordered_list_remove_first_node(ordered_list_handle *handle) +{ + if (handle == NULL) { + pcep_log( + LOG_WARNING, + "%s: ordered_list_remove_first_node, the list has not been initialized", + __func__); + return NULL; + } + + if (handle->head == NULL) { + return NULL; + } + handle->num_entries--; + + void *data = handle->head->data; + ordered_list_node *next_node = handle->head->next_node; + pceplib_free(PCEPLIB_INFRA, handle->head); + handle->head = next_node; + + return data; +} + + +void * +ordered_list_remove_first_node_equals2(ordered_list_handle *handle, void *data, + ordered_compare_function compare_func) +{ + if (handle == NULL) { + pcep_log( + LOG_WARNING, + "%s: ordered_list_remove_first_node_equals2, the list has not been initialized", + __func__); + return NULL; + } + + if (handle->head == NULL) { + return NULL; + } + + ordered_list_node *prev_node = handle->head; + ordered_list_node *node = prev_node; + bool keep_walking = true; + void *return_data = NULL; + int compare_result; + + while (node != NULL && keep_walking) { + compare_result = compare_func(node->data, data); + if (compare_result == 0) { + return_data = node->data; + keep_walking = false; + handle->num_entries--; + + /* adjust the corresponding pointers accordingly */ + if (handle->head == node) { + /* its the first node in the list */ + handle->head = node->next_node; + } else { + prev_node->next_node = node->next_node; + } + + pceplib_free(PCEPLIB_INFRA, node); + } else { + prev_node = node; + node = node->next_node; + } + } + + return return_data; +} + + +void *ordered_list_remove_first_node_equals(ordered_list_handle *handle, + void *data) +{ + if (handle == NULL) { + pcep_log( + LOG_WARNING, + "%s: ordered_list_remove_first_node_equals, the list has not been initialized", + __func__); + return NULL; + } + + return ordered_list_remove_first_node_equals2(handle, data, + handle->compare_function); +} + + +void *ordered_list_remove_node(ordered_list_handle *handle, + ordered_list_node *prev_node, + ordered_list_node *node_toRemove) +{ + if (handle == NULL) { + pcep_log( + LOG_WARNING, + "%s: ordered_list_remove_node, the list has not been initialized", + __func__); + return NULL; + } + + if (handle->head == NULL) { + return NULL; + } + + void *return_data = node_toRemove->data; + handle->num_entries--; + + if (node_toRemove == handle->head) { + handle->head = node_toRemove->next_node; + } else { + prev_node->next_node = node_toRemove->next_node; + } + + pceplib_free(PCEPLIB_INFRA, node_toRemove); + + return return_data; +} + +void *ordered_list_remove_node2(ordered_list_handle *handle, + ordered_list_node *node_to_remove) +{ + if (handle == NULL) { + pcep_log( + LOG_WARNING, + "%s: ordered_list_remove_node2, the list has not been initialized", + __func__); + return NULL; + } + + if (handle->head == NULL) { + return NULL; + } + + ordered_list_node *node = handle->head; + ordered_list_node *prev_node = handle->head; + + while (node != NULL) { + if (node == node_to_remove) { + return (ordered_list_remove_node(handle, prev_node, + node)); + } else { + prev_node = node; + node = node->next_node; + } + } + + return NULL; +} diff --git a/pceplib/pcep_utils_ordered_list.h b/pceplib/pcep_utils_ordered_list.h new file mode 100644 index 0000000000..ec132dc164 --- /dev/null +++ b/pceplib/pcep_utils_ordered_list.h @@ -0,0 +1,109 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Brady Johnson <brady@voltanet.io> + * + */ + + +#ifndef INCLUDE_PCEPUTILSORDEREDLIST_H_ +#define INCLUDE_PCEPUTILSORDEREDLIST_H_ + +#include <stdbool.h> + +typedef struct ordered_list_node_ { + struct ordered_list_node_ *next_node; + void *data; + +} ordered_list_node; + +/* The implementation of this function will receive a pointer to the + * new data to be inserted and a pointer to the list_entry, and should + * return: + * < 0 if new_entry < list_entry + * == 0 if new_entry == list_entry (new_entry will be inserted after + * list_entry) > 0 if new_entry > list_entry + */ +typedef int (*ordered_compare_function)(void *list_entry, void *new_entry); + +/* Compare function that compares pointers */ +int pointer_compare_function(void *list_entry, void *new_entry); + +typedef struct ordered_list_handle_ { + ordered_list_node *head; + unsigned int num_entries; + ordered_compare_function compare_function; + +} ordered_list_handle; + +ordered_list_handle *ordered_list_initialize(ordered_compare_function func_ptr); +void ordered_list_destroy(ordered_list_handle *handle); + +/* Add a new ordered_list_node to the list, using the ordered_compare_function + * to determine where in the list to add it. The newly created ordered_list_node + * will be returned. + */ +ordered_list_node *ordered_list_add_node(ordered_list_handle *handle, + void *data); + +/* Find an entry in the ordered_list using the ordered_compare_function to + * compare the data passed in. + * Return the node if found, NULL otherwise. + */ +ordered_list_node *ordered_list_find(ordered_list_handle *handle, void *data); + +/* The same as the previous function, but with a specific orderedComparefunction + */ +ordered_list_node *ordered_list_find2(ordered_list_handle *handle, void *data, + ordered_compare_function compare_func); + +/* Remove the first entry in the list and return the data it points to. + * Will return NULL if the handle is NULL or if the list is empty. + */ +void *ordered_list_remove_first_node(ordered_list_handle *handle); + +/* Remove the first entry in the list that has the same data, using the + * ordered_compare_function, and return the data it points to. + * Will return NULL if the handle is NULL or if the list is empty or + * if no entry is found that equals data. + */ +void *ordered_list_remove_first_node_equals(ordered_list_handle *handle, + void *data); + +/* The same as the previous function, but with a specific orderedComparefunction + */ +void *ordered_list_remove_first_node_equals2(ordered_list_handle *handle, + void *data, + ordered_compare_function func_ptr); + +/* Remove the node "node_to_remove" and adjust the "prev_node" pointers + * accordingly, returning the data pointed to by "node_to_remove". Will return + * NULL if the handle is NULL or if the list is empty. + */ +void *ordered_list_remove_node(ordered_list_handle *handle, + ordered_list_node *prev_node, + ordered_list_node *node_to_remove); + +/* Remove the node "node_to_remove" by searching for it in the entire list, + * returning the data pointed to by "node_to_remove". + * Will return NULL if the handle is NULL or if the list is empty. + */ +void *ordered_list_remove_node2(ordered_list_handle *handle, + ordered_list_node *node_to_remove); + +#endif /* INCLUDE_PCEPUTILSORDEREDLIST_H_ */ diff --git a/pceplib/pcep_utils_queue.c b/pceplib/pcep_utils_queue.c new file mode 100644 index 0000000000..e8c3f2be0e --- /dev/null +++ b/pceplib/pcep_utils_queue.c @@ -0,0 +1,150 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Brady Johnson <brady@voltanet.io> + * + */ + + +#include <stdbool.h> +#include <stdio.h> +#include <string.h> + +#include "pcep_utils_logging.h" +#include "pcep_utils_memory.h" +#include "pcep_utils_queue.h" + +queue_handle *queue_initialize() +{ + /* Set the max_entries to 0 to disable it */ + return queue_initialize_with_size(0); +} + + +queue_handle *queue_initialize_with_size(unsigned int max_entries) +{ + queue_handle *handle = + pceplib_malloc(PCEPLIB_INFRA, sizeof(queue_handle)); + memset(handle, 0, sizeof(queue_handle)); + handle->max_entries = max_entries; + + return handle; +} + + +void queue_destroy(queue_handle *handle) +{ + if (handle == NULL) { + pcep_log( + LOG_DEBUG, + "%s: queue_destroy, the queue has not been initialized", + __func__); + return; + } + + while (queue_dequeue(handle) != NULL) { + } + pceplib_free(PCEPLIB_INFRA, handle); +} + + +void queue_destroy_with_data(queue_handle *handle) +{ + if (handle == NULL) { + pcep_log( + LOG_DEBUG, + "%s: queue_destroy_with_data, the queue has not been initialized", + __func__); + return; + } + + void *data = queue_dequeue(handle); + while (data != NULL) { + pceplib_free(PCEPLIB_INFRA, data); + data = queue_dequeue(handle); + } + pceplib_free(PCEPLIB_INFRA, handle); +} + + +queue_node *queue_enqueue(queue_handle *handle, void *data) +{ + if (handle == NULL) { + pcep_log( + LOG_DEBUG, + "%s: queue_enqueue, the queue has not been initialized", + __func__); + return NULL; + } + + if (handle->max_entries > 0 + && handle->num_entries >= handle->max_entries) { + pcep_log( + LOG_DEBUG, + "%s: queue_enqueue, cannot enqueue: max entries hit [%u]", + handle->num_entries); + return NULL; + } + + queue_node *new_node = + pceplib_malloc(PCEPLIB_INFRA, sizeof(queue_node)); + memset(new_node, 0, sizeof(queue_node)); + new_node->data = data; + new_node->next_node = NULL; + + (handle->num_entries)++; + if (handle->head == NULL) { + /* its the first entry in the queue */ + handle->head = handle->tail = new_node; + } else { + handle->tail->next_node = new_node; + handle->tail = new_node; + } + + return new_node; +} + + +void *queue_dequeue(queue_handle *handle) +{ + if (handle == NULL) { + pcep_log( + LOG_DEBUG, + "%s: queue_dequeue, the queue has not been initialized", + __func__); + return NULL; + } + + if (handle->head == NULL) { + return NULL; + } + + void *node_data = handle->head->data; + queue_node *node = handle->head; + (handle->num_entries)--; + if (handle->head == handle->tail) { + /* its the last entry in the queue */ + handle->head = handle->tail = NULL; + } else { + handle->head = node->next_node; + } + + pceplib_free(PCEPLIB_INFRA, node); + + return node_data; +} diff --git a/pceplib/pcep_utils_queue.h b/pceplib/pcep_utils_queue.h new file mode 100644 index 0000000000..838067640e --- /dev/null +++ b/pceplib/pcep_utils_queue.h @@ -0,0 +1,49 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Brady Johnson <brady@voltanet.io> + * + */ + + +#ifndef INCLUDE_PCEPUTILSQUEUE_H_ +#define INCLUDE_PCEPUTILSQUEUE_H_ + +typedef struct queue_node_ { + struct queue_node_ *next_node; + void *data; + +} queue_node; + +typedef struct queue_handle_ { + queue_node *head; + queue_node *tail; + unsigned int num_entries; + /* Set to 0 to disable */ + unsigned int max_entries; + +} queue_handle; + +queue_handle *queue_initialize(void); +queue_handle *queue_initialize_with_size(unsigned int max_entries); +void queue_destroy(queue_handle *handle); +void queue_destroy_with_data(queue_handle *handle); +queue_node *queue_enqueue(queue_handle *handle, void *data); +void *queue_dequeue(queue_handle *handle); + +#endif /* INCLUDE_PCEPUTILSQUEUE_H_ */ diff --git a/pceplib/subdir.am b/pceplib/subdir.am new file mode 100644 index 0000000000..eee2ec28c7 --- /dev/null +++ b/pceplib/subdir.am @@ -0,0 +1,62 @@ +if PATHD_PCEP + +noinst_LTLIBRARIES = pceplib/libpcep_pcc.la pceplib/libsocket_comm_mock.la +pceplib_libpcep_pcc_la_CFLAGS = -fPIC +pceplib_libpcep_pcc_la_SOURCES = pceplib/pcep_msg_messages.c \ + pceplib/pcep_msg_objects.c \ + pceplib/pcep_msg_tlvs.c \ + pceplib/pcep_msg_tools.c \ + pceplib/pcep_msg_messages_encoding.c \ + pceplib/pcep_msg_objects_encoding.c \ + pceplib/pcep_msg_tlvs_encoding.c \ + pceplib/pcep_msg_object_error_types.c \ + pceplib/pcep_pcc_api.c \ + pceplib/pcep_session_logic.c \ + pceplib/pcep_session_logic_loop.c \ + pceplib/pcep_session_logic_states.c \ + pceplib/pcep_session_logic_counters.c \ + pceplib/pcep_socket_comm_loop.c \ + pceplib/pcep_socket_comm.c \ + pceplib/pcep_timers_event_loop.c \ + pceplib/pcep_timers.c \ + pceplib/pcep_utils_counters.c \ + pceplib/pcep_utils_double_linked_list.c \ + pceplib/pcep_utils_logging.c \ + pceplib/pcep_utils_memory.c \ + pceplib/pcep_utils_ordered_list.c \ + pceplib/pcep_utils_queue.c + +if PATHD_PCEP_TEST +# SocketComm Mock library used for Unit Testing +pceplib_libsocket_comm_mock_la_SOURCES = pceplib/pcep_socket_comm_mock.c +endif + +noinst_HEADERS += pceplib/pcep.h \ + pceplib/pcep_msg_encoding.h \ + pceplib/pcep_msg_messages.h \ + pceplib/pcep_msg_object_error_types.h \ + pceplib/pcep_msg_objects.h \ + pceplib/pcep_msg_tlvs.h \ + pceplib/pcep_msg_tools.h \ + pceplib/pcep_pcc_api.h \ + pceplib/pcep_session_logic.h \ + pceplib/pcep_session_logic_internals.h \ + pceplib/pcep_socket_comm.h \ + pceplib/pcep_socket_comm_internals.h \ + pceplib/pcep_socket_comm_loop.h \ + pceplib/pcep_socket_comm_mock.h \ + pceplib/pcep_timer_internals.h \ + pceplib/pcep_timers.h \ + pceplib/pcep_timers_event_loop.h \ + pceplib/pcep_utils_counters.h \ + pceplib/pcep_utils_double_linked_list.h \ + pceplib/pcep_utils_logging.h \ + pceplib/pcep_utils_memory.h \ + pceplib/pcep_utils_ordered_list.h \ + pceplib/pcep_utils_queue.h + +noinst_PROGRAMS += pceplib/pcep_pcc +pceplib_pcep_pcc_SOURCES = pceplib/pcep_pcc.c +pceplib_pcep_pcc_LDADD = pceplib/libpcep_pcc.la lib/libfrr.la -lpthread + +endif diff --git a/pceplib/test/pcep_msg_messages_test.c b/pceplib/test/pcep_msg_messages_test.c new file mode 100644 index 0000000000..b8984a42bc --- /dev/null +++ b/pceplib/test/pcep_msg_messages_test.c @@ -0,0 +1,514 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Brady Johnson <brady@voltanet.io> + * + */ + + +#include <stdlib.h> + +#include <CUnit/CUnit.h> + +#include "pcep_msg_encoding.h" +#include "pcep_msg_messages.h" +#include "pcep_msg_objects.h" +#include "pcep_msg_tools.h" +#include "pcep_utils_double_linked_list.h" +#include "pcep_utils_memory.h" +#include "pcep_msg_messages_test.h" + +/* + * Notice: + * All of these message Unit Tests encode the created messages by explicitly + * calling pcep_encode_message() thus testing the message creation and the + * message encoding. + */ + +static struct pcep_versioning *versioning = NULL; + +int pcep_messages_test_suite_setup(void) +{ + pceplib_memory_reset(); + return 0; +} + +int pcep_messages_test_suite_teardown(void) +{ + printf("\n"); + pceplib_memory_dump(); + return 0; +} + +void pcep_messages_test_setup() +{ + versioning = create_default_pcep_versioning(); +} + +void pcep_messages_test_teardown() +{ + destroy_pcep_versioning(versioning); +} + +void test_pcep_msg_create_open() +{ + uint8_t keepalive = 30; + uint8_t deadtimer = 60; + uint8_t sid = 255; + + struct pcep_message *message = + pcep_msg_create_open(keepalive, deadtimer, sid); + CU_ASSERT_PTR_NOT_NULL(message); + pcep_encode_message(message, versioning); + CU_ASSERT_PTR_NOT_NULL(message->msg_header); + CU_ASSERT_PTR_NOT_NULL(message->obj_list); + CU_ASSERT_EQUAL(message->obj_list->num_entries, 1); + CU_ASSERT_EQUAL(message->encoded_message_length, + MESSAGE_HEADER_LENGTH + + pcep_object_get_length(PCEP_OBJ_CLASS_OPEN, + PCEP_OBJ_TYPE_OPEN)); + CU_ASSERT_EQUAL(message->msg_header->type, PCEP_TYPE_OPEN); + CU_ASSERT_EQUAL(message->msg_header->pcep_version, + PCEP_MESSAGE_HEADER_VERSION); + + /* Just check the class and type, the rest of the hdr fields + * are verified in pcep-objects-test.c */ + struct pcep_object_open *open_obj = + (struct pcep_object_open *)message->obj_list->head->data; + CU_ASSERT_EQUAL(open_obj->header.object_class, PCEP_OBJ_CLASS_OPEN); + CU_ASSERT_EQUAL(open_obj->header.object_type, PCEP_OBJ_TYPE_OPEN); + + CU_ASSERT_EQUAL(open_obj->open_deadtimer, deadtimer); + CU_ASSERT_EQUAL(open_obj->open_keepalive, keepalive); + CU_ASSERT_EQUAL(open_obj->open_sid, sid); + CU_ASSERT_EQUAL(open_obj->open_version, PCEP_OBJECT_OPEN_VERSION); + pcep_msg_free_message(message); +} + + +void test_pcep_msg_create_request() +{ + /* First test with NULL objects */ + struct pcep_message *message = + pcep_msg_create_request(NULL, NULL, NULL); + CU_ASSERT_PTR_NULL(message); + + /* 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 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); + + CU_ASSERT_PTR_NOT_NULL(message); + pcep_encode_message(message, versioning); + CU_ASSERT_PTR_NOT_NULL(message->msg_header); + CU_ASSERT_PTR_NOT_NULL(message->obj_list); + CU_ASSERT_EQUAL(message->obj_list->num_entries, 2); + CU_ASSERT_EQUAL( + message->encoded_message_length, + MESSAGE_HEADER_LENGTH + + pcep_object_get_length_by_hdr(&rp_obj->header) + + pcep_object_get_length_by_hdr(&ipv4_obj->header)); + CU_ASSERT_EQUAL(message->msg_header->type, PCEP_TYPE_PCREQ); + CU_ASSERT_EQUAL(message->msg_header->pcep_version, + PCEP_MESSAGE_HEADER_VERSION); + pcep_msg_free_message(message); + + /* Test IPv6 */ + rp_obj = pcep_obj_create_rp(0, false, false, false, false, 10, NULL); + struct in6_addr src_addr_ipv6, dst_addr_ipv6; + struct pcep_object_endpoints_ipv6 *ipv6_obj = + pcep_obj_create_endpoint_ipv6(&src_addr_ipv6, &dst_addr_ipv6); + message = pcep_msg_create_request_ipv6(rp_obj, ipv6_obj, NULL); + + CU_ASSERT_PTR_NOT_NULL(message); + pcep_encode_message(message, versioning); + CU_ASSERT_PTR_NOT_NULL(message->msg_header); + CU_ASSERT_PTR_NOT_NULL(message->obj_list); + CU_ASSERT_EQUAL(message->obj_list->num_entries, 2); + CU_ASSERT_EQUAL( + message->encoded_message_length, + MESSAGE_HEADER_LENGTH + + pcep_object_get_length_by_hdr(&rp_obj->header) + + pcep_object_get_length_by_hdr(&ipv6_obj->header)); + CU_ASSERT_EQUAL(message->msg_header->type, PCEP_TYPE_PCREQ); + CU_ASSERT_EQUAL(message->msg_header->pcep_version, + PCEP_MESSAGE_HEADER_VERSION); + pcep_msg_free_message(message); + + /* The objects get deleted with the message, so they need to be created + * again */ + rp_obj = pcep_obj_create_rp(0, false, false, false, false, 10, NULL); + ipv4_obj = pcep_obj_create_endpoint_ipv4(&src_addr, &dst_addr); + struct pcep_object_bandwidth *bandwidth_obj = + pcep_obj_create_bandwidth(4.2); + double_linked_list *obj_list = dll_initialize(); + dll_append(obj_list, bandwidth_obj); + message = pcep_msg_create_request(rp_obj, ipv4_obj, obj_list); + + CU_ASSERT_PTR_NOT_NULL(message); + pcep_encode_message(message, versioning); + CU_ASSERT_PTR_NOT_NULL(message->msg_header); + CU_ASSERT_PTR_NOT_NULL(message->obj_list); + CU_ASSERT_EQUAL(message->obj_list->num_entries, 3); + CU_ASSERT_EQUAL( + message->encoded_message_length, + MESSAGE_HEADER_LENGTH + + pcep_object_get_length_by_hdr(&rp_obj->header) + + pcep_object_get_length_by_hdr(&ipv4_obj->header) + + pcep_object_get_length_by_hdr( + &bandwidth_obj->header)); + CU_ASSERT_EQUAL(message->msg_header->type, PCEP_TYPE_PCREQ); + CU_ASSERT_EQUAL(message->msg_header->pcep_version, + PCEP_MESSAGE_HEADER_VERSION); + pcep_msg_free_message(message); +} + + +void test_pcep_msg_create_request_svec() +{ +} + + +void test_pcep_msg_create_reply_nopath() +{ + struct pcep_object_rp *rp_obj = + pcep_obj_create_rp(0, false, false, false, false, 10, NULL); + struct pcep_object_nopath *nopath_obj = pcep_obj_create_nopath( + false, false, PCEP_NOPATH_TLV_ERR_NO_TLV); + double_linked_list *obj_list = dll_initialize(); + dll_append(obj_list, nopath_obj); + + struct pcep_message *message = pcep_msg_create_reply(rp_obj, obj_list); + CU_ASSERT_PTR_NOT_NULL(message); + pcep_encode_message(message, versioning); + CU_ASSERT_PTR_NOT_NULL(message->msg_header); + CU_ASSERT_PTR_NOT_NULL(message->obj_list); + CU_ASSERT_EQUAL(message->obj_list->num_entries, 2); + CU_ASSERT_EQUAL(message->encoded_message_length, + (MESSAGE_HEADER_LENGTH + + pcep_object_get_length_by_hdr(&rp_obj->header) + + pcep_object_get_length_by_hdr(&nopath_obj->header))); + CU_ASSERT_EQUAL(message->msg_header->type, PCEP_TYPE_PCREP); + CU_ASSERT_EQUAL(message->msg_header->pcep_version, + PCEP_MESSAGE_HEADER_VERSION); + pcep_msg_free_message(message); +} + + +void test_pcep_msg_create_reply() +{ + /* First test with NULL ero and rp objects */ + struct pcep_message *message = pcep_msg_create_reply(NULL, NULL); + + CU_ASSERT_PTR_NOT_NULL(message); + pcep_encode_message(message, versioning); + CU_ASSERT_PTR_NOT_NULL(message->msg_header); + CU_ASSERT_PTR_NOT_NULL(message->obj_list); + CU_ASSERT_EQUAL(message->obj_list->num_entries, 0); + CU_ASSERT_EQUAL(message->encoded_message_length, MESSAGE_HEADER_LENGTH); + CU_ASSERT_EQUAL(message->msg_header->type, PCEP_TYPE_PCREP); + CU_ASSERT_EQUAL(message->msg_header->pcep_version, + PCEP_MESSAGE_HEADER_VERSION); + pcep_msg_free_message(message); + + double_linked_list *ero_subobj_list = dll_initialize(); + struct pcep_object_ro_subobj *ero_subobj = + (struct pcep_object_ro_subobj *) + pcep_obj_create_ro_subobj_32label(true, 1, 10); + dll_append(ero_subobj_list, ero_subobj); + struct pcep_object_ro *ero = pcep_obj_create_ero(ero_subobj_list); + + double_linked_list *object_list = dll_initialize(); + dll_append(object_list, ero); + struct pcep_object_rp *rp_obj = + pcep_obj_create_rp(0, false, false, false, false, 10, NULL); + message = pcep_msg_create_reply(rp_obj, object_list); + CU_ASSERT_PTR_NOT_NULL(message); + pcep_encode_message(message, versioning); + CU_ASSERT_PTR_NOT_NULL(message->msg_header); + CU_ASSERT_PTR_NOT_NULL(message->obj_list); + CU_ASSERT_EQUAL(message->obj_list->num_entries, 2); + CU_ASSERT_EQUAL(message->encoded_message_length, + MESSAGE_HEADER_LENGTH + + pcep_object_get_length_by_hdr(&rp_obj->header) + + OBJECT_HEADER_LENGTH + + OBJECT_RO_SUBOBJ_HEADER_LENGTH + + 6 /* size of the 32label */); + CU_ASSERT_EQUAL(message->msg_header->type, PCEP_TYPE_PCREP); + CU_ASSERT_EQUAL(message->msg_header->pcep_version, + PCEP_MESSAGE_HEADER_VERSION); + pcep_msg_free_message(message); +} + + +void test_pcep_msg_create_close() +{ + uint8_t reason = PCEP_CLOSE_REASON_UNREC_MSG; + + struct pcep_message *message = pcep_msg_create_close(reason); + CU_ASSERT_PTR_NOT_NULL(message); + pcep_encode_message(message, versioning); + CU_ASSERT_PTR_NOT_NULL(message->msg_header); + CU_ASSERT_PTR_NOT_NULL(message->obj_list); + CU_ASSERT_EQUAL(message->obj_list->num_entries, 1); + CU_ASSERT_EQUAL(message->encoded_message_length, + MESSAGE_HEADER_LENGTH + + pcep_object_get_length(PCEP_OBJ_CLASS_CLOSE, + PCEP_OBJ_TYPE_CLOSE)); + CU_ASSERT_EQUAL(message->msg_header->type, PCEP_TYPE_CLOSE); + CU_ASSERT_EQUAL(message->msg_header->pcep_version, + PCEP_MESSAGE_HEADER_VERSION); + + /* Just check the class and type, the rest of the hdr fields + * are verified in pcep-objects-test.c */ + struct pcep_object_close *close_obj = + (struct pcep_object_close *)message->obj_list->head->data; + CU_ASSERT_EQUAL(close_obj->header.object_class, PCEP_OBJ_CLASS_CLOSE); + CU_ASSERT_EQUAL(close_obj->header.object_type, PCEP_OBJ_TYPE_CLOSE); + CU_ASSERT_EQUAL(close_obj->reason, reason); + pcep_msg_free_message(message); +} + + +void test_pcep_msg_create_error() +{ + uint8_t error_type = PCEP_ERRT_RECEPTION_OF_INV_OBJECT; + uint8_t error_value = PCEP_ERRV_KEEPALIVEWAIT_TIMED_OUT; + + struct pcep_message *message = + pcep_msg_create_error(error_type, error_value); + CU_ASSERT_PTR_NOT_NULL(message); + pcep_encode_message(message, versioning); + CU_ASSERT_PTR_NOT_NULL(message->msg_header); + CU_ASSERT_PTR_NOT_NULL(message->obj_list); + CU_ASSERT_EQUAL(message->obj_list->num_entries, 1); + CU_ASSERT_EQUAL(message->encoded_message_length, + MESSAGE_HEADER_LENGTH + + pcep_object_get_length(PCEP_OBJ_CLASS_ERROR, + PCEP_OBJ_TYPE_ERROR)); + CU_ASSERT_EQUAL(message->msg_header->type, PCEP_TYPE_ERROR); + CU_ASSERT_EQUAL(message->msg_header->pcep_version, + PCEP_MESSAGE_HEADER_VERSION); + + /* Just check the class and type, the rest of the hdr fields + * are verified in pcep-objects-test.c */ + struct pcep_object_error *error_obj = + (struct pcep_object_error *)message->obj_list->head->data; + CU_ASSERT_EQUAL(error_obj->header.object_class, PCEP_OBJ_CLASS_ERROR); + CU_ASSERT_EQUAL(error_obj->header.object_type, PCEP_OBJ_TYPE_ERROR); + + CU_ASSERT_EQUAL(error_obj->error_type, error_type); + CU_ASSERT_EQUAL(error_obj->error_value, error_value); + pcep_msg_free_message(message); +} + + +void test_pcep_msg_create_keepalive() +{ + struct pcep_message *message = pcep_msg_create_keepalive(); + CU_ASSERT_PTR_NOT_NULL(message); + pcep_encode_message(message, versioning); + CU_ASSERT_PTR_NOT_NULL(message->msg_header); + CU_ASSERT_PTR_NOT_NULL(message->obj_list); + CU_ASSERT_EQUAL(message->obj_list->num_entries, 0); + CU_ASSERT_EQUAL(message->encoded_message_length, MESSAGE_HEADER_LENGTH); + CU_ASSERT_EQUAL(message->msg_header->type, PCEP_TYPE_KEEPALIVE); + CU_ASSERT_EQUAL(message->msg_header->pcep_version, + PCEP_MESSAGE_HEADER_VERSION); + pcep_msg_free_message(message); +} + +void test_pcep_msg_create_report() +{ + double_linked_list *obj_list = dll_initialize(); + + /* Should return NULL if obj_list is empty */ + struct pcep_message *message = pcep_msg_create_report(NULL); + CU_ASSERT_PTR_NULL(message); + + struct pcep_object_lsp *lsp = + pcep_obj_create_lsp(100, PCEP_LSP_OPERATIONAL_UP, true, true, + true, true, true, NULL); + dll_append(obj_list, lsp); + message = pcep_msg_create_report(obj_list); + CU_ASSERT_PTR_NOT_NULL(message); + pcep_encode_message(message, versioning); + CU_ASSERT_PTR_NOT_NULL(message->msg_header); + CU_ASSERT_PTR_NOT_NULL(message->obj_list); + CU_ASSERT_EQUAL(message->obj_list->num_entries, 1); + CU_ASSERT_EQUAL(message->encoded_message_length, + MESSAGE_HEADER_LENGTH + + lsp->header.encoded_object_length); + CU_ASSERT_EQUAL(message->msg_header->type, PCEP_TYPE_REPORT); + CU_ASSERT_EQUAL(message->msg_header->pcep_version, + PCEP_MESSAGE_HEADER_VERSION); + + pcep_msg_free_message(message); +} + +void test_pcep_msg_create_update() +{ + double_linked_list *obj_list = dll_initialize(); + double_linked_list *ero_subobj_list = dll_initialize(); + + struct pcep_message *message = pcep_msg_create_update(NULL); + CU_ASSERT_PTR_NULL(message); + + /* 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 = + pcep_obj_create_lsp(100, PCEP_LSP_OPERATIONAL_UP, true, true, + true, true, true, NULL); + dll_append(ero_subobj_list, pcep_obj_create_ro_subobj_asn(0x0102)); + struct pcep_object_ro *ero = pcep_obj_create_ero(ero_subobj_list); + + /* Should return NULL if obj_list does not have 3 entries */ + dll_append(obj_list, srp); + dll_append(obj_list, lsp); + message = pcep_msg_create_update(obj_list); + 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); + CU_ASSERT_PTR_NOT_NULL(message->msg_header); + CU_ASSERT_PTR_NOT_NULL(message->obj_list); + CU_ASSERT_EQUAL(message->obj_list->num_entries, 3); + CU_ASSERT_EQUAL(message->encoded_message_length, + MESSAGE_HEADER_LENGTH + + srp->header.encoded_object_length + + lsp->header.encoded_object_length + + ero->header.encoded_object_length); + CU_ASSERT_EQUAL(message->msg_header->type, PCEP_TYPE_UPDATE); + CU_ASSERT_EQUAL(message->msg_header->pcep_version, + PCEP_MESSAGE_HEADER_VERSION); + + pcep_msg_free_message(message); +} + +void test_pcep_msg_create_initiate() +{ + double_linked_list *obj_list = dll_initialize(); + double_linked_list *ero_subobj_list = dll_initialize(); + + /* 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 = + pcep_obj_create_lsp(100, PCEP_LSP_OPERATIONAL_UP, true, true, + true, true, true, NULL); + dll_append(ero_subobj_list, pcep_obj_create_ro_subobj_asn(0x0102)); + struct pcep_object_ro *ero = pcep_obj_create_ero(ero_subobj_list); + + /* Should return NULL if obj_list does not have 2 entries */ + 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); + message = pcep_msg_create_initiate(obj_list); + CU_ASSERT_PTR_NOT_NULL(message); + pcep_encode_message(message, versioning); + CU_ASSERT_PTR_NOT_NULL(message->msg_header); + CU_ASSERT_PTR_NOT_NULL(message->obj_list); + CU_ASSERT_EQUAL(message->obj_list->num_entries, 3); + CU_ASSERT_EQUAL(message->encoded_message_length, + MESSAGE_HEADER_LENGTH + + srp->header.encoded_object_length + + lsp->header.encoded_object_length + + ero->header.encoded_object_length); + CU_ASSERT_EQUAL(message->msg_header->type, PCEP_TYPE_INITIATE); + CU_ASSERT_EQUAL(message->msg_header->pcep_version, + PCEP_MESSAGE_HEADER_VERSION); + + pcep_msg_free_message(message); +} + +void test_pcep_msg_create_notify(void) +{ + struct pcep_object_notify *notify_obj = pcep_obj_create_notify( + PCEP_NOTIFY_TYPE_PENDING_REQUEST_CANCELLED, + PCEP_NOTIFY_VALUE_PCC_CANCELLED_REQUEST); + + /* Should return NULL if the notify obj is empty */ + struct pcep_message *message = pcep_msg_create_notify(NULL, NULL); + CU_ASSERT_PTR_NULL(message); + + message = pcep_msg_create_notify(notify_obj, NULL); + CU_ASSERT_PTR_NOT_NULL(message); + pcep_encode_message(message, versioning); + CU_ASSERT_PTR_NOT_NULL(message->obj_list); + CU_ASSERT_EQUAL(message->obj_list->num_entries, 1); + CU_ASSERT_EQUAL(message->encoded_message_length, + MESSAGE_HEADER_LENGTH + + notify_obj->header.encoded_object_length); + CU_ASSERT_EQUAL(message->msg_header->type, PCEP_TYPE_PCNOTF); + CU_ASSERT_EQUAL(message->msg_header->pcep_version, + PCEP_MESSAGE_HEADER_VERSION); + + pcep_msg_free_message(message); + + struct pcep_object_rp *rp_obj = + pcep_obj_create_rp(0, false, false, false, false, 10, NULL); + double_linked_list *obj_list = dll_initialize(); + dll_append(obj_list, rp_obj); + notify_obj = pcep_obj_create_notify( + PCEP_NOTIFY_TYPE_PENDING_REQUEST_CANCELLED, + PCEP_NOTIFY_VALUE_PCC_CANCELLED_REQUEST); + + message = pcep_msg_create_notify(notify_obj, obj_list); + CU_ASSERT_PTR_NOT_NULL(message); + pcep_encode_message(message, versioning); + CU_ASSERT_PTR_NOT_NULL(message->obj_list); + CU_ASSERT_EQUAL(message->obj_list->num_entries, 2); + CU_ASSERT_EQUAL(message->encoded_message_length, + MESSAGE_HEADER_LENGTH + + notify_obj->header.encoded_object_length + + rp_obj->header.encoded_object_length); + CU_ASSERT_EQUAL(message->msg_header->type, PCEP_TYPE_PCNOTF); + CU_ASSERT_EQUAL(message->msg_header->pcep_version, + PCEP_MESSAGE_HEADER_VERSION); + + pcep_msg_free_message(message); +} diff --git a/pceplib/test/pcep_msg_messages_test.h b/pceplib/test/pcep_msg_messages_test.h new file mode 100644 index 0000000000..a3295c74eb --- /dev/null +++ b/pceplib/test/pcep_msg_messages_test.h @@ -0,0 +1,48 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Javier Garcia <javier.garcia@voltanet.io> + * + */ + +/* + * Timer definitions to be used internally by the pcep_timers library. + */ + +#ifndef PCEP_MSG_MSG_TEST_H_ +#define PCEP_MSG_MSG_TEST_H_ + +/* functions to be tested from pcep-messages.c */ +int pcep_messages_test_suite_setup(void); +int pcep_messages_test_suite_teardown(void); +void pcep_messages_test_setup(void); +void pcep_messages_test_teardown(void); +void test_pcep_msg_create_open(void); +void test_pcep_msg_create_request(void); +void test_pcep_msg_create_request_svec(void); +void test_pcep_msg_create_reply_nopath(void); +void test_pcep_msg_create_reply(void); +void test_pcep_msg_create_close(void); +void test_pcep_msg_create_error(void); +void test_pcep_msg_create_keepalive(void); +void test_pcep_msg_create_report(void); +void test_pcep_msg_create_update(void); +void test_pcep_msg_create_initiate(void); +void test_pcep_msg_create_notify(void); + +#endif /* PCEPTIMERINTERNALS_H_ */ diff --git a/pceplib/test/pcep_msg_messages_tests.c b/pceplib/test/pcep_msg_messages_tests.c new file mode 100644 index 0000000000..bd85a16530 --- /dev/null +++ b/pceplib/test/pcep_msg_messages_tests.c @@ -0,0 +1,256 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Brady Johnson <brady@voltanet.io> + * + */ + + +#include <CUnit/Basic.h> +#include <CUnit/CUnit.h> +#include <CUnit/TestDB.h> + +#include "pcep_msg_messages_test.h" +#include "pcep_msg_tools_test.h" +#include "pcep_msg_object_error_types.h" +#include "pcep_msg_object_error_types_test.h" +#include "pcep_msg_tlvs_test.h" +#include "pcep_msg_objects_test.h" + + +int main(int argc, char **argv) +{ + /* Unused parameters cause compilation warnings */ + (void)argc; + (void)argv; + + CU_initialize_registry(); + + CU_pSuite messages_suite = CU_add_suite_with_setup_and_teardown( + "PCEP Messages Test Suite", pcep_messages_test_suite_setup, + pcep_messages_test_suite_teardown, /* suite setup and cleanup + function pointers */ + pcep_messages_test_setup, pcep_messages_test_teardown); + CU_add_test(messages_suite, "test_pcep_msg_create_open", + test_pcep_msg_create_open); + CU_add_test(messages_suite, "test_pcep_msg_create_request", + test_pcep_msg_create_request); + CU_add_test(messages_suite, "test_pcep_msg_create_request_svec", + test_pcep_msg_create_request_svec); + CU_add_test(messages_suite, "test_pcep_msg_create_reply_nopath", + test_pcep_msg_create_reply_nopath); + CU_add_test(messages_suite, "test_pcep_msg_create_reply", + test_pcep_msg_create_reply); + CU_add_test(messages_suite, "test_pcep_msg_create_close", + test_pcep_msg_create_close); + CU_add_test(messages_suite, "test_pcep_msg_create_error", + test_pcep_msg_create_error); + CU_add_test(messages_suite, "test_pcep_msg_create_keepalive", + test_pcep_msg_create_keepalive); + CU_add_test(messages_suite, "test_pcep_msg_create_report", + test_pcep_msg_create_report); + CU_add_test(messages_suite, "test_pcep_msg_create_update", + test_pcep_msg_create_update); + CU_add_test(messages_suite, "test_pcep_msg_create_initiate", + test_pcep_msg_create_initiate); + CU_add_test(messages_suite, "test_pcep_msg_create_notify", + test_pcep_msg_create_notify); + + CU_pSuite tlvs_suite = CU_add_suite_with_setup_and_teardown( + "PCEP TLVs Test Suite", pcep_tlvs_test_suite_setup, + pcep_tlvs_test_suite_teardown, /* suite setup and cleanup + function pointers */ + pcep_tlvs_test_setup, pcep_tlvs_test_teardown); + CU_add_test(tlvs_suite, "test_pcep_tlv_create_stateful_pce_capability", + test_pcep_tlv_create_stateful_pce_capability); + CU_add_test(tlvs_suite, "test_pcep_tlv_create_speaker_entity_id", + test_pcep_tlv_create_speaker_entity_id); + CU_add_test(tlvs_suite, "test_pcep_tlv_create_lsp_db_version", + test_pcep_tlv_create_lsp_db_version); + CU_add_test(tlvs_suite, "test_pcep_tlv_create_path_setup_type", + test_pcep_tlv_create_path_setup_type); + CU_add_test(tlvs_suite, + "test_pcep_tlv_create_path_setup_type_capability", + test_pcep_tlv_create_path_setup_type_capability); + CU_add_test(tlvs_suite, "test_pcep_tlv_create_sr_pce_capability", + test_pcep_tlv_create_sr_pce_capability); + CU_add_test(tlvs_suite, "test_pcep_tlv_create_symbolic_path_name", + test_pcep_tlv_create_symbolic_path_name); + CU_add_test(tlvs_suite, "test_pcep_tlv_create_ipv4_lsp_identifiers", + test_pcep_tlv_create_ipv4_lsp_identifiers); + CU_add_test(tlvs_suite, "test_pcep_tlv_create_ipv6_lsp_identifiers", + test_pcep_tlv_create_ipv6_lsp_identifiers); + CU_add_test(tlvs_suite, "test_pcep_tlv_create_srpag_pol_id_ipv4", + test_pcep_tlv_create_srpag_pol_id_ipv4); + CU_add_test(tlvs_suite, "test_pcep_tlv_create_srpag_pol_id_ipv6", + test_pcep_tlv_create_srpag_pol_id_ipv6); + CU_add_test(tlvs_suite, "test_pcep_tlv_create_srpag_pol_name", + test_pcep_tlv_create_srpag_pol_name); + CU_add_test(tlvs_suite, "test_pcep_tlv_create_srpag_cp_id", + test_pcep_tlv_create_srpag_cp_id); + CU_add_test(tlvs_suite, "test_pcep_tlv_create_srpag_cp_pref", + test_pcep_tlv_create_srpag_cp_pref); + CU_add_test(tlvs_suite, "test_pcep_tlv_create_lsp_error_code", + test_pcep_tlv_create_lsp_error_code); + CU_add_test(tlvs_suite, "test_pcep_tlv_create_rsvp_ipv4_error_spec", + test_pcep_tlv_create_rsvp_ipv4_error_spec); + CU_add_test(tlvs_suite, "test_pcep_tlv_create_rsvp_ipv6_error_spec", + test_pcep_tlv_create_rsvp_ipv6_error_spec); + CU_add_test(tlvs_suite, "test_pcep_tlv_create_nopath_vector", + test_pcep_tlv_create_nopath_vector); + CU_add_test(tlvs_suite, "test_pcep_tlv_create_arbitrary", + test_pcep_tlv_create_arbitrary); + + CU_pSuite objects_suite = CU_add_suite_with_setup_and_teardown( + "PCEP Objects Test Suite", pcep_objects_test_suite_setup, + pcep_objects_test_suite_teardown, /* suite setup and cleanup + function pointers */ + pcep_objects_test_setup, pcep_objects_test_teardown); + CU_add_test(objects_suite, "test_pcep_obj_create_open", + test_pcep_obj_create_open); + CU_add_test(objects_suite, "test_pcep_obj_create_open", + test_pcep_obj_create_open_with_tlvs); + CU_add_test(objects_suite, "test_pcep_obj_create_rp", + test_pcep_obj_create_rp); + CU_add_test(objects_suite, "test_pcep_obj_create_nopath", + test_pcep_obj_create_nopath); + CU_add_test(objects_suite, "test_pcep_obj_create_enpoint_ipv4", + test_pcep_obj_create_endpoint_ipv4); + CU_add_test(objects_suite, "test_pcep_obj_create_enpoint_ipv6", + test_pcep_obj_create_endpoint_ipv6); + CU_add_test(objects_suite, "test_pcep_obj_create_association_ipv4", + test_pcep_obj_create_association_ipv4); + CU_add_test(objects_suite, "test_pcep_obj_create_association_ipv6", + test_pcep_obj_create_association_ipv6); + CU_add_test(objects_suite, "test_pcep_obj_create_bandwidth", + test_pcep_obj_create_bandwidth); + CU_add_test(objects_suite, "test_pcep_obj_create_metric", + test_pcep_obj_create_metric); + CU_add_test(objects_suite, "test_pcep_obj_create_lspa", + test_pcep_obj_create_lspa); + CU_add_test(objects_suite, "test_pcep_obj_create_svec", + test_pcep_obj_create_svec); + CU_add_test(objects_suite, "test_pcep_obj_create_error", + test_pcep_obj_create_error); + CU_add_test(objects_suite, "test_pcep_obj_create_close", + test_pcep_obj_create_close); + CU_add_test(objects_suite, "test_pcep_obj_create_srp", + test_pcep_obj_create_srp); + CU_add_test(objects_suite, "test_pcep_obj_create_lsp", + test_pcep_obj_create_lsp); + CU_add_test(objects_suite, "test_pcep_obj_create_vendor_info", + test_pcep_obj_create_vendor_info); + + CU_add_test(objects_suite, "test_pcep_obj_create_ero", + test_pcep_obj_create_ero); + CU_add_test(objects_suite, "test_pcep_obj_create_rro", + test_pcep_obj_create_rro); + CU_add_test(objects_suite, "test_pcep_obj_create_iro", + test_pcep_obj_create_iro); + CU_add_test(objects_suite, "test_pcep_obj_create_ro_subobj_ipv4", + test_pcep_obj_create_ro_subobj_ipv4); + CU_add_test(objects_suite, "test_pcep_obj_create_ro_subobj_ipv6", + test_pcep_obj_create_ro_subobj_ipv6); + CU_add_test(objects_suite, "test_pcep_obj_create_ro_subobj_unnum", + test_pcep_obj_create_ro_subobj_unnum); + CU_add_test(objects_suite, "test_pcep_obj_create_ro_subobj_32label", + test_pcep_obj_create_ro_subobj_32label); + CU_add_test(objects_suite, "test_pcep_obj_create_ro_subobj_asn", + test_pcep_obj_create_ro_subobj_asn); + + CU_add_test(objects_suite, "test_pcep_obj_create_ro_subobj_sr_nonai", + test_pcep_obj_create_ro_subobj_sr_nonai); + CU_add_test(objects_suite, + "test_pcep_obj_create_ro_subobj_sr_ipv4_node", + test_pcep_obj_create_ro_subobj_sr_ipv4_node); + CU_add_test(objects_suite, + "test_pcep_obj_create_ro_subobj_sr_ipv6_node", + test_pcep_obj_create_ro_subobj_sr_ipv6_node); + CU_add_test(objects_suite, "test_pcep_obj_create_ro_subobj_sr_ipv4_adj", + test_pcep_obj_create_ro_subobj_sr_ipv4_adj); + CU_add_test(objects_suite, "test_pcep_obj_create_ro_subobj_sr_ipv6_adj", + test_pcep_obj_create_ro_subobj_sr_ipv6_adj); + CU_add_test(objects_suite, + "test_pcep_obj_create_ro_subobj_sr_unnumbered_ipv4_adj", + test_pcep_obj_create_ro_subobj_sr_unnumbered_ipv4_adj); + CU_add_test(objects_suite, + "test_pcep_obj_create_ro_subobj_sr_linklocal_ipv6_adj", + test_pcep_obj_create_ro_subobj_sr_linklocal_ipv6_adj); + + CU_pSuite tools_suite = CU_add_suite_with_setup_and_teardown( + "PCEP Tools Test Suite", pcep_tools_test_suite_setup, + pcep_tools_test_suite_teardown, pcep_tools_test_setup, + pcep_tools_test_teardown); + CU_add_test(tools_suite, "test_pcep_msg_read_pcep_initiate", + test_pcep_msg_read_pcep_initiate); + CU_add_test(tools_suite, "test_pcep_msg_read_pcep_initiate2", + test_pcep_msg_read_pcep_initiate2); + CU_add_test(tools_suite, "test_pcep_msg_read_pcep_update", + test_pcep_msg_read_pcep_update); + CU_add_test(tools_suite, "test_pcep_msg_read_pcep_open", + test_pcep_msg_read_pcep_open); + CU_add_test(tools_suite, "test_pcep_msg_read_pcep_open_initiate", + test_pcep_msg_read_pcep_open_initiate); + CU_add_test(tools_suite, "test_validate_message_header", + test_validate_message_header); + CU_add_test(tools_suite, "test_validate_message_objects", + test_validate_message_objects); + CU_add_test(tools_suite, "test_validate_message_objects_invalid", + test_validate_message_objects_invalid); + CU_add_test(tools_suite, "test_pcep_msg_read_pcep_open_cisco_pce", + test_pcep_msg_read_pcep_open_cisco_pce); + CU_add_test(tools_suite, "test_pcep_msg_read_pcep_update_cisco_pce", + test_pcep_msg_read_pcep_update_cisco_pce); + CU_add_test(tools_suite, "test_pcep_msg_read_pcep_report_cisco_pcc", + test_pcep_msg_read_pcep_report_cisco_pcc); + CU_add_test(tools_suite, "test_pcep_msg_read_pcep_initiate_cisco_pcc", + test_pcep_msg_read_pcep_initiate_cisco_pcc); + + CU_pSuite obj_errors_suite = CU_add_suite_with_setup_and_teardown( + "PCEP Object Error Types Test Suite", + pcep_object_error_types_test_suite_setup, + pcep_object_error_types_test_suite_teardown, + pcep_object_error_types_test_setup, + pcep_object_error_types_test_teardown); + CU_add_test(obj_errors_suite, "test_get_error_type_str", + test_get_error_type_str); + CU_add_test(obj_errors_suite, "test_get_error_value_str", + test_get_error_value_str); + + CU_basic_set_mode(CU_BRM_VERBOSE); + CU_basic_run_tests(); + CU_FailureRecord *failure_record = CU_get_failure_list(); + if (failure_record != NULL) { + printf("\nFailed tests:\n\t [Suite] [Test] [File:line-number]\n"); + do { + printf("\t [%s] [%s] [%s:%d]\n", + failure_record->pSuite->pName, + failure_record->pTest->pName, + failure_record->strFileName, + failure_record->uiLineNumber); + failure_record = failure_record->pNext; + + } while (failure_record != NULL); + } + + CU_pRunSummary run_summary = CU_get_run_summary(); + int result = run_summary->nTestsFailed; + CU_cleanup_registry(); + + return result; +} diff --git a/pceplib/test/pcep_msg_object_error_types_test.c b/pceplib/test/pcep_msg_object_error_types_test.c new file mode 100644 index 0000000000..7275eaf098 --- /dev/null +++ b/pceplib/test/pcep_msg_object_error_types_test.c @@ -0,0 +1,84 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Brady Johnson <brady@voltanet.io> + * + */ + + +#include <stdio.h> + +#include <CUnit/CUnit.h> + +#include "pcep_msg_object_error_types.h" +#include "pcep_msg_object_error_types_test.h" +#include "pcep_utils_logging.h" +#include "pcep_utils_memory.h" + +int pcep_object_error_types_test_suite_setup(void) +{ + pceplib_memory_reset(); + set_logging_level(LOG_DEBUG); + return 0; +} + +int pcep_object_error_types_test_suite_teardown(void) +{ + printf("\n"); + pceplib_memory_dump(); + return 0; +} + +void pcep_object_error_types_test_setup(void) +{ +} + +void pcep_object_error_types_test_teardown(void) +{ +} + +void test_get_error_type_str() +{ + const char *error_type_str; + int i = 0; + for (; i < MAX_ERROR_TYPE; i++) { + error_type_str = get_error_type_str(i); + CU_ASSERT_PTR_NOT_NULL(error_type_str); + } + + CU_ASSERT_PTR_NULL(get_error_type_str(-1)); + CU_ASSERT_PTR_NULL(get_error_type_str(MAX_ERROR_TYPE)); +} + +void test_get_error_value_str() +{ + const char *error_value_str; + int i = 0, j = 0; + + for (; i < MAX_ERROR_TYPE; i++) { + for (; j < MAX_ERROR_VALUE; j++) { + error_value_str = get_error_value_str(i, j); + CU_ASSERT_PTR_NOT_NULL(error_value_str); + } + } + + CU_ASSERT_PTR_NULL(get_error_value_str(-1, 0)); + CU_ASSERT_PTR_NULL(get_error_value_str(MAX_ERROR_TYPE, 0)); + CU_ASSERT_PTR_NULL(get_error_value_str(1, -1)); + CU_ASSERT_PTR_NULL(get_error_value_str(1, MAX_ERROR_VALUE)); +} diff --git a/pceplib/test/pcep_msg_object_error_types_test.h b/pceplib/test/pcep_msg_object_error_types_test.h new file mode 100644 index 0000000000..863517d1e3 --- /dev/null +++ b/pceplib/test/pcep_msg_object_error_types_test.h @@ -0,0 +1,37 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Javier Garcia <javier.garcia@voltanet.io> + * + */ + +/* + * Timer definitions to be used internally by the pcep_timers library. + */ + +#ifndef PCEP_MSG_OBJECT_ERROR_TYPES_TEST_ +#define PCEP_MSG_OBJECT_ERROR_TYPES_TEST_ + +int pcep_object_error_types_test_suite_setup(void); +int pcep_object_error_types_test_suite_teardown(void); +void pcep_object_error_types_test_setup(void); +void pcep_object_error_types_test_teardown(void); +void test_get_error_type_str(void); +void test_get_error_value_str(void); + +#endif /* PCEPTIMERINTERNALS_H_ */ diff --git a/pceplib/test/pcep_msg_objects_test.c b/pceplib/test/pcep_msg_objects_test.c new file mode 100644 index 0000000000..a4c069945c --- /dev/null +++ b/pceplib/test/pcep_msg_objects_test.c @@ -0,0 +1,1289 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Brady Johnson <brady@voltanet.io> + * + */ + + +#include <stdlib.h> + +#include <CUnit/CUnit.h> + +#include "pcep_msg_encoding.h" +#include "pcep_msg_objects.h" +#include "pcep_msg_tools.h" +#include "pcep_utils_memory.h" +#include "pcep_msg_objects_test.h" + +/* + * Notice: + * All of these object Unit Tests encode the created objects by explicitly + * calling pcep_encode_object() thus testing the object creation and the object + * encoding. All APIs expect IPs to be in network byte order. + */ + +static struct pcep_versioning *versioning = NULL; +static uint8_t object_buf[2000]; + +void reset_objects_buffer(void); + +int pcep_objects_test_suite_setup(void) +{ + pceplib_memory_reset(); + return 0; +} + +int pcep_objects_test_suite_teardown(void) +{ + printf("\n"); + pceplib_memory_dump(); + return 0; +} + +void reset_objects_buffer() +{ + memset(object_buf, 0, 2000); +} + +void pcep_objects_test_setup() +{ + versioning = create_default_pcep_versioning(); + reset_objects_buffer(); +} + +void pcep_objects_test_teardown() +{ + destroy_pcep_versioning(versioning); +} + +/* Internal util verification function */ +static void verify_pcep_obj_header2(uint8_t obj_class, uint8_t obj_type, + uint16_t obj_length, const uint8_t *obj_buf) +{ + /* Object Header + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Object-Class | OT |Res|P|I| Object Length (bytes) | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + + /* Not using CU_ASSERT_EQUAL here, so that in case of failure, + * we can provide more info in the error message. */ + if (obj_buf[0] != obj_class) { + fprintf(stderr, + "Test failure obj_class expected [%d] found [%d]\n", + obj_class, obj_buf[0]); + CU_FAIL("Object Header Class"); + } + + uint8_t found8 = (obj_buf[1] >> 4) & 0x0f; + if (obj_type != found8) { + fprintf(stderr, + "Test failure obj_class [%d] obj_type expected [%d] found [%d]\n", + obj_class, obj_type, found8); + CU_FAIL("Object Header Type"); + } + + uint8_t exp8 = 0; + found8 = obj_buf[1] & 0x0f; + if (exp8 != found8) { + fprintf(stderr, + "Test failure obj_class [%d] flags expected [%d] found [%d]\n", + obj_class, exp8, found8); + CU_FAIL("Object Header Flags"); + } + + uint16_t found16 = ntohs(*((uint16_t *)(obj_buf + 2))); + if (obj_length != found16) { + fprintf(stderr, + "Test failure obj_class [%d] obj_length expected [%d] found [%d]\n", + obj_class, obj_length, found16); + CU_FAIL("Object Header Length"); + } +} + +/* Internal util verification function */ +static void verify_pcep_obj_header(uint8_t obj_class, uint8_t obj_type, + struct pcep_object_header *obj_hdr) +{ + verify_pcep_obj_header2(obj_class, obj_type, + pcep_object_get_length_by_hdr(obj_hdr), + obj_hdr->encoded_object); +} + +void test_pcep_obj_create_open() +{ + uint8_t deadtimer = 60; + uint8_t keepalive = 30; + uint8_t sid = 1; + + struct pcep_object_open *open = + pcep_obj_create_open(keepalive, deadtimer, sid, NULL); + + CU_ASSERT_PTR_NOT_NULL(open); + pcep_encode_object(&open->header, versioning, object_buf); + verify_pcep_obj_header(PCEP_OBJ_CLASS_OPEN, PCEP_OBJ_TYPE_OPEN, + &open->header); + + CU_ASSERT_EQUAL(open->header.encoded_object[4], + (PCEP_OBJECT_OPEN_VERSION << 5) & 0xe0); + CU_ASSERT_EQUAL(open->header.encoded_object[4] & 0x1f, 0); + CU_ASSERT_EQUAL(open->header.encoded_object[5], keepalive); + CU_ASSERT_EQUAL(open->header.encoded_object[6], deadtimer); + CU_ASSERT_EQUAL(open->header.encoded_object[7], sid); + + pcep_obj_free_object((struct pcep_object_header *)open); +} + +void test_pcep_obj_create_open_with_tlvs() +{ + uint8_t deadtimer = 60; + uint8_t keepalive = 30; + uint8_t sid = 1; + double_linked_list *tlv_list = dll_initialize(); + + struct pcep_object_tlv_stateful_pce_capability *tlv = + pcep_tlv_create_stateful_pce_capability(true, true, true, true, + true, true); + dll_append(tlv_list, tlv); + struct pcep_object_open *open = + pcep_obj_create_open(keepalive, deadtimer, sid, tlv_list); + + CU_ASSERT_PTR_NOT_NULL(open); + pcep_encode_object(&open->header, versioning, object_buf); + verify_pcep_obj_header2(PCEP_OBJ_CLASS_OPEN, PCEP_OBJ_TYPE_OPEN, + pcep_object_get_length_by_hdr(&open->header) + + sizeof(uint32_t) * 2, + open->header.encoded_object); + CU_ASSERT_PTR_NOT_NULL(open->header.tlv_list); + CU_ASSERT_EQUAL(open->header.tlv_list->num_entries, 1); + + CU_ASSERT_EQUAL(open->header.encoded_object[4], + (PCEP_OBJECT_OPEN_VERSION << 5) & 0xe0); + CU_ASSERT_EQUAL(open->header.encoded_object[4] & 0x1f, 0); + CU_ASSERT_EQUAL(open->header.encoded_object[5], keepalive); + CU_ASSERT_EQUAL(open->header.encoded_object[6], deadtimer); + CU_ASSERT_EQUAL(open->header.encoded_object[7], sid); + + pcep_obj_free_object((struct pcep_object_header *)open); +} + +void test_pcep_obj_create_rp() +{ + uint32_t reqid = 15; + uint8_t invalid_priority = 100; + uint8_t priority = 7; + + struct pcep_object_rp *rp = pcep_obj_create_rp( + invalid_priority, true, false, false, true, reqid, NULL); + CU_ASSERT_PTR_NULL(rp); + + rp = pcep_obj_create_rp(priority, true, false, false, true, reqid, + NULL); + CU_ASSERT_PTR_NOT_NULL(rp); + pcep_encode_object(&rp->header, versioning, object_buf); + verify_pcep_obj_header(PCEP_OBJ_CLASS_RP, PCEP_OBJ_TYPE_RP, + &rp->header); + + CU_ASSERT_EQUAL(rp->header.encoded_object[4], 0); + CU_ASSERT_EQUAL(rp->header.encoded_object[5], 0); + CU_ASSERT_EQUAL(rp->header.encoded_object[6], 0); + CU_ASSERT_EQUAL((rp->header.encoded_object[7] & 0x07), priority); + CU_ASSERT_TRUE(rp->header.encoded_object[7] & OBJECT_RP_FLAG_R); + CU_ASSERT_TRUE(rp->header.encoded_object[7] & OBJECT_RP_FLAG_OF); + CU_ASSERT_TRUE(rp->header.encoded_object[7] & ~OBJECT_RP_FLAG_B); + CU_ASSERT_TRUE(rp->header.encoded_object[7] & ~OBJECT_RP_FLAG_O); + CU_ASSERT_EQUAL(*((uint32_t *)(rp->header.encoded_object + 8)), + htonl(reqid)); + + pcep_obj_free_object((struct pcep_object_header *)rp); +} + +void test_pcep_obj_create_nopath() +{ + uint8_t ni = 8; + uint32_t errorcode = 42; + + struct pcep_object_nopath *nopath = + pcep_obj_create_nopath(ni, true, errorcode); + + CU_ASSERT_PTR_NOT_NULL(nopath); + pcep_encode_object(&nopath->header, versioning, object_buf); + verify_pcep_obj_header(PCEP_OBJ_CLASS_NOPATH, PCEP_OBJ_TYPE_NOPATH, + &nopath->header); + + CU_ASSERT_EQUAL(nopath->header.encoded_object[4], ni); + CU_ASSERT_TRUE(nopath->header.encoded_object[5] & OBJECT_NOPATH_FLAG_C); + CU_ASSERT_EQUAL(nopath->header.encoded_object[6], 0); + CU_ASSERT_EQUAL(nopath->header.encoded_object[7], 0); + + /* Verify the TLV */ + CU_ASSERT_PTR_NOT_NULL(nopath->header.tlv_list); + struct pcep_object_tlv_nopath_vector *tlv = + (struct pcep_object_tlv_nopath_vector *) + nopath->header.tlv_list->head->data; + CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, 4); + CU_ASSERT_EQUAL(tlv->header.type, 1); + CU_ASSERT_EQUAL(tlv->error_code, errorcode); + + CU_ASSERT_EQUAL(*((uint16_t *)(nopath->header.encoded_object + 8)), + htons(PCEP_OBJ_TLV_TYPE_NO_PATH_VECTOR)); + CU_ASSERT_EQUAL(*((uint16_t *)(nopath->header.encoded_object + 10)), + htons(4)); + CU_ASSERT_EQUAL(*((uint32_t *)(nopath->header.encoded_object + 12)), + htonl(errorcode)); + + pcep_obj_free_object((struct pcep_object_header *)nopath); +} +void test_pcep_obj_create_association_ipv4() +{ + + uint16_t all_assoc_groups = 0xffff; + struct in_addr src; + inet_pton(AF_INET, "192.168.1.2", &src); + + struct pcep_object_association_ipv4 *assoc = + pcep_obj_create_association_ipv4( + false, PCEP_ASSOCIATION_TYPE_SR_POLICY_ASSOCIATION_TYPE, + all_assoc_groups, src); + CU_ASSERT_PTR_NOT_NULL(assoc); + CU_ASSERT_EQUAL(assoc->association_type, + PCEP_ASSOCIATION_TYPE_SR_POLICY_ASSOCIATION_TYPE); + CU_ASSERT_EQUAL(assoc->association_id, all_assoc_groups); + CU_ASSERT_EQUAL(assoc->header.object_class, PCEP_OBJ_CLASS_ASSOCIATION); + CU_ASSERT_EQUAL(assoc->header.object_type, + PCEP_OBJ_TYPE_ASSOCIATION_IPV4); + CU_ASSERT_EQUAL(assoc->src.s_addr, src.s_addr); + + pcep_obj_free_object((struct pcep_object_header *)assoc); +} + +void test_pcep_obj_create_association_ipv6() +{ + uint32_t all_assoc_groups = 0xffff; + struct in6_addr src; + inet_pton(AF_INET6, "2001:db8::8a2e:370:7334", &src); + + struct pcep_object_association_ipv6 *assoc = + pcep_obj_create_association_ipv6( + false, PCEP_ASSOCIATION_TYPE_SR_POLICY_ASSOCIATION_TYPE, + all_assoc_groups, src); + CU_ASSERT_PTR_NOT_NULL(assoc); + CU_ASSERT_EQUAL(assoc->association_type, + PCEP_ASSOCIATION_TYPE_SR_POLICY_ASSOCIATION_TYPE); + CU_ASSERT_EQUAL(assoc->association_id, all_assoc_groups); + CU_ASSERT_EQUAL(assoc->header.object_class, PCEP_OBJ_CLASS_ASSOCIATION); + CU_ASSERT_EQUAL(assoc->header.object_type, + PCEP_OBJ_TYPE_ASSOCIATION_IPV6); + CU_ASSERT_EQUAL(assoc->src.__in6_u.__u6_addr32[0], + (src.__in6_u.__u6_addr32[0])); + CU_ASSERT_EQUAL(assoc->src.__in6_u.__u6_addr32[1], + (src.__in6_u.__u6_addr32[1])); + CU_ASSERT_EQUAL(assoc->src.__in6_u.__u6_addr32[2], + (src.__in6_u.__u6_addr32[2])); + CU_ASSERT_EQUAL(assoc->src.__in6_u.__u6_addr32[3], + (src.__in6_u.__u6_addr32[3])); + + pcep_obj_free_object((struct pcep_object_header *)assoc); +} + +void test_pcep_obj_create_endpoint_ipv4() +{ + struct in_addr src_ipv4, dst_ipv4; + inet_pton(AF_INET, "192.168.1.2", &src_ipv4); + inet_pton(AF_INET, "172.168.1.2", &dst_ipv4); + + struct pcep_object_endpoints_ipv4 *ipv4 = + pcep_obj_create_endpoint_ipv4(NULL, NULL); + CU_ASSERT_PTR_NULL(ipv4); + + ipv4 = pcep_obj_create_endpoint_ipv4(&src_ipv4, NULL); + CU_ASSERT_PTR_NULL(ipv4); + + ipv4 = pcep_obj_create_endpoint_ipv4(NULL, &dst_ipv4); + CU_ASSERT_PTR_NULL(ipv4); + + ipv4 = pcep_obj_create_endpoint_ipv4(&src_ipv4, &dst_ipv4); + CU_ASSERT_PTR_NOT_NULL(ipv4); + pcep_encode_object(&ipv4->header, versioning, object_buf); + verify_pcep_obj_header(PCEP_OBJ_CLASS_ENDPOINTS, + PCEP_OBJ_TYPE_ENDPOINT_IPV4, &ipv4->header); + CU_ASSERT_EQUAL(*((uint32_t *)(ipv4->header.encoded_object + 4)), + src_ipv4.s_addr); + CU_ASSERT_EQUAL(*((uint32_t *)(ipv4->header.encoded_object + 8)), + dst_ipv4.s_addr); + + pcep_obj_free_object((struct pcep_object_header *)ipv4); +} + +void test_pcep_obj_create_endpoint_ipv6() +{ + struct in6_addr src_ipv6, dst_ipv6; + inet_pton(AF_INET6, "2001:db8::8a2e:370:7334", &src_ipv6); + inet_pton(AF_INET6, "2001:db8::8a2e:370:8446", &dst_ipv6); + + struct pcep_object_endpoints_ipv6 *ipv6 = + pcep_obj_create_endpoint_ipv6(NULL, NULL); + CU_ASSERT_PTR_NULL(ipv6); + + ipv6 = pcep_obj_create_endpoint_ipv6(&src_ipv6, NULL); + CU_ASSERT_PTR_NULL(ipv6); + + ipv6 = pcep_obj_create_endpoint_ipv6(NULL, &dst_ipv6); + CU_ASSERT_PTR_NULL(ipv6); + + ipv6 = pcep_obj_create_endpoint_ipv6(&src_ipv6, &dst_ipv6); + CU_ASSERT_PTR_NOT_NULL(ipv6); + pcep_encode_object(&ipv6->header, versioning, object_buf); + verify_pcep_obj_header(PCEP_OBJ_CLASS_ENDPOINTS, + PCEP_OBJ_TYPE_ENDPOINT_IPV6, &ipv6->header); + uint32_t *uint32_ptr = (uint32_t *)(ipv6->header.encoded_object + 4); + CU_ASSERT_EQUAL(uint32_ptr[0], src_ipv6.__in6_u.__u6_addr32[0]); + CU_ASSERT_EQUAL(uint32_ptr[1], src_ipv6.__in6_u.__u6_addr32[1]); + CU_ASSERT_EQUAL(uint32_ptr[2], src_ipv6.__in6_u.__u6_addr32[2]); + CU_ASSERT_EQUAL(uint32_ptr[3], src_ipv6.__in6_u.__u6_addr32[3]); + CU_ASSERT_EQUAL(uint32_ptr[4], dst_ipv6.__in6_u.__u6_addr32[0]); + CU_ASSERT_EQUAL(uint32_ptr[5], dst_ipv6.__in6_u.__u6_addr32[1]); + CU_ASSERT_EQUAL(uint32_ptr[6], dst_ipv6.__in6_u.__u6_addr32[2]); + CU_ASSERT_EQUAL(uint32_ptr[7], dst_ipv6.__in6_u.__u6_addr32[3]); + + pcep_obj_free_object((struct pcep_object_header *)ipv6); +} + +void test_pcep_obj_create_bandwidth() +{ + /* 1.8 => binary 1.11001101 + * exponent = 127 => 0111 1111 + * fraction = 1100 1101 0000 0000 0000 000 */ + float bandwidth = 1.8; + + struct pcep_object_bandwidth *bw = pcep_obj_create_bandwidth(bandwidth); + + CU_ASSERT_PTR_NOT_NULL(bw); + pcep_encode_object(&bw->header, versioning, object_buf); + verify_pcep_obj_header(PCEP_OBJ_CLASS_BANDWIDTH, + PCEP_OBJ_TYPE_BANDWIDTH_REQ, &bw->header); + CU_ASSERT_EQUAL(bw->header.encoded_object[4], 0x3f); + CU_ASSERT_EQUAL(bw->header.encoded_object[5], 0xe6); + CU_ASSERT_EQUAL(bw->header.encoded_object[6], 0x66); + CU_ASSERT_EQUAL(bw->header.encoded_object[7], 0x66); + + pcep_obj_free_object((struct pcep_object_header *)bw); +} + +void test_pcep_obj_create_metric() +{ + uint8_t type = PCEP_METRIC_BORDER_NODE_COUNT; + /* https://en.wikipedia.org/wiki/IEEE_754-1985 + * 0.15625 = 1/8 + 1/32 = binary 0.00101 = 1.01 x 10^-3 + * Exponent bias = 127, so exponent = (127-3) = 124 = 0111 1100 + * Sign Exponent Fraction + * (8 bits) (23 bits) + * 0.15625 => 0 0111 1100 010 0000 ... 0000 */ + float value = 0.15625; + + struct pcep_object_metric *metric = + pcep_obj_create_metric(type, true, true, value); + + CU_ASSERT_PTR_NOT_NULL(metric); + pcep_encode_object(&metric->header, versioning, object_buf); + verify_pcep_obj_header(PCEP_OBJ_CLASS_METRIC, PCEP_OBJ_TYPE_METRIC, + &metric->header); + CU_ASSERT_EQUAL(metric->header.encoded_object[4], 0); + CU_ASSERT_EQUAL(metric->header.encoded_object[5], 0); + CU_ASSERT_TRUE(metric->header.encoded_object[6] & OBJECT_METRIC_FLAC_B); + CU_ASSERT_TRUE(metric->header.encoded_object[6] & OBJECT_METRIC_FLAC_C); + CU_ASSERT_EQUAL(metric->header.encoded_object[7], type); + /* See comments above for explanation of these values */ + CU_ASSERT_EQUAL(metric->header.encoded_object[8], 0x3e); + CU_ASSERT_EQUAL(metric->header.encoded_object[9], 0x20); + CU_ASSERT_EQUAL(metric->header.encoded_object[10], 0x00); + CU_ASSERT_EQUAL(metric->header.encoded_object[11], 0x00); + + pcep_obj_free_object((struct pcep_object_header *)metric); +} + +void test_pcep_obj_create_lspa() +{ + uint32_t exclude_any = 10; + uint32_t include_any = 20; + uint32_t include_all = 30; + uint8_t prio = 0; + uint8_t hold_prio = 10; + + struct pcep_object_lspa *lspa = pcep_obj_create_lspa( + exclude_any, include_any, include_all, prio, hold_prio, true); + + CU_ASSERT_PTR_NOT_NULL(lspa); + pcep_encode_object(&lspa->header, versioning, object_buf); + verify_pcep_obj_header(PCEP_OBJ_CLASS_LSPA, PCEP_OBJ_TYPE_LSPA, + &lspa->header); + uint32_t *uint32_ptr = (uint32_t *)(lspa->header.encoded_object + 4); + CU_ASSERT_EQUAL(uint32_ptr[0], htonl(exclude_any)); + CU_ASSERT_EQUAL(uint32_ptr[1], htonl(include_any)); + CU_ASSERT_EQUAL(uint32_ptr[2], htonl(include_all)); + CU_ASSERT_EQUAL(lspa->header.encoded_object[16], prio); + CU_ASSERT_EQUAL(lspa->header.encoded_object[17], hold_prio); + CU_ASSERT_TRUE(lspa->header.encoded_object[18] & OBJECT_LSPA_FLAG_L); + CU_ASSERT_EQUAL(lspa->header.encoded_object[19], 0); + + pcep_obj_free_object((struct pcep_object_header *)lspa); +} + +void test_pcep_obj_create_svec() +{ + struct pcep_object_svec *svec = + pcep_obj_create_svec(true, true, true, NULL); + CU_ASSERT_PTR_NULL(svec); + + double_linked_list *id_list = dll_initialize(); + uint32_t *uint32_ptr = + pceplib_malloc(PCEPLIB_MESSAGES, sizeof(uint32_t)); + *uint32_ptr = 10; + dll_append(id_list, uint32_ptr); + + svec = pcep_obj_create_svec(true, true, true, id_list); + CU_ASSERT_PTR_NOT_NULL(svec); + pcep_encode_object(&svec->header, versioning, object_buf); + verify_pcep_obj_header2(PCEP_OBJ_CLASS_SVEC, PCEP_OBJ_TYPE_SVEC, + (OBJECT_HEADER_LENGTH + sizeof(uint32_t) * 2), + svec->header.encoded_object); + CU_ASSERT_EQUAL(svec->header.encoded_object[4], 0); + CU_ASSERT_EQUAL(svec->header.encoded_object[5], 0); + CU_ASSERT_EQUAL(svec->header.encoded_object[6], 0); + CU_ASSERT_TRUE(svec->header.encoded_object[7] & OBJECT_SVEC_FLAG_S); + CU_ASSERT_TRUE(svec->header.encoded_object[7] & OBJECT_SVEC_FLAG_N); + CU_ASSERT_TRUE(svec->header.encoded_object[7] & OBJECT_SVEC_FLAG_L); + CU_ASSERT_EQUAL(*((uint32_t *)(svec->header.encoded_object + 8)), + htonl(*uint32_ptr)); + + pcep_obj_free_object((struct pcep_object_header *)svec); +} + +void test_pcep_obj_create_error() +{ + uint8_t error_type = PCEP_ERRT_SESSION_FAILURE; + uint8_t error_value = PCEP_ERRV_RECVD_INVALID_OPEN_MSG; + + struct pcep_object_error *error = + pcep_obj_create_error(error_type, error_value); + + CU_ASSERT_PTR_NOT_NULL(error); + pcep_encode_object(&error->header, versioning, object_buf); + verify_pcep_obj_header(PCEP_OBJ_CLASS_ERROR, PCEP_OBJ_TYPE_ERROR, + &error->header); + CU_ASSERT_EQUAL(error->header.encoded_object[4], 0); + CU_ASSERT_EQUAL(error->header.encoded_object[5], 0); + CU_ASSERT_EQUAL(error->header.encoded_object[6], error_type); + CU_ASSERT_EQUAL(error->header.encoded_object[7], error_value); + + pcep_obj_free_object((struct pcep_object_header *)error); +} + +void test_pcep_obj_create_close() +{ + uint8_t reason = PCEP_CLOSE_REASON_DEADTIMER; + + struct pcep_object_close *close = pcep_obj_create_close(reason); + + CU_ASSERT_PTR_NOT_NULL(close); + pcep_encode_object(&close->header, versioning, object_buf); + verify_pcep_obj_header(PCEP_OBJ_CLASS_CLOSE, PCEP_OBJ_TYPE_CLOSE, + &close->header); + CU_ASSERT_EQUAL(close->header.encoded_object[4], 0); + CU_ASSERT_EQUAL(close->header.encoded_object[5], 0); + CU_ASSERT_EQUAL(close->header.encoded_object[6], 0); + CU_ASSERT_EQUAL(close->header.encoded_object[7], reason); + + pcep_obj_free_object((struct pcep_object_header *)close); +} + +void test_pcep_obj_create_srp() +{ + bool lsp_remove = true; + uint32_t srp_id_number = 0x89674523; + struct pcep_object_srp *srp = + pcep_obj_create_srp(lsp_remove, srp_id_number, NULL); + + CU_ASSERT_PTR_NOT_NULL(srp); + pcep_encode_object(&srp->header, versioning, object_buf); + verify_pcep_obj_header(PCEP_OBJ_CLASS_SRP, PCEP_OBJ_TYPE_SRP, + &srp->header); + CU_ASSERT_EQUAL(srp->header.encoded_object[4], 0); + CU_ASSERT_EQUAL(srp->header.encoded_object[5], 0); + CU_ASSERT_EQUAL(srp->header.encoded_object[6], 0); + CU_ASSERT_TRUE(srp->header.encoded_object[7] & OBJECT_SRP_FLAG_R); + CU_ASSERT_EQUAL(*((uint32_t *)(srp->header.encoded_object + 8)), + htonl(srp_id_number)); + + pcep_obj_free_object((struct pcep_object_header *)srp); +} + +void test_pcep_obj_create_lsp() +{ + uint32_t plsp_id = 0x000fffff; + enum pcep_lsp_operational_status status = PCEP_LSP_OPERATIONAL_ACTIVE; + bool c_flag = true; + bool a_flag = true; + bool r_flag = true; + bool s_flag = true; + bool d_flag = true; + + /* Should return for invalid plsp_id */ + struct pcep_object_lsp *lsp = + pcep_obj_create_lsp(0x001fffff, status, c_flag, a_flag, r_flag, + s_flag, d_flag, NULL); + CU_ASSERT_PTR_NULL(lsp); + + /* Should return for invalid status */ + lsp = pcep_obj_create_lsp(plsp_id, 8, c_flag, a_flag, r_flag, s_flag, + d_flag, NULL); + CU_ASSERT_PTR_NULL(lsp); + + lsp = pcep_obj_create_lsp(plsp_id, status, c_flag, a_flag, r_flag, + s_flag, d_flag, NULL); + + CU_ASSERT_PTR_NOT_NULL(lsp); + pcep_encode_object(&lsp->header, versioning, object_buf); + verify_pcep_obj_header(PCEP_OBJ_CLASS_LSP, PCEP_OBJ_TYPE_LSP, + &lsp->header); + CU_ASSERT_EQUAL((ntohl(*((uint32_t *)(lsp->header.encoded_object + 4))) + >> 12) & 0x000fffff, + plsp_id); + CU_ASSERT_EQUAL((lsp->header.encoded_object[7] >> 4) & 0x07, status); + CU_ASSERT_TRUE(lsp->header.encoded_object[7] & OBJECT_LSP_FLAG_A); + CU_ASSERT_TRUE(lsp->header.encoded_object[7] & OBJECT_LSP_FLAG_C); + CU_ASSERT_TRUE(lsp->header.encoded_object[7] & OBJECT_LSP_FLAG_D); + CU_ASSERT_TRUE(lsp->header.encoded_object[7] & OBJECT_LSP_FLAG_R); + CU_ASSERT_TRUE(lsp->header.encoded_object[7] & OBJECT_LSP_FLAG_S); + + pcep_obj_free_object((struct pcep_object_header *)lsp); +} + +void test_pcep_obj_create_vendor_info() +{ + uint32_t enterprise_number = 0x01020304; + uint32_t enterprise_specific_info = 0x05060708; + + struct pcep_object_vendor_info *obj = pcep_obj_create_vendor_info( + enterprise_number, enterprise_specific_info); + + CU_ASSERT_PTR_NOT_NULL(obj); + pcep_encode_object(&obj->header, versioning, object_buf); + verify_pcep_obj_header(PCEP_OBJ_CLASS_VENDOR_INFO, + PCEP_OBJ_TYPE_VENDOR_INFO, &obj->header); + uint32_t *uint32_ptr = (uint32_t *)(obj->header.encoded_object + 4); + CU_ASSERT_EQUAL(uint32_ptr[0], htonl(enterprise_number)); + CU_ASSERT_EQUAL(uint32_ptr[1], htonl(enterprise_specific_info)); + + pcep_obj_free_object((struct pcep_object_header *)obj); +} + +/* Internal test function. The only difference between pcep_obj_create_ero(), + * pcep_obj_create_iro(), and pcep_obj_create_rro() is the object_class + * and the object_type. + */ +typedef struct pcep_object_ro *(*ro_func)(double_linked_list *); +static void test_pcep_obj_create_object_common(ro_func func_to_test, + uint8_t object_class, + uint8_t object_type) +{ + double_linked_list *ero_list = dll_initialize(); + + struct pcep_object_ro *ero = func_to_test(NULL); + CU_ASSERT_PTR_NOT_NULL(ero); + pcep_encode_object(&ero->header, versioning, object_buf); + verify_pcep_obj_header2(object_class, object_type, OBJECT_HEADER_LENGTH, + ero->header.encoded_object); + pcep_obj_free_object((struct pcep_object_header *)ero); + + reset_objects_buffer(); + ero = func_to_test(ero_list); + CU_ASSERT_PTR_NOT_NULL(ero); + pcep_encode_object(&ero->header, versioning, object_buf); + verify_pcep_obj_header2(object_class, object_type, OBJECT_HEADER_LENGTH, + ero->header.encoded_object); + pcep_obj_free_object((struct pcep_object_header *)ero); + + reset_objects_buffer(); + struct pcep_ro_subobj_32label *ro_subobj = + pcep_obj_create_ro_subobj_32label(false, 0, 101); + ero_list = dll_initialize(); + dll_append(ero_list, ro_subobj); + ero = func_to_test(ero_list); + CU_ASSERT_PTR_NOT_NULL(ero); + pcep_encode_object(&ero->header, versioning, object_buf); + /* 4 bytes for obj header + + * 2 bytes for ro_subobj header + + * 2 bytes for lable c-type and flags + + * 4 bytes for label */ + verify_pcep_obj_header2(object_class, object_type, + OBJECT_HEADER_LENGTH + sizeof(uint32_t) * 2, + ero->header.encoded_object); + pcep_obj_free_object((struct pcep_object_header *)ero); +} + +void test_pcep_obj_create_ero() +{ + test_pcep_obj_create_object_common( + pcep_obj_create_ero, PCEP_OBJ_CLASS_ERO, PCEP_OBJ_TYPE_ERO); +} + +void test_pcep_obj_create_rro() +{ + test_pcep_obj_create_object_common( + pcep_obj_create_rro, PCEP_OBJ_CLASS_RRO, PCEP_OBJ_TYPE_RRO); +} + +void test_pcep_obj_create_iro() +{ + test_pcep_obj_create_object_common( + pcep_obj_create_iro, PCEP_OBJ_CLASS_IRO, PCEP_OBJ_TYPE_IRO); +} + +/* Internal util function to wrap an RO Subobj in a RO and encode it */ +static struct pcep_object_ro *encode_ro_subobj(struct pcep_object_ro_subobj *sr) +{ + double_linked_list *sr_subobj_list = dll_initialize(); + dll_append(sr_subobj_list, sr); + struct pcep_object_ro *ro = pcep_obj_create_ero(sr_subobj_list); + pcep_encode_object(&ro->header, versioning, object_buf); + + return ro; +} + +static void verify_pcep_obj_ro_header(struct pcep_object_ro *ro, + struct pcep_object_ro_subobj *ro_subobj, + uint8_t ro_subobj_type, bool loose_hop, + uint16_t length) +{ + (void)ro_subobj; + + verify_pcep_obj_header2(PCEP_OBJ_CLASS_ERO, PCEP_OBJ_TYPE_ERO, length, + ro->header.encoded_object); + + /* TODO consider printing the stack trace: + * https://stackoverflow.com/questions/105659/how-can-one-grab-a-stack-trace-in-c + */ + + /* Not using CU_ASSERT_EQUAL here, so that in case of failure, + * we can provide more info in the error message. */ + uint8_t found_type = (ro->header.encoded_object[4] + & 0x7f); /* remove the Loose hop bit */ + if (found_type != ro_subobj_type) { + fprintf(stderr, + "Test failure ro_sub_obj_type expected [%d] found [%d]\n", + ro_subobj_type, found_type); + CU_FAIL("Sub Object Header Type"); + } + + bool loose_hop_found = (ro->header.encoded_object[4] & 0x80); + if (loose_hop != loose_hop_found) { + fprintf(stderr, + "Test failure ro_sub_obj Loose Hop bit expected [%d] found [%d]\n", + loose_hop, loose_hop_found); + CU_FAIL("Sub Object Header Loose Hop bit"); + } + + if (length - 4 != ro->header.encoded_object[5]) { + fprintf(stderr, + "Test failure ro_sub_obj length expected [%d] found [%d]\n", + length - 4, ro->header.encoded_object[5]); + CU_FAIL("Sub Object Length"); + } +} + +static void +verify_pcep_obj_ro_sr_header(struct pcep_object_ro *ro, + struct pcep_object_ro_subobj *ro_subobj, + uint8_t nai_type, bool loose_hop, uint16_t length) +{ + verify_pcep_obj_ro_header(ro, ro_subobj, RO_SUBOBJ_TYPE_SR, loose_hop, + length); + uint8_t found_nai_type = ((ro->header.encoded_object[6] >> 4) & 0x0f); + if (nai_type != found_nai_type) { + fprintf(stderr, + "Test failure ro_sr_sub_obj nai_type expected [%d] found [%d]\n", + nai_type, found_nai_type); + CU_FAIL("Sub Object SR NAI Type"); + } +} + +void test_pcep_obj_create_ro_subobj_ipv4() +{ + struct in_addr ro_ipv4; + inet_pton(AF_INET, "192.168.1.2", &ro_ipv4); + uint8_t prefix_len = 8; + + struct pcep_ro_subobj_ipv4 *ipv4 = + pcep_obj_create_ro_subobj_ipv4(true, NULL, prefix_len, false); + CU_ASSERT_PTR_NULL(ipv4); + + ipv4 = pcep_obj_create_ro_subobj_ipv4(false, &ro_ipv4, prefix_len, + true); + CU_ASSERT_PTR_NOT_NULL(ipv4); + struct pcep_object_ro *ro = encode_ro_subobj(&ipv4->ro_subobj); + verify_pcep_obj_ro_header(ro, &ipv4->ro_subobj, RO_SUBOBJ_TYPE_IPV4, + false, sizeof(uint32_t) * 3); + CU_ASSERT_EQUAL(*((uint32_t *)(ro->header.encoded_object + 6)), + ro_ipv4.s_addr); + CU_ASSERT_EQUAL(ro->header.encoded_object[10], prefix_len); + CU_ASSERT_TRUE(ro->header.encoded_object[11] + & OBJECT_SUBOBJ_IP_FLAG_LOCAL_PROT); + pcep_obj_free_object((struct pcep_object_header *)ro); + + reset_objects_buffer(); + ipv4 = pcep_obj_create_ro_subobj_ipv4(true, &ro_ipv4, prefix_len, + false); + CU_ASSERT_PTR_NOT_NULL(ipv4); + ro = encode_ro_subobj(&ipv4->ro_subobj); + verify_pcep_obj_ro_header(ro, &ipv4->ro_subobj, RO_SUBOBJ_TYPE_IPV4, + true, sizeof(uint32_t) * 3); + CU_ASSERT_EQUAL(*((uint32_t *)(ro->header.encoded_object + 6)), + ro_ipv4.s_addr); + CU_ASSERT_EQUAL(ro->header.encoded_object[10], prefix_len); + CU_ASSERT_EQUAL(ro->header.encoded_object[11], 0); + pcep_obj_free_object((struct pcep_object_header *)ro); +} + +void test_pcep_obj_create_ro_subobj_ipv6() +{ + struct in6_addr ro_ipv6; + uint8_t prefix_len = 16; + + struct pcep_ro_subobj_ipv6 *ipv6 = + pcep_obj_create_ro_subobj_ipv6(true, NULL, prefix_len, true); + CU_ASSERT_PTR_NULL(ipv6); + + inet_pton(AF_INET6, "2001:db8::8a2e:370:7334", &ro_ipv6); + ipv6 = pcep_obj_create_ro_subobj_ipv6(false, &ro_ipv6, prefix_len, + true); + CU_ASSERT_PTR_NOT_NULL(ipv6); + struct pcep_object_ro *ro = encode_ro_subobj(&ipv6->ro_subobj); + verify_pcep_obj_ro_header(ro, &ipv6->ro_subobj, RO_SUBOBJ_TYPE_IPV6, + false, sizeof(uint32_t) * 6); + uint32_t *uint32_ptr = (uint32_t *)(ro->header.encoded_object + 6); + CU_ASSERT_EQUAL(uint32_ptr[0], ro_ipv6.__in6_u.__u6_addr32[0]); + CU_ASSERT_EQUAL(uint32_ptr[1], ro_ipv6.__in6_u.__u6_addr32[1]); + CU_ASSERT_EQUAL(uint32_ptr[2], ro_ipv6.__in6_u.__u6_addr32[2]); + CU_ASSERT_EQUAL(uint32_ptr[3], ro_ipv6.__in6_u.__u6_addr32[3]); + CU_ASSERT_EQUAL(ro->header.encoded_object[22], prefix_len); + CU_ASSERT_TRUE(ro->header.encoded_object[23] + & OBJECT_SUBOBJ_IP_FLAG_LOCAL_PROT); + pcep_obj_free_object((struct pcep_object_header *)ro); + + reset_objects_buffer(); + ipv6 = pcep_obj_create_ro_subobj_ipv6(true, &ro_ipv6, prefix_len, + false); + CU_ASSERT_PTR_NOT_NULL(ipv6); + ro = encode_ro_subobj(&ipv6->ro_subobj); + verify_pcep_obj_ro_header(ro, &ipv6->ro_subobj, RO_SUBOBJ_TYPE_IPV6, + true, sizeof(uint32_t) * 6); + uint32_ptr = (uint32_t *)(ro->header.encoded_object + 6); + CU_ASSERT_EQUAL(uint32_ptr[0], ro_ipv6.__in6_u.__u6_addr32[0]); + CU_ASSERT_EQUAL(uint32_ptr[1], ro_ipv6.__in6_u.__u6_addr32[1]); + CU_ASSERT_EQUAL(uint32_ptr[2], ro_ipv6.__in6_u.__u6_addr32[2]); + CU_ASSERT_EQUAL(uint32_ptr[3], ro_ipv6.__in6_u.__u6_addr32[3]); + CU_ASSERT_EQUAL(ro->header.encoded_object[22], prefix_len); + CU_ASSERT_EQUAL(ro->header.encoded_object[23], 0); + pcep_obj_free_object((struct pcep_object_header *)ro); +} + +void test_pcep_obj_create_ro_subobj_unnum() +{ + struct in_addr router_id; + uint32_t if_id = 123; + + struct pcep_ro_subobj_unnum *unnum = + pcep_obj_create_ro_subobj_unnum(NULL, if_id); + CU_ASSERT_PTR_NULL(unnum); + + inet_pton(AF_INET, "192.168.1.2", &router_id); + unnum = pcep_obj_create_ro_subobj_unnum(&router_id, if_id); + CU_ASSERT_PTR_NOT_NULL(unnum); + struct pcep_object_ro *ro = encode_ro_subobj(&unnum->ro_subobj); + verify_pcep_obj_ro_header(ro, &unnum->ro_subobj, RO_SUBOBJ_TYPE_UNNUM, + false, sizeof(uint32_t) * 4); + CU_ASSERT_EQUAL(ro->header.encoded_object[6], 0); + CU_ASSERT_EQUAL(ro->header.encoded_object[7], 0); + CU_ASSERT_EQUAL(*((uint32_t *)(ro->header.encoded_object + 8)), + router_id.s_addr); + CU_ASSERT_EQUAL(*((uint32_t *)(ro->header.encoded_object + 12)), + htonl(if_id)); + + pcep_obj_free_object((struct pcep_object_header *)ro); +} + +void test_pcep_obj_create_ro_subobj_32label() +{ + uint8_t class_type = 1; + uint32_t label = 0xeeffaabb; + + struct pcep_ro_subobj_32label *label32 = + pcep_obj_create_ro_subobj_32label(true, class_type, label); + CU_ASSERT_PTR_NOT_NULL(label32); + struct pcep_object_ro *ro = encode_ro_subobj(&label32->ro_subobj); + verify_pcep_obj_ro_header(ro, &label32->ro_subobj, RO_SUBOBJ_TYPE_LABEL, + false, sizeof(uint32_t) * 3); + CU_ASSERT_TRUE(ro->header.encoded_object[6] + & OBJECT_SUBOBJ_LABEL_FLAG_GLOGAL); + CU_ASSERT_EQUAL(ro->header.encoded_object[7], class_type); + CU_ASSERT_EQUAL(*((uint32_t *)(ro->header.encoded_object + 8)), + htonl(label)); + + pcep_obj_free_object((struct pcep_object_header *)ro); +} + +void test_pcep_obj_create_ro_subobj_asn() +{ + uint16_t asn = 0x0102; + + struct pcep_ro_subobj_asn *asn_obj = pcep_obj_create_ro_subobj_asn(asn); + CU_ASSERT_PTR_NOT_NULL(asn_obj); + struct pcep_object_ro *ro = encode_ro_subobj(&asn_obj->ro_subobj); + verify_pcep_obj_ro_header(ro, &asn_obj->ro_subobj, RO_SUBOBJ_TYPE_ASN, + false, sizeof(uint32_t) * 2); + CU_ASSERT_EQUAL(*((uint16_t *)(ro->header.encoded_object + 6)), + htons(asn)); + + pcep_obj_free_object((struct pcep_object_header *)ro); +} + +void test_pcep_obj_create_ro_subobj_sr_nonai() +{ + uint32_t sid = 0x01020304; + + struct pcep_ro_subobj_sr *sr = + pcep_obj_create_ro_subobj_sr_nonai(false, sid, false, false); + CU_ASSERT_PTR_NOT_NULL(sr); + struct pcep_object_ro *ro = encode_ro_subobj(&sr->ro_subobj); + verify_pcep_obj_ro_sr_header(ro, &sr->ro_subobj, + PCEP_SR_SUBOBJ_NAI_ABSENT, false, + sizeof(uint32_t) * 3); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_S); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_F); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_C); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_M); + pcep_obj_free_object((struct pcep_object_header *)ro); + + reset_objects_buffer(); + sr = pcep_obj_create_ro_subobj_sr_nonai(true, sid, true, true); + CU_ASSERT_PTR_NOT_NULL(sr); + ro = encode_ro_subobj(&sr->ro_subobj); + verify_pcep_obj_ro_sr_header(ro, &sr->ro_subobj, + PCEP_SR_SUBOBJ_NAI_ABSENT, true, + sizeof(uint32_t) * 3); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_S); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_F); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_C); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_M); + pcep_obj_free_object((struct pcep_object_header *)ro); +} + +void test_pcep_obj_create_ro_subobj_sr_ipv4_node() +{ + uint32_t sid = 0x01020304; + struct in_addr ipv4_node_id; + inet_pton(AF_INET, "192.168.1.2", &ipv4_node_id); + + /* (loose_hop, sid_absent, c_flag, m_flag, sid, ipv4_node_id) */ + struct pcep_ro_subobj_sr *sr = pcep_obj_create_ro_subobj_sr_ipv4_node( + true, false, true, true, sid, NULL); + CU_ASSERT_PTR_NULL(sr); + + /* Test the sid is absent */ + sr = pcep_obj_create_ro_subobj_sr_ipv4_node(true, true, false, false, + sid, &ipv4_node_id); + CU_ASSERT_PTR_NOT_NULL(sr); + struct pcep_object_ro *ro = encode_ro_subobj(&sr->ro_subobj); + verify_pcep_obj_ro_sr_header(ro, &sr->ro_subobj, + PCEP_SR_SUBOBJ_NAI_IPV4_NODE, true, + sizeof(uint32_t) * 3); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_S); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_F); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_C); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_M); + CU_ASSERT_EQUAL(sr->sid, 0); + CU_ASSERT_EQUAL(*((uint32_t *)(ro->header.encoded_object + 8)), + ipv4_node_id.s_addr); + pcep_obj_free_object((struct pcep_object_header *)ro); + + /* Test the sid is present */ + reset_objects_buffer(); + inet_pton(AF_INET, "192.168.1.2", &ipv4_node_id); + sr = pcep_obj_create_ro_subobj_sr_ipv4_node(false, false, true, true, + sid, &ipv4_node_id); + CU_ASSERT_PTR_NOT_NULL(sr); + ro = encode_ro_subobj(&sr->ro_subobj); + verify_pcep_obj_ro_sr_header(ro, &sr->ro_subobj, + PCEP_SR_SUBOBJ_NAI_IPV4_NODE, false, + sizeof(uint32_t) * 4); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_C); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_M); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_S); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_F); + CU_ASSERT_EQUAL(*((uint32_t *)(ro->header.encoded_object + 8)), + htonl(sid)); + CU_ASSERT_EQUAL(*((uint32_t *)(ro->header.encoded_object + 12)), + ipv4_node_id.s_addr); + pcep_obj_free_object((struct pcep_object_header *)ro); +} + +void test_pcep_obj_create_ro_subobj_sr_ipv6_node() +{ + uint32_t sid = 0x01020304; + struct in6_addr ipv6_node_id; + inet_pton(AF_INET6, "2001:db8::8a2e:370:7334", &ipv6_node_id); + + /* (loose_hop, sid_absent, c_flag, m_flag, sid, ipv6_node_id) */ + struct pcep_ro_subobj_sr *sr = pcep_obj_create_ro_subobj_sr_ipv6_node( + false, true, true, true, sid, NULL); + CU_ASSERT_PTR_NULL(sr); + + /* Test the sid is absent */ + sr = pcep_obj_create_ro_subobj_sr_ipv6_node(true, true, true, true, sid, + &ipv6_node_id); + CU_ASSERT_PTR_NOT_NULL(sr); + struct pcep_object_ro *ro = encode_ro_subobj(&sr->ro_subobj); + verify_pcep_obj_ro_sr_header(ro, &sr->ro_subobj, + PCEP_SR_SUBOBJ_NAI_IPV6_NODE, true, + sizeof(uint32_t) * 6); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_S); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_F); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_C); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_M); + uint32_t *uint32_ptr = (uint32_t *)(ro->header.encoded_object + 8); + CU_ASSERT_EQUAL(uint32_ptr[0], ipv6_node_id.__in6_u.__u6_addr32[0]); + CU_ASSERT_EQUAL(uint32_ptr[1], ipv6_node_id.__in6_u.__u6_addr32[1]); + CU_ASSERT_EQUAL(uint32_ptr[2], ipv6_node_id.__in6_u.__u6_addr32[2]); + CU_ASSERT_EQUAL(uint32_ptr[3], ipv6_node_id.__in6_u.__u6_addr32[3]); + pcep_obj_free_object((struct pcep_object_header *)ro); + + /* Test the sid is present */ + reset_objects_buffer(); + inet_pton(AF_INET6, "2001:db8::8a2e:370:7334", &ipv6_node_id); + sr = pcep_obj_create_ro_subobj_sr_ipv6_node(false, false, true, true, + sid, &ipv6_node_id); + CU_ASSERT_PTR_NOT_NULL(sr); + ro = encode_ro_subobj(&sr->ro_subobj); + verify_pcep_obj_ro_sr_header(ro, &sr->ro_subobj, + PCEP_SR_SUBOBJ_NAI_IPV6_NODE, false, + sizeof(uint32_t) * 7); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_M); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_C); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_S); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_F); + uint32_ptr = (uint32_t *)(ro->header.encoded_object + 8); + CU_ASSERT_EQUAL(uint32_ptr[0], htonl(sid)); + CU_ASSERT_EQUAL(uint32_ptr[1], ipv6_node_id.__in6_u.__u6_addr32[0]); + CU_ASSERT_EQUAL(uint32_ptr[2], ipv6_node_id.__in6_u.__u6_addr32[1]); + CU_ASSERT_EQUAL(uint32_ptr[3], ipv6_node_id.__in6_u.__u6_addr32[2]); + CU_ASSERT_EQUAL(uint32_ptr[4], ipv6_node_id.__in6_u.__u6_addr32[3]); + pcep_obj_free_object((struct pcep_object_header *)ro); +} + +void test_pcep_obj_create_ro_subobj_sr_ipv4_adj() +{ + struct in_addr local_ipv4; + struct in_addr remote_ipv4; + inet_pton(AF_INET, "192.168.1.2", &local_ipv4); + inet_pton(AF_INET, "172.168.1.2", &remote_ipv4); + + uint32_t sid = ENCODE_SR_ERO_SID(3, 7, 0, 188); + CU_ASSERT_EQUAL(sid, 16060); + + /* (loose_hop, sid_absent, c_flag, m_flag, sid, local_ipv4, remote_ipv4) + */ + struct pcep_ro_subobj_sr *sr = pcep_obj_create_ro_subobj_sr_ipv4_adj( + false, true, true, true, sid, NULL, NULL); + CU_ASSERT_PTR_NULL(sr); + + sr = pcep_obj_create_ro_subobj_sr_ipv4_adj(false, true, true, true, sid, + &local_ipv4, NULL); + CU_ASSERT_PTR_NULL(sr); + + sr = pcep_obj_create_ro_subobj_sr_ipv4_adj(false, true, true, true, sid, + NULL, &remote_ipv4); + CU_ASSERT_PTR_NULL(sr); + + /* Test the sid is absent */ + sr = pcep_obj_create_ro_subobj_sr_ipv4_adj(true, true, true, true, sid, + &local_ipv4, &remote_ipv4); + CU_ASSERT_PTR_NOT_NULL(sr); + struct pcep_object_ro *ro = encode_ro_subobj(&sr->ro_subobj); + verify_pcep_obj_ro_sr_header(ro, &sr->ro_subobj, + PCEP_SR_SUBOBJ_NAI_IPV4_ADJACENCY, true, + sizeof(uint32_t) * 4); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_S); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_F); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_C); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_M); + CU_ASSERT_EQUAL(sr->sid, 0); + uint32_t *uint32_ptr = (uint32_t *)(ro->header.encoded_object + 8); + CU_ASSERT_EQUAL(uint32_ptr[0], local_ipv4.s_addr); + CU_ASSERT_EQUAL(uint32_ptr[1], remote_ipv4.s_addr); + pcep_obj_free_object((struct pcep_object_header *)ro); + + /* Test the sid is present */ + inet_pton(AF_INET, "192.168.1.2", &local_ipv4); + inet_pton(AF_INET, "172.168.1.2", &remote_ipv4); + reset_objects_buffer(); + sr = pcep_obj_create_ro_subobj_sr_ipv4_adj( + false, false, true, true, sid, &local_ipv4, &remote_ipv4); + CU_ASSERT_PTR_NOT_NULL(sr); + ro = encode_ro_subobj(&sr->ro_subobj); + verify_pcep_obj_ro_sr_header(ro, &sr->ro_subobj, + PCEP_SR_SUBOBJ_NAI_IPV4_ADJACENCY, false, + sizeof(uint32_t) * 5); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_C); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_M); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_S); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_F); + uint32_ptr = (uint32_t *)(ro->header.encoded_object + 8); + CU_ASSERT_EQUAL(uint32_ptr[0], htonl(sid)); + CU_ASSERT_EQUAL(uint32_ptr[1], local_ipv4.s_addr); + CU_ASSERT_EQUAL(uint32_ptr[2], remote_ipv4.s_addr); + pcep_obj_free_object((struct pcep_object_header *)ro); +} + +void test_pcep_obj_create_ro_subobj_sr_ipv6_adj() +{ + uint32_t sid = 0x01020304; + struct in6_addr local_ipv6; + struct in6_addr remote_ipv6; + inet_pton(AF_INET6, "2001:db8::8a2e:370:8221", &local_ipv6); + inet_pton(AF_INET6, "2001:db8::8a2e:370:7334", &remote_ipv6); + + /* (loose_hop, sid_absent, c_flag, m_flag, sid, local_ipv6, remote_ipv6) + */ + struct pcep_ro_subobj_sr *sr = pcep_obj_create_ro_subobj_sr_ipv6_adj( + false, true, true, true, sid, NULL, NULL); + CU_ASSERT_PTR_NULL(sr); + + sr = pcep_obj_create_ro_subobj_sr_ipv6_adj(false, true, true, true, sid, + &local_ipv6, NULL); + CU_ASSERT_PTR_NULL(sr); + + sr = pcep_obj_create_ro_subobj_sr_ipv6_adj(false, true, true, true, sid, + NULL, &remote_ipv6); + CU_ASSERT_PTR_NULL(sr); + + /* Test the sid is absent */ + sr = pcep_obj_create_ro_subobj_sr_ipv6_adj(true, true, true, true, sid, + &local_ipv6, &remote_ipv6); + CU_ASSERT_PTR_NOT_NULL(sr); + struct pcep_object_ro *ro = encode_ro_subobj(&sr->ro_subobj); + verify_pcep_obj_ro_sr_header(ro, &sr->ro_subobj, + PCEP_SR_SUBOBJ_NAI_IPV6_ADJACENCY, true, + sizeof(uint32_t) * 10); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_S); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_F); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_C); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_M); + CU_ASSERT_EQUAL(sr->sid, 0); + uint32_t *uint32_ptr = (uint32_t *)(ro->header.encoded_object + 8); + CU_ASSERT_EQUAL(uint32_ptr[0], local_ipv6.__in6_u.__u6_addr32[0]); + CU_ASSERT_EQUAL(uint32_ptr[1], local_ipv6.__in6_u.__u6_addr32[1]); + CU_ASSERT_EQUAL(uint32_ptr[2], local_ipv6.__in6_u.__u6_addr32[2]); + CU_ASSERT_EQUAL(uint32_ptr[3], local_ipv6.__in6_u.__u6_addr32[3]); + + CU_ASSERT_EQUAL(uint32_ptr[4], remote_ipv6.__in6_u.__u6_addr32[0]); + CU_ASSERT_EQUAL(uint32_ptr[5], remote_ipv6.__in6_u.__u6_addr32[1]); + CU_ASSERT_EQUAL(uint32_ptr[6], remote_ipv6.__in6_u.__u6_addr32[2]); + CU_ASSERT_EQUAL(uint32_ptr[7], remote_ipv6.__in6_u.__u6_addr32[3]); + pcep_obj_free_object((struct pcep_object_header *)ro); + + /* Test the sid is present */ + reset_objects_buffer(); + inet_pton(AF_INET6, "2001:db8::8a2e:370:8221", &local_ipv6); + inet_pton(AF_INET6, "2001:db8::8a2e:370:7334", &remote_ipv6); + sr = pcep_obj_create_ro_subobj_sr_ipv6_adj( + false, false, true, false, sid, &local_ipv6, &remote_ipv6); + CU_ASSERT_PTR_NOT_NULL(sr); + ro = encode_ro_subobj(&sr->ro_subobj); + verify_pcep_obj_ro_sr_header(ro, &sr->ro_subobj, + PCEP_SR_SUBOBJ_NAI_IPV6_ADJACENCY, false, + sizeof(uint32_t) * 11); + /* All flags are false */ + CU_ASSERT_EQUAL(ro->header.encoded_object[7], 0); + uint32_ptr = (uint32_t *)(ro->header.encoded_object + 8); + CU_ASSERT_EQUAL(uint32_ptr[0], htonl(sid)); + CU_ASSERT_EQUAL(uint32_ptr[1], local_ipv6.__in6_u.__u6_addr32[0]); + CU_ASSERT_EQUAL(uint32_ptr[2], local_ipv6.__in6_u.__u6_addr32[1]); + CU_ASSERT_EQUAL(uint32_ptr[3], local_ipv6.__in6_u.__u6_addr32[2]); + CU_ASSERT_EQUAL(uint32_ptr[4], local_ipv6.__in6_u.__u6_addr32[3]); + + CU_ASSERT_EQUAL(uint32_ptr[5], remote_ipv6.__in6_u.__u6_addr32[0]); + CU_ASSERT_EQUAL(uint32_ptr[6], remote_ipv6.__in6_u.__u6_addr32[1]); + CU_ASSERT_EQUAL(uint32_ptr[7], remote_ipv6.__in6_u.__u6_addr32[2]); + CU_ASSERT_EQUAL(uint32_ptr[8], remote_ipv6.__in6_u.__u6_addr32[3]); + pcep_obj_free_object((struct pcep_object_header *)ro); +} + +void test_pcep_obj_create_ro_subobj_sr_unnumbered_ipv4_adj() +{ + uint32_t sid = 0x01020304; + uint32_t local_node_id = 0x11223344; + uint32_t local_if_id = 0x55667788; + uint32_t remote_node_id = 0x99aabbcc; + uint32_t remote_if_id = 0xddeeff11; + + /* (loose_hop, sid_absent, c_flag, m_flag, + sid, local_node_id, local_if_id, remote_node_id, remote_if_id) */ + + /* Test the sid is absent */ + struct pcep_ro_subobj_sr *sr = + pcep_obj_create_ro_subobj_sr_unnumbered_ipv4_adj( + true, true, true, true, sid, local_node_id, local_if_id, + remote_node_id, remote_if_id); + CU_ASSERT_PTR_NOT_NULL(sr); + struct pcep_object_ro *ro = encode_ro_subobj(&sr->ro_subobj); + verify_pcep_obj_ro_sr_header( + ro, &sr->ro_subobj, + PCEP_SR_SUBOBJ_NAI_UNNUMBERED_IPV4_ADJACENCY, true, + sizeof(uint32_t) * 6); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_S); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_F); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_C); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_M); + CU_ASSERT_EQUAL(sr->sid, 0); + uint32_t *uint32_ptr = (uint32_t *)(ro->header.encoded_object + 8); + CU_ASSERT_EQUAL(uint32_ptr[0], local_node_id); + CU_ASSERT_EQUAL(uint32_ptr[1], local_if_id); + CU_ASSERT_EQUAL(uint32_ptr[2], remote_node_id); + CU_ASSERT_EQUAL(uint32_ptr[3], remote_if_id); + pcep_obj_free_object((struct pcep_object_header *)ro); + + /* Test the sid is present */ + reset_objects_buffer(); + sr = pcep_obj_create_ro_subobj_sr_unnumbered_ipv4_adj( + false, false, true, true, sid, local_node_id, local_if_id, + remote_node_id, remote_if_id); + CU_ASSERT_PTR_NOT_NULL(sr); + ro = encode_ro_subobj(&sr->ro_subobj); + verify_pcep_obj_ro_sr_header( + ro, &sr->ro_subobj, + PCEP_SR_SUBOBJ_NAI_UNNUMBERED_IPV4_ADJACENCY, false, + sizeof(uint32_t) * 7); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_C); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_M); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_S); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_F); + uint32_ptr = (uint32_t *)(ro->header.encoded_object + 8); + CU_ASSERT_EQUAL(uint32_ptr[0], htonl(sid)); + CU_ASSERT_EQUAL(uint32_ptr[1], local_node_id); + CU_ASSERT_EQUAL(uint32_ptr[2], local_if_id); + CU_ASSERT_EQUAL(uint32_ptr[3], remote_node_id); + CU_ASSERT_EQUAL(uint32_ptr[4], remote_if_id); + pcep_obj_free_object((struct pcep_object_header *)ro); + + /* TODO Test draft07 types */ +} + +void test_pcep_obj_create_ro_subobj_sr_linklocal_ipv6_adj() +{ + uint32_t sid = 0x01020304; + uint32_t local_if_id = 0x11002200; + uint32_t remote_if_id = 0x00110022; + struct in6_addr local_ipv6; + struct in6_addr remote_ipv6; + inet_pton(AF_INET6, "2001:db8::8a2e:370:8221", &local_ipv6); + inet_pton(AF_INET6, "2001:db8::8a2e:370:7334", &remote_ipv6); + + /* (loose_hop, sid_absent, c_flag, m_flag, sid, local_ipv6, local_if_id, + * remote_ipv6, remote_if_id */ + struct pcep_ro_subobj_sr *sr = + pcep_obj_create_ro_subobj_sr_linklocal_ipv6_adj( + false, true, true, true, sid, NULL, local_if_id, NULL, + remote_if_id); + CU_ASSERT_PTR_NULL(sr); + + sr = pcep_obj_create_ro_subobj_sr_linklocal_ipv6_adj( + false, true, true, true, sid, &local_ipv6, local_if_id, NULL, + remote_if_id); + CU_ASSERT_PTR_NULL(sr); + + sr = pcep_obj_create_ro_subobj_sr_linklocal_ipv6_adj( + false, true, true, true, sid, NULL, local_if_id, &remote_ipv6, + remote_if_id); + CU_ASSERT_PTR_NULL(sr); + + /* Test the sid is absent */ + sr = pcep_obj_create_ro_subobj_sr_linklocal_ipv6_adj( + true, true, true, true, sid, &local_ipv6, local_if_id, + &remote_ipv6, remote_if_id); + CU_ASSERT_PTR_NOT_NULL(sr); + struct pcep_object_ro *ro = encode_ro_subobj(&sr->ro_subobj); + verify_pcep_obj_ro_sr_header( + ro, &sr->ro_subobj, + PCEP_SR_SUBOBJ_NAI_LINK_LOCAL_IPV6_ADJACENCY, true, + sizeof(uint32_t) * 12); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_S); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_F); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_C); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_M); + CU_ASSERT_EQUAL(sr->sid, 0); + uint32_t *uint32_ptr = (uint32_t *)(ro->header.encoded_object + 8); + CU_ASSERT_EQUAL(uint32_ptr[0], local_ipv6.__in6_u.__u6_addr32[0]); + CU_ASSERT_EQUAL(uint32_ptr[1], local_ipv6.__in6_u.__u6_addr32[1]); + CU_ASSERT_EQUAL(uint32_ptr[2], local_ipv6.__in6_u.__u6_addr32[2]); + CU_ASSERT_EQUAL(uint32_ptr[3], local_ipv6.__in6_u.__u6_addr32[3]); + CU_ASSERT_EQUAL(uint32_ptr[4], local_if_id); + + CU_ASSERT_EQUAL(uint32_ptr[5], remote_ipv6.__in6_u.__u6_addr32[0]); + CU_ASSERT_EQUAL(uint32_ptr[6], remote_ipv6.__in6_u.__u6_addr32[1]); + CU_ASSERT_EQUAL(uint32_ptr[7], remote_ipv6.__in6_u.__u6_addr32[2]); + CU_ASSERT_EQUAL(uint32_ptr[8], remote_ipv6.__in6_u.__u6_addr32[3]); + CU_ASSERT_EQUAL(uint32_ptr[9], remote_if_id); + pcep_obj_free_object((struct pcep_object_header *)ro); + + /* Test the sid is present */ + inet_pton(AF_INET6, "2001:db8::8a2e:370:8221", &local_ipv6); + inet_pton(AF_INET6, "2001:db8::8a2e:370:7334", &remote_ipv6); + reset_objects_buffer(); + sr = pcep_obj_create_ro_subobj_sr_linklocal_ipv6_adj( + false, false, true, true, sid, &local_ipv6, local_if_id, + &remote_ipv6, remote_if_id); + CU_ASSERT_PTR_NOT_NULL(sr); + ro = encode_ro_subobj(&sr->ro_subobj); + verify_pcep_obj_ro_sr_header( + ro, &sr->ro_subobj, + PCEP_SR_SUBOBJ_NAI_LINK_LOCAL_IPV6_ADJACENCY, false, + sizeof(uint32_t) * 13); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_C); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_M); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_S); + CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_F); + uint32_ptr = (uint32_t *)(ro->header.encoded_object + 8); + CU_ASSERT_EQUAL(uint32_ptr[0], htonl(sid)); + CU_ASSERT_EQUAL(uint32_ptr[1], local_ipv6.__in6_u.__u6_addr32[0]); + CU_ASSERT_EQUAL(uint32_ptr[2], local_ipv6.__in6_u.__u6_addr32[1]); + CU_ASSERT_EQUAL(uint32_ptr[3], local_ipv6.__in6_u.__u6_addr32[2]); + CU_ASSERT_EQUAL(uint32_ptr[4], local_ipv6.__in6_u.__u6_addr32[3]); + CU_ASSERT_EQUAL(uint32_ptr[5], local_if_id); + + CU_ASSERT_EQUAL(uint32_ptr[6], remote_ipv6.__in6_u.__u6_addr32[0]); + CU_ASSERT_EQUAL(uint32_ptr[7], remote_ipv6.__in6_u.__u6_addr32[1]); + CU_ASSERT_EQUAL(uint32_ptr[8], remote_ipv6.__in6_u.__u6_addr32[2]); + CU_ASSERT_EQUAL(uint32_ptr[9], remote_ipv6.__in6_u.__u6_addr32[3]); + CU_ASSERT_EQUAL(uint32_ptr[10], remote_if_id); + pcep_obj_free_object((struct pcep_object_header *)ro); +} diff --git a/pceplib/test/pcep_msg_objects_test.h b/pceplib/test/pcep_msg_objects_test.h new file mode 100644 index 0000000000..0f08193a59 --- /dev/null +++ b/pceplib/test/pcep_msg_objects_test.h @@ -0,0 +1,64 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Javier Garcia <javier.garcia@voltanet.io> + * + */ + + +#ifndef PCEP_MSG_OBJECTS_TEST_H_ +#define PCEP_MSG_OBJECTS_TEST_H_ + +int pcep_objects_test_suite_setup(void); +int pcep_objects_test_suite_teardown(void); +void pcep_objects_test_setup(void); +void pcep_objects_test_teardown(void); +void test_pcep_obj_create_open(void); +void test_pcep_obj_create_open_with_tlvs(void); +void test_pcep_obj_create_rp(void); +void test_pcep_obj_create_nopath(void); +void test_pcep_obj_create_endpoint_ipv4(void); +void test_pcep_obj_create_endpoint_ipv6(void); +void test_pcep_obj_create_association_ipv4(void); +void test_pcep_obj_create_association_ipv6(void); +void test_pcep_obj_create_bandwidth(void); +void test_pcep_obj_create_metric(void); +void test_pcep_obj_create_lspa(void); +void test_pcep_obj_create_svec(void); +void test_pcep_obj_create_error(void); +void test_pcep_obj_create_close(void); +void test_pcep_obj_create_srp(void); +void test_pcep_obj_create_lsp(void); +void test_pcep_obj_create_vendor_info(void); +void test_pcep_obj_create_ero(void); +void test_pcep_obj_create_rro(void); +void test_pcep_obj_create_iro(void); +void test_pcep_obj_create_ro_subobj_ipv4(void); +void test_pcep_obj_create_ro_subobj_ipv6(void); +void test_pcep_obj_create_ro_subobj_unnum(void); +void test_pcep_obj_create_ro_subobj_32label(void); +void test_pcep_obj_create_ro_subobj_asn(void); +void test_pcep_obj_create_ro_subobj_sr_nonai(void); +void test_pcep_obj_create_ro_subobj_sr_ipv4_node(void); +void test_pcep_obj_create_ro_subobj_sr_ipv6_node(void); +void test_pcep_obj_create_ro_subobj_sr_ipv4_adj(void); +void test_pcep_obj_create_ro_subobj_sr_ipv6_adj(void); +void test_pcep_obj_create_ro_subobj_sr_unnumbered_ipv4_adj(void); +void test_pcep_obj_create_ro_subobj_sr_linklocal_ipv6_adj(void); + +#endif diff --git a/pceplib/test/pcep_msg_tests_valgrind.sh b/pceplib/test/pcep_msg_tests_valgrind.sh new file mode 100755 index 0000000000..4a9a99939d --- /dev/null +++ b/pceplib/test/pcep_msg_tests_valgrind.sh @@ -0,0 +1,2 @@ +source pceplib/test/pcep_tests_valgrind.sh +valgrind_test pceplib/test/pcep_msg_tests diff --git a/pceplib/test/pcep_msg_tlvs_test.c b/pceplib/test/pcep_msg_tlvs_test.c new file mode 100644 index 0000000000..6b650f6823 --- /dev/null +++ b/pceplib/test/pcep_msg_tlvs_test.c @@ -0,0 +1,691 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Brady Johnson <brady@voltanet.io> + * + */ + + +#include <stdlib.h> + +#include <CUnit/CUnit.h> + +#include "pcep_msg_encoding.h" +#include "pcep_msg_objects.h" +#include "pcep_msg_tlvs.h" +#include "pcep_msg_tools.h" +#include "pcep_utils_memory.h" +#include "pcep_msg_tlvs_test.h" + +/* + * Notice: + * All of these TLV Unit Tests encode the created TLVs by explicitly calling + * pcep_encode_tlv() thus testing the TLV creation and the TLV encoding. + * All APIs expect IPs to be in network byte order. + */ + +static struct pcep_versioning *versioning = NULL; +static uint8_t tlv_buf[2000]; + +void reset_tlv_buffer(void); + +int pcep_tlvs_test_suite_setup(void) +{ + pceplib_memory_reset(); + return 0; +} + +int pcep_tlvs_test_suite_teardown(void) +{ + printf("\n"); + pceplib_memory_dump(); + return 0; +} + +void reset_tlv_buffer() +{ + memset(tlv_buf, 0, 2000); +} + +void pcep_tlvs_test_setup() +{ + versioning = create_default_pcep_versioning(); + reset_tlv_buffer(); +} + +void pcep_tlvs_test_teardown() +{ + destroy_pcep_versioning(versioning); +} + +void test_pcep_tlv_create_stateful_pce_capability() +{ + struct pcep_object_tlv_stateful_pce_capability *tlv = + pcep_tlv_create_stateful_pce_capability(true, true, true, true, + true, true); + CU_ASSERT_PTR_NOT_NULL(tlv); + + pcep_encode_tlv(&tlv->header, versioning, tlv_buf); + CU_ASSERT_EQUAL(tlv->header.type, + PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY); + CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, sizeof(uint32_t)); + CU_ASSERT_TRUE(tlv->flag_u_lsp_update_capability); + CU_ASSERT_TRUE(tlv->flag_s_include_db_version); + CU_ASSERT_TRUE(tlv->flag_i_lsp_instantiation_capability); + CU_ASSERT_TRUE(tlv->flag_t_triggered_resync); + CU_ASSERT_TRUE(tlv->flag_d_delta_lsp_sync); + CU_ASSERT_TRUE(tlv->flag_f_triggered_initial_sync); + CU_ASSERT_EQUAL(tlv->header.encoded_tlv[7], 0x3f); + /* TODO add a new function: verify_tlv_header(tlv->header.encoded_tlv) + * to all tests */ + + pcep_obj_free_tlv(&tlv->header); +} + +void test_pcep_tlv_create_speaker_entity_id() +{ + struct pcep_object_tlv_speaker_entity_identifier *tlv = + pcep_tlv_create_speaker_entity_id(NULL); + CU_ASSERT_PTR_NULL(tlv); + + 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)); + *speaker_entity = 42; + dll_append(list, speaker_entity); + tlv = pcep_tlv_create_speaker_entity_id(list); + CU_ASSERT_PTR_NOT_NULL(tlv); + + pcep_encode_tlv(&tlv->header, versioning, tlv_buf); + CU_ASSERT_EQUAL(tlv->header.type, PCEP_OBJ_TLV_TYPE_SPEAKER_ENTITY_ID); + CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, sizeof(uint32_t)); + CU_ASSERT_PTR_NOT_NULL(tlv->speaker_entity_id_list); + CU_ASSERT_EQUAL(tlv->speaker_entity_id_list->num_entries, 1); + uint32_t *uint32_ptr = (uint32_t *)tlv->header.encoded_tlv; + CU_ASSERT_EQUAL(uint32_ptr[1], htonl(*speaker_entity)); + + pcep_obj_free_tlv(&tlv->header); +} + +void test_pcep_tlv_create_lsp_db_version() +{ + uint64_t lsp_db_version = 0xf005ba11ba5eba11; + struct pcep_object_tlv_lsp_db_version *tlv = + pcep_tlv_create_lsp_db_version(lsp_db_version); + CU_ASSERT_PTR_NOT_NULL(tlv); + + pcep_encode_tlv(&tlv->header, versioning, tlv_buf); + CU_ASSERT_EQUAL(tlv->header.type, PCEP_OBJ_TLV_TYPE_LSP_DB_VERSION); + CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, sizeof(uint64_t)); + CU_ASSERT_EQUAL(tlv->lsp_db_version, lsp_db_version); + CU_ASSERT_EQUAL(*((uint64_t *)(tlv->header.encoded_tlv + 4)), + be64toh(lsp_db_version)); + + pcep_obj_free_tlv(&tlv->header); +} + +void test_pcep_tlv_create_path_setup_type() +{ + uint8_t pst = 0x89; + + struct pcep_object_tlv_path_setup_type *tlv = + pcep_tlv_create_path_setup_type(pst); + CU_ASSERT_PTR_NOT_NULL(tlv); + pcep_encode_tlv(&tlv->header, versioning, tlv_buf); + CU_ASSERT_EQUAL(tlv->header.type, PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE); + CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, sizeof(uint32_t)); + CU_ASSERT_EQUAL(tlv->path_setup_type, pst); + uint32_t *uint32_ptr = (uint32_t *)tlv->header.encoded_tlv; + CU_ASSERT_EQUAL(uint32_ptr[1], htonl(0x000000FF & pst)); + + pcep_obj_free_tlv(&tlv->header); +} + +void test_pcep_tlv_create_path_setup_type_capability() +{ + /* The sub_tlv list is optional */ + + /* Should return NULL if pst_list is NULL */ + struct pcep_object_tlv_path_setup_type_capability *tlv = + pcep_tlv_create_path_setup_type_capability(NULL, NULL); + CU_ASSERT_PTR_NULL(tlv); + + /* Should return NULL if pst_list is empty */ + 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); + uint8_t *pst2 = pceplib_malloc(PCEPLIB_MESSAGES, 1); + uint8_t *pst3 = pceplib_malloc(PCEPLIB_MESSAGES, 1); + *pst1 = 1; + *pst2 = 2; + *pst3 = 3; + dll_append(pst_list, pst1); + dll_append(pst_list, pst2); + dll_append(pst_list, pst3); + 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, + PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE_CAPABILITY); + CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, sizeof(uint32_t) * 2); + CU_ASSERT_PTR_NOT_NULL(tlv->pst_list); + CU_ASSERT_EQUAL(tlv->pst_list->num_entries, 3); + uint32_t *uint32_ptr = (uint32_t *)tlv->header.encoded_tlv; + CU_ASSERT_EQUAL(uint32_ptr[1], htonl(0x00000003)); + CU_ASSERT_EQUAL(uint32_ptr[2], htonl(0x01020300)); + pcep_obj_free_tlv(&tlv->header); + + /* Now test populating both the pst_list and the sub_tlv_list */ + reset_tlv_buffer(); + struct pcep_object_tlv_header *sub_tlv = + (struct pcep_object_tlv_header *) + pcep_tlv_create_sr_pce_capability(true, true, 0); + pst_list = dll_initialize(); + sub_tlv_list = dll_initialize(); + pst1 = pceplib_malloc(PCEPLIB_MESSAGES, 1); + *pst1 = 1; + dll_append(pst_list, pst1); + dll_append(sub_tlv_list, sub_tlv); + tlv = pcep_tlv_create_path_setup_type_capability(pst_list, + sub_tlv_list); + CU_ASSERT_PTR_NOT_NULL(tlv); + + pcep_encode_tlv(&tlv->header, versioning, tlv_buf); + CU_ASSERT_EQUAL(tlv->header.type, + PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE_CAPABILITY); + CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, + sizeof(uint32_t) * 2 + TLV_HEADER_LENGTH + + sub_tlv->encoded_tlv_length); + CU_ASSERT_PTR_NOT_NULL(tlv->pst_list); + CU_ASSERT_PTR_NOT_NULL(tlv->sub_tlv_list); + uint32_ptr = (uint32_t *)tlv->header.encoded_tlv; + uint16_t *uint16_ptr = (uint16_t *)tlv->header.encoded_tlv; + CU_ASSERT_EQUAL(uint16_ptr[0], + htons(PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE_CAPABILITY)); + CU_ASSERT_EQUAL(uint16_ptr[1], htons(tlv->header.encoded_tlv_length)); + CU_ASSERT_EQUAL(uint32_ptr[1], htonl(0x00000001)); + CU_ASSERT_EQUAL(uint32_ptr[2], htonl(0x01000000)); + /* Verify the Sub-TLV */ + uint16_ptr = (uint16_t *)(tlv->header.encoded_tlv + 12); + CU_ASSERT_EQUAL(uint16_ptr[0], + htons(PCEP_OBJ_TLV_TYPE_SR_PCE_CAPABILITY)); + CU_ASSERT_EQUAL(uint16_ptr[1], htons(4)); + CU_ASSERT_EQUAL(uint16_ptr[2], 0); + CU_ASSERT_EQUAL(uint16_ptr[3], htons(0x0300)); + + pcep_obj_free_tlv(&tlv->header); +} + +void test_pcep_tlv_create_sr_pce_capability() +{ + struct pcep_object_tlv_sr_pce_capability *tlv = + pcep_tlv_create_sr_pce_capability(true, true, 8); + CU_ASSERT_PTR_NOT_NULL(tlv); + + pcep_encode_tlv(&tlv->header, versioning, tlv_buf); + CU_ASSERT_EQUAL(tlv->header.type, PCEP_OBJ_TLV_TYPE_SR_PCE_CAPABILITY); + CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, sizeof(uint32_t)); + uint16_t *uint16_ptr = (uint16_t *)tlv->header.encoded_tlv; + CU_ASSERT_EQUAL(uint16_ptr[0], + htons(PCEP_OBJ_TLV_TYPE_SR_PCE_CAPABILITY)); + CU_ASSERT_EQUAL(uint16_ptr[1], htons(tlv->header.encoded_tlv_length)); + uint32_t *uint32_ptr = (uint32_t *)tlv->header.encoded_tlv; + CU_ASSERT_EQUAL(uint32_ptr[1], htonl(0x00000308)); + + pcep_obj_free_tlv(&tlv->header); +} + +void test_pcep_tlv_create_symbolic_path_name() +{ + /* char *symbolic_path_name, uint16_t symbolic_path_name_length); */ + char path_name[16] = "Some Path Name"; + uint16_t path_name_length = 14; + struct pcep_object_tlv_symbolic_path_name *tlv = + pcep_tlv_create_symbolic_path_name(path_name, path_name_length); + CU_ASSERT_PTR_NOT_NULL(tlv); + + pcep_encode_tlv(&tlv->header, versioning, tlv_buf); + CU_ASSERT_EQUAL(tlv->header.type, PCEP_OBJ_TLV_TYPE_SYMBOLIC_PATH_NAME); + CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, path_name_length); + /* Test the padding is correct */ + CU_ASSERT_EQUAL(0, strncmp((char *)&(tlv->header.encoded_tlv[4]), + &path_name[0], 4)); + CU_ASSERT_EQUAL(0, strncmp((char *)&(tlv->header.encoded_tlv[8]), + &path_name[4], 4)); + CU_ASSERT_EQUAL(0, strncmp((char *)&(tlv->header.encoded_tlv[12]), + &path_name[8], 4)); + CU_ASSERT_EQUAL(tlv->header.encoded_tlv[16], 'm'); + CU_ASSERT_EQUAL(tlv->header.encoded_tlv[17], 'e'); + CU_ASSERT_EQUAL(tlv->header.encoded_tlv[18], 0); + CU_ASSERT_EQUAL(tlv->header.encoded_tlv[19], 0); + pcep_obj_free_tlv(&tlv->header); + + reset_tlv_buffer(); + tlv = pcep_tlv_create_symbolic_path_name(path_name, 3); + CU_ASSERT_PTR_NOT_NULL(tlv); + pcep_encode_tlv(&tlv->header, versioning, tlv_buf); + CU_ASSERT_EQUAL(tlv->header.type, PCEP_OBJ_TLV_TYPE_SYMBOLIC_PATH_NAME); + CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, 3); + CU_ASSERT_EQUAL(tlv->header.encoded_tlv[4], 'S'); + CU_ASSERT_EQUAL(tlv->header.encoded_tlv[5], 'o'); + CU_ASSERT_EQUAL(tlv->header.encoded_tlv[6], 'm'); + CU_ASSERT_EQUAL(tlv->header.encoded_tlv[7], 0); + + pcep_obj_free_tlv(&tlv->header); +} + +void test_pcep_tlv_create_ipv4_lsp_identifiers() +{ + struct in_addr sender_ip, endpoint_ip; + uint16_t lsp_id = 7; + uint16_t tunnel_id = 16; + struct in_addr extended_tunnel_id; + extended_tunnel_id.s_addr = 256; + inet_pton(AF_INET, "192.168.1.1", &sender_ip); + inet_pton(AF_INET, "192.168.1.2", &endpoint_ip); + + struct pcep_object_tlv_ipv4_lsp_identifier *tlv = + pcep_tlv_create_ipv4_lsp_identifiers(NULL, &endpoint_ip, lsp_id, + tunnel_id, + &extended_tunnel_id); + CU_ASSERT_PTR_NULL(tlv); + + tlv = pcep_tlv_create_ipv4_lsp_identifiers( + &sender_ip, NULL, lsp_id, tunnel_id, &extended_tunnel_id); + CU_ASSERT_PTR_NULL(tlv); + + tlv = pcep_tlv_create_ipv4_lsp_identifiers( + NULL, NULL, lsp_id, tunnel_id, &extended_tunnel_id); + CU_ASSERT_PTR_NULL(tlv); + + tlv = pcep_tlv_create_ipv4_lsp_identifiers(&sender_ip, &endpoint_ip, + lsp_id, tunnel_id, + &extended_tunnel_id); + CU_ASSERT_PTR_NOT_NULL(tlv); + + pcep_encode_tlv(&tlv->header, versioning, tlv_buf); + CU_ASSERT_EQUAL(tlv->header.type, + PCEP_OBJ_TLV_TYPE_IPV4_LSP_IDENTIFIERS); + CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, sizeof(uint32_t) * 4); + uint32_t *uint32_ptr = (uint32_t *)tlv->header.encoded_tlv; + CU_ASSERT_EQUAL(uint32_ptr[1], sender_ip.s_addr); + CU_ASSERT_EQUAL(uint32_ptr[2], + (uint32_t)(htons(tunnel_id) << 16) | htons(lsp_id)); + CU_ASSERT_EQUAL(uint32_ptr[3], extended_tunnel_id.s_addr); + CU_ASSERT_EQUAL(uint32_ptr[4], endpoint_ip.s_addr); + pcep_obj_free_tlv(&tlv->header); + + reset_tlv_buffer(); + tlv = pcep_tlv_create_ipv4_lsp_identifiers(&sender_ip, &endpoint_ip, + lsp_id, tunnel_id, NULL); + CU_ASSERT_PTR_NOT_NULL(tlv); + + pcep_encode_tlv(&tlv->header, versioning, tlv_buf); + CU_ASSERT_EQUAL(tlv->header.type, + PCEP_OBJ_TLV_TYPE_IPV4_LSP_IDENTIFIERS); + CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, sizeof(uint32_t) * 4); + uint32_ptr = (uint32_t *)tlv->header.encoded_tlv; + CU_ASSERT_EQUAL(uint32_ptr[1], sender_ip.s_addr); + CU_ASSERT_EQUAL(uint32_ptr[2], + (uint32_t)(htons(tunnel_id) << 16) | htons(lsp_id)); + CU_ASSERT_EQUAL(uint32_ptr[3], INADDR_ANY); + CU_ASSERT_EQUAL(uint32_ptr[4], endpoint_ip.s_addr); + pcep_obj_free_tlv(&tlv->header); +} + +void test_pcep_tlv_create_ipv6_lsp_identifiers() +{ + struct in6_addr sender_ip, endpoint_ip; + uint16_t lsp_id = 3; + uint16_t tunnel_id = 16; + uint32_t extended_tunnel_id[4]; + + inet_pton(AF_INET6, "2001:db8::8a2e:370:7334", &sender_ip); + inet_pton(AF_INET6, "2001:db8::8a2e:370:8446", &endpoint_ip); + extended_tunnel_id[0] = 1; + extended_tunnel_id[1] = 2; + extended_tunnel_id[2] = 3; + extended_tunnel_id[3] = 4; + + struct pcep_object_tlv_ipv6_lsp_identifier *tlv = + pcep_tlv_create_ipv6_lsp_identifiers( + NULL, &endpoint_ip, lsp_id, tunnel_id, + (struct in6_addr *)&extended_tunnel_id); + CU_ASSERT_PTR_NULL(tlv); + + tlv = pcep_tlv_create_ipv6_lsp_identifiers( + &sender_ip, NULL, lsp_id, tunnel_id, + (struct in6_addr *)&extended_tunnel_id); + CU_ASSERT_PTR_NULL(tlv); + + tlv = pcep_tlv_create_ipv6_lsp_identifiers( + NULL, NULL, lsp_id, tunnel_id, + (struct in6_addr *)&extended_tunnel_id); + CU_ASSERT_PTR_NULL(tlv); + + tlv = pcep_tlv_create_ipv6_lsp_identifiers( + &sender_ip, &endpoint_ip, lsp_id, tunnel_id, + (struct in6_addr *)&extended_tunnel_id); + CU_ASSERT_PTR_NOT_NULL(tlv); + + pcep_encode_tlv(&tlv->header, versioning, tlv_buf); + CU_ASSERT_EQUAL(tlv->header.type, + PCEP_OBJ_TLV_TYPE_IPV6_LSP_IDENTIFIERS); + CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, 52); + uint32_t *uint32_ptr = (uint32_t *)tlv->header.encoded_tlv; + CU_ASSERT_EQUAL(uint32_ptr[5], + (uint32_t)(htons(tunnel_id) << 16) | htons(lsp_id)); + + pcep_obj_free_tlv(&tlv->header); +} +void test_pcep_tlv_create_srpag_pol_id_ipv4() +{ + uint32_t color = 1; + struct in_addr src; + inet_pton(AF_INET, "192.168.1.2", &src); + + struct pcep_object_tlv_srpag_pol_id *tlv = + pcep_tlv_create_srpag_pol_id_ipv4(color, (void *)&src); + CU_ASSERT_PTR_NOT_NULL(tlv); + + pcep_encode_tlv(&tlv->header, versioning, tlv_buf); + CU_ASSERT_EQUAL(tlv->header.type, (PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_ID)); + CU_ASSERT_EQUAL( + tlv->header.encoded_tlv_length, + (8 /*draft-barth-pce-segment-routing-policy-cp-04#5.1*/)); + CU_ASSERT_EQUAL(tlv->color, (color)); + uint32_t aux_color = htonl(color); // Is color right encoded + CU_ASSERT_EQUAL(0, memcmp(&tlv_buf[0] + TLV_HEADER_LENGTH, &aux_color, + sizeof(color))); + CU_ASSERT_EQUAL(tlv->end_point.ipv4.s_addr, (src.s_addr)); + // Are simetrical? + struct pcep_object_tlv_header *dec_hdr = pcep_decode_tlv(tlv_buf); + struct pcep_object_tlv_srpag_pol_id *dec_tlv = + (struct pcep_object_tlv_srpag_pol_id *)dec_hdr; + CU_ASSERT_EQUAL(tlv->color, dec_tlv->color); + + pceplib_free(PCEPLIB_MESSAGES, dec_hdr); + pcep_obj_free_tlv(&tlv->header); +} +void test_pcep_tlv_create_srpag_pol_id_ipv6() +{ + + uint32_t color = 1; + struct in6_addr src; + inet_pton(AF_INET6, "2001:db8::8a2e:370:7334", &src); + + struct pcep_object_tlv_srpag_pol_id *tlv = + pcep_tlv_create_srpag_pol_id_ipv6(color, &src); + + pcep_encode_tlv(&tlv->header, versioning, tlv_buf); + CU_ASSERT_EQUAL(tlv->header.type, (PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_ID)); + CU_ASSERT_EQUAL( + tlv->header.encoded_tlv_length, + (20 /*draft-barth-pce-segment-routing-policy-cp-04#5.1*/)); + CU_ASSERT_EQUAL(tlv->color, (color)); + CU_ASSERT_EQUAL(0, memcmp(&tlv->end_point.ipv6, &src, sizeof(src))); + + uint32_t aux_color = htonl(color); + CU_ASSERT_EQUAL(0, memcmp(&aux_color, tlv_buf + TLV_HEADER_LENGTH, + sizeof(tlv->color))); + // Are simetrical? + struct pcep_object_tlv_header *dec_hdr = pcep_decode_tlv(tlv_buf); + struct pcep_object_tlv_srpag_pol_id *dec_tlv = + (struct pcep_object_tlv_srpag_pol_id *)dec_hdr; + CU_ASSERT_EQUAL(tlv->color, dec_tlv->color); + + pceplib_free(PCEPLIB_MESSAGES, dec_hdr); + pcep_obj_free_tlv(&tlv->header); +} +void test_pcep_tlv_create_srpag_pol_name() +{ + const char *pol_name = "Some Pol Name"; + + struct pcep_object_tlv_srpag_pol_name *tlv = + pcep_tlv_create_srpag_pol_name(pol_name, strlen(pol_name)); + CU_ASSERT_PTR_NOT_NULL(tlv); + + pcep_encode_tlv(&tlv->header, versioning, tlv_buf); + CU_ASSERT_EQUAL(tlv->header.type, + (PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_NAME)); + CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, + (normalize_pcep_tlv_length(strlen(pol_name)))); + CU_ASSERT_EQUAL(0, strcmp(pol_name, (char *)tlv->name)); + + + pcep_obj_free_tlv(&tlv->header); +} + +void test_pcep_tlv_create_srpag_cp_id() +{ + // draft-ietf-spring-segment-routing-policy-06.pdf#2.3 + // 10 PCEP, 20 BGP SR Policy, 30 Via Configuration + uint8_t proto_origin = 10; + uint32_t ASN = 0; + struct in6_addr with_mapped_ipv4; + inet_pton(AF_INET6, "::ffff:192.0.2.128", &with_mapped_ipv4); + uint32_t discriminator = 0; + + struct pcep_object_tlv_srpag_cp_id *tlv = pcep_tlv_create_srpag_cp_id( + proto_origin, ASN, &with_mapped_ipv4, discriminator); + + pcep_encode_tlv(&tlv->header, versioning, tlv_buf); + CU_ASSERT_EQUAL(tlv->header.type, + (PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_ID)); + CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, + (sizeof(proto_origin) + sizeof(ASN) + + sizeof(with_mapped_ipv4) + sizeof(discriminator))); + CU_ASSERT_EQUAL(tlv->proto, (proto_origin)); + CU_ASSERT_EQUAL(tlv->orig_asn, (ASN)); + CU_ASSERT_EQUAL(0, memcmp(&tlv->orig_addres, &with_mapped_ipv4, + sizeof(with_mapped_ipv4))); + CU_ASSERT_EQUAL(tlv->discriminator, (discriminator)); + // Are simetrical? + struct pcep_object_tlv_header *dec_hdr = pcep_decode_tlv(tlv_buf); + struct pcep_object_tlv_srpag_cp_id *dec_tlv = + (struct pcep_object_tlv_srpag_cp_id *)dec_hdr; + CU_ASSERT_EQUAL(tlv->proto, dec_tlv->proto); + + pceplib_free(PCEPLIB_MESSAGES, dec_hdr); + pcep_obj_free_tlv(&tlv->header); +} + +void test_pcep_tlv_create_srpag_cp_pref() +{ + uint32_t preference_default = 100; + + struct pcep_object_tlv_srpag_cp_pref *tlv = + pcep_tlv_create_srpag_cp_pref(preference_default); + CU_ASSERT_PTR_NOT_NULL(tlv); + + pcep_encode_tlv(&tlv->header, versioning, tlv_buf); + CU_ASSERT_EQUAL(tlv->header.type, + (PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_PREFERENCE)); + printf(" encoded length vs sizeof pref (%d) vs (%ld)\n", + tlv->header.encoded_tlv_length, sizeof(preference_default)); + CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, + sizeof(preference_default)); + CU_ASSERT_EQUAL(tlv->preference, (preference_default)); + uint32_t aux_pref = htonl(preference_default); // Is pref right encoded + CU_ASSERT_EQUAL(0, memcmp(tlv_buf + TLV_HEADER_LENGTH, &aux_pref, + sizeof(preference_default))); + // Are simetrical? + struct pcep_object_tlv_header *dec_hdr = pcep_decode_tlv(tlv_buf); + struct pcep_object_tlv_srpag_cp_pref *dec_tlv = + (struct pcep_object_tlv_srpag_cp_pref *)dec_hdr; + CU_ASSERT_EQUAL(tlv->preference, dec_tlv->preference); + + pceplib_free(PCEPLIB_MESSAGES, dec_hdr); + pcep_obj_free_tlv(&tlv->header); +} +void test_pcep_tlv_create_lsp_error_code() +{ + struct pcep_object_tlv_lsp_error_code *tlv = + pcep_tlv_create_lsp_error_code( + PCEP_TLV_LSP_ERROR_CODE_RSVP_SIGNALING_ERROR); + CU_ASSERT_PTR_NOT_NULL(tlv); + + pcep_encode_tlv(&tlv->header, versioning, tlv_buf); + CU_ASSERT_EQUAL(tlv->header.type, PCEP_OBJ_TLV_TYPE_LSP_ERROR_CODE); + CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, sizeof(uint32_t)); + uint32_t *uint32_ptr = (uint32_t *)tlv->header.encoded_tlv; + CU_ASSERT_EQUAL(uint32_ptr[1], + htonl(PCEP_TLV_LSP_ERROR_CODE_RSVP_SIGNALING_ERROR)); + + pcep_obj_free_tlv(&tlv->header); +} + +void test_pcep_tlv_create_rsvp_ipv4_error_spec() +{ + struct in_addr error_node_ip; + inet_pton(AF_INET, "192.168.1.1", &error_node_ip); + uint8_t error_code = 8; + uint16_t error_value = 0xaabb; + + struct pcep_object_tlv_rsvp_error_spec *tlv = + pcep_tlv_create_rsvp_ipv4_error_spec(NULL, error_code, + error_value); + CU_ASSERT_PTR_NULL(tlv); + + tlv = pcep_tlv_create_rsvp_ipv4_error_spec(&error_node_ip, error_code, + error_value); + CU_ASSERT_PTR_NOT_NULL(tlv); + + pcep_encode_tlv(&tlv->header, versioning, tlv_buf); + CU_ASSERT_EQUAL(tlv->header.type, PCEP_OBJ_TLV_TYPE_RSVP_ERROR_SPEC); + CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, 12); + + pcep_obj_free_tlv(&tlv->header); +} + +void test_pcep_tlv_create_rsvp_ipv6_error_spec() +{ + struct in6_addr error_node_ip; + inet_pton(AF_INET6, "2001:db8::8a2e:370:7334", &error_node_ip); + uint8_t error_code = 8; + uint16_t error_value = 0xaabb; + + struct pcep_object_tlv_rsvp_error_spec *tlv = + pcep_tlv_create_rsvp_ipv6_error_spec(NULL, error_code, + error_value); + CU_ASSERT_PTR_NULL(tlv); + + tlv = pcep_tlv_create_rsvp_ipv6_error_spec(&error_node_ip, error_code, + error_value); + CU_ASSERT_PTR_NOT_NULL(tlv); + + pcep_encode_tlv(&tlv->header, versioning, tlv_buf); + CU_ASSERT_EQUAL(tlv->header.type, PCEP_OBJ_TLV_TYPE_RSVP_ERROR_SPEC); + CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, 24); + + pcep_obj_free_tlv(&tlv->header); +} + +void test_pcep_tlv_create_nopath_vector() +{ + uint32_t enterprise_number = 0x01020304; + uint32_t enterprise_specific_info = 0x05060708; + + struct pcep_object_tlv_vendor_info *tlv = pcep_tlv_create_vendor_info( + enterprise_number, enterprise_specific_info); + CU_ASSERT_PTR_NOT_NULL(tlv); + + pcep_encode_tlv(&tlv->header, versioning, tlv_buf); + CU_ASSERT_EQUAL(tlv->header.type, PCEP_OBJ_TLV_TYPE_VENDOR_INFO); + CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, 8); + uint32_t *uint32_ptr = (uint32_t *)tlv->header.encoded_tlv; + CU_ASSERT_EQUAL(uint32_ptr[1], htonl(enterprise_number)); + CU_ASSERT_EQUAL(uint32_ptr[2], htonl(enterprise_specific_info)); + + pcep_obj_free_tlv(&tlv->header); +} + +void test_pcep_tlv_create_arbitrary() +{ + char data[16] = "Some Data"; + uint16_t data_length = 9; + uint16_t tlv_id_unknown = 1; // 65505; // Whatever id to be created + struct pcep_object_tlv_arbitrary *tlv = pcep_tlv_create_tlv_arbitrary( + data, data_length, tlv_id_unknown); + CU_ASSERT_PTR_NOT_NULL(tlv); + + pcep_encode_tlv(&tlv->header, versioning, tlv_buf); + CU_ASSERT_EQUAL(tlv->header.type, tlv_id_unknown); + CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, data_length); + /* Test the padding is correct */ + CU_ASSERT_EQUAL( + 0, strncmp((char *)&(tlv->header.encoded_tlv[4]), &data[0], 4)); + CU_ASSERT_EQUAL( + 0, strncmp((char *)&(tlv->header.encoded_tlv[8]), &data[4], 4)); + CU_ASSERT_EQUAL(tlv->header.encoded_tlv[11], 't'); + CU_ASSERT_EQUAL(tlv->header.encoded_tlv[12], 'a'); + CU_ASSERT_EQUAL(tlv->header.encoded_tlv[13], 0); + CU_ASSERT_EQUAL(tlv->header.encoded_tlv[14], 0); + pcep_obj_free_tlv(&tlv->header); + + reset_tlv_buffer(); + tlv = pcep_tlv_create_tlv_arbitrary(data, 3, tlv_id_unknown); + CU_ASSERT_PTR_NOT_NULL(tlv); + pcep_encode_tlv(&tlv->header, versioning, tlv_buf); + CU_ASSERT_EQUAL(tlv->header.type, tlv_id_unknown); + CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, 3); + CU_ASSERT_EQUAL(tlv->header.encoded_tlv[4], 'S'); + CU_ASSERT_EQUAL(tlv->header.encoded_tlv[5], 'o'); + CU_ASSERT_EQUAL(tlv->header.encoded_tlv[6], 'm'); + CU_ASSERT_EQUAL(tlv->header.encoded_tlv[7], 0); + + pcep_obj_free_tlv(&tlv->header); +} diff --git a/pceplib/test/pcep_msg_tlvs_test.h b/pceplib/test/pcep_msg_tlvs_test.h new file mode 100644 index 0000000000..a961d7e473 --- /dev/null +++ b/pceplib/test/pcep_msg_tlvs_test.h @@ -0,0 +1,51 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Javier Garcia <javier.garcia@voltanet.io> + * + */ + +#ifndef PCEP_MSG_TLVS_TEST_H_ +#define PCEP_MSG_TLVS_TEST_H_ + +int pcep_tlvs_test_suite_setup(void); +int pcep_tlvs_test_suite_teardown(void); +void pcep_tlvs_test_setup(void); +void pcep_tlvs_test_teardown(void); +void test_pcep_tlv_create_stateful_pce_capability(void); +void test_pcep_tlv_create_speaker_entity_id(void); +void test_pcep_tlv_create_lsp_db_version(void); +void test_pcep_tlv_create_path_setup_type(void); +void test_pcep_tlv_create_path_setup_type_capability(void); +void test_pcep_tlv_create_sr_pce_capability(void); +void test_pcep_tlv_create_symbolic_path_name(void); +void test_pcep_tlv_create_ipv4_lsp_identifiers(void); +void test_pcep_tlv_create_ipv6_lsp_identifiers(void); +void test_pcep_tlv_create_lsp_error_code(void); +void test_pcep_tlv_create_rsvp_ipv4_error_spec(void); +void test_pcep_tlv_create_rsvp_ipv6_error_spec(void); +void test_pcep_tlv_create_srpag_pol_id_ipv4(void); +void test_pcep_tlv_create_srpag_pol_id_ipv6(void); +void test_pcep_tlv_create_srpag_pol_name(void); +void test_pcep_tlv_create_srpag_cp_id(void); +void test_pcep_tlv_create_srpag_cp_pref(void); +void test_pcep_tlv_create_nopath_vector(void); +void test_pcep_tlv_create_arbitrary(void); + + +#endif diff --git a/pceplib/test/pcep_msg_tools_test.c b/pceplib/test/pcep_msg_tools_test.c new file mode 100644 index 0000000000..ff5fc62390 --- /dev/null +++ b/pceplib/test/pcep_msg_tools_test.c @@ -0,0 +1,1305 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Brady Johnson <brady@voltanet.io> + * + */ + + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> + + +#include <CUnit/CUnit.h> + +#include "pcep_msg_encoding.h" +#include "pcep_msg_messages.h" +#include "pcep_msg_tools.h" +#include "pcep_msg_tools_test.h" +#include "pcep_utils_double_linked_list.h" +#include "pcep_utils_logging.h" +#include "pcep_utils_memory.h" + +const uint8_t any_obj_class = 255; + +uint16_t pcep_open_hexbyte_strs_length = 28; +const char *pcep_open_odl_hexbyte_strs[] = { + "20", "01", "00", "1c", "01", "10", "00", "18", "20", "1e", + "78", "55", "00", "10", "00", "04", "00", "00", "00", "3f", + "00", "1a", "00", "04", "00", "00", "00", "00"}; + +/* PCEP INITIATE str received from ODL with 4 objects: [SRP, LSP, Endpoints, + * ERO] The LSP has a SYMBOLIC_PATH_NAME TLV. The ERO has 2 IPV4 Endpoints. */ +uint16_t pcep_initiate_hexbyte_strs_length = 68; +const char *pcep_initiate_hexbyte_strs[] = { + "20", "0c", "00", "44", "21", "12", "00", "0c", "00", "00", "00", "00", + "00", "00", "00", "01", "20", "10", "00", "14", "00", "00", "00", "09", + "00", "11", "00", "08", "66", "61", "39", "33", "33", "39", "32", "39", + "04", "10", "00", "0c", "7f", "00", "00", "01", "28", "28", "28", "28", + "07", "10", "00", "14", "01", "08", "0a", "00", "01", "01", "18", "00", + "01", "08", "0a", "00", "07", "04", "18", "00"}; + +uint16_t pcep_initiate2_hexbyte_strs_length = 72; +const char *pcep_initiate2_hexbyte_strs[] = { + "20", "0c", "00", "48", "21", "12", "00", "14", "00", "00", "00", "00", + "00", "00", "00", "01", "00", "1c", "00", "04", "00", "00", "00", "01", + "20", "10", "00", "14", "00", "00", "00", "09", "00", "11", "00", "08", + "36", "65", "31", "31", "38", "39", "32", "31", "04", "10", "00", "0c", + "c0", "a8", "14", "05", "01", "01", "01", "01", "07", "10", "00", "10", + "05", "0c", "10", "01", "03", "e8", "a0", "00", "01", "01", "01", "01"}; + +uint16_t pcep_update_hexbyte_strs_length = 48; +const char *pcep_update_hexbyte_strs[] = { + "20", "0b", "00", "30", "21", "12", "00", "14", "00", "00", "00", "00", + "00", "00", "00", "01", "00", "1c", "00", "04", "00", "00", "00", "01", + "20", "10", "00", "08", "00", "02", "a0", "09", "07", "10", "00", "10", + "05", "0c", "10", "01", "03", "e8", "a0", "00", "01", "01", "01", "01"}; + +/* Test that pcep_msg_read() can read multiple messages in 1 call */ +uint16_t pcep_open_initiate_hexbyte_strs_length = 100; +const char *pcep_open_initiate_odl_hexbyte_strs[] = { + "20", "01", "00", "1c", "01", "10", "00", "18", "20", "1e", "78", "55", + "00", "10", "00", "04", "00", "00", "00", "3f", "00", "1a", "00", "04", + "00", "00", "00", "00", "20", "0c", "00", "48", "21", "12", "00", "14", + "00", "00", "00", "00", "00", "00", "00", "01", "00", "1c", "00", "04", + "00", "00", "00", "01", "20", "10", "00", "14", "00", "00", "00", "09", + "00", "11", "00", "08", "36", "65", "31", "31", "38", "39", "32", "31", + "04", "10", "00", "0c", "c0", "a8", "14", "05", "01", "01", "01", "01", + "07", "10", "00", "10", "05", "0c", "10", "01", "03", "e8", "a0", "00", + "01", "01", "01", "01"}; + +uint16_t pcep_open_cisco_pce_hexbyte_strs_length = 28; +const char *pcep_open_cisco_pce_hexbyte_strs[] = { + "20", "01", "00", "1c", "01", "10", "00", "18", "20", "3c", + "78", "00", "00", "10", "00", "04", "00", "00", "00", "05", + "00", "1a", "00", "04", "00", "00", "00", "0a"}; + +uint16_t pcep_update_cisco_pce_hexbyte_strs_length = 100; +const char *pcep_update_cisco_pce_hexbyte_strs[] = { + "20", "0b", "00", "64", "21", "10", "00", "14", "00", "00", "00", "00", + "00", "00", "00", "01", "00", "1c", "00", "04", "00", "00", "00", "01", + "20", "10", "00", "18", "80", "00", "f0", "89", "00", "07", "00", "0c", + "00", "00", "00", "09", "00", "03", "00", "04", "00", "00", "00", "01", + "07", "10", "00", "28", "24", "0c", "10", "01", "04", "65", "50", "00", + "0a", "0a", "0a", "05", "24", "0c", "10", "01", "04", "65", "20", "00", + "0a", "0a", "0a", "02", "24", "0c", "10", "01", "04", "65", "10", "00", + "0a", "0a", "0a", "01", "06", "10", "00", "0c", "00", "00", "00", "02", + "41", "f0", "00", "00"}; + +uint16_t pcep_report_cisco_pcc_hexbyte_strs_length = 148; +const char *pcep_report_cisco_pcc_hexbyte_strs[] = { + "20", "0a", "00", "94", "21", "10", "00", "14", "00", "00", "00", "00", + "00", "00", "00", "00", "00", "1c", "00", "04", "00", "00", "00", "01", + "20", "10", "00", "3c", "80", "00", "f0", "09", "00", "12", "00", "10", + "0a", "0a", "0a", "06", "00", "02", "00", "0f", "0a", "0a", "0a", "06", + "0a", "0a", "0a", "01", "00", "11", "00", "0d", "63", "66", "67", "5f", + "52", "36", "2d", "74", "6f", "2d", "52", "31", "00", "00", "00", "00", + "ff", "e1", "00", "06", "00", "00", "05", "dd", "70", "00", "00", "00", + "07", "10", "00", "04", "09", "10", "00", "14", "00", "00", "00", "00", + "00", "00", "00", "00", "00", "00", "00", "00", "07", "07", "01", "00", + "05", "12", "00", "08", "00", "00", "00", "00", "05", "52", "00", "08", + "00", "00", "00", "00", "06", "10", "00", "0c", "00", "00", "00", "02", + "00", "00", "00", "00", "06", "10", "00", "0c", "00", "00", "01", "04", + "41", "80", "00", "00"}; + +/* Cisco PcInitiate with the following objects: + * SRP, LSP, Endpoint, Inter-layer, Switch-layer, ERO + */ +uint16_t pcep_initiate_cisco_pcc_hexbyte_strs_length = 104; +const char *pcep_initiate_cisco_pcc_hexbyte_strs[] = { + "20", "0c", "00", "68", "21", "10", "00", "14", "00", "00", "00", "00", + "00", "00", "00", "01", "00", "1c", "00", "04", "00", "00", "00", "01", + "20", "10", "00", "30", "00", "00", "00", "89", "00", "11", "00", "13", + "50", "4f", "4c", "31", "5f", "50", "43", "49", "4e", "49", "54", "41", + "54", "45", "5f", "54", "45", "53", "54", "00", "00", "07", "00", "0c", + "00", "00", "00", "09", "00", "03", "00", "04", "00", "00", "00", "01", + "04", "10", "00", "0c", "0a", "0a", "0a", "0a", "0a", "0a", "0a", "04", + "24", "10", "00", "08", "00", "00", "01", "4d", "25", "10", "00", "08", + "00", "00", "00", "64", "07", "10", "00", "04"}; + +struct pcep_message *create_message(uint8_t msg_type, uint8_t obj1_class, + uint8_t obj2_class, uint8_t obj3_class, + uint8_t obj4_class); +int convert_hexstrs_to_binary(const char *hexbyte_strs[], + uint16_t hexbyte_strs_length); + +int pcep_tools_test_suite_setup(void) +{ + pceplib_memory_reset(); + return 0; +} + +int pcep_tools_test_suite_teardown(void) +{ + printf("\n"); + pceplib_memory_dump(); + return 0; +} + +void pcep_tools_test_setup(void) +{ +} + +void pcep_tools_test_teardown(void) +{ +} + +/* Reads an array of hexbyte strs, and writes them to a temporary file. + * The caller should close the returned file. */ +int convert_hexstrs_to_binary(const char *hexbyte_strs[], + uint16_t hexbyte_strs_length) +{ + 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++) { + uint8_t byte = (uint8_t)strtol(hexbyte_strs[i], 0, 16); + if (write(fd, (char *)&byte, 1) < 0) { + return -1; + } + } + + /* Go back to the beginning of the file */ + lseek(fd, 0, SEEK_SET); + return fd; +} + +static bool pcep_obj_has_tlv(struct pcep_object_header *obj_hdr) +{ + if (obj_hdr->tlv_list == NULL) { + return false; + } + + return (obj_hdr->tlv_list->num_entries > 0); +} + +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); + + struct pcep_message *msg = (struct pcep_message *)msg_list->head->data; + CU_ASSERT_EQUAL(msg->obj_list->num_entries, 4); + CU_ASSERT_EQUAL(msg->msg_header->type, PCEP_TYPE_INITIATE); + CU_ASSERT_EQUAL(msg->encoded_message_length, + pcep_initiate_hexbyte_strs_length); + + /* Verify each of the object types */ + + /* SRP object */ + double_linked_list_node *node = msg->obj_list->head; + struct pcep_object_header *obj_hdr = + (struct pcep_object_header *)node->data; + CU_ASSERT_EQUAL(obj_hdr->object_class, PCEP_OBJ_CLASS_SRP); + CU_ASSERT_EQUAL(obj_hdr->object_type, PCEP_OBJ_TYPE_SRP); + CU_ASSERT_EQUAL(obj_hdr->encoded_object_length, + pcep_object_get_length_by_hdr(obj_hdr)); + CU_ASSERT_FALSE(pcep_obj_has_tlv(obj_hdr)); + + /* LSP object and its TLV*/ + node = node->next_node; + obj_hdr = (struct pcep_object_header *)node->data; + CU_ASSERT_EQUAL(obj_hdr->object_class, PCEP_OBJ_CLASS_LSP); + CU_ASSERT_EQUAL(obj_hdr->object_type, PCEP_OBJ_TYPE_LSP); + CU_ASSERT_EQUAL(obj_hdr->encoded_object_length, 20); + CU_ASSERT_EQUAL(((struct pcep_object_lsp *)obj_hdr)->plsp_id, 0); + CU_ASSERT_TRUE(((struct pcep_object_lsp *)obj_hdr)->flag_d); + CU_ASSERT_TRUE(((struct pcep_object_lsp *)obj_hdr)->flag_a); + CU_ASSERT_FALSE(((struct pcep_object_lsp *)obj_hdr)->flag_s); + CU_ASSERT_FALSE(((struct pcep_object_lsp *)obj_hdr)->flag_r); + CU_ASSERT_FALSE(((struct pcep_object_lsp *)obj_hdr)->flag_c); + + /* LSP TLV */ + CU_ASSERT_TRUE(pcep_obj_has_tlv(obj_hdr)); + CU_ASSERT_EQUAL(obj_hdr->tlv_list->num_entries, 1); + struct pcep_object_tlv_header *tlv = + (struct pcep_object_tlv_header *)obj_hdr->tlv_list->head->data; + CU_ASSERT_EQUAL(tlv->type, PCEP_OBJ_TLV_TYPE_SYMBOLIC_PATH_NAME); + CU_ASSERT_EQUAL(tlv->encoded_tlv_length, 8); + + /* Endpoints object */ + node = node->next_node; + obj_hdr = (struct pcep_object_header *)node->data; + CU_ASSERT_EQUAL(obj_hdr->object_class, PCEP_OBJ_CLASS_ENDPOINTS); + CU_ASSERT_EQUAL(obj_hdr->object_type, PCEP_OBJ_TYPE_ENDPOINT_IPV4); + CU_ASSERT_EQUAL(obj_hdr->encoded_object_length, + pcep_object_get_length_by_hdr(obj_hdr)); + CU_ASSERT_FALSE(pcep_obj_has_tlv(obj_hdr)); + + /* ERO object */ + node = node->next_node; + obj_hdr = (struct pcep_object_header *)node->data; + CU_ASSERT_EQUAL(obj_hdr->object_class, PCEP_OBJ_CLASS_ERO); + CU_ASSERT_EQUAL(obj_hdr->object_type, PCEP_OBJ_TYPE_ERO); + CU_ASSERT_EQUAL(obj_hdr->encoded_object_length, 20); + + /* ERO Subobjects */ + double_linked_list *ero_subobj_list = + ((struct pcep_object_ro *)obj_hdr)->sub_objects; + CU_ASSERT_PTR_NOT_NULL(ero_subobj_list); + CU_ASSERT_EQUAL(ero_subobj_list->num_entries, 2); + double_linked_list_node *subobj_node = ero_subobj_list->head; + struct pcep_object_ro_subobj *subobj_hdr = + (struct pcep_object_ro_subobj *)subobj_node->data; + CU_ASSERT_EQUAL(subobj_hdr->ro_subobj_type, RO_SUBOBJ_TYPE_IPV4); + struct in_addr ero_subobj_ip; + inet_pton(AF_INET, "10.0.1.1", &ero_subobj_ip); + CU_ASSERT_EQUAL( + ((struct pcep_ro_subobj_ipv4 *)subobj_hdr)->ip_addr.s_addr, + ero_subobj_ip.s_addr); + CU_ASSERT_EQUAL( + ((struct pcep_ro_subobj_ipv4 *)subobj_hdr)->prefix_length, 24); + + subobj_hdr = + (struct pcep_object_ro_subobj *)subobj_node->next_node->data; + CU_ASSERT_EQUAL(subobj_hdr->ro_subobj_type, RO_SUBOBJ_TYPE_IPV4); + inet_pton(AF_INET, "10.0.7.4", &ero_subobj_ip); + CU_ASSERT_EQUAL( + ((struct pcep_ro_subobj_ipv4 *)subobj_hdr)->ip_addr.s_addr, + ero_subobj_ip.s_addr); + CU_ASSERT_EQUAL( + ((struct pcep_ro_subobj_ipv4 *)subobj_hdr)->prefix_length, 24); + + pcep_msg_free_message_list(msg_list); + close(fd); +} + + +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); + + struct pcep_message *msg = (struct pcep_message *)msg_list->head->data; + CU_ASSERT_EQUAL(msg->obj_list->num_entries, 4); + CU_ASSERT_EQUAL(msg->msg_header->type, PCEP_TYPE_INITIATE); + CU_ASSERT_EQUAL(msg->encoded_message_length, + pcep_initiate2_hexbyte_strs_length); + + /* Verify each of the object types */ + + /* SRP object */ + double_linked_list_node *node = msg->obj_list->head; + struct pcep_object_header *obj_hdr = + (struct pcep_object_header *)node->data; + CU_ASSERT_EQUAL(obj_hdr->object_class, PCEP_OBJ_CLASS_SRP); + CU_ASSERT_EQUAL(obj_hdr->object_type, PCEP_OBJ_TYPE_SRP); + CU_ASSERT_EQUAL(obj_hdr->encoded_object_length, 20); + CU_ASSERT_TRUE(pcep_obj_has_tlv(obj_hdr)); + /* TODO test the TLVs */ + + /* LSP object and its TLV*/ + node = node->next_node; + obj_hdr = (struct pcep_object_header *)node->data; + CU_ASSERT_EQUAL(obj_hdr->object_class, PCEP_OBJ_CLASS_LSP); + CU_ASSERT_EQUAL(obj_hdr->object_type, PCEP_OBJ_TYPE_LSP); + CU_ASSERT_EQUAL(obj_hdr->encoded_object_length, 20); + + /* LSP TLV */ + CU_ASSERT_TRUE(pcep_obj_has_tlv(obj_hdr)); + CU_ASSERT_EQUAL(obj_hdr->tlv_list->num_entries, 1); + struct pcep_object_tlv_header *tlv = + (struct pcep_object_tlv_header *)obj_hdr->tlv_list->head->data; + CU_ASSERT_EQUAL(tlv->type, PCEP_OBJ_TLV_TYPE_SYMBOLIC_PATH_NAME); + CU_ASSERT_EQUAL(tlv->encoded_tlv_length, 8); + + /* Endpoints object */ + node = node->next_node; + obj_hdr = (struct pcep_object_header *)node->data; + CU_ASSERT_EQUAL(obj_hdr->object_class, PCEP_OBJ_CLASS_ENDPOINTS); + CU_ASSERT_EQUAL(obj_hdr->object_type, PCEP_OBJ_TYPE_ENDPOINT_IPV4); + CU_ASSERT_EQUAL(obj_hdr->encoded_object_length, + pcep_object_get_length_by_hdr(obj_hdr)); + CU_ASSERT_FALSE(pcep_obj_has_tlv(obj_hdr)); + + /* ERO object */ + node = node->next_node; + obj_hdr = (struct pcep_object_header *)node->data; + CU_ASSERT_EQUAL(obj_hdr->object_class, PCEP_OBJ_CLASS_ERO); + CU_ASSERT_EQUAL(obj_hdr->object_type, PCEP_OBJ_TYPE_ERO); + CU_ASSERT_EQUAL(obj_hdr->encoded_object_length, 16); + + /* ERO Subobjects */ + double_linked_list *ero_subobj_list = + ((struct pcep_object_ro *)obj_hdr)->sub_objects; + CU_ASSERT_PTR_NOT_NULL(ero_subobj_list); + CU_ASSERT_EQUAL(ero_subobj_list->num_entries, 0); + double_linked_list_node *subobj_node = ero_subobj_list->head; + CU_ASSERT_PTR_NULL(subobj_node); + /* We no longer support draft07 SR sub-object type=5, and only support + type=36 struct pcep_object_ro_subobj *subobj_hdr = (struct + pcep_object_ro_subobj *) subobj_node->data; + CU_ASSERT_EQUAL(subobj_hdr->ro_subobj_type, RO_SUBOBJ_TYPE_SR); + struct pcep_ro_subobj_sr *subobj_sr = (struct pcep_ro_subobj_sr *) + subobj_hdr; CU_ASSERT_EQUAL(subobj_sr->nai_type, + PCEP_SR_SUBOBJ_NAI_IPV4_NODE); CU_ASSERT_TRUE(subobj_sr->flag_m); + CU_ASSERT_FALSE(subobj_sr->flag_c); + CU_ASSERT_FALSE(subobj_sr->flag_s); + CU_ASSERT_FALSE(subobj_sr->flag_f); + CU_ASSERT_EQUAL(subobj_sr->sid, 65576960); + CU_ASSERT_EQUAL(*((uint32_t *) subobj_sr->nai_list->head->data), + 0x01010101); + */ + + pcep_msg_free_message_list(msg_list); + close(fd); +} + +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); + + struct pcep_message *msg = (struct pcep_message *)msg_list->head->data; + CU_ASSERT_EQUAL(msg->obj_list->num_entries, 1); + CU_ASSERT_EQUAL(msg->msg_header->type, PCEP_TYPE_OPEN); + CU_ASSERT_EQUAL(msg->encoded_message_length, + pcep_open_hexbyte_strs_length); + + /* Verify the Open message */ + struct pcep_object_header *obj_hdr = + (struct pcep_object_header *)msg->obj_list->head->data; + CU_ASSERT_EQUAL(obj_hdr->object_class, PCEP_OBJ_CLASS_OPEN); + CU_ASSERT_EQUAL(obj_hdr->object_type, PCEP_OBJ_TYPE_OPEN); + CU_ASSERT_EQUAL(obj_hdr->encoded_object_length, 24); + CU_ASSERT_TRUE(pcep_obj_has_tlv(obj_hdr)); + + /* Open TLV: Stateful PCE Capability */ + CU_ASSERT_EQUAL(obj_hdr->tlv_list->num_entries, 2); + double_linked_list_node *tlv_node = obj_hdr->tlv_list->head; + struct pcep_object_tlv_header *tlv = + (struct pcep_object_tlv_header *)tlv_node->data; + CU_ASSERT_EQUAL(tlv->type, PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY); + CU_ASSERT_EQUAL(tlv->encoded_tlv_length, 4); + + /* Open TLV: SR PCE Capability */ + tlv_node = tlv_node->next_node; + tlv = (struct pcep_object_tlv_header *)tlv_node->data; + CU_ASSERT_EQUAL(tlv->type, PCEP_OBJ_TLV_TYPE_SR_PCE_CAPABILITY); + CU_ASSERT_EQUAL(tlv->encoded_tlv_length, 4); + + pcep_msg_free_message_list(msg_list); + close(fd); +} + +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); + + struct pcep_message *msg = (struct pcep_message *)msg_list->head->data; + CU_ASSERT_EQUAL(msg->obj_list->num_entries, 3); + + CU_ASSERT_EQUAL(msg->msg_header->type, PCEP_TYPE_UPDATE); + CU_ASSERT_EQUAL(msg->encoded_message_length, + pcep_update_hexbyte_strs_length); + + /* Verify each of the object types */ + + double_linked_list_node *node = msg->obj_list->head; + + /* SRP object */ + struct pcep_object_header *obj_hdr = + (struct pcep_object_header *)node->data; + CU_ASSERT_EQUAL(obj_hdr->object_class, PCEP_OBJ_CLASS_SRP); + CU_ASSERT_EQUAL(obj_hdr->object_type, PCEP_OBJ_TYPE_SRP); + CU_ASSERT_EQUAL(obj_hdr->encoded_object_length, 20); + CU_ASSERT_TRUE(pcep_obj_has_tlv(obj_hdr)); + + /* SRP TLV */ + CU_ASSERT_EQUAL(obj_hdr->tlv_list->num_entries, 1); + struct pcep_object_tlv_header *tlv = + (struct pcep_object_tlv_header *)obj_hdr->tlv_list->head->data; + CU_ASSERT_EQUAL(tlv->type, PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE); + CU_ASSERT_EQUAL(tlv->encoded_tlv_length, 4); + /* TODO verify the path setup type */ + + /* LSP object */ + node = node->next_node; + obj_hdr = (struct pcep_object_header *)node->data; + CU_ASSERT_EQUAL(obj_hdr->object_class, PCEP_OBJ_CLASS_LSP); + CU_ASSERT_EQUAL(obj_hdr->object_type, PCEP_OBJ_TYPE_LSP); + CU_ASSERT_EQUAL(obj_hdr->encoded_object_length, + pcep_object_get_length_by_hdr(obj_hdr)); + CU_ASSERT_FALSE(pcep_obj_has_tlv(obj_hdr)); + + /* ERO object */ + node = node->next_node; + obj_hdr = (struct pcep_object_header *)node->data; + CU_ASSERT_EQUAL(obj_hdr->object_class, PCEP_OBJ_CLASS_ERO); + CU_ASSERT_EQUAL(obj_hdr->object_type, PCEP_OBJ_TYPE_ERO); + CU_ASSERT_EQUAL(obj_hdr->encoded_object_length, 16); + + /* ERO Subobjects */ + double_linked_list *ero_subobj_list = + ((struct pcep_object_ro *)obj_hdr)->sub_objects; + CU_ASSERT_PTR_NOT_NULL(ero_subobj_list); + CU_ASSERT_EQUAL(ero_subobj_list->num_entries, 0); + double_linked_list_node *subobj_node = ero_subobj_list->head; + CU_ASSERT_PTR_NULL(subobj_node); + /* We no longer support draft07 SR sub-object type=5, and only support + type=36 struct pcep_object_ro_subobj *subobj_hdr = (struct + pcep_object_ro_subobj *) subobj_node->data; + CU_ASSERT_EQUAL(subobj_hdr->ro_subobj_type, RO_SUBOBJ_TYPE_SR); + struct pcep_ro_subobj_sr *subobj_sr = (struct pcep_ro_subobj_sr *) + subobj_hdr; CU_ASSERT_EQUAL(subobj_sr->nai_type, + PCEP_SR_SUBOBJ_NAI_IPV4_NODE); CU_ASSERT_TRUE(subobj_sr->flag_m); + CU_ASSERT_FALSE(subobj_sr->flag_c); + CU_ASSERT_FALSE(subobj_sr->flag_s); + CU_ASSERT_FALSE(subobj_sr->flag_f); + CU_ASSERT_EQUAL(subobj_sr->sid, 65576960); + CU_ASSERT_EQUAL(*((uint32_t *) subobj_sr->nai_list->head->data), + 0x01010101); + */ + + pcep_msg_free_message_list(msg_list); + close(fd); +} + +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); + + struct pcep_message *msg = (struct pcep_message *)msg_list->head->data; + CU_ASSERT_EQUAL(msg->obj_list->num_entries, 1); + CU_ASSERT_EQUAL(msg->msg_header->type, PCEP_TYPE_OPEN); + CU_ASSERT_EQUAL(msg->encoded_message_length, + pcep_open_hexbyte_strs_length); + + msg = (struct pcep_message *)msg_list->head->next_node->data; + CU_ASSERT_EQUAL(msg->obj_list->num_entries, 4); + CU_ASSERT_EQUAL(msg->msg_header->type, PCEP_TYPE_INITIATE); + CU_ASSERT_EQUAL(msg->encoded_message_length, + pcep_initiate2_hexbyte_strs_length); + + pcep_msg_free_message_list(msg_list); + close(fd); +} + +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); + + struct pcep_message *msg = (struct pcep_message *)msg_list->head->data; + CU_ASSERT_EQUAL(msg->msg_header->type, PCEP_TYPE_OPEN); + CU_ASSERT_EQUAL(msg->encoded_message_length, + pcep_open_hexbyte_strs_length); + CU_ASSERT_EQUAL(msg->obj_list->num_entries, 1); + + /* Open object */ + struct pcep_object_open *open = + (struct pcep_object_open *)msg->obj_list->head->data; + CU_ASSERT_EQUAL(open->header.object_class, PCEP_OBJ_CLASS_OPEN); + CU_ASSERT_EQUAL(open->header.object_type, PCEP_OBJ_TYPE_OPEN); + CU_ASSERT_EQUAL(open->header.encoded_object_length, 24); + CU_ASSERT_EQUAL(open->open_deadtimer, 120); + CU_ASSERT_EQUAL(open->open_keepalive, 60); + CU_ASSERT_EQUAL(open->open_sid, 0); + CU_ASSERT_EQUAL(open->open_version, 1); + CU_ASSERT_PTR_NOT_NULL(open->header.tlv_list); + CU_ASSERT_EQUAL(open->header.tlv_list->num_entries, 2); + + /* Stateful PCE Capability TLV */ + double_linked_list_node *tlv_node = open->header.tlv_list->head; + struct pcep_object_tlv_stateful_pce_capability *pce_cap_tlv = + (struct pcep_object_tlv_stateful_pce_capability *) + tlv_node->data; + CU_ASSERT_EQUAL(pce_cap_tlv->header.type, + PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY); + CU_ASSERT_EQUAL(pce_cap_tlv->header.encoded_tlv_length, 4); + CU_ASSERT_TRUE(pce_cap_tlv->flag_u_lsp_update_capability); + CU_ASSERT_TRUE(pce_cap_tlv->flag_i_lsp_instantiation_capability); + CU_ASSERT_FALSE(pce_cap_tlv->flag_s_include_db_version); + CU_ASSERT_FALSE(pce_cap_tlv->flag_t_triggered_resync); + CU_ASSERT_FALSE(pce_cap_tlv->flag_d_delta_lsp_sync); + CU_ASSERT_FALSE(pce_cap_tlv->flag_f_triggered_initial_sync); + + /* SR PCE Capability TLV */ + tlv_node = tlv_node->next_node; + struct pcep_object_tlv_sr_pce_capability *sr_pce_cap_tlv = + (struct pcep_object_tlv_sr_pce_capability *)tlv_node->data; + CU_ASSERT_EQUAL(sr_pce_cap_tlv->header.type, + PCEP_OBJ_TLV_TYPE_SR_PCE_CAPABILITY); + CU_ASSERT_EQUAL(sr_pce_cap_tlv->header.encoded_tlv_length, 4); + CU_ASSERT_FALSE(sr_pce_cap_tlv->flag_n); + CU_ASSERT_FALSE(sr_pce_cap_tlv->flag_x); + CU_ASSERT_EQUAL(sr_pce_cap_tlv->max_sid_depth, 10); + + pcep_msg_free_message_list(msg_list); + close(fd); +} + +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); + + struct pcep_message *msg = (struct pcep_message *)msg_list->head->data; + CU_ASSERT_EQUAL(msg->msg_header->type, PCEP_TYPE_UPDATE); + CU_ASSERT_EQUAL(msg->encoded_message_length, + pcep_update_cisco_pce_hexbyte_strs_length); + CU_ASSERT_EQUAL(msg->obj_list->num_entries, 4); + + /* SRP object */ + double_linked_list_node *obj_node = msg->obj_list->head; + struct pcep_object_srp *srp = (struct pcep_object_srp *)obj_node->data; + CU_ASSERT_EQUAL(srp->header.object_class, PCEP_OBJ_CLASS_SRP); + CU_ASSERT_EQUAL(srp->header.object_type, PCEP_OBJ_TYPE_SRP); + CU_ASSERT_EQUAL(srp->header.encoded_object_length, 20); + CU_ASSERT_PTR_NOT_NULL(srp->header.tlv_list); + CU_ASSERT_EQUAL(srp->header.tlv_list->num_entries, 1); + CU_ASSERT_EQUAL(srp->srp_id_number, 1); + CU_ASSERT_FALSE(srp->flag_lsp_remove); + + /* SRP Path Setup Type TLV */ + double_linked_list_node *tlv_node = srp->header.tlv_list->head; + struct pcep_object_tlv_path_setup_type *pst_tlv = + (struct pcep_object_tlv_path_setup_type *)tlv_node->data; + CU_ASSERT_EQUAL(pst_tlv->header.type, + PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE); + CU_ASSERT_EQUAL(pst_tlv->header.encoded_tlv_length, 4); + CU_ASSERT_EQUAL(pst_tlv->path_setup_type, 1); + + /* LSP object */ + obj_node = obj_node->next_node; + struct pcep_object_lsp *lsp = (struct pcep_object_lsp *)obj_node->data; + CU_ASSERT_EQUAL(lsp->header.object_class, PCEP_OBJ_CLASS_LSP); + CU_ASSERT_EQUAL(lsp->header.object_type, PCEP_OBJ_TYPE_LSP); + CU_ASSERT_EQUAL(lsp->header.encoded_object_length, 24); + CU_ASSERT_PTR_NOT_NULL(lsp->header.tlv_list); + CU_ASSERT_EQUAL(lsp->header.tlv_list->num_entries, 1); + CU_ASSERT_EQUAL(lsp->plsp_id, 524303); + CU_ASSERT_EQUAL(lsp->operational_status, PCEP_LSP_OPERATIONAL_DOWN); + CU_ASSERT_TRUE(lsp->flag_a); + CU_ASSERT_TRUE(lsp->flag_c); + CU_ASSERT_TRUE(lsp->flag_d); + CU_ASSERT_FALSE(lsp->flag_r); + CU_ASSERT_FALSE(lsp->flag_s); + + /* LSP Vendor Info TLV */ + tlv_node = lsp->header.tlv_list->head; + struct pcep_object_tlv_vendor_info *vendor_tlv = + (struct pcep_object_tlv_vendor_info *)tlv_node->data; + CU_ASSERT_EQUAL(vendor_tlv->header.type, PCEP_OBJ_TLV_TYPE_VENDOR_INFO); + CU_ASSERT_EQUAL(vendor_tlv->header.encoded_tlv_length, 12); + CU_ASSERT_EQUAL(vendor_tlv->enterprise_number, 9); + CU_ASSERT_EQUAL(vendor_tlv->enterprise_specific_info, 0x00030004); + + /* ERO object */ + obj_node = obj_node->next_node; + struct pcep_object_ro *ero = (struct pcep_object_ro *)obj_node->data; + CU_ASSERT_EQUAL(ero->header.object_class, PCEP_OBJ_CLASS_ERO); + CU_ASSERT_EQUAL(ero->header.object_type, PCEP_OBJ_TYPE_ERO); + CU_ASSERT_EQUAL(ero->header.encoded_object_length, 40); + CU_ASSERT_PTR_NULL(ero->header.tlv_list); + CU_ASSERT_PTR_NOT_NULL(ero->sub_objects); + CU_ASSERT_EQUAL(ero->sub_objects->num_entries, 3); + + /* ERO Subobjects */ + double_linked_list_node *ero_subobj_node = ero->sub_objects->head; + struct pcep_ro_subobj_sr *sr_subobj_ipv4_node = + (struct pcep_ro_subobj_sr *)ero_subobj_node->data; + CU_ASSERT_EQUAL(sr_subobj_ipv4_node->ro_subobj.ro_subobj_type, + RO_SUBOBJ_TYPE_SR); + CU_ASSERT_FALSE(sr_subobj_ipv4_node->ro_subobj.flag_subobj_loose_hop); + CU_ASSERT_EQUAL(sr_subobj_ipv4_node->nai_type, + PCEP_SR_SUBOBJ_NAI_IPV4_NODE); + CU_ASSERT_TRUE(sr_subobj_ipv4_node->flag_m); + CU_ASSERT_FALSE(sr_subobj_ipv4_node->flag_c); + CU_ASSERT_FALSE(sr_subobj_ipv4_node->flag_f); + CU_ASSERT_FALSE(sr_subobj_ipv4_node->flag_s); + CU_ASSERT_EQUAL(sr_subobj_ipv4_node->sid, 73748480); + CU_ASSERT_EQUAL( + *((uint32_t *)sr_subobj_ipv4_node->nai_list->head->data), + htonl(0x0a0a0a05)); + + ero_subobj_node = ero_subobj_node->next_node; + sr_subobj_ipv4_node = (struct pcep_ro_subobj_sr *)ero_subobj_node->data; + CU_ASSERT_EQUAL(sr_subobj_ipv4_node->ro_subobj.ro_subobj_type, + RO_SUBOBJ_TYPE_SR); + CU_ASSERT_FALSE(sr_subobj_ipv4_node->ro_subobj.flag_subobj_loose_hop); + CU_ASSERT_EQUAL(sr_subobj_ipv4_node->nai_type, + PCEP_SR_SUBOBJ_NAI_IPV4_NODE); + CU_ASSERT_TRUE(sr_subobj_ipv4_node->flag_m); + CU_ASSERT_FALSE(sr_subobj_ipv4_node->flag_c); + CU_ASSERT_FALSE(sr_subobj_ipv4_node->flag_f); + CU_ASSERT_FALSE(sr_subobj_ipv4_node->flag_s); + CU_ASSERT_EQUAL(sr_subobj_ipv4_node->sid, 73736192); + CU_ASSERT_EQUAL( + *((uint32_t *)sr_subobj_ipv4_node->nai_list->head->data), + htonl(0x0a0a0a02)); + + ero_subobj_node = ero_subobj_node->next_node; + sr_subobj_ipv4_node = (struct pcep_ro_subobj_sr *)ero_subobj_node->data; + CU_ASSERT_EQUAL(sr_subobj_ipv4_node->ro_subobj.ro_subobj_type, + RO_SUBOBJ_TYPE_SR); + CU_ASSERT_FALSE(sr_subobj_ipv4_node->ro_subobj.flag_subobj_loose_hop); + CU_ASSERT_EQUAL(sr_subobj_ipv4_node->nai_type, + PCEP_SR_SUBOBJ_NAI_IPV4_NODE); + CU_ASSERT_TRUE(sr_subobj_ipv4_node->flag_m); + CU_ASSERT_FALSE(sr_subobj_ipv4_node->flag_c); + CU_ASSERT_FALSE(sr_subobj_ipv4_node->flag_f); + CU_ASSERT_FALSE(sr_subobj_ipv4_node->flag_s); + CU_ASSERT_EQUAL(sr_subobj_ipv4_node->sid, 73732096); + CU_ASSERT_EQUAL( + *((uint32_t *)sr_subobj_ipv4_node->nai_list->head->data), + htonl(0x0a0a0a01)); + + /* Metric object */ + obj_node = obj_node->next_node; + struct pcep_object_metric *metric = + (struct pcep_object_metric *)obj_node->data; + CU_ASSERT_EQUAL(metric->header.object_class, PCEP_OBJ_CLASS_METRIC); + CU_ASSERT_EQUAL(metric->header.object_type, PCEP_OBJ_TYPE_METRIC); + CU_ASSERT_EQUAL(metric->header.encoded_object_length, 12); + CU_ASSERT_PTR_NULL(metric->header.tlv_list); + CU_ASSERT_FALSE(metric->flag_b); + CU_ASSERT_FALSE(metric->flag_c); + CU_ASSERT_EQUAL(metric->type, PCEP_METRIC_TE); + CU_ASSERT_EQUAL(metric->value, 30.0); + + pcep_msg_free_message_list(msg_list); + close(fd); +} + +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); + + struct pcep_message *msg = (struct pcep_message *)msg_list->head->data; + CU_ASSERT_EQUAL(msg->msg_header->type, PCEP_TYPE_REPORT); + CU_ASSERT_EQUAL(msg->encoded_message_length, + pcep_report_cisco_pcc_hexbyte_strs_length); + CU_ASSERT_EQUAL(msg->obj_list->num_entries, 8); + + /* SRP object */ + double_linked_list_node *obj_node = msg->obj_list->head; + struct pcep_object_srp *srp = (struct pcep_object_srp *)obj_node->data; + CU_ASSERT_EQUAL(srp->header.object_class, PCEP_OBJ_CLASS_SRP); + CU_ASSERT_EQUAL(srp->header.object_type, PCEP_OBJ_TYPE_SRP); + CU_ASSERT_EQUAL(srp->header.encoded_object_length, 20); + CU_ASSERT_PTR_NOT_NULL(srp->header.tlv_list); + CU_ASSERT_EQUAL(srp->header.tlv_list->num_entries, 1); + CU_ASSERT_EQUAL(srp->srp_id_number, 0); + CU_ASSERT_FALSE(srp->flag_lsp_remove); + + /* SRP Path Setup Type TLV */ + double_linked_list_node *tlv_node = srp->header.tlv_list->head; + struct pcep_object_tlv_path_setup_type *pst_tlv = + (struct pcep_object_tlv_path_setup_type *)tlv_node->data; + CU_ASSERT_EQUAL(pst_tlv->header.type, + PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE); + CU_ASSERT_EQUAL(pst_tlv->header.encoded_tlv_length, 4); + CU_ASSERT_EQUAL(pst_tlv->path_setup_type, 1); + + /* LSP object */ + obj_node = obj_node->next_node; + struct pcep_object_lsp *lsp = (struct pcep_object_lsp *)obj_node->data; + CU_ASSERT_EQUAL(lsp->header.object_class, PCEP_OBJ_CLASS_LSP); + CU_ASSERT_EQUAL(lsp->header.object_type, PCEP_OBJ_TYPE_LSP); + CU_ASSERT_EQUAL(lsp->header.encoded_object_length, 60); + CU_ASSERT_PTR_NOT_NULL(lsp->header.tlv_list); + /* The TLV with ID 65505 is not recognized, and its not in the list */ + CU_ASSERT_EQUAL(lsp->header.tlv_list->num_entries, 2); + CU_ASSERT_EQUAL(lsp->plsp_id, 524303); + CU_ASSERT_EQUAL(lsp->operational_status, PCEP_LSP_OPERATIONAL_DOWN); + CU_ASSERT_TRUE(lsp->flag_a); + CU_ASSERT_TRUE(lsp->flag_d); + CU_ASSERT_FALSE(lsp->flag_c); + CU_ASSERT_FALSE(lsp->flag_r); + CU_ASSERT_FALSE(lsp->flag_s); + + /* LSP IPv4 LSP Identifier TLV */ + tlv_node = lsp->header.tlv_list->head; + struct pcep_object_tlv_ipv4_lsp_identifier *ipv4_lsp_id = + (struct pcep_object_tlv_ipv4_lsp_identifier *)tlv_node->data; + CU_ASSERT_EQUAL(ipv4_lsp_id->header.type, + PCEP_OBJ_TLV_TYPE_IPV4_LSP_IDENTIFIERS); + CU_ASSERT_EQUAL(ipv4_lsp_id->header.encoded_tlv_length, 16); + CU_ASSERT_EQUAL(ipv4_lsp_id->ipv4_tunnel_sender.s_addr, + htonl(0x0a0a0a06)); + CU_ASSERT_EQUAL(ipv4_lsp_id->ipv4_tunnel_endpoint.s_addr, + htonl(0x0a0a0a01)); + CU_ASSERT_EQUAL(ipv4_lsp_id->extended_tunnel_id.s_addr, + htonl(0x0a0a0a06)); + CU_ASSERT_EQUAL(ipv4_lsp_id->tunnel_id, 15); + CU_ASSERT_EQUAL(ipv4_lsp_id->lsp_id, 2); + + /* LSP Symbolic Path Name TLV */ + tlv_node = tlv_node->next_node; + struct pcep_object_tlv_symbolic_path_name *sym_path_name = + (struct pcep_object_tlv_symbolic_path_name *)tlv_node->data; + CU_ASSERT_EQUAL(sym_path_name->header.type, + PCEP_OBJ_TLV_TYPE_SYMBOLIC_PATH_NAME); + CU_ASSERT_EQUAL(sym_path_name->header.encoded_tlv_length, 13); + CU_ASSERT_EQUAL(sym_path_name->symbolic_path_name_length, 13); + CU_ASSERT_EQUAL( + strncmp(sym_path_name->symbolic_path_name, "cfg_R6-to-R1", 13), + 0); + + /* ERO object */ + obj_node = obj_node->next_node; + struct pcep_object_ro *ero = (struct pcep_object_ro *)obj_node->data; + CU_ASSERT_EQUAL(ero->header.object_class, PCEP_OBJ_CLASS_ERO); + CU_ASSERT_EQUAL(ero->header.object_type, PCEP_OBJ_TYPE_ERO); + CU_ASSERT_EQUAL(ero->header.encoded_object_length, 4); + CU_ASSERT_PTR_NULL(ero->header.tlv_list); + CU_ASSERT_PTR_NOT_NULL(ero->sub_objects); + CU_ASSERT_EQUAL(ero->sub_objects->num_entries, 0); + + /* LSPA object */ + obj_node = obj_node->next_node; + struct pcep_object_lspa *lspa = + (struct pcep_object_lspa *)obj_node->data; + CU_ASSERT_EQUAL(lspa->header.object_class, PCEP_OBJ_CLASS_LSPA); + CU_ASSERT_EQUAL(lspa->header.object_type, PCEP_OBJ_TYPE_LSPA); + CU_ASSERT_EQUAL(lspa->header.encoded_object_length, 20); + CU_ASSERT_PTR_NULL(lspa->header.tlv_list); + CU_ASSERT_TRUE(lspa->flag_local_protection); + CU_ASSERT_EQUAL(lspa->holding_priority, 7); + CU_ASSERT_EQUAL(lspa->setup_priority, 7); + CU_ASSERT_EQUAL(lspa->lspa_include_all, 0); + CU_ASSERT_EQUAL(lspa->lspa_include_any, 0); + CU_ASSERT_EQUAL(lspa->lspa_exclude_any, 0); + + /* Bandwidth object 1 */ + obj_node = obj_node->next_node; + struct pcep_object_bandwidth *bandwidth = + (struct pcep_object_bandwidth *)obj_node->data; + CU_ASSERT_EQUAL(bandwidth->header.object_class, + PCEP_OBJ_CLASS_BANDWIDTH); + CU_ASSERT_EQUAL(bandwidth->header.object_type, + PCEP_OBJ_TYPE_BANDWIDTH_REQ); + CU_ASSERT_EQUAL(bandwidth->header.encoded_object_length, 8); + CU_ASSERT_EQUAL(bandwidth->bandwidth, 0); + + /* Bandwidth object 2 */ + obj_node = obj_node->next_node; + bandwidth = (struct pcep_object_bandwidth *)obj_node->data; + CU_ASSERT_EQUAL(bandwidth->header.object_class, + PCEP_OBJ_CLASS_BANDWIDTH); + CU_ASSERT_EQUAL(bandwidth->header.object_type, + PCEP_OBJ_TYPE_BANDWIDTH_CISCO); + CU_ASSERT_EQUAL(bandwidth->header.encoded_object_length, 8); + CU_ASSERT_EQUAL(bandwidth->bandwidth, 0); + + /* Metric object 1 */ + obj_node = obj_node->next_node; + struct pcep_object_metric *metric = + (struct pcep_object_metric *)obj_node->data; + CU_ASSERT_EQUAL(metric->header.object_class, PCEP_OBJ_CLASS_METRIC); + CU_ASSERT_EQUAL(metric->header.object_type, PCEP_OBJ_TYPE_METRIC); + CU_ASSERT_EQUAL(metric->header.encoded_object_length, 12); + CU_ASSERT_PTR_NULL(metric->header.tlv_list); + CU_ASSERT_FALSE(metric->flag_b); + CU_ASSERT_FALSE(metric->flag_c); + CU_ASSERT_EQUAL(metric->type, PCEP_METRIC_TE); + CU_ASSERT_EQUAL(metric->value, 0); + + /* Metric object 2 */ + obj_node = obj_node->next_node; + metric = (struct pcep_object_metric *)obj_node->data; + CU_ASSERT_EQUAL(metric->header.object_class, PCEP_OBJ_CLASS_METRIC); + CU_ASSERT_EQUAL(metric->header.object_type, PCEP_OBJ_TYPE_METRIC); + CU_ASSERT_EQUAL(metric->header.encoded_object_length, 12); + CU_ASSERT_PTR_NULL(metric->header.tlv_list); + CU_ASSERT_TRUE(metric->flag_b); + CU_ASSERT_FALSE(metric->flag_c); + CU_ASSERT_EQUAL(metric->type, PCEP_METRIC_AGGREGATE_BW); + CU_ASSERT_EQUAL(metric->value, 16.0); + + pcep_msg_free_message_list(msg_list); + close(fd); +} + +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); + + struct pcep_message *msg = (struct pcep_message *)msg_list->head->data; + CU_ASSERT_EQUAL(msg->msg_header->type, PCEP_TYPE_INITIATE); + CU_ASSERT_EQUAL(msg->encoded_message_length, + pcep_initiate_cisco_pcc_hexbyte_strs_length); + CU_ASSERT_EQUAL(msg->obj_list->num_entries, 6); + + /* SRP object */ + double_linked_list_node *obj_node = msg->obj_list->head; + struct pcep_object_srp *srp = (struct pcep_object_srp *)obj_node->data; + CU_ASSERT_EQUAL(srp->header.object_class, PCEP_OBJ_CLASS_SRP); + CU_ASSERT_EQUAL(srp->header.object_type, PCEP_OBJ_TYPE_SRP); + CU_ASSERT_EQUAL(srp->header.encoded_object_length, 20); + CU_ASSERT_PTR_NOT_NULL(srp->header.tlv_list); + CU_ASSERT_EQUAL(srp->header.tlv_list->num_entries, 1); + CU_ASSERT_EQUAL(srp->srp_id_number, 1); + CU_ASSERT_FALSE(srp->flag_lsp_remove); + + /* LSP object */ + obj_node = obj_node->next_node; + struct pcep_object_lsp *lsp = (struct pcep_object_lsp *)obj_node->data; + CU_ASSERT_EQUAL(lsp->header.object_class, PCEP_OBJ_CLASS_LSP); + CU_ASSERT_EQUAL(lsp->header.object_type, PCEP_OBJ_TYPE_LSP); + CU_ASSERT_EQUAL(lsp->header.encoded_object_length, 48); + CU_ASSERT_PTR_NOT_NULL(lsp->header.tlv_list); + CU_ASSERT_EQUAL(lsp->header.tlv_list->num_entries, 2); + CU_ASSERT_EQUAL(lsp->plsp_id, 0); + CU_ASSERT_EQUAL(lsp->operational_status, PCEP_LSP_OPERATIONAL_DOWN); + CU_ASSERT_TRUE(lsp->flag_a); + CU_ASSERT_TRUE(lsp->flag_d); + CU_ASSERT_TRUE(lsp->flag_c); + CU_ASSERT_FALSE(lsp->flag_r); + CU_ASSERT_FALSE(lsp->flag_s); + + /* Endpoint object */ + obj_node = obj_node->next_node; + struct pcep_object_endpoints_ipv4 *endpoint = + (struct pcep_object_endpoints_ipv4 *)obj_node->data; + CU_ASSERT_EQUAL(endpoint->header.object_class, + PCEP_OBJ_CLASS_ENDPOINTS); + CU_ASSERT_EQUAL(endpoint->header.object_type, + PCEP_OBJ_TYPE_ENDPOINT_IPV4); + CU_ASSERT_EQUAL(endpoint->header.encoded_object_length, 12); + CU_ASSERT_PTR_NULL(endpoint->header.tlv_list); + CU_ASSERT_EQUAL(endpoint->src_ipv4.s_addr, htonl(0x0a0a0a0a)); + CU_ASSERT_EQUAL(endpoint->dst_ipv4.s_addr, htonl(0x0a0a0a04)); + + /* Inter-Layer object */ + obj_node = obj_node->next_node; + struct pcep_object_inter_layer *inter_layer = + (struct pcep_object_inter_layer *)obj_node->data; + CU_ASSERT_EQUAL(inter_layer->header.object_class, + PCEP_OBJ_CLASS_INTER_LAYER); + CU_ASSERT_EQUAL(inter_layer->header.object_type, + PCEP_OBJ_TYPE_INTER_LAYER); + CU_ASSERT_EQUAL(inter_layer->header.encoded_object_length, 8); + CU_ASSERT_PTR_NULL(inter_layer->header.tlv_list); + CU_ASSERT_TRUE(inter_layer->flag_i); + CU_ASSERT_FALSE(inter_layer->flag_m); + CU_ASSERT_TRUE(inter_layer->flag_t); + + /* Switch-Layer object */ + obj_node = obj_node->next_node; + struct pcep_object_switch_layer *switch_layer = + (struct pcep_object_switch_layer *)obj_node->data; + CU_ASSERT_EQUAL(switch_layer->header.object_class, + PCEP_OBJ_CLASS_SWITCH_LAYER); + CU_ASSERT_EQUAL(switch_layer->header.object_type, + PCEP_OBJ_TYPE_SWITCH_LAYER); + CU_ASSERT_EQUAL(switch_layer->header.encoded_object_length, 8); + CU_ASSERT_PTR_NULL(switch_layer->header.tlv_list); + CU_ASSERT_PTR_NOT_NULL(switch_layer->switch_layer_rows); + CU_ASSERT_EQUAL(switch_layer->switch_layer_rows->num_entries, 1); + struct pcep_object_switch_layer_row *switch_layer_row = + (struct pcep_object_switch_layer_row *) + switch_layer->switch_layer_rows->head->data; + CU_ASSERT_EQUAL(switch_layer_row->lsp_encoding_type, 0); + CU_ASSERT_EQUAL(switch_layer_row->switching_type, 0); + CU_ASSERT_FALSE(switch_layer_row->flag_i); + + /* ERO object */ + obj_node = obj_node->next_node; + struct pcep_object_ro *ero = (struct pcep_object_ro *)obj_node->data; + CU_ASSERT_EQUAL(ero->header.object_class, PCEP_OBJ_CLASS_ERO); + CU_ASSERT_EQUAL(ero->header.object_type, PCEP_OBJ_TYPE_ERO); + CU_ASSERT_EQUAL(ero->header.encoded_object_length, 4); + CU_ASSERT_PTR_NULL(ero->header.tlv_list); + + pcep_msg_free_message_list(msg_list); + close(fd); +} + +void test_validate_message_header() +{ + uint8_t pcep_message_invalid_version[] = {0x40, 0x01, 0x04, 0x00}; + uint8_t pcep_message_invalid_flags[] = {0x22, 0x01, 0x04, 0x00}; + uint8_t pcep_message_invalid_length[] = {0x20, 0x01, 0x00, 0x00}; + uint8_t pcep_message_invalid_type[] = {0x20, 0xff, 0x04, 0x00}; + uint8_t pcep_message_valid[] = {0x20, 0x01, 0x00, 0x04}; + + /* Verify invalid message header version */ + CU_ASSERT_TRUE( + pcep_decode_validate_msg_header(pcep_message_invalid_version) + < 0); + + /* Verify invalid message header flags */ + CU_ASSERT_TRUE( + pcep_decode_validate_msg_header(pcep_message_invalid_flags) + < 0); + + /* Verify invalid message header lengths */ + CU_ASSERT_TRUE( + pcep_decode_validate_msg_header(pcep_message_invalid_length) + < 0); + pcep_message_invalid_length[3] = 0x05; + CU_ASSERT_TRUE( + pcep_decode_validate_msg_header(pcep_message_invalid_length) + < 0); + + /* Verify invalid message header types */ + CU_ASSERT_TRUE( + pcep_decode_validate_msg_header(pcep_message_invalid_type) < 0); + pcep_message_invalid_type[1] = 0x00; + CU_ASSERT_TRUE( + pcep_decode_validate_msg_header(pcep_message_invalid_type) < 0); + + /* Verify a valid message header */ + CU_ASSERT_EQUAL(pcep_decode_validate_msg_header(pcep_message_valid), 4); +} + +/* Internal util function */ +struct pcep_message *create_message(uint8_t msg_type, uint8_t obj1_class, + uint8_t obj2_class, uint8_t obj3_class, + uint8_t obj4_class) +{ + struct pcep_message *msg = + pceplib_malloc(PCEPLIB_MESSAGES, sizeof(struct pcep_message)); + msg->obj_list = dll_initialize(); + msg->msg_header = pceplib_malloc(PCEPLIB_MESSAGES, + sizeof(struct pcep_message_header)); + msg->msg_header->type = msg_type; + msg->encoded_message = NULL; + + if (obj1_class > 0) { + struct pcep_object_header *obj_hdr = pceplib_malloc( + PCEPLIB_MESSAGES, sizeof(struct pcep_object_header)); + obj_hdr->object_class = obj1_class; + obj_hdr->tlv_list = NULL; + dll_append(msg->obj_list, obj_hdr); + } + + if (obj2_class > 0) { + struct pcep_object_header *obj_hdr = pceplib_malloc( + PCEPLIB_MESSAGES, sizeof(struct pcep_object_header)); + obj_hdr->object_class = obj2_class; + obj_hdr->tlv_list = NULL; + dll_append(msg->obj_list, obj_hdr); + } + + if (obj3_class > 0) { + struct pcep_object_header *obj_hdr = pceplib_malloc( + PCEPLIB_MESSAGES, sizeof(struct pcep_object_header)); + obj_hdr->object_class = obj3_class; + obj_hdr->tlv_list = NULL; + dll_append(msg->obj_list, obj_hdr); + } + + if (obj4_class > 0) { + struct pcep_object_header *obj_hdr = pceplib_malloc( + PCEPLIB_MESSAGES, sizeof(struct pcep_object_header)); + obj_hdr->object_class = obj4_class; + obj_hdr->tlv_list = NULL; + dll_append(msg->obj_list, obj_hdr); + } + + return msg; +} + +void test_validate_message_objects() +{ + /* Valid Open message */ + struct pcep_message *msg = + create_message(PCEP_TYPE_OPEN, PCEP_OBJ_CLASS_OPEN, 0, 0, 0); + CU_ASSERT_TRUE(validate_message_objects(msg)); + pcep_msg_free_message(msg); + + /* Valid KeepAlive message */ + msg = create_message(PCEP_TYPE_KEEPALIVE, 0, 0, 0, 0); + CU_ASSERT_TRUE(validate_message_objects(msg)); + pcep_msg_free_message(msg); + + /* Valid PcReq message */ + /* Using object_class=255 to verify it can take any object */ + msg = create_message(PCEP_TYPE_PCREQ, PCEP_OBJ_CLASS_RP, + PCEP_OBJ_CLASS_ENDPOINTS, any_obj_class, 0); + CU_ASSERT_TRUE(validate_message_objects(msg)); + pcep_msg_free_message(msg); + + /* Valid PcRep message */ + msg = create_message(PCEP_TYPE_PCREP, PCEP_OBJ_CLASS_RP, any_obj_class, + 0, 0); + CU_ASSERT_TRUE(validate_message_objects(msg)); + pcep_msg_free_message(msg); + + /* Valid Notify message */ + msg = create_message(PCEP_TYPE_PCNOTF, PCEP_OBJ_CLASS_NOTF, + any_obj_class, 0, 0); + CU_ASSERT_TRUE(validate_message_objects(msg)); + pcep_msg_free_message(msg); + + /* Valid Error message */ + msg = create_message(PCEP_TYPE_ERROR, PCEP_OBJ_CLASS_ERROR, + any_obj_class, 0, 0); + CU_ASSERT_TRUE(validate_message_objects(msg)); + pcep_msg_free_message(msg); + + /* Valid Close message */ + msg = create_message(PCEP_TYPE_CLOSE, PCEP_OBJ_CLASS_CLOSE, 0, 0, 0); + CU_ASSERT_TRUE(validate_message_objects(msg)); + pcep_msg_free_message(msg); + + /* Valid Report message */ + msg = create_message(PCEP_TYPE_REPORT, PCEP_OBJ_CLASS_SRP, + PCEP_OBJ_CLASS_LSP, any_obj_class, any_obj_class); + CU_ASSERT_TRUE(validate_message_objects(msg)); + pcep_msg_free_message(msg); + + /* Valid Update message */ + msg = create_message(PCEP_TYPE_UPDATE, PCEP_OBJ_CLASS_SRP, + PCEP_OBJ_CLASS_LSP, any_obj_class, any_obj_class); + CU_ASSERT_TRUE(validate_message_objects(msg)); + pcep_msg_free_message(msg); + + /* Valid Initiate message */ + msg = create_message(PCEP_TYPE_INITIATE, PCEP_OBJ_CLASS_SRP, + PCEP_OBJ_CLASS_LSP, any_obj_class, any_obj_class); + CU_ASSERT_TRUE(validate_message_objects(msg)); + pcep_msg_free_message(msg); +} + +void test_validate_message_objects_invalid() +{ + /* unsupported message ID = 0 + * {NO_OBJECT, NO_OBJECT, NO_OBJECT, NO_OBJECT} */ + struct pcep_message *msg = create_message(0, any_obj_class, 0, 0, 0); + CU_ASSERT_FALSE(validate_message_objects(msg)); + pcep_msg_free_message(msg); + + /* Open message + * {PCEP_OBJ_CLASS_OPEN, NO_OBJECT, NO_OBJECT, NO_OBJECT} */ + msg = create_message(PCEP_TYPE_OPEN, 0, 0, 0, 0); + CU_ASSERT_FALSE(validate_message_objects(msg)); + pcep_msg_free_message(msg); + + msg = create_message(PCEP_TYPE_OPEN, any_obj_class, 0, 0, 0); + CU_ASSERT_FALSE(validate_message_objects(msg)); + pcep_msg_free_message(msg); + + msg = create_message(PCEP_TYPE_OPEN, PCEP_OBJ_CLASS_OPEN, any_obj_class, + 0, 0); + CU_ASSERT_FALSE(validate_message_objects(msg)); + pcep_msg_free_message(msg); + + /* KeepAlive message + * {NO_OBJECT, NO_OBJECT, NO_OBJECT, NO_OBJECT} */ + msg = create_message(PCEP_TYPE_KEEPALIVE, any_obj_class, 0, 0, 0); + CU_ASSERT_FALSE(validate_message_objects(msg)); + pcep_msg_free_message(msg); + + /* PcReq message + * {PCEP_OBJ_CLASS_RP, PCEP_OBJ_CLASS_ENDPOINTS, ANY_OBJECT, ANY_OBJECT} + */ + msg = create_message(PCEP_TYPE_PCREQ, 0, 0, 0, 0); + CU_ASSERT_FALSE(validate_message_objects(msg)); + pcep_msg_free_message(msg); + + msg = create_message(PCEP_TYPE_PCREQ, PCEP_OBJ_CLASS_RP, any_obj_class, + 0, 0); + CU_ASSERT_FALSE(validate_message_objects(msg)); + pcep_msg_free_message(msg); + + /* PcRep message + * {PCEP_OBJ_CLASS_RP, ANY_OBJECT, ANY_OBJECT, ANY_OBJECT} */ + msg = create_message(PCEP_TYPE_PCREP, 0, 0, 0, 0); + CU_ASSERT_FALSE(validate_message_objects(msg)); + pcep_msg_free_message(msg); + + msg = create_message(PCEP_TYPE_PCREP, any_obj_class, 0, 0, 0); + CU_ASSERT_FALSE(validate_message_objects(msg)); + pcep_msg_free_message(msg); + + /* Notify message + * {PCEP_OBJ_CLASS_NOTF, ANY_OBJECT, ANY_OBJECT, ANY_OBJECT} */ + msg = create_message(PCEP_TYPE_PCNOTF, 0, 0, 0, 0); + CU_ASSERT_FALSE(validate_message_objects(msg)); + pcep_msg_free_message(msg); + + msg = create_message(PCEP_TYPE_PCNOTF, any_obj_class, 0, 0, 0); + CU_ASSERT_FALSE(validate_message_objects(msg)); + pcep_msg_free_message(msg); + + /* Error message + * {PCEP_OBJ_CLASS_ERROR, ANY_OBJECT, ANY_OBJECT, ANY_OBJECT} */ + msg = create_message(PCEP_TYPE_ERROR, 0, 0, 0, 0); + CU_ASSERT_FALSE(validate_message_objects(msg)); + pcep_msg_free_message(msg); + + msg = create_message(PCEP_TYPE_ERROR, any_obj_class, 0, 0, 0); + CU_ASSERT_FALSE(validate_message_objects(msg)); + pcep_msg_free_message(msg); + + /* Close message + * {PCEP_OBJ_CLASS_CLOSE, NO_OBJECT, NO_OBJECT, NO_OBJECT} */ + msg = create_message(PCEP_TYPE_CLOSE, 0, 0, 0, 0); + CU_ASSERT_FALSE(validate_message_objects(msg)); + pcep_msg_free_message(msg); + + msg = create_message(PCEP_TYPE_CLOSE, any_obj_class, 0, 0, 0); + CU_ASSERT_FALSE(validate_message_objects(msg)); + pcep_msg_free_message(msg); + + /* unsupported message ID = 8 + * {NO_OBJECT, NO_OBJECT, NO_OBJECT, NO_OBJECT} */ + msg = create_message(8, any_obj_class, 0, 0, 0); + CU_ASSERT_FALSE(validate_message_objects(msg)); + pcep_msg_free_message(msg); + + /* unsupported message ID = 9 + * {NO_OBJECT, NO_OBJECT, NO_OBJECT, NO_OBJECT} */ + msg = create_message(9, any_obj_class, 0, 0, 0); + CU_ASSERT_FALSE(validate_message_objects(msg)); + pcep_msg_free_message(msg); + + /* Report message + * {PCEP_OBJ_CLASS_SRP, PCEP_OBJ_CLASS_LSP, ANY_OBJECT, ANY_OBJECT} */ + msg = create_message(PCEP_TYPE_REPORT, 0, 0, 0, 0); + CU_ASSERT_FALSE(validate_message_objects(msg)); + pcep_msg_free_message(msg); + + msg = create_message(PCEP_TYPE_REPORT, any_obj_class, 0, 0, 0); + CU_ASSERT_FALSE(validate_message_objects(msg)); + pcep_msg_free_message(msg); + + msg = create_message(PCEP_TYPE_REPORT, PCEP_OBJ_CLASS_SRP, 0, 0, 0); + CU_ASSERT_FALSE(validate_message_objects(msg)); + pcep_msg_free_message(msg); + + msg = create_message(PCEP_TYPE_REPORT, PCEP_OBJ_CLASS_SRP, + any_obj_class, 0, 0); + CU_ASSERT_FALSE(validate_message_objects(msg)); + pcep_msg_free_message(msg); + + /* Update message + * {PCEP_OBJ_CLASS_SRP, PCEP_OBJ_CLASS_LSP, ANY_OBJECT, ANY_OBJECT} */ + msg = create_message(PCEP_TYPE_UPDATE, 0, 0, 0, 0); + CU_ASSERT_FALSE(validate_message_objects(msg)); + pcep_msg_free_message(msg); + + msg = create_message(PCEP_TYPE_UPDATE, any_obj_class, 0, 0, 0); + CU_ASSERT_FALSE(validate_message_objects(msg)); + pcep_msg_free_message(msg); + + msg = create_message(PCEP_TYPE_UPDATE, PCEP_OBJ_CLASS_SRP, 0, 0, 0); + CU_ASSERT_FALSE(validate_message_objects(msg)); + pcep_msg_free_message(msg); + + msg = create_message(PCEP_TYPE_UPDATE, PCEP_OBJ_CLASS_SRP, + any_obj_class, 0, 0); + CU_ASSERT_FALSE(validate_message_objects(msg)); + pcep_msg_free_message(msg); + + /* Initiate message + * {PCEP_OBJ_CLASS_SRP, PCEP_OBJ_CLASS_LSP, ANY_OBJECT, ANY_OBJECT} */ + msg = create_message(PCEP_TYPE_INITIATE, 0, 0, 0, 0); + CU_ASSERT_FALSE(validate_message_objects(msg)); + pcep_msg_free_message(msg); + + msg = create_message(PCEP_TYPE_INITIATE, any_obj_class, 0, 0, 0); + CU_ASSERT_FALSE(validate_message_objects(msg)); + pcep_msg_free_message(msg); + + msg = create_message(PCEP_TYPE_INITIATE, PCEP_OBJ_CLASS_SRP, 0, 0, 0); + CU_ASSERT_FALSE(validate_message_objects(msg)); + pcep_msg_free_message(msg); + + msg = create_message(PCEP_TYPE_INITIATE, PCEP_OBJ_CLASS_SRP, + any_obj_class, 0, 0); + CU_ASSERT_FALSE(validate_message_objects(msg)); + pcep_msg_free_message(msg); +} diff --git a/pceplib/test/pcep_msg_tools_test.h b/pceplib/test/pcep_msg_tools_test.h new file mode 100644 index 0000000000..dc66390801 --- /dev/null +++ b/pceplib/test/pcep_msg_tools_test.h @@ -0,0 +1,48 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Javier Garcia <javier.garcia@voltanet.io> + * + */ + +/* + * Timer definitions to be used internally by the pcep_timers library. + */ + +#ifndef PCEP_MSG_TOOLS_TEST_H_ +#define PCEP_MSG_TOOLS_TEST_H_ + + +int pcep_tools_test_suite_setup(void); +int pcep_tools_test_suite_teardown(void); +void pcep_tools_test_setup(void); +void pcep_tools_test_teardown(void); +void test_pcep_msg_read_pcep_initiate(void); +void test_pcep_msg_read_pcep_initiate2(void); +void test_pcep_msg_read_pcep_update(void); +void test_pcep_msg_read_pcep_open(void); +void test_pcep_msg_read_pcep_open_initiate(void); +void test_validate_message_header(void); +void test_validate_message_objects(void); +void test_validate_message_objects_invalid(void); +void test_pcep_msg_read_pcep_open_cisco_pce(void); +void test_pcep_msg_read_pcep_update_cisco_pce(void); +void test_pcep_msg_read_pcep_report_cisco_pcc(void); +void test_pcep_msg_read_pcep_initiate_cisco_pcc(void); + +#endif /* PCEPTIMERINTERNALS_H_ */ diff --git a/pceplib/test/pcep_pcc_api_test.c b/pceplib/test/pcep_pcc_api_test.c new file mode 100644 index 0000000000..c227dc1a3d --- /dev/null +++ b/pceplib/test/pcep_pcc_api_test.c @@ -0,0 +1,285 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Brady Johnson <brady@voltanet.io> + * + */ + + +#include <netdb.h> // gethostbyname +#include <pthread.h> +#include <stdlib.h> +#include <unistd.h> + +#include <CUnit/CUnit.h> + +#include "pcep_pcc_api.h" +#include "pcep_pcc_api_test.h" +#include "pcep_socket_comm_mock.h" +#include "pcep_utils_memory.h" + +extern pcep_event_queue *session_logic_event_queue_; +extern const char MESSAGE_RECEIVED_STR[]; +extern const char UNKNOWN_EVENT_STR[]; + +/* + * Test suite setup and teardown called before AND after the test suite. + */ + +int pcep_pcc_api_test_suite_setup() +{ + pceplib_memory_reset(); + return 0; +} + +int pcep_pcc_api_test_suite_teardown() +{ + printf("\n"); + pceplib_memory_dump(); + return 0; +} + +/* + * Test case setup and teardown called before AND after each test. + */ + +void pcep_pcc_api_test_setup() +{ + setup_mock_socket_comm_info(); +} + + +void pcep_pcc_api_test_teardown() +{ + teardown_mock_socket_comm_info(); +} + +/* + * Unit test cases + */ + +void test_initialize_pcc() +{ + CU_ASSERT_TRUE(initialize_pcc()); + /* Give the PCC time to initialize */ + sleep(1); + CU_ASSERT_TRUE(destroy_pcc()); +} + +void test_connect_pce() +{ + pcep_configuration *config = create_default_pcep_configuration(); + struct hostent *host_info = gethostbyname("localhost"); + struct in_addr dest_address; + memcpy(&dest_address, host_info->h_addr, host_info->h_length); + mock_socket_comm_info *mock_info = get_mock_socket_comm_info(); + mock_info->send_message_save_message = true; + + initialize_pcc(); + + pcep_session *session = connect_pce(config, &dest_address); + + CU_ASSERT_PTR_NOT_NULL(session); + CU_ASSERT_EQUAL(mock_info->sent_message_list->num_entries, 1); + /* What gets saved in the mock is the msg byte buffer. The msg struct + * was deleted when it was sent. Instead of inspecting the msg byte + * buffer, lets just decode it. */ + uint8_t *encoded_msg = + dll_delete_first_node(mock_info->sent_message_list); + CU_ASSERT_PTR_NOT_NULL(encoded_msg); + struct pcep_message *open_msg = pcep_decode_message(encoded_msg); + CU_ASSERT_PTR_NOT_NULL(open_msg); + CU_ASSERT_EQUAL(open_msg->msg_header->type, PCEP_TYPE_OPEN); + + pcep_msg_free_message(open_msg); + destroy_pcep_session(session); + destroy_pcep_configuration(config); + pceplib_free(PCEPLIB_MESSAGES, encoded_msg); + + destroy_pcc(); +} + +void test_connect_pce_ipv6() +{ + pcep_configuration *config = create_default_pcep_configuration(); + struct in6_addr dest_address; + dest_address.__in6_u.__u6_addr32[0] = 0; + dest_address.__in6_u.__u6_addr32[1] = 0; + dest_address.__in6_u.__u6_addr32[2] = 0; + dest_address.__in6_u.__u6_addr32[3] = htonl(1); + mock_socket_comm_info *mock_info = get_mock_socket_comm_info(); + mock_info->send_message_save_message = true; + + initialize_pcc(); + + pcep_session *session = connect_pce_ipv6(config, &dest_address); + + CU_ASSERT_PTR_NOT_NULL(session); + CU_ASSERT_TRUE(session->socket_comm_session->is_ipv6); + CU_ASSERT_EQUAL(mock_info->sent_message_list->num_entries, 1); + /* What gets saved in the mock is the msg byte buffer. The msg struct + * was deleted when it was sent. Instead of inspecting the msg byte + * buffer, lets just decode it. */ + uint8_t *encoded_msg = + dll_delete_first_node(mock_info->sent_message_list); + CU_ASSERT_PTR_NOT_NULL(encoded_msg); + struct pcep_message *open_msg = pcep_decode_message(encoded_msg); + CU_ASSERT_PTR_NOT_NULL(open_msg); + CU_ASSERT_EQUAL(open_msg->msg_header->type, PCEP_TYPE_OPEN); + + pcep_msg_free_message(open_msg); + destroy_pcep_session(session); + destroy_pcep_configuration(config); + pceplib_free(PCEPLIB_MESSAGES, encoded_msg); + + destroy_pcc(); +} + +void test_connect_pce_with_src_ip() +{ + pcep_configuration *config = create_default_pcep_configuration(); + struct hostent *host_info = gethostbyname("localhost"); + struct in_addr dest_address; + memcpy(&dest_address, host_info->h_addr, host_info->h_length); + mock_socket_comm_info *mock_info = get_mock_socket_comm_info(); + mock_info->send_message_save_message = true; + config->src_ip.src_ipv4.s_addr = 0x0a0a0102; + + initialize_pcc(); + + pcep_session *session = connect_pce(config, &dest_address); + + CU_ASSERT_PTR_NOT_NULL(session); + CU_ASSERT_EQUAL(mock_info->sent_message_list->num_entries, 1); + uint8_t *encoded_msg = + dll_delete_first_node(mock_info->sent_message_list); + CU_ASSERT_PTR_NOT_NULL(encoded_msg); + struct pcep_message *open_msg = pcep_decode_message(encoded_msg); + CU_ASSERT_PTR_NOT_NULL(open_msg); + CU_ASSERT_EQUAL(open_msg->msg_header->type, PCEP_TYPE_OPEN); + + pcep_msg_free_message(open_msg); + destroy_pcep_session(session); + destroy_pcep_configuration(config); + pceplib_free(PCEPLIB_MESSAGES, encoded_msg); + + destroy_pcc(); +} + +void test_disconnect_pce() +{ + pcep_configuration *config = create_default_pcep_configuration(); + struct hostent *host_info = gethostbyname("localhost"); + struct in_addr dest_address; + memcpy(&dest_address, host_info->h_addr, host_info->h_length); + mock_socket_comm_info *mock_info = get_mock_socket_comm_info(); + mock_info->send_message_save_message = true; + + initialize_pcc(); + + pcep_session *session = connect_pce(config, &dest_address); + disconnect_pce(session); + + CU_ASSERT_EQUAL(mock_info->sent_message_list->num_entries, 2); + + /* First there should be an open message from connect_pce() */ + uint8_t *encoded_msg = + dll_delete_first_node(mock_info->sent_message_list); + CU_ASSERT_PTR_NOT_NULL(encoded_msg); + struct pcep_message *msg = pcep_decode_message(encoded_msg); + CU_ASSERT_PTR_NOT_NULL(msg); + CU_ASSERT_EQUAL(msg->msg_header->type, PCEP_TYPE_OPEN); + pcep_msg_free_message(msg); + pceplib_free(PCEPLIB_MESSAGES, encoded_msg); + + /* Then there should be a close message from disconnect_pce() */ + encoded_msg = dll_delete_first_node(mock_info->sent_message_list); + CU_ASSERT_PTR_NOT_NULL(encoded_msg); + msg = pcep_decode_message(encoded_msg); + CU_ASSERT_PTR_NOT_NULL(msg); + CU_ASSERT_EQUAL(msg->msg_header->type, PCEP_TYPE_CLOSE); + + pcep_msg_free_message(msg); + destroy_pcep_session(session); + destroy_pcep_configuration(config); + pceplib_free(PCEPLIB_MESSAGES, encoded_msg); + + destroy_pcc(); +} + + +void test_send_message() +{ + pcep_configuration *config = create_default_pcep_configuration(); + struct hostent *host_info = gethostbyname("localhost"); + struct in_addr dest_address; + + initialize_pcc(); + + memcpy(&dest_address, host_info->h_addr, host_info->h_length); + pcep_session *session = connect_pce(config, &dest_address); + verify_socket_comm_times_called(0, 0, 1, 1, 0, 0, 0); + + struct pcep_message *msg = pcep_msg_create_keepalive(); + send_message(session, msg, false); + + verify_socket_comm_times_called(0, 0, 1, 2, 0, 0, 0); + + pcep_msg_free_message(msg); + destroy_pcep_session(session); + destroy_pcep_configuration(config); + + destroy_pcc(); +} + +void test_event_queue() +{ + /* This initializes the event_queue */ + CU_ASSERT_TRUE(initialize_pcc()); + + /* Verify correct behavior when the queue is empty */ + CU_ASSERT_TRUE(event_queue_is_empty()); + CU_ASSERT_EQUAL(event_queue_num_events_available(), 0); + CU_ASSERT_PTR_NULL(event_queue_get_event()); + destroy_pcep_event(NULL); + + /* Create an empty event and put it on the queue */ + pcep_event *event = pceplib_malloc(PCEPLIB_INFRA, sizeof(pcep_event)); + memset(event, 0, sizeof(pcep_event)); + pthread_mutex_lock(&session_logic_event_queue_->event_queue_mutex); + queue_enqueue(session_logic_event_queue_->event_queue, event); + pthread_mutex_unlock(&session_logic_event_queue_->event_queue_mutex); + + /* Verify correct behavior when there is an entry in the queue */ + CU_ASSERT_FALSE(event_queue_is_empty()); + CU_ASSERT_EQUAL(event_queue_num_events_available(), 1); + pcep_event *queued_event = event_queue_get_event(); + CU_ASSERT_PTR_NOT_NULL(queued_event); + CU_ASSERT_PTR_EQUAL(event, queued_event); + destroy_pcep_event(queued_event); + + CU_ASSERT_TRUE(destroy_pcc()); +} + +void test_get_event_type_str() +{ + CU_ASSERT_EQUAL(strcmp(get_event_type_str(MESSAGE_RECEIVED), + MESSAGE_RECEIVED_STR), + 0); + CU_ASSERT_EQUAL(strcmp(get_event_type_str(1000), UNKNOWN_EVENT_STR), 0); +} diff --git a/pceplib/test/pcep_pcc_api_test.h b/pceplib/test/pcep_pcc_api_test.h new file mode 100644 index 0000000000..d3db96e0ce --- /dev/null +++ b/pceplib/test/pcep_pcc_api_test.h @@ -0,0 +1,43 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Javier Garcia <javier.garcia@voltanet.io> + * + */ + +/* + * Timer definitions to be used internally by the pcep_timers library. + */ + +#ifndef PCEP_PCC_API_TEST_ +#define PCEP_PCC_API_TEST_ + +int pcep_pcc_api_test_suite_setup(void); +int pcep_pcc_api_test_suite_teardown(void); +void pcep_pcc_api_test_setup(void); +void pcep_pcc_api_test_teardown(void); +void test_initialize_pcc(void); +void test_connect_pce(void); +void test_connect_pce_ipv6(void); +void test_connect_pce_with_src_ip(void); +void test_disconnect_pce(void); +void test_send_message(void); +void test_event_queue(void); +void test_get_event_type_str(void); + +#endif /* PCEPTIMERINTERNALS_H_ */ diff --git a/pceplib/test/pcep_pcc_api_tests.c b/pceplib/test/pcep_pcc_api_tests.c new file mode 100644 index 0000000000..04895d6340 --- /dev/null +++ b/pceplib/test/pcep_pcc_api_tests.c @@ -0,0 +1,88 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Brady Johnson <brady@voltanet.io> + * + */ + + +#include <CUnit/Basic.h> +#include <CUnit/CUnit.h> +#include <CUnit/TestDB.h> + +#include "pcep_pcc_api_test.h" + +int main(int argc, char **argv) +{ + /* Unused parameters cause compilation warnings */ + (void)argc; + (void)argv; + + CU_initialize_registry(); + + /* + * Tests defined in pcep_socket_comm_test.c + */ + CU_pSuite test_pcc_api_suite = CU_add_suite_with_setup_and_teardown( + "PCEP PCC API Test Suite", + pcep_pcc_api_test_suite_setup, // suite setup and cleanup + // function pointers + pcep_pcc_api_test_suite_teardown, + pcep_pcc_api_test_setup, // test case setup function pointer + pcep_pcc_api_test_teardown); // test case teardown function + // pointer + + CU_add_test(test_pcc_api_suite, "test_initialize_pcc", + test_initialize_pcc); + CU_add_test(test_pcc_api_suite, "test_connect_pce", test_connect_pce); + CU_add_test(test_pcc_api_suite, "test_connect_pce_ipv6", + test_connect_pce_ipv6); + CU_add_test(test_pcc_api_suite, "test_connect_pce_with_src_ip", + test_connect_pce_with_src_ip); + CU_add_test(test_pcc_api_suite, "test_disconnect_pce", + test_disconnect_pce); + CU_add_test(test_pcc_api_suite, "test_send_message", test_send_message); + CU_add_test(test_pcc_api_suite, "test_event_queue", test_event_queue); + CU_add_test(test_pcc_api_suite, "test_get_event_type_str", + test_get_event_type_str); + + /* + * Run the tests and cleanup. + */ + CU_basic_set_mode(CU_BRM_VERBOSE); + CU_basic_run_tests(); + CU_FailureRecord *failure_record = CU_get_failure_list(); + if (failure_record != NULL) { + printf("\nFailed tests:\n\t [Suite] [Test] [File:line-number]\n"); + do { + printf("\t [%s] [%s] [%s:%d]\n", + failure_record->pSuite->pName, + failure_record->pTest->pName, + failure_record->strFileName, + failure_record->uiLineNumber); + failure_record = failure_record->pNext; + + } while (failure_record != NULL); + } + + CU_pRunSummary run_summary = CU_get_run_summary(); + int result = run_summary->nTestsFailed; + CU_cleanup_registry(); + + return result; +} diff --git a/pceplib/test/pcep_pcc_api_tests_valgrind.sh b/pceplib/test/pcep_pcc_api_tests_valgrind.sh new file mode 100755 index 0000000000..74494b7521 --- /dev/null +++ b/pceplib/test/pcep_pcc_api_tests_valgrind.sh @@ -0,0 +1,2 @@ +source pceplib/test/pcep_tests_valgrind.sh +valgrind_test pceplib/test/pcep_pcc_api_tests diff --git a/pceplib/test/pcep_session_logic_loop_test.c b/pceplib/test/pcep_session_logic_loop_test.c new file mode 100644 index 0000000000..3a40f59bb9 --- /dev/null +++ b/pceplib/test/pcep_session_logic_loop_test.c @@ -0,0 +1,235 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Brady Johnson <brady@voltanet.io> + * + */ + + +#include <pthread.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include <CUnit/CUnit.h> + +#include "pcep_msg_encoding.h" +#include "pcep_session_logic.h" +#include "pcep_session_logic_internals.h" +#include "pcep_timers.h" +#include "pcep_utils_ordered_list.h" +#include "pcep_utils_memory.h" +#include "pcep_session_logic_loop_test.h" + + +extern pcep_session_logic_handle *session_logic_handle_; +extern pcep_event_queue *session_logic_event_queue_; + +/* + * Test suite setup and teardown called before AND after the test suite. + */ + +int pcep_session_logic_loop_test_suite_setup(void) +{ + pceplib_memory_reset(); + return 0; +} + +int pcep_session_logic_loop_test_suite_teardown(void) +{ + printf("\n"); + pceplib_memory_dump(); + return 0; +} + + +/* + * Test case setup and teardown called before AND after each test. + */ + +void pcep_session_logic_loop_test_setup() +{ + /* We need to setup the session_logic_handle_ without starting the + * thread */ + session_logic_handle_ = pceplib_malloc( + 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_list = + ordered_list_initialize(pointer_compare_function); + session_logic_handle_->session_event_queue = queue_initialize(); + pthread_cond_init(&(session_logic_handle_->session_logic_cond_var), + NULL); + 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)); + session_logic_event_queue_->event_queue = queue_initialize(); +} + + +void pcep_session_logic_loop_test_teardown() +{ + ordered_list_destroy(session_logic_handle_->session_list); + queue_destroy(session_logic_handle_->session_event_queue); + pthread_mutex_unlock(&(session_logic_handle_->session_logic_mutex)); + pthread_mutex_destroy(&(session_logic_handle_->session_logic_mutex)); + pthread_mutex_destroy(&(session_logic_handle_->session_list_mutex)); + pceplib_free(PCEPLIB_INFRA, session_logic_handle_); + session_logic_handle_ = NULL; + + queue_destroy(session_logic_event_queue_->event_queue); + pceplib_free(PCEPLIB_INFRA, session_logic_event_queue_); + session_logic_event_queue_ = NULL; +} + + +/* + * Test cases + */ + +void test_session_logic_loop_null_data() +{ + /* Just testing that it does not core dump */ + session_logic_loop(NULL); +} + + +void test_session_logic_loop_inactive() +{ + session_logic_handle_->active = false; + + session_logic_loop(session_logic_handle_); +} + + +void test_session_logic_msg_ready_handler() +{ + /* Just testing that it does not core dump */ + CU_ASSERT_EQUAL(session_logic_msg_ready_handler(NULL, 0), -1); + + /* Read from an empty file should return 0, thus + * session_logic_msg_ready_handler returns -1 */ + 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; + CU_ASSERT_EQUAL(session_logic_msg_ready_handler(&session, fd), 0); + CU_ASSERT_EQUAL(session_logic_handle_->session_event_queue->num_entries, + 1); + pcep_event *e = queue_dequeue(session_logic_event_queue_->event_queue); + CU_ASSERT_EQUAL(PCE_CLOSED_SOCKET, e->event_type); + pceplib_free(PCEPLIB_INFRA, e); + pcep_session_event *socket_event = (pcep_session_event *)queue_dequeue( + session_logic_handle_->session_event_queue); + CU_ASSERT_PTR_NOT_NULL(socket_event); + CU_ASSERT_TRUE(socket_event->socket_closed); + pceplib_free(PCEPLIB_INFRA, socket_event); + + /* A pcep_session_event should be created */ + struct pcep_versioning *versioning = create_default_pcep_versioning(); + struct pcep_message *keep_alive_msg = pcep_msg_create_keepalive(); + pcep_encode_message(keep_alive_msg, versioning); + int retval = write(fd, (char *)keep_alive_msg->encoded_message, + keep_alive_msg->encoded_message_length); + CU_ASSERT_TRUE(retval > 0); + lseek(fd, 0, SEEK_SET); + CU_ASSERT_EQUAL(session_logic_msg_ready_handler(&session, fd), + keep_alive_msg->encoded_message_length); + CU_ASSERT_EQUAL(session_logic_handle_->session_event_queue->num_entries, + 1); + socket_event = (pcep_session_event *)queue_dequeue( + session_logic_handle_->session_event_queue); + CU_ASSERT_PTR_NOT_NULL(socket_event); + CU_ASSERT_FALSE(socket_event->socket_closed); + CU_ASSERT_PTR_EQUAL(socket_event->session, &session); + CU_ASSERT_EQUAL(socket_event->expired_timer_id, TIMER_ID_NOT_SET); + CU_ASSERT_PTR_NOT_NULL(socket_event->received_msg_list); + pcep_msg_free_message_list(socket_event->received_msg_list); + pcep_msg_free_message(keep_alive_msg); + destroy_pcep_versioning(versioning); + pceplib_free(PCEPLIB_INFRA, socket_event); + close(fd); +} + + +void test_session_logic_conn_except_notifier() +{ + /* Just testing that it does not core dump */ + session_logic_conn_except_notifier(NULL, 1); + + /* A pcep_session_event should be created */ + pcep_session session; + memset(&session, 0, sizeof(pcep_session)); + session.session_id = 100; + session_logic_conn_except_notifier(&session, 10); + CU_ASSERT_EQUAL(session_logic_handle_->session_event_queue->num_entries, + 1); + pcep_session_event *socket_event = (pcep_session_event *)queue_dequeue( + session_logic_handle_->session_event_queue); + CU_ASSERT_PTR_NOT_NULL_FATAL(socket_event); + CU_ASSERT_TRUE(socket_event->socket_closed); + CU_ASSERT_PTR_EQUAL(socket_event->session, &session); + CU_ASSERT_EQUAL(socket_event->expired_timer_id, TIMER_ID_NOT_SET); + CU_ASSERT_PTR_NULL(socket_event->received_msg_list); + + pceplib_free(PCEPLIB_INFRA, socket_event); +} + + +void test_session_logic_timer_expire_handler() +{ + /* Just testing that it does not core dump */ + session_logic_timer_expire_handler(NULL, 42); + + /* A pcep_session_event should be created */ + pcep_session session; + memset(&session, 0, sizeof(pcep_session)); + session.session_id = 100; + session_logic_timer_expire_handler(&session, 42); + CU_ASSERT_EQUAL(session_logic_handle_->session_event_queue->num_entries, + 1); + pcep_session_event *socket_event = (pcep_session_event *)queue_dequeue( + session_logic_handle_->session_event_queue); + CU_ASSERT_PTR_NOT_NULL_FATAL(socket_event); + CU_ASSERT_FALSE(socket_event->socket_closed); + CU_ASSERT_PTR_EQUAL(socket_event->session, &session); + CU_ASSERT_EQUAL(socket_event->expired_timer_id, 42); + CU_ASSERT_PTR_NULL(socket_event->received_msg_list); + + pceplib_free(PCEPLIB_INFRA, socket_event); +} diff --git a/pceplib/test/pcep_session_logic_loop_test.h b/pceplib/test/pcep_session_logic_loop_test.h new file mode 100644 index 0000000000..ae3c3e3753 --- /dev/null +++ b/pceplib/test/pcep_session_logic_loop_test.h @@ -0,0 +1,40 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Javier Garcia <javier.garcia@voltanet.io> + * + */ + +/* + * Timer definitions to be used internally by the pcep_timers library. + */ + +#ifndef PCEP_SESSION_LOGIC_LOOP_TEST_H_ +#define PCEP_SESSION_LOGIC_LOOP_TEST_H_ + +int pcep_session_logic_loop_test_suite_setup(void); +int pcep_session_logic_loop_test_suite_teardown(void); +void pcep_session_logic_loop_test_setup(void); +void pcep_session_logic_loop_test_teardown(void); +void test_session_logic_loop_null_data(void); +void test_session_logic_loop_inactive(void); +void test_session_logic_msg_ready_handler(void); +void test_session_logic_conn_except_notifier(void); +void test_session_logic_timer_expire_handler(void); + +#endif /* PCEPTIMERINTERNALS_H_ */ diff --git a/pceplib/test/pcep_session_logic_states_test.c b/pceplib/test/pcep_session_logic_states_test.c new file mode 100644 index 0000000000..f75c16e397 --- /dev/null +++ b/pceplib/test/pcep_session_logic_states_test.c @@ -0,0 +1,919 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Brady Johnson <brady@voltanet.io> + * + */ + + +#include <stdlib.h> +#include <string.h> + +#include <CUnit/CUnit.h> + +#include "pcep_socket_comm_mock.h" +#include "pcep_session_logic.h" +#include "pcep_session_logic_internals.h" +#include "pcep_timers.h" +#include "pcep_utils_ordered_list.h" +#include "pcep_utils_double_linked_list.h" +#include "pcep_utils_memory.h" +#include "pcep_msg_objects.h" +#include "pcep_msg_tools.h" +#include "pcep_session_logic_states_test.h" + +/* Functions being tested */ +extern pcep_session_logic_handle *session_logic_handle_; +extern pcep_event_queue *session_logic_event_queue_; + +static pcep_session_event event; +static pcep_session session; +/* A message list is a dll of struct pcep_messages_list_node items */ +static double_linked_list *msg_list; +struct pcep_message *message; +static bool free_msg_list; +static bool msg_enqueued; +/* Forward declaration */ +void destroy_message_for_test(void); +void create_message_for_test(uint8_t msg_type, bool free_msg_list_at_teardown, + bool was_msg_enqueued); +void test_handle_timer_event_open_keep_alive(void); + +/* + * Test suite setup and teardown called before AND after the test suite. + */ + +int pcep_session_logic_states_test_suite_setup(void) +{ + pceplib_memory_reset(); + return 0; +} + +int pcep_session_logic_states_test_suite_teardown(void) +{ + printf("\n"); + pceplib_memory_dump(); + return 0; +} + +/* + * Test case setup and teardown called before AND after each test. + */ + +void pcep_session_logic_states_test_setup() +{ + session_logic_handle_ = pceplib_malloc( + PCEPLIB_INFRA, sizeof(pcep_session_logic_handle)); + memset(session_logic_handle_, 0, sizeof(pcep_session_logic_handle)); + + session_logic_event_queue_ = + pceplib_malloc(PCEPLIB_INFRA, sizeof(pcep_event_queue)); + memset(session_logic_event_queue_, 0, sizeof(pcep_event_queue)); + session_logic_event_queue_->event_queue = queue_initialize(); + + memset(&session, 0, sizeof(pcep_session)); + session.pcc_config.keep_alive_seconds = 5; + session.pcc_config.keep_alive_pce_negotiated_timer_seconds = 5; + session.pcc_config.min_keep_alive_seconds = 1; + session.pcc_config.max_keep_alive_seconds = 10; + session.pcc_config.dead_timer_seconds = 5; + session.pcc_config.dead_timer_pce_negotiated_seconds = 5; + session.pcc_config.min_dead_timer_seconds = 1; + session.pcc_config.max_dead_timer_seconds = 10; + session.pcc_config.max_unknown_messages = 2; + memcpy(&session.pce_config, &session.pcc_config, + sizeof(pcep_configuration)); + session.num_unknown_messages_time_queue = queue_initialize(); + + memset(&event, 0, sizeof(pcep_session_event)); + event.socket_closed = false; + event.session = &session; + + setup_mock_socket_comm_info(); + free_msg_list = false; + msg_enqueued = false; +} + + +void pcep_session_logic_states_test_teardown() +{ + destroy_message_for_test(); + pceplib_free(PCEPLIB_INFRA, session_logic_handle_); + queue_destroy(session_logic_event_queue_->event_queue); + pceplib_free(PCEPLIB_INFRA, session_logic_event_queue_); + session_logic_handle_ = NULL; + session_logic_event_queue_ = NULL; + queue_destroy_with_data(session.num_unknown_messages_time_queue); + teardown_mock_socket_comm_info(); +} + +void create_message_for_test(uint8_t msg_type, bool free_msg_list_at_teardown, + bool was_msg_enqueued) +{ + /* See the comments in destroy_message_for_test() about these 2 + * variables */ + free_msg_list = free_msg_list_at_teardown; + msg_enqueued = was_msg_enqueued; + + message = pceplib_malloc(PCEPLIB_MESSAGES, sizeof(struct pcep_message)); + memset(message, 0, sizeof(struct pcep_message)); + + message->msg_header = pceplib_malloc( + PCEPLIB_MESSAGES, sizeof(struct pcep_message_header)); + memset(message->msg_header, 0, sizeof(struct pcep_message_header)); + message->obj_list = dll_initialize(); + message->msg_header->type = msg_type; + + msg_list = dll_initialize(); + dll_append(msg_list, message); + event.received_msg_list = msg_list; +} + +void destroy_message_for_test() +{ + /* Some test cases internally free the message list, so we dont + * want to double free it */ + if (free_msg_list == true) { + /* This will destroy both the msg_list and the obj_list */ + pcep_msg_free_message_list(msg_list); + } + + /* Some tests cause the message to be enqueued and dont delete it, + * so we have to delete it here */ + if (msg_enqueued == true) { + pcep_msg_free_message(message); + } +} + +/* + * Test cases + */ + +void test_handle_timer_event_dead_timer() +{ + /* Dead Timer expired */ + event.expired_timer_id = session.timer_id_dead_timer = 100; + + handle_timer_event(&event); + + CU_ASSERT_EQUAL(session.timer_id_dead_timer, TIMER_ID_NOT_SET); + CU_ASSERT_EQUAL(session.session_state, SESSION_STATE_INITIALIZED); + CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries, + 1); + + pcep_event *e = queue_dequeue(session_logic_event_queue_->event_queue); + CU_ASSERT_EQUAL(PCE_DEAD_TIMER_EXPIRED, e->event_type); + pceplib_free(PCEPLIB_INFRA, e); + + /* verify_socket_comm_times_called( + * initialized, teardown, connect, send_message, close_after_write, + * close, destroy); */ + verify_socket_comm_times_called(0, 0, 0, 1, 1, 0, 0); +} + + +void test_handle_timer_event_keep_alive() +{ + /* Keep Alive timer expired */ + event.expired_timer_id = session.timer_id_keep_alive = 200; + + handle_timer_event(&event); + + CU_ASSERT_EQUAL(session.timer_id_keep_alive, TIMER_ID_NOT_SET); + verify_socket_comm_times_called(0, 0, 0, 1, 0, 0, 0); +} + + +void test_handle_timer_event_open_keep_wait() +{ + /* Open Keep Wait timer expired */ + event.expired_timer_id = session.timer_id_open_keep_wait = 300; + session.session_state = SESSION_STATE_PCEP_CONNECTING; + handle_timer_event(&event); + + CU_ASSERT_EQUAL(session.timer_id_open_keep_wait, TIMER_ID_NOT_SET); + CU_ASSERT_EQUAL(session.session_state, SESSION_STATE_INITIALIZED); + CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries, + 1); + verify_socket_comm_times_called(0, 0, 0, 0, 1, 0, 0); + + pcep_event *e = queue_dequeue(session_logic_event_queue_->event_queue); + CU_ASSERT_EQUAL(PCE_OPEN_KEEP_WAIT_TIMER_EXPIRED, e->event_type); + pceplib_free(PCEPLIB_INFRA, e); + + /* If the state is not SESSION_STATE_PCEP_CONNECTED, then nothing should + * happen */ + reset_mock_socket_comm_info(); + session.session_state = SESSION_STATE_UNKNOWN; + event.expired_timer_id = session.timer_id_open_keep_wait = 300; + handle_timer_event(&event); + + CU_ASSERT_EQUAL(session.timer_id_open_keep_wait, 300); + CU_ASSERT_EQUAL(session.session_state, SESSION_STATE_UNKNOWN); + verify_socket_comm_times_called(0, 0, 0, 0, 0, 0, 0); +} + + +void test_handle_timer_event_open_keep_alive() +{ + /* Open Keep Alive timer expired, but the Keep Alive should not be sent + * since the PCE Open has not been received yet */ + event.expired_timer_id = session.timer_id_open_keep_alive = 300; + session.session_state = SESSION_STATE_PCEP_CONNECTING; + session.pce_open_keep_alive_sent = false; + session.pce_open_received = false; + handle_timer_event(&event); + + CU_ASSERT_EQUAL(session.timer_id_open_keep_alive, TIMER_ID_NOT_SET); + CU_ASSERT_EQUAL(session.session_state, SESSION_STATE_PCEP_CONNECTING); + CU_ASSERT_FALSE(session.pce_open_keep_alive_sent); + + /* Open Keep Alive timer expired, the Keep Alive should be sent, + * but the session should not be connected, since the PCC Open + * has not been accepted yet */ + event.expired_timer_id = session.timer_id_open_keep_alive = 300; + session.session_state = SESSION_STATE_PCEP_CONNECTING; + session.pce_open_keep_alive_sent = false; + session.pce_open_received = true; + session.pce_open_rejected = false; + session.pcc_open_accepted = false; + handle_timer_event(&event); + + CU_ASSERT_EQUAL(session.timer_id_open_keep_alive, TIMER_ID_NOT_SET); + CU_ASSERT_EQUAL(session.session_state, SESSION_STATE_PCEP_CONNECTING); + CU_ASSERT_TRUE(session.pce_open_keep_alive_sent); + + /* Open Keep Alive timer expired, the Keep Alive should be sent, + * and the session is connected */ + event.expired_timer_id = session.timer_id_open_keep_alive = 300; + session.session_state = SESSION_STATE_PCEP_CONNECTING; + session.pce_open_keep_alive_sent = false; + session.pce_open_received = true; + session.pce_open_rejected = false; + session.pcc_open_accepted = true; + handle_timer_event(&event); + + CU_ASSERT_EQUAL(session.timer_id_open_keep_alive, TIMER_ID_NOT_SET); + CU_ASSERT_EQUAL(session.session_state, SESSION_STATE_PCEP_CONNECTED); + CU_ASSERT_FALSE(session.pce_open_keep_alive_sent); +} + + +void test_handle_socket_comm_event_null_params() +{ + /* Verify it doesnt core dump */ + handle_socket_comm_event(NULL); + verify_socket_comm_times_called(0, 0, 0, 0, 0, 0, 0); + reset_mock_socket_comm_info(); + + event.received_msg_list = NULL; + handle_socket_comm_event(&event); + verify_socket_comm_times_called(0, 0, 0, 0, 0, 0, 0); +} + + +void test_handle_socket_comm_event_close() +{ + event.socket_closed = true; + handle_socket_comm_event(&event); + + CU_ASSERT_EQUAL(session.session_state, SESSION_STATE_INITIALIZED); + CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries, + 1); + verify_socket_comm_times_called(0, 0, 0, 0, 0, 1, 0); + + pcep_event *e = queue_dequeue(session_logic_event_queue_->event_queue); + CU_ASSERT_EQUAL(PCE_CLOSED_SOCKET, e->event_type); + pceplib_free(PCEPLIB_INFRA, e); +} + + +void test_handle_socket_comm_event_open() +{ + /* + * Test when a PCE Open is received, but the PCC Open has not been + * accepted yet + */ + create_message_for_test(PCEP_TYPE_OPEN, false, true); + struct pcep_object_open *open_object = + pcep_obj_create_open(1, 1, 1, NULL); + dll_append(message->obj_list, open_object); + session.pcc_open_accepted = false; + session.pce_open_received = false; + session.pce_open_accepted = false; + session.timer_id_open_keep_alive = 100; + session.session_state = SESSION_STATE_PCEP_CONNECTING; + + handle_socket_comm_event(&event); + + CU_ASSERT_TRUE(session.pce_open_received); + CU_ASSERT_TRUE(session.pce_open_accepted); + CU_ASSERT_FALSE(session.pce_open_rejected); + CU_ASSERT_FALSE(session.pce_open_keep_alive_sent); + CU_ASSERT_EQUAL(session.session_state, SESSION_STATE_PCEP_CONNECTING); + CU_ASSERT_NOT_EQUAL(session.timer_id_open_keep_alive, 100); + /* A keep alive response should NOT be sent yet */ + verify_socket_comm_times_called(0, 0, 0, 0, 0, 0, 0); + CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries, + 1); + pcep_event *e = queue_dequeue(session_logic_event_queue_->event_queue); + CU_ASSERT_EQUAL(MESSAGE_RECEIVED, e->event_type); + CU_ASSERT_EQUAL(PCEP_TYPE_OPEN, e->message->msg_header->type); + pceplib_free(PCEPLIB_INFRA, e); + destroy_message_for_test(); + + /* + * Test when a PCE Open is received, and the PCC Open has been accepted + */ + create_message_for_test(PCEP_TYPE_OPEN, false, true); + reset_mock_socket_comm_info(); + open_object = pcep_obj_create_open(1, 1, 1, NULL); + dll_append(message->obj_list, open_object); + session.pcc_open_accepted = true; + session.pce_open_received = false; + session.pce_open_accepted = false; + session.session_state = SESSION_STATE_PCEP_CONNECTING; + + handle_socket_comm_event(&event); + + CU_ASSERT_TRUE(session.pce_open_received); + CU_ASSERT_TRUE(session.pce_open_accepted); + CU_ASSERT_FALSE(session.pce_open_rejected); + CU_ASSERT_TRUE(session.pce_open_keep_alive_sent); + CU_ASSERT_EQUAL(session.session_state, SESSION_STATE_PCEP_CONNECTED); + /* A keep alive response should be sent, accepting the Open */ + verify_socket_comm_times_called(0, 0, 0, 1, 0, 0, 0); + CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries, + 2); + e = queue_dequeue(session_logic_event_queue_->event_queue); + CU_ASSERT_EQUAL(MESSAGE_RECEIVED, e->event_type); + CU_ASSERT_EQUAL(PCEP_TYPE_OPEN, e->message->msg_header->type); + pceplib_free(PCEPLIB_INFRA, e); + e = queue_dequeue(session_logic_event_queue_->event_queue); + CU_ASSERT_EQUAL(PCC_CONNECTED_TO_PCE, e->event_type); + pceplib_free(PCEPLIB_INFRA, e); + destroy_message_for_test(); + + /* + * Send a 2nd Open, an error should be sent + */ + create_message_for_test(PCEP_TYPE_OPEN, false, false); + reset_mock_socket_comm_info(); + mock_socket_comm_info *mock_info = get_mock_socket_comm_info(); + mock_info->send_message_save_message = true; + + handle_socket_comm_event(&event); + + CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries, + 0); + verify_socket_comm_times_called(0, 0, 0, 1, 0, 0, 0); + /* What gets saved in the mock is the msg byte buffer. The msg struct + * was deleted when it was sent. Instead of inspecting the msg byte + * buffer, lets just decode it. */ + uint8_t *encoded_msg = + dll_delete_first_node(mock_info->sent_message_list); + CU_ASSERT_PTR_NOT_NULL(encoded_msg); + struct pcep_message *msg = pcep_decode_message(encoded_msg); + CU_ASSERT_PTR_NOT_NULL(msg); + CU_ASSERT_EQUAL(PCEP_TYPE_ERROR, msg->msg_header->type); + /* Verify the error object */ + CU_ASSERT_EQUAL(1, msg->obj_list->num_entries); + struct pcep_object_error *error_obj = msg->obj_list->head->data; + CU_ASSERT_EQUAL(PCEP_OBJ_CLASS_ERROR, error_obj->header.object_class); + CU_ASSERT_EQUAL(PCEP_OBJ_TYPE_ERROR, error_obj->header.object_type); + CU_ASSERT_EQUAL(PCEP_ERRT_ATTEMPT_TO_ESTABLISH_2ND_PCEP_SESSION, + error_obj->error_type); + CU_ASSERT_EQUAL(PCEP_ERRV_RECVD_INVALID_OPEN_MSG, + error_obj->error_value); + pcep_msg_free_message(msg); + pceplib_free(PCEPLIB_MESSAGES, encoded_msg); +} + + +void test_handle_socket_comm_event_open_error() +{ + /* Test when the PCE rejects the PCC Open with an Error + * that a "corrected" Open message is sent. */ + + create_message_for_test(PCEP_TYPE_ERROR, false, true); + struct pcep_object_error *error_object = pcep_obj_create_error( + PCEP_ERRT_SESSION_FAILURE, PCEP_ERRV_UNACCEPTABLE_OPEN_MSG_NEG); + struct pcep_object_open *error_open_object = + pcep_obj_create_open(1, 1, 1, NULL); + /* The configured [Keep-alive, Dead-timer] values are [5, 5], + * this error open object will request they be changed to [10, 10] */ + error_open_object->open_keepalive = 10; + error_open_object->open_deadtimer = 10; + dll_append(message->obj_list, error_object); + dll_append(message->obj_list, error_open_object); + session.session_state = SESSION_STATE_PCEP_CONNECTING; + mock_socket_comm_info *mock_info = get_mock_socket_comm_info(); + mock_info->send_message_save_message = true; + + handle_socket_comm_event(&event); + + CU_ASSERT_TRUE(session.pcc_open_rejected); + CU_ASSERT_FALSE(session.pce_open_keep_alive_sent); + CU_ASSERT_EQUAL(session.session_state, SESSION_STATE_PCEP_CONNECTING); + /* Another Open should be sent */ + verify_socket_comm_times_called(0, 0, 0, 1, 0, 0, 0); + CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries, + 2); + + pcep_event *e = queue_dequeue(session_logic_event_queue_->event_queue); + CU_ASSERT_EQUAL(PCC_SENT_INVALID_OPEN, e->event_type); + pceplib_free(PCEPLIB_INFRA, e); + + e = queue_dequeue(session_logic_event_queue_->event_queue); + CU_ASSERT_EQUAL(MESSAGE_RECEIVED, e->event_type); + CU_ASSERT_EQUAL(PCEP_TYPE_ERROR, e->message->msg_header->type); + pceplib_free(PCEPLIB_INFRA, e); + + /* Check the Corrected Open Message */ + + /* What gets saved in the mock is the msg byte buffer. The msg struct + * was deleted when it was sent. Instead of inspecting the msg byte + * buffer, lets just decode it. */ + uint8_t *encoded_msg = + dll_delete_first_node(mock_info->sent_message_list); + CU_ASSERT_PTR_NOT_NULL(encoded_msg); + struct pcep_message *open_msg_corrected = + pcep_decode_message(encoded_msg); + CU_ASSERT_PTR_NOT_NULL(open_msg_corrected); + struct pcep_object_open *open_object_corrected = + (struct pcep_object_open *)pcep_obj_get( + open_msg_corrected->obj_list, PCEP_OBJ_CLASS_OPEN); + CU_ASSERT_PTR_NOT_NULL(open_object_corrected); + /* Verify the Keep-alive and Dead timers have been negotiated */ + CU_ASSERT_EQUAL(error_open_object->open_keepalive, + open_object_corrected->open_keepalive); + CU_ASSERT_EQUAL(error_open_object->open_deadtimer, + open_object_corrected->open_deadtimer); + CU_ASSERT_EQUAL(session.pcc_config.dead_timer_pce_negotiated_seconds, + open_object_corrected->open_deadtimer); + CU_ASSERT_EQUAL( + session.pcc_config.keep_alive_pce_negotiated_timer_seconds, + open_object_corrected->open_keepalive); + CU_ASSERT_NOT_EQUAL( + session.pcc_config.dead_timer_pce_negotiated_seconds, + session.pcc_config.dead_timer_seconds); + CU_ASSERT_NOT_EQUAL( + session.pcc_config.keep_alive_pce_negotiated_timer_seconds, + session.pcc_config.keep_alive_seconds); + + pcep_msg_free_message(open_msg_corrected); + pceplib_free(PCEPLIB_MESSAGES, encoded_msg); +} + + +void test_handle_socket_comm_event_keep_alive() +{ + /* Test when a Keep Alive is received, but the PCE Open has not been + * received yet */ + create_message_for_test(PCEP_TYPE_KEEPALIVE, false, false); + session.session_state = SESSION_STATE_PCEP_CONNECTING; + session.timer_id_dead_timer = 100; + session.timer_id_open_keep_wait = 200; + session.pce_open_accepted = false; + session.pce_open_received = false; + session.pcc_open_accepted = false; + + handle_socket_comm_event(&event); + + CU_ASSERT_TRUE(session.pcc_open_accepted); + CU_ASSERT_FALSE(session.pce_open_keep_alive_sent); + CU_ASSERT_FALSE(session.pcc_open_rejected); + CU_ASSERT_FALSE(session.pce_open_accepted); + CU_ASSERT_EQUAL(session.session_state, SESSION_STATE_PCEP_CONNECTING); + CU_ASSERT_EQUAL(session.timer_id_open_keep_wait, TIMER_ID_NOT_SET); + CU_ASSERT_EQUAL(session.timer_id_dead_timer, 100); + verify_socket_comm_times_called(0, 0, 0, 0, 0, 0, 0); + CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries, + 0); + + /* Test when a Keep Alive is received, and the PCE Open has been + * received and accepted */ + create_message_for_test(PCEP_TYPE_KEEPALIVE, false, false); + session.session_state = SESSION_STATE_PCEP_CONNECTING; + session.timer_id_dead_timer = 100; + session.timer_id_open_keep_wait = 200; + session.pce_open_received = true; + session.pce_open_accepted = true; + session.pcc_open_accepted = false; + + handle_socket_comm_event(&event); + + CU_ASSERT_TRUE(session.pcc_open_accepted); + CU_ASSERT_TRUE(session.pce_open_keep_alive_sent); + CU_ASSERT_FALSE(session.pcc_open_rejected); + CU_ASSERT_EQUAL(session.session_state, SESSION_STATE_PCEP_CONNECTED); + CU_ASSERT_EQUAL(session.timer_id_open_keep_wait, TIMER_ID_NOT_SET); + CU_ASSERT_EQUAL(session.timer_id_dead_timer, 100); + verify_socket_comm_times_called(0, 0, 0, 1, 0, 0, 0); + + /* Test when a Keep Alive is received, and the PCE Open has been + * received and rejected */ + create_message_for_test(PCEP_TYPE_KEEPALIVE, false, false); + session.session_state = SESSION_STATE_PCEP_CONNECTING; + session.timer_id_dead_timer = 100; + session.timer_id_open_keep_wait = 200; + session.pce_open_received = true; + session.pce_open_accepted = false; + session.pce_open_rejected = true; + session.pce_open_keep_alive_sent = false; + session.pcc_open_accepted = true; + + handle_socket_comm_event(&event); + + CU_ASSERT_TRUE(session.pcc_open_accepted); + CU_ASSERT_FALSE(session.pce_open_keep_alive_sent); + CU_ASSERT_FALSE(session.pcc_open_rejected); + CU_ASSERT_EQUAL(session.session_state, SESSION_STATE_PCEP_CONNECTING); + CU_ASSERT_EQUAL(session.timer_id_open_keep_wait, TIMER_ID_NOT_SET); + CU_ASSERT_EQUAL(session.timer_id_dead_timer, 100); + verify_socket_comm_times_called(0, 0, 0, 1, 0, 0, 0); + + /* The session is considered connected, when both the + * PCE and PCC Open messages have been accepted */ + pcep_event *e = queue_dequeue(session_logic_event_queue_->event_queue); + CU_ASSERT_EQUAL(PCC_CONNECTED_TO_PCE, e->event_type); + pceplib_free(PCEPLIB_INFRA, e); +} + + +void test_handle_socket_comm_event_pcrep() +{ + create_message_for_test(PCEP_TYPE_PCREP, false, true); + struct pcep_object_rp *rp = + pcep_obj_create_rp(1, true, true, true, true, 1, NULL); + dll_append(message->obj_list, rp); + + handle_socket_comm_event(&event); + + CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries, + 1); + verify_socket_comm_times_called(0, 0, 0, 0, 0, 0, 0); + pcep_event *e = queue_dequeue(session_logic_event_queue_->event_queue); + CU_ASSERT_EQUAL(MESSAGE_RECEIVED, e->event_type); + pceplib_free(PCEPLIB_INFRA, e); +} + + +void test_handle_socket_comm_event_pcreq() +{ + create_message_for_test(PCEP_TYPE_PCREQ, false, false); + mock_socket_comm_info *mock_info = get_mock_socket_comm_info(); + mock_info->send_message_save_message = true; + + handle_socket_comm_event(&event); + + /* The PCC does not support receiving PcReq messages, so an error should + * be sent */ + CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries, + 0); + verify_socket_comm_times_called(0, 0, 0, 1, 0, 0, 0); + uint8_t *encoded_msg = + dll_delete_first_node(mock_info->sent_message_list); + CU_ASSERT_PTR_NOT_NULL(encoded_msg); + struct pcep_message *error_msg = pcep_decode_message(encoded_msg); + CU_ASSERT_PTR_NOT_NULL(error_msg); + CU_ASSERT_EQUAL(PCEP_TYPE_ERROR, error_msg->msg_header->type); + /* Verify the error object */ + CU_ASSERT_EQUAL(1, error_msg->obj_list->num_entries); + struct pcep_object_error *obj = error_msg->obj_list->head->data; + CU_ASSERT_EQUAL(PCEP_OBJ_CLASS_ERROR, obj->header.object_class); + CU_ASSERT_EQUAL(PCEP_OBJ_TYPE_ERROR, obj->header.object_type); + CU_ASSERT_EQUAL(PCEP_ERRT_CAPABILITY_NOT_SUPPORTED, obj->error_type); + CU_ASSERT_EQUAL(PCEP_ERRV_UNASSIGNED, obj->error_value); + pcep_msg_free_message(error_msg); + pceplib_free(PCEPLIB_MESSAGES, encoded_msg); +} + + +void test_handle_socket_comm_event_report() +{ + create_message_for_test(PCEP_TYPE_REPORT, false, false); + mock_socket_comm_info *mock_info = get_mock_socket_comm_info(); + mock_info->send_message_save_message = true; + + handle_socket_comm_event(&event); + + /* The PCC does not support receiving Report messages, so an error + * should be sent */ + CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries, + 0); + verify_socket_comm_times_called(0, 0, 0, 1, 0, 0, 0); + uint8_t *encoded_msg = + dll_delete_first_node(mock_info->sent_message_list); + CU_ASSERT_PTR_NOT_NULL(encoded_msg); + struct pcep_message *error_msg = pcep_decode_message(encoded_msg); + CU_ASSERT_PTR_NOT_NULL(error_msg); + CU_ASSERT_EQUAL(PCEP_TYPE_ERROR, error_msg->msg_header->type); + /* Verify the error object */ + CU_ASSERT_EQUAL(1, error_msg->obj_list->num_entries); + struct pcep_object_error *obj = error_msg->obj_list->head->data; + CU_ASSERT_EQUAL(PCEP_OBJ_CLASS_ERROR, obj->header.object_class); + CU_ASSERT_EQUAL(PCEP_OBJ_TYPE_ERROR, obj->header.object_type); + CU_ASSERT_EQUAL(PCEP_ERRT_CAPABILITY_NOT_SUPPORTED, obj->error_type); + CU_ASSERT_EQUAL(PCEP_ERRV_UNASSIGNED, obj->error_value); + pcep_msg_free_message(error_msg); + pceplib_free(PCEPLIB_MESSAGES, encoded_msg); +} + + +void test_handle_socket_comm_event_update() +{ + create_message_for_test(PCEP_TYPE_UPDATE, false, true); + struct pcep_object_srp *srp = pcep_obj_create_srp(false, 100, NULL); + struct pcep_object_lsp *lsp = + pcep_obj_create_lsp(100, PCEP_LSP_OPERATIONAL_UP, true, true, + true, true, true, NULL); + double_linked_list *ero_subobj_list = dll_initialize(); + dll_append(ero_subobj_list, pcep_obj_create_ro_subobj_asn(0x0102)); + struct pcep_object_ro *ero = pcep_obj_create_ero(ero_subobj_list); + struct pcep_object_metric *metric = + pcep_obj_create_metric(PCEP_METRIC_TE, false, true, 16.0); + dll_append(message->obj_list, srp); + dll_append(message->obj_list, lsp); + dll_append(message->obj_list, ero); + dll_append(message->obj_list, metric); + mock_socket_comm_info *mock_info = get_mock_socket_comm_info(); + mock_info->send_message_save_message = true; + + handle_socket_comm_event(&event); + + CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries, + 1); + verify_socket_comm_times_called(0, 0, 0, 0, 0, 0, 0); + pcep_event *e = queue_dequeue(session_logic_event_queue_->event_queue); + CU_ASSERT_EQUAL(MESSAGE_RECEIVED, e->event_type); + CU_ASSERT_EQUAL(PCEP_TYPE_UPDATE, e->message->msg_header->type); + pceplib_free(PCEPLIB_INFRA, e); +} + + +void test_handle_socket_comm_event_initiate() +{ + create_message_for_test(PCEP_TYPE_INITIATE, false, true); + struct pcep_object_srp *srp = pcep_obj_create_srp(false, 100, NULL); + struct pcep_object_lsp *lsp = + pcep_obj_create_lsp(100, PCEP_LSP_OPERATIONAL_UP, true, true, + true, true, true, NULL); + dll_append(message->obj_list, srp); + dll_append(message->obj_list, lsp); + mock_socket_comm_info *mock_info = get_mock_socket_comm_info(); + mock_info->send_message_save_message = true; + + handle_socket_comm_event(&event); + + CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries, + 1); + verify_socket_comm_times_called(0, 0, 0, 0, 0, 0, 0); + pcep_event *e = queue_dequeue(session_logic_event_queue_->event_queue); + CU_ASSERT_EQUAL(MESSAGE_RECEIVED, e->event_type); + CU_ASSERT_EQUAL(PCEP_TYPE_INITIATE, e->message->msg_header->type); + pceplib_free(PCEPLIB_INFRA, e); +} + + +void test_handle_socket_comm_event_notify() +{ + create_message_for_test(PCEP_TYPE_PCNOTF, false, true); + handle_socket_comm_event(&event); + + CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries, + 1); + verify_socket_comm_times_called(0, 0, 0, 0, 0, 0, 0); + pcep_event *e = queue_dequeue(session_logic_event_queue_->event_queue); + CU_ASSERT_EQUAL(MESSAGE_RECEIVED, e->event_type); + CU_ASSERT_EQUAL(PCEP_TYPE_PCNOTF, e->message->msg_header->type); + pceplib_free(PCEPLIB_INFRA, e); +} + + +void test_handle_socket_comm_event_error() +{ + create_message_for_test(PCEP_TYPE_ERROR, false, true); + handle_socket_comm_event(&event); + + CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries, + 1); + verify_socket_comm_times_called(0, 0, 0, 0, 0, 0, 0); + pcep_event *e = queue_dequeue(session_logic_event_queue_->event_queue); + CU_ASSERT_EQUAL(MESSAGE_RECEIVED, e->event_type); + CU_ASSERT_EQUAL(PCEP_TYPE_ERROR, e->message->msg_header->type); + pceplib_free(PCEPLIB_INFRA, e); +} + + +void test_handle_socket_comm_event_unknown_msg() +{ + create_message_for_test(13, false, false); + mock_socket_comm_info *mock_info = get_mock_socket_comm_info(); + mock_info->send_message_save_message = true; + + handle_socket_comm_event(&event); + + /* Sending an unsupported message type, so an error should be sent, + * but the connection should remain open, since max_unknown_messages = 2 + */ + CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries, + 0); + verify_socket_comm_times_called(0, 0, 0, 1, 0, 0, 0); + uint8_t *encoded_msg = + dll_delete_first_node(mock_info->sent_message_list); + CU_ASSERT_PTR_NOT_NULL(encoded_msg); + struct pcep_message *msg = pcep_decode_message(encoded_msg); + CU_ASSERT_PTR_NOT_NULL(msg); + CU_ASSERT_EQUAL(PCEP_TYPE_ERROR, msg->msg_header->type); + /* Verify the error object */ + CU_ASSERT_EQUAL(1, msg->obj_list->num_entries); + struct pcep_object_error *error_obj = msg->obj_list->head->data; + CU_ASSERT_EQUAL(PCEP_OBJ_CLASS_ERROR, error_obj->header.object_class); + CU_ASSERT_EQUAL(PCEP_OBJ_TYPE_ERROR, error_obj->header.object_type); + CU_ASSERT_EQUAL(PCEP_ERRT_CAPABILITY_NOT_SUPPORTED, + error_obj->error_type); + CU_ASSERT_EQUAL(PCEP_ERRV_UNASSIGNED, error_obj->error_value); + pcep_msg_free_message(msg); + pceplib_free(PCEPLIB_MESSAGES, encoded_msg); + destroy_message_for_test(); + + /* Send another unsupported message type, an error should be sent and + * the connection should be closed, since max_unknown_messages = 2 */ + create_message_for_test(13, false, false); + reset_mock_socket_comm_info(); + mock_info = get_mock_socket_comm_info(); + mock_info->send_message_save_message = true; + + handle_socket_comm_event(&event); + + verify_socket_comm_times_called(0, 0, 0, 2, 1, 0, 0); + CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries, + 1); + pcep_event *e = queue_dequeue(session_logic_event_queue_->event_queue); + CU_ASSERT_EQUAL(PCC_RCVD_MAX_UNKOWN_MSGS, e->event_type); + pceplib_free(PCEPLIB_INFRA, e); + + /* Verify the error message */ + encoded_msg = dll_delete_first_node(mock_info->sent_message_list); + CU_ASSERT_PTR_NOT_NULL(encoded_msg); + msg = pcep_decode_message(encoded_msg); + CU_ASSERT_PTR_NOT_NULL(msg); + CU_ASSERT_EQUAL(PCEP_TYPE_ERROR, msg->msg_header->type); + /* Verify the error object */ + CU_ASSERT_EQUAL(1, msg->obj_list->num_entries); + error_obj = msg->obj_list->head->data; + CU_ASSERT_EQUAL(PCEP_OBJ_CLASS_ERROR, error_obj->header.object_class); + CU_ASSERT_EQUAL(PCEP_OBJ_TYPE_ERROR, error_obj->header.object_type); + CU_ASSERT_EQUAL(PCEP_ERRT_CAPABILITY_NOT_SUPPORTED, + error_obj->error_type); + CU_ASSERT_EQUAL(PCEP_ERRV_UNASSIGNED, error_obj->error_value); + pcep_msg_free_message(msg); + pceplib_free(PCEPLIB_MESSAGES, encoded_msg); + + /* Verify the Close message */ + encoded_msg = dll_delete_first_node(mock_info->sent_message_list); + CU_ASSERT_PTR_NOT_NULL(encoded_msg); + msg = pcep_decode_message(encoded_msg); + CU_ASSERT_PTR_NOT_NULL(msg); + CU_ASSERT_EQUAL(PCEP_TYPE_CLOSE, msg->msg_header->type); + /* Verify the error object */ + CU_ASSERT_EQUAL(1, msg->obj_list->num_entries); + struct pcep_object_close *close_obj = msg->obj_list->head->data; + CU_ASSERT_EQUAL(PCEP_OBJ_CLASS_CLOSE, close_obj->header.object_class); + CU_ASSERT_EQUAL(PCEP_OBJ_TYPE_CLOSE, close_obj->header.object_type); + CU_ASSERT_EQUAL(PCEP_CLOSE_REASON_UNREC_MSG, close_obj->reason); + pcep_msg_free_message(msg); + pceplib_free(PCEPLIB_MESSAGES, encoded_msg); +} + + +void test_connection_failure(void) +{ + /* + * Test when 2 invalid Open messages are received that a + * PCC_CONNECTION_FAILURE event is generated. + */ + create_message_for_test(PCEP_TYPE_OPEN, false, false); + reset_mock_socket_comm_info(); + struct pcep_object_open *open_object = + pcep_obj_create_open(1, 1, 1, NULL); + /* Make the Open message invalid */ + open_object->open_deadtimer = + session.pcc_config.max_dead_timer_seconds + 1; + dll_append(message->obj_list, open_object); + session.pce_open_received = false; + session.pce_open_accepted = false; + session.pce_open_rejected = false; + session.session_state = SESSION_STATE_PCEP_CONNECTING; + + handle_socket_comm_event(&event); + + CU_ASSERT_TRUE(session.pce_open_received); + CU_ASSERT_TRUE(session.pce_open_rejected); + CU_ASSERT_FALSE(session.pce_open_accepted); + CU_ASSERT_EQUAL(session.session_state, SESSION_STATE_PCEP_CONNECTING); + /* An error response should be sent, rejecting the Open */ + verify_socket_comm_times_called(0, 0, 0, 1, 0, 0, 0); + CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries, + 1); + pcep_event *e = queue_dequeue(session_logic_event_queue_->event_queue); + CU_ASSERT_EQUAL(PCC_RCVD_INVALID_OPEN, e->event_type); + pceplib_free(PCEPLIB_INFRA, e); + destroy_message_for_test(); + + /* Send the same erroneous Open again */ + create_message_for_test(PCEP_TYPE_OPEN, false, false); + reset_mock_socket_comm_info(); + open_object = pcep_obj_create_open(1, 1, 1, NULL); + /* Make the Open message invalid */ + open_object->open_deadtimer = + session.pcc_config.max_dead_timer_seconds + 1; + dll_append(message->obj_list, open_object); + + handle_socket_comm_event(&event); + + CU_ASSERT_TRUE(session.pce_open_received); + CU_ASSERT_TRUE(session.pce_open_rejected); + CU_ASSERT_FALSE(session.pce_open_accepted); + CU_ASSERT_EQUAL(session.session_state, SESSION_STATE_INITIALIZED); + /* An error response should be sent, rejecting the Open */ + verify_socket_comm_times_called(0, 0, 0, 1, 1, 0, 0); + CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries, + 2); + e = queue_dequeue(session_logic_event_queue_->event_queue); + CU_ASSERT_EQUAL(PCC_RCVD_INVALID_OPEN, e->event_type); + pceplib_free(PCEPLIB_INFRA, e); + e = queue_dequeue(session_logic_event_queue_->event_queue); + CU_ASSERT_EQUAL(PCC_CONNECTION_FAILURE, e->event_type); + pceplib_free(PCEPLIB_INFRA, e); + + destroy_message_for_test(); + + /* + * Test when 2 invalid Open messages are sent that a + * PCC_CONNECTION_FAILURE event is generated. + */ + create_message_for_test(PCEP_TYPE_ERROR, false, false); + reset_mock_socket_comm_info(); + struct pcep_object_error *error_object = pcep_obj_create_error( + PCEP_ERRT_SESSION_FAILURE, PCEP_ERRV_UNACCEPTABLE_OPEN_MSG_NEG); + dll_append(message->obj_list, error_object); + session.pcc_open_accepted = false; + session.pcc_open_rejected = false; + session.session_state = SESSION_STATE_PCEP_CONNECTING; + + handle_socket_comm_event(&event); + + CU_ASSERT_TRUE(session.pcc_open_rejected); + CU_ASSERT_FALSE(session.pcc_open_accepted); + CU_ASSERT_EQUAL(session.session_state, SESSION_STATE_PCEP_CONNECTING); + /* Another Open should be sent */ + verify_socket_comm_times_called(0, 0, 0, 1, 0, 0, 0); + CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries, + 2); + e = queue_dequeue(session_logic_event_queue_->event_queue); + CU_ASSERT_EQUAL(PCC_SENT_INVALID_OPEN, e->event_type); + pceplib_free(PCEPLIB_INFRA, e); + e = queue_dequeue(session_logic_event_queue_->event_queue); + CU_ASSERT_EQUAL(MESSAGE_RECEIVED, e->event_type); + CU_ASSERT_EQUAL(PCEP_TYPE_ERROR, e->message->msg_header->type); + pceplib_free(PCEPLIB_INFRA, e); + destroy_message_for_test(); + + /* Send a socket close while connecting, which should + * generate a PCC_CONNECTION_FAILURE event */ + reset_mock_socket_comm_info(); + event.socket_closed = true; + event.received_msg_list = NULL; + + handle_socket_comm_event(&event); + + CU_ASSERT_TRUE(session.pcc_open_rejected); + CU_ASSERT_FALSE(session.pcc_open_accepted); + CU_ASSERT_EQUAL(session.session_state, SESSION_STATE_INITIALIZED); + verify_socket_comm_times_called(0, 0, 0, 0, 0, 1, 0); + CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries, + 2); + e = queue_dequeue(session_logic_event_queue_->event_queue); + CU_ASSERT_EQUAL(PCE_CLOSED_SOCKET, e->event_type); + pceplib_free(PCEPLIB_INFRA, e); + e = queue_dequeue(session_logic_event_queue_->event_queue); + CU_ASSERT_EQUAL(PCC_CONNECTION_FAILURE, e->event_type); + pceplib_free(PCEPLIB_INFRA, e); +} diff --git a/pceplib/test/pcep_session_logic_states_test.h b/pceplib/test/pcep_session_logic_states_test.h new file mode 100644 index 0000000000..e42b501ed9 --- /dev/null +++ b/pceplib/test/pcep_session_logic_states_test.h @@ -0,0 +1,52 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Javier Garcia <javier.garcia@voltanet.io> + * + */ + +/* + * Timer definitions to be used internally by the pcep_timers library. + */ + +#ifndef PCEP_SESSION_LOGIC_STATES_TEST_H +#define PCEP_SESSION_LOGIC_STATES_TEST_H + +int pcep_session_logic_states_test_suite_setup(void); +int pcep_session_logic_states_test_suite_teardown(void); +void pcep_session_logic_states_test_setup(void); +void pcep_session_logic_states_test_teardown(void); +void test_handle_timer_event_dead_timer(void); +void test_handle_timer_event_keep_alive(void); +void test_handle_timer_event_open_keep_wait(void); +void test_handle_socket_comm_event_null_params(void); +void test_handle_socket_comm_event_close(void); +void test_handle_socket_comm_event_open(void); +void test_handle_socket_comm_event_open_error(void); +void test_handle_socket_comm_event_keep_alive(void); +void test_handle_socket_comm_event_pcrep(void); +void test_handle_socket_comm_event_pcreq(void); +void test_handle_socket_comm_event_report(void); +void test_handle_socket_comm_event_update(void); +void test_handle_socket_comm_event_initiate(void); +void test_handle_socket_comm_event_notify(void); +void test_handle_socket_comm_event_error(void); +void test_handle_socket_comm_event_unknown_msg(void); +void test_connection_failure(void); + +#endif /* PCEPTIMERINTERNALS_H_ */ diff --git a/pceplib/test/pcep_session_logic_test.c b/pceplib/test/pcep_session_logic_test.c new file mode 100644 index 0000000000..66db4fbaea --- /dev/null +++ b/pceplib/test/pcep_session_logic_test.c @@ -0,0 +1,360 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Brady Johnson <brady@voltanet.io> + * + */ + + +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#include <CUnit/CUnit.h> + +#include "pcep_socket_comm_mock.h" +#include "pcep_session_logic.h" +#include "pcep_session_logic_test.h" + +/* + * Test suite setup and teardown called before AND after the test suite. + */ + +int pcep_session_logic_test_suite_setup(void) +{ + pceplib_memory_reset(); + return 0; +} + +int pcep_session_logic_test_suite_teardown(void) +{ + printf("\n"); + pceplib_memory_dump(); + return 0; +} + +/* + * Test case setup and teardown called before AND after each test. + */ + +void pcep_session_logic_test_setup() +{ + setup_mock_socket_comm_info(); +} + + +void pcep_session_logic_test_teardown() +{ + stop_session_logic(); + teardown_mock_socket_comm_info(); +} + + +/* + * Test cases + */ + +void test_run_stop_session_logic() +{ + CU_ASSERT_TRUE(run_session_logic()); + CU_ASSERT_TRUE(stop_session_logic()); +} + + +void test_run_session_logic_twice() +{ + CU_ASSERT_TRUE(run_session_logic()); + CU_ASSERT_FALSE(run_session_logic()); +} + + +void test_session_logic_without_run() +{ + /* Verify the functions that depend on run_session_logic() being called + */ + CU_ASSERT_FALSE(stop_session_logic()); +} + + +void test_create_pcep_session_null_params() +{ + pcep_configuration config; + struct in_addr pce_ip; + + CU_ASSERT_PTR_NULL(create_pcep_session(NULL, NULL)); + CU_ASSERT_PTR_NULL(create_pcep_session(NULL, &pce_ip)); + CU_ASSERT_PTR_NULL(create_pcep_session(&config, NULL)); +} + + +void test_create_destroy_pcep_session() +{ + pcep_session *session; + pcep_configuration config; + struct in_addr pce_ip; + + run_session_logic(); + + memset(&config, 0, sizeof(pcep_configuration)); + config.keep_alive_seconds = 5; + config.dead_timer_seconds = 5; + config.request_time_seconds = 5; + config.max_unknown_messages = 5; + config.max_unknown_requests = 5; + inet_pton(AF_INET, "127.0.0.1", &(pce_ip)); + + mock_socket_comm_info *mock_info = get_mock_socket_comm_info(); + mock_info->send_message_save_message = true; + session = create_pcep_session(&config, &pce_ip); + CU_ASSERT_PTR_NOT_NULL(session); + /* What gets saved in the mock is the msg byte buffer. The msg struct + * was deleted when it was sent. Instead of inspecting the msg byte + * buffer, lets just decode it. */ + uint8_t *encoded_msg = + dll_delete_first_node(mock_info->sent_message_list); + CU_ASSERT_PTR_NOT_NULL(encoded_msg); + struct pcep_message *open_msg = pcep_decode_message(encoded_msg); + CU_ASSERT_PTR_NOT_NULL(open_msg); + /* Should be an Open, with no TLVs: length = 12 */ + CU_ASSERT_EQUAL(open_msg->msg_header->type, PCEP_TYPE_OPEN); + CU_ASSERT_EQUAL(open_msg->encoded_message_length, 12); + destroy_pcep_session(session); + pcep_msg_free_message(open_msg); + pceplib_free(PCEPLIB_MESSAGES, encoded_msg); + + stop_session_logic(); +} + + +void test_create_destroy_pcep_session_ipv6() +{ + pcep_session *session; + pcep_configuration config; + struct in6_addr pce_ip; + + run_session_logic(); + + memset(&config, 0, sizeof(pcep_configuration)); + config.keep_alive_seconds = 5; + config.dead_timer_seconds = 5; + config.request_time_seconds = 5; + config.max_unknown_messages = 5; + config.max_unknown_requests = 5; + config.is_src_ipv6 = true; + inet_pton(AF_INET6, "::1", &pce_ip); + + mock_socket_comm_info *mock_info = get_mock_socket_comm_info(); + mock_info->send_message_save_message = true; + session = create_pcep_session_ipv6(&config, &pce_ip); + CU_ASSERT_PTR_NOT_NULL(session); + CU_ASSERT_TRUE(session->socket_comm_session->is_ipv6); + /* What gets saved in the mock is the msg byte buffer. The msg struct + * was deleted when it was sent. Instead of inspecting the msg byte + * buffer, lets just decode it. */ + uint8_t *encoded_msg = + dll_delete_first_node(mock_info->sent_message_list); + CU_ASSERT_PTR_NOT_NULL(encoded_msg); + struct pcep_message *open_msg = pcep_decode_message(encoded_msg); + CU_ASSERT_PTR_NOT_NULL(open_msg); + /* Should be an Open, with no TLVs: length = 12 */ + CU_ASSERT_EQUAL(open_msg->msg_header->type, PCEP_TYPE_OPEN); + CU_ASSERT_EQUAL(open_msg->encoded_message_length, 12); + destroy_pcep_session(session); + pcep_msg_free_message(open_msg); + pceplib_free(PCEPLIB_MESSAGES, encoded_msg); + + stop_session_logic(); +} + + +void test_create_pcep_session_open_tlvs() +{ + pcep_session *session; + struct in_addr pce_ip; + struct pcep_message *open_msg; + struct pcep_object_header *open_obj; + pcep_configuration config; + memset(&config, 0, sizeof(pcep_configuration)); + config.pcep_msg_versioning = create_default_pcep_versioning(); + inet_pton(AF_INET, "127.0.0.1", &(pce_ip)); + + run_session_logic(); + + /* Verify the created Open message only has 1 TLV: + * pcep_tlv_create_stateful_pce_capability() */ + mock_socket_comm_info *mock_info = get_mock_socket_comm_info(); + mock_info->send_message_save_message = true; + config.support_stateful_pce_lsp_update = true; + config.pcep_msg_versioning->draft_ietf_pce_segment_routing_07 = false; + config.support_sr_te_pst = false; + + session = create_pcep_session(&config, &pce_ip); + CU_ASSERT_PTR_NOT_NULL(session); + /* Get and verify the Open Message */ + uint8_t *encoded_msg = + dll_delete_first_node(mock_info->sent_message_list); + CU_ASSERT_PTR_NOT_NULL(encoded_msg); + open_msg = pcep_decode_message(encoded_msg); + CU_ASSERT_PTR_NOT_NULL(open_msg); + /* Get and verify the Open Message objects */ + CU_ASSERT_PTR_NOT_NULL(open_msg->obj_list); + CU_ASSERT_TRUE(open_msg->obj_list->num_entries > 0); + /* Get and verify the Open object */ + open_obj = pcep_obj_get(open_msg->obj_list, PCEP_OBJ_CLASS_OPEN); + CU_ASSERT_PTR_NOT_NULL(open_obj); + /* Get and verify the Open object TLVs */ + CU_ASSERT_PTR_NOT_NULL(open_obj->tlv_list); + CU_ASSERT_EQUAL(open_obj->tlv_list->num_entries, 1); + CU_ASSERT_EQUAL(((struct pcep_object_tlv_header *) + open_obj->tlv_list->head->data) + ->type, + PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY); + + destroy_pcep_session(session); + pcep_msg_free_message(open_msg); + pceplib_free(PCEPLIB_MESSAGES, encoded_msg); + + /* Verify the created Open message only has 2 TLVs: + * pcep_tlv_create_stateful_pce_capability() + * pcep_tlv_create_lsp_db_version() */ + reset_mock_socket_comm_info(); + mock_info->send_message_save_message = true; + config.support_include_db_version = true; + config.lsp_db_version = 100; + + session = create_pcep_session(&config, &pce_ip); + CU_ASSERT_PTR_NOT_NULL(session); + /* Get and verify the Open Message */ + encoded_msg = dll_delete_first_node(mock_info->sent_message_list); + CU_ASSERT_PTR_NOT_NULL(encoded_msg); + open_msg = pcep_decode_message(encoded_msg); + CU_ASSERT_PTR_NOT_NULL(open_msg); + /* Get and verify the Open Message objects */ + CU_ASSERT_PTR_NOT_NULL(open_msg->obj_list); + CU_ASSERT_TRUE(open_msg->obj_list->num_entries > 0); + /* Get and verify the Open object */ + open_obj = pcep_obj_get(open_msg->obj_list, PCEP_OBJ_CLASS_OPEN); + CU_ASSERT_PTR_NOT_NULL(open_obj); + /* Get and verify the Open object TLVs */ + CU_ASSERT_PTR_NOT_NULL(open_obj->tlv_list); + CU_ASSERT_EQUAL(open_obj->tlv_list->num_entries, 2); + CU_ASSERT_EQUAL(((struct pcep_object_tlv_header *) + open_obj->tlv_list->head->data) + ->type, + PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY); + CU_ASSERT_EQUAL(((struct pcep_object_tlv_header *) + open_obj->tlv_list->head->next_node->data) + ->type, + PCEP_OBJ_TLV_TYPE_LSP_DB_VERSION); + + destroy_pcep_session(session); + pcep_msg_free_message(open_msg); + pceplib_free(PCEPLIB_MESSAGES, encoded_msg); + + + /* Verify the created Open message only has 4 TLVs: + * pcep_tlv_create_stateful_pce_capability() + * pcep_tlv_create_lsp_db_version() + * pcep_tlv_create_sr_pce_capability() + * pcep_tlv_create_path_setup_type_capability() */ + reset_mock_socket_comm_info(); + mock_info->send_message_save_message = true; + config.support_sr_te_pst = true; + + session = create_pcep_session(&config, &pce_ip); + CU_ASSERT_PTR_NOT_NULL(session); + /* Get and verify the Open Message */ + encoded_msg = dll_delete_first_node(mock_info->sent_message_list); + CU_ASSERT_PTR_NOT_NULL(encoded_msg); + open_msg = pcep_decode_message(encoded_msg); + CU_ASSERT_PTR_NOT_NULL(open_msg); + /* Get and verify the Open Message objects */ + CU_ASSERT_PTR_NOT_NULL(open_msg->obj_list); + CU_ASSERT_TRUE(open_msg->obj_list->num_entries > 0); + /* Get and verify the Open object */ + open_obj = pcep_obj_get(open_msg->obj_list, PCEP_OBJ_CLASS_OPEN); + CU_ASSERT_PTR_NOT_NULL(open_obj); + /* Get and verify the Open object TLVs */ + CU_ASSERT_PTR_NOT_NULL(open_obj->tlv_list); + CU_ASSERT_EQUAL(open_obj->tlv_list->num_entries, 3); + double_linked_list_node *tlv_node = open_obj->tlv_list->head; + CU_ASSERT_EQUAL(((struct pcep_object_tlv_header *)tlv_node->data)->type, + PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY); + tlv_node = tlv_node->next_node; + CU_ASSERT_EQUAL(((struct pcep_object_tlv_header *)tlv_node->data)->type, + PCEP_OBJ_TLV_TYPE_LSP_DB_VERSION); + tlv_node = tlv_node->next_node; + CU_ASSERT_EQUAL(((struct pcep_object_tlv_header *)tlv_node->data)->type, + PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE_CAPABILITY); + + destroy_pcep_session(session); + pcep_msg_free_message(open_msg); + pceplib_free(PCEPLIB_MESSAGES, encoded_msg); + + /* Verify the created Open message only has 4 TLVs: + * pcep_tlv_create_stateful_pce_capability() + * pcep_tlv_create_lsp_db_version() + * pcep_tlv_create_sr_pce_capability() + * pcep_tlv_create_path_setup_type_capability() */ + reset_mock_socket_comm_info(); + mock_info->send_message_save_message = true; + config.pcep_msg_versioning->draft_ietf_pce_segment_routing_07 = true; + + session = create_pcep_session(&config, &pce_ip); + CU_ASSERT_PTR_NOT_NULL(session); + /* Get and verify the Open Message */ + encoded_msg = dll_delete_first_node(mock_info->sent_message_list); + CU_ASSERT_PTR_NOT_NULL(encoded_msg); + open_msg = pcep_decode_message(encoded_msg); + CU_ASSERT_PTR_NOT_NULL(open_msg); + /* Get and verify the Open Message objects */ + CU_ASSERT_PTR_NOT_NULL(open_msg->obj_list); + CU_ASSERT_TRUE(open_msg->obj_list->num_entries > 0); + /* Get and verify the Open object */ + open_obj = pcep_obj_get(open_msg->obj_list, PCEP_OBJ_CLASS_OPEN); + CU_ASSERT_PTR_NOT_NULL(open_obj); + /* Get and verify the Open object TLVs */ + CU_ASSERT_PTR_NOT_NULL(open_obj->tlv_list); + CU_ASSERT_EQUAL(open_obj->tlv_list->num_entries, 4); + tlv_node = open_obj->tlv_list->head; + CU_ASSERT_EQUAL(((struct pcep_object_tlv_header *)tlv_node->data)->type, + PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY); + tlv_node = tlv_node->next_node; + CU_ASSERT_EQUAL(((struct pcep_object_tlv_header *)tlv_node->data)->type, + PCEP_OBJ_TLV_TYPE_LSP_DB_VERSION); + tlv_node = tlv_node->next_node; + CU_ASSERT_EQUAL(((struct pcep_object_tlv_header *)tlv_node->data)->type, + PCEP_OBJ_TLV_TYPE_SR_PCE_CAPABILITY); + tlv_node = tlv_node->next_node; + CU_ASSERT_EQUAL(((struct pcep_object_tlv_header *)tlv_node->data)->type, + PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE_CAPABILITY); + + destroy_pcep_versioning(config.pcep_msg_versioning); + destroy_pcep_session(session); + pcep_msg_free_message(open_msg); + pceplib_free(PCEPLIB_MESSAGES, encoded_msg); + + stop_session_logic(); +} + + +void test_destroy_pcep_session_null_session() +{ + /* Just testing that it does not core dump */ + destroy_pcep_session(NULL); +} diff --git a/pceplib/test/pcep_session_logic_test.h b/pceplib/test/pcep_session_logic_test.h new file mode 100644 index 0000000000..6cc1963250 --- /dev/null +++ b/pceplib/test/pcep_session_logic_test.h @@ -0,0 +1,43 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Javier Garcia <javier.garcia@voltanet.io> + * + */ + +/* + * Timer definitions to be used internally by the pcep_timers library. + */ + +#ifndef PCEP_SESSION_LOGIC_TEST_H_ +#define PCEP_SESSION_LOGIC_TEST_H_ + +int pcep_session_logic_test_suite_setup(void); +int pcep_session_logic_test_suite_teardown(void); +void pcep_session_logic_test_setup(void); +void pcep_session_logic_test_teardown(void); +void test_run_stop_session_logic(void); +void test_run_session_logic_twice(void); +void test_session_logic_without_run(void); +void test_create_pcep_session_null_params(void); +void test_create_destroy_pcep_session(void); +void test_create_destroy_pcep_session_ipv6(void); +void test_create_pcep_session_open_tlvs(void); +void test_destroy_pcep_session_null_session(void); + +#endif /* PCEPTIMERINTERNALS_H_ */ diff --git a/pceplib/test/pcep_session_logic_tests.c b/pceplib/test/pcep_session_logic_tests.c new file mode 100644 index 0000000000..67bf6e22ef --- /dev/null +++ b/pceplib/test/pcep_session_logic_tests.c @@ -0,0 +1,201 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Brady Johnson <brady@voltanet.io> + * + */ + + +#include <CUnit/Basic.h> +#include <CUnit/CUnit.h> +#include <CUnit/TestDB.h> + +#include "pcep_session_logic_loop_test.h" +#include "pcep_session_logic_states_test.h" +#include "pcep_session_logic_test.h" + + +int main(int argc, char **argv) +{ + /* Unused parameters cause compilation warnings */ + (void)argc; + (void)argv; + + CU_initialize_registry(); + + /* + * Tests defined in pcep_socket_comm_test.c + */ + CU_pSuite test_session_logic_suite = + CU_add_suite_with_setup_and_teardown( + "PCEP Session Logic Test Suite", + pcep_session_logic_test_suite_setup, // suite setup and + // cleanup function + // pointers + pcep_session_logic_test_suite_teardown, + pcep_session_logic_test_setup, // test case setup + // function pointer + pcep_session_logic_test_teardown); // test case teardown + // function pointer + + CU_add_test(test_session_logic_suite, "test_run_stop_session_logic", + test_run_stop_session_logic); + CU_add_test(test_session_logic_suite, "test_run_session_logic_twice", + test_run_session_logic_twice); + CU_add_test(test_session_logic_suite, "test_session_logic_without_run", + test_session_logic_without_run); + CU_add_test(test_session_logic_suite, + "test_create_pcep_session_null_params", + test_create_pcep_session_null_params); + CU_add_test(test_session_logic_suite, + "test_create_destroy_pcep_session", + test_create_destroy_pcep_session); + CU_add_test(test_session_logic_suite, + "test_create_destroy_pcep_session_ipv6", + test_create_destroy_pcep_session_ipv6); + CU_add_test(test_session_logic_suite, + "test_create_pcep_session_open_tlvs", + test_create_pcep_session_open_tlvs); + CU_add_test(test_session_logic_suite, + "test_destroy_pcep_session_null_session", + test_destroy_pcep_session_null_session); + + CU_pSuite test_session_logic_loop_suite = + CU_add_suite_with_setup_and_teardown( + "PCEP Session Logic Loop Test Suite", + pcep_session_logic_loop_test_suite_setup, // suite setup + // and cleanup + // function + // pointers + pcep_session_logic_loop_test_suite_teardown, + pcep_session_logic_loop_test_setup, // test case setup + // function pointer + pcep_session_logic_loop_test_teardown); // test case + // teardown + // function + // pointer + + CU_add_test(test_session_logic_loop_suite, + "test_session_logic_loop_null_data", + test_session_logic_loop_null_data); + CU_add_test(test_session_logic_loop_suite, + "test_session_logic_loop_inactive", + test_session_logic_loop_inactive); + CU_add_test(test_session_logic_loop_suite, + "test_session_logic_msg_ready_handler", + test_session_logic_msg_ready_handler); + CU_add_test(test_session_logic_loop_suite, + "test_session_logic_conn_except_notifier", + test_session_logic_conn_except_notifier); + CU_add_test(test_session_logic_loop_suite, + "test_session_logic_timer_expire_handler", + test_session_logic_timer_expire_handler); + + CU_pSuite test_session_logic_states_suite = + CU_add_suite_with_setup_and_teardown( + "PCEP Session Logic States Test Suite", + pcep_session_logic_states_test_suite_setup, // suite + // setup and + // cleanup + // function + // pointers + pcep_session_logic_states_test_suite_teardown, + pcep_session_logic_states_test_setup, // test case setup + // function + // pointer + pcep_session_logic_states_test_teardown); // test case + // teardown + // function + // pointer + + CU_add_test(test_session_logic_states_suite, + "test_handle_timer_event_dead_timer", + test_handle_timer_event_dead_timer); + CU_add_test(test_session_logic_states_suite, + "test_handle_timer_event_keep_alive", + test_handle_timer_event_keep_alive); + CU_add_test(test_session_logic_states_suite, + "test_handle_timer_event_open_keep_wait", + test_handle_timer_event_open_keep_wait); + CU_add_test(test_session_logic_states_suite, + "test_handle_socket_comm_event_null_params", + test_handle_socket_comm_event_null_params); + CU_add_test(test_session_logic_states_suite, + "test_handle_socket_comm_event_close", + test_handle_socket_comm_event_close); + CU_add_test(test_session_logic_states_suite, + "test_handle_socket_comm_event_open", + test_handle_socket_comm_event_open); + CU_add_test(test_session_logic_states_suite, + "test_handle_socket_comm_event_open_error", + test_handle_socket_comm_event_open_error); + CU_add_test(test_session_logic_states_suite, + "test_handle_socket_comm_event_keep_alive", + test_handle_socket_comm_event_keep_alive); + CU_add_test(test_session_logic_states_suite, + "test_handle_socket_comm_event_pcrep", + test_handle_socket_comm_event_pcrep); + CU_add_test(test_session_logic_states_suite, + "test_handle_socket_comm_event_pcreq", + test_handle_socket_comm_event_pcreq); + CU_add_test(test_session_logic_states_suite, + "test_handle_socket_comm_event_report", + test_handle_socket_comm_event_report); + CU_add_test(test_session_logic_states_suite, + "test_handle_socket_comm_event_update", + test_handle_socket_comm_event_update); + CU_add_test(test_session_logic_states_suite, + "test_handle_socket_comm_event_initiate", + test_handle_socket_comm_event_initiate); + CU_add_test(test_session_logic_states_suite, + "test_handle_socket_comm_event_notify", + test_handle_socket_comm_event_notify); + CU_add_test(test_session_logic_states_suite, + "test_handle_socket_comm_event_error", + test_handle_socket_comm_event_error); + CU_add_test(test_session_logic_states_suite, + "test_handle_socket_comm_event_unknown_msg", + test_handle_socket_comm_event_unknown_msg); + CU_add_test(test_session_logic_states_suite, "test_connection_failure", + test_connection_failure); + + /* + * Run the tests and cleanup. + */ + CU_basic_set_mode(CU_BRM_VERBOSE); + CU_basic_run_tests(); + CU_FailureRecord *failure_record = CU_get_failure_list(); + if (failure_record != NULL) { + printf("\nFailed tests:\n\t [Suite] [Test] [File:line-number]\n"); + do { + printf("\t [%s] [%s] [%s:%d]\n", + failure_record->pSuite->pName, + failure_record->pTest->pName, + failure_record->strFileName, + failure_record->uiLineNumber); + failure_record = failure_record->pNext; + + } while (failure_record != NULL); + } + + CU_pRunSummary run_summary = CU_get_run_summary(); + int result = run_summary->nTestsFailed; + CU_cleanup_registry(); + + return result; +} diff --git a/pceplib/test/pcep_session_logic_tests_valgrind.sh b/pceplib/test/pcep_session_logic_tests_valgrind.sh new file mode 100755 index 0000000000..435bb3d5c4 --- /dev/null +++ b/pceplib/test/pcep_session_logic_tests_valgrind.sh @@ -0,0 +1,2 @@ +source pceplib/test/pcep_tests_valgrind.sh +valgrind_test pceplib/test/pcep_session_logic_tests diff --git a/pceplib/test/pcep_socket_comm_loop_test.c b/pceplib/test/pcep_socket_comm_loop_test.c new file mode 100644 index 0000000000..94f0983ca7 --- /dev/null +++ b/pceplib/test/pcep_socket_comm_loop_test.c @@ -0,0 +1,194 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Brady Johnson <brady@voltanet.io> + * + */ + + +#include <pthread.h> +#include <stdlib.h> + +#include <CUnit/CUnit.h> + +#include "pcep_socket_comm_internals.h" +#include "pcep_socket_comm_loop.h" +#include "pcep_socket_comm_loop_test.h" +#include "pcep_socket_comm.h" +#include "pcep_utils_memory.h" + +void test_loop_conn_except_notifier(void *session_data, int socket_fd); + +/* + * Functions to be tested, implemented in pcep_socket_comm_loop.c + */ + +typedef struct ready_to_read_handler_info_ { + bool handler_called; + bool except_handler_called; + void *data; + int socket_fd; + int bytes_read; + +} ready_to_read_handler_info; + +static ready_to_read_handler_info read_handler_info; +static pcep_socket_comm_session *test_comm_session; +static pcep_socket_comm_handle *test_socket_comm_handle = NULL; + +static int test_loop_message_ready_to_read_handler(void *session_data, + int socket_fd) +{ + read_handler_info.handler_called = true; + read_handler_info.data = session_data; + read_handler_info.socket_fd = socket_fd; + + return read_handler_info.bytes_read; +} + + +void test_loop_conn_except_notifier(void *session_data, int socket_fd) +{ + (void)session_data; + (void)socket_fd; + read_handler_info.except_handler_called = true; +} + + +/* + * Test case setup and teardown called before AND after each test. + */ +void pcep_socket_comm_loop_test_setup() +{ + test_socket_comm_handle = + pceplib_malloc(PCEPLIB_INFRA, sizeof(pcep_socket_comm_handle)); + memset(test_socket_comm_handle, 0, sizeof(pcep_socket_comm_handle)); + test_socket_comm_handle->active = false; + test_socket_comm_handle->read_list = + ordered_list_initialize(socket_fd_node_compare); + test_socket_comm_handle->write_list = + ordered_list_initialize(socket_fd_node_compare); + test_socket_comm_handle->session_list = + ordered_list_initialize(pointer_compare_function); + pthread_mutex_init(&test_socket_comm_handle->socket_comm_mutex, NULL); + test_socket_comm_handle->num_active_sessions = 0; + + test_comm_session = + pceplib_malloc(PCEPLIB_INFRA, sizeof(pcep_socket_comm_session)); + memset(test_comm_session, 0, sizeof(pcep_socket_comm_session)); + test_comm_session->message_ready_to_read_handler = + test_loop_message_ready_to_read_handler; + ordered_list_add_node(test_socket_comm_handle->session_list, + test_comm_session); + + read_handler_info.handler_called = false; + read_handler_info.except_handler_called = false; + read_handler_info.data = NULL; + read_handler_info.socket_fd = -1; + read_handler_info.bytes_read = 0; +} + + +void pcep_socket_comm_loop_test_teardown() +{ + pthread_mutex_destroy(&test_socket_comm_handle->socket_comm_mutex); + ordered_list_destroy(test_socket_comm_handle->read_list); + ordered_list_destroy(test_socket_comm_handle->write_list); + ordered_list_destroy(test_socket_comm_handle->session_list); + pceplib_free(PCEPLIB_INFRA, test_socket_comm_handle); + test_socket_comm_handle = NULL; + + if (test_comm_session != NULL) { + pceplib_free(PCEPLIB_INFRA, test_comm_session); + test_comm_session = NULL; + } +} + + +/* + * Test cases + */ + +void test_socket_comm_loop_null_handle() +{ + /* Verify that socket_comm_loop() correctly handles a NULL + * timers_context */ + socket_comm_loop(NULL); +} + + +void test_socket_comm_loop_not_active() +{ + /* Verify that event_loop() correctly handles an inactive flag */ + pcep_socket_comm_handle handle; + handle.active = false; + socket_comm_loop(&handle); +} + + +void test_handle_reads_no_read() +{ + CU_ASSERT_PTR_NULL(test_socket_comm_handle->read_list->head); + + handle_reads(test_socket_comm_handle); + + CU_ASSERT_FALSE(read_handler_info.handler_called); + CU_ASSERT_FALSE(read_handler_info.except_handler_called); + CU_ASSERT_PTR_NULL(test_socket_comm_handle->read_list->head); +} + + +void test_handle_reads_read_message() +{ + /* Setup the comm session so that it can read. + * It should read 100 bytes, which simulates a successful read */ + test_comm_session->socket_fd = 10; + read_handler_info.bytes_read = 100; + FD_SET(test_comm_session->socket_fd, + &test_socket_comm_handle->read_master_set); + ordered_list_add_node(test_socket_comm_handle->read_list, + test_comm_session); + + handle_reads(test_socket_comm_handle); + + CU_ASSERT_TRUE(read_handler_info.handler_called); + CU_ASSERT_FALSE(read_handler_info.except_handler_called); + CU_ASSERT_EQUAL(test_comm_session->received_bytes, + read_handler_info.bytes_read); +} + + +void test_handle_reads_read_message_close() +{ + /* Setup the comm session so that it can read. + * It should read 0 bytes, which simulates that the socket closed */ + test_comm_session->socket_fd = 11; + read_handler_info.bytes_read = 0; + FD_SET(test_comm_session->socket_fd, + &test_socket_comm_handle->read_master_set); + ordered_list_add_node(test_socket_comm_handle->read_list, + test_comm_session); + + handle_reads(test_socket_comm_handle); + + CU_ASSERT_TRUE(read_handler_info.handler_called); + CU_ASSERT_FALSE(read_handler_info.except_handler_called); + CU_ASSERT_EQUAL(test_comm_session->received_bytes, + read_handler_info.bytes_read); + CU_ASSERT_PTR_NULL(test_socket_comm_handle->read_list->head); +} diff --git a/pceplib/test/pcep_socket_comm_loop_test.h b/pceplib/test/pcep_socket_comm_loop_test.h new file mode 100644 index 0000000000..d2e3f21ee1 --- /dev/null +++ b/pceplib/test/pcep_socket_comm_loop_test.h @@ -0,0 +1,38 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Javier Garcia <javier.garcia@voltanet.io> + * + */ + +/* + * Timer definitions to be used internally by the pcep_timers library. + */ + +#ifndef PCEP_SOCKET_COMM_LOOP_TEST_H_ +#define PCEP_SOCKET_COMM_LOOP_TEST_H_ + +void pcep_socket_comm_loop_test_setup(void); +void pcep_socket_comm_loop_test_teardown(void); +void test_socket_comm_loop_null_handle(void); +void test_socket_comm_loop_not_active(void); +void test_handle_reads_no_read(void); +void test_handle_reads_read_message(void); +void test_handle_reads_read_message_close(void); + +#endif /* PCEPTIMERINTERNALS_H_ */ diff --git a/pceplib/test/pcep_socket_comm_test.c b/pceplib/test/pcep_socket_comm_test.c new file mode 100644 index 0000000000..35afbcbb13 --- /dev/null +++ b/pceplib/test/pcep_socket_comm_test.c @@ -0,0 +1,308 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Brady Johnson <brady@voltanet.io> + * + */ + + +#include <netinet/in.h> + +#include <CUnit/CUnit.h> + +#include "pcep_socket_comm.h" +#include "pcep_socket_comm_internals.h" +#include "pcep_socket_comm_test.h" + +extern pcep_socket_comm_handle *socket_comm_handle_; + +static pcep_socket_comm_session *test_session = NULL; +static struct in_addr test_host_ip; +static struct in_addr test_src_ip; +static struct in6_addr test_host_ipv6; +static struct in6_addr test_src_ipv6; +static short test_port = 4789; +static short test_src_port = 4999; +static uint32_t connect_timeout_millis = 500; + +/* + * Unit Test Basic pcep_socket_comm API usage. + * Testing sending messages, etc via sockets should be done + * with integration tests, not unit tests. + */ + +/* + * Different socket_comm handler test implementations + */ +static void test_message_received_handler(void *session_data, + const char *message_data, + unsigned int message_length) +{ + (void)session_data; + (void)message_data; + (void)message_length; +} + +static int test_message_ready_to_read_handler(void *session_data, int socket_fd) +{ + (void)session_data; + (void)socket_fd; + return 1; +} + +static void test_message_sent_handler(void *session_data, int socket_fd) +{ + (void)session_data; + (void)socket_fd; + return; +} + +static void test_connection_except_notifier(void *session_data, int socket_fd) +{ + (void)session_data; + (void)socket_fd; +} + + +/* + * Test case setup and teardown called before AND after each test. + */ +void pcep_socket_comm_test_setup() +{ + inet_pton(AF_INET, "127.0.0.1", &(test_host_ip)); + inet_pton(AF_INET, "127.0.0.1", &(test_src_ip)); + inet_pton(AF_INET6, "::1", &(test_host_ipv6)); + inet_pton(AF_INET6, "::1", &(test_src_ipv6)); +} + +void pcep_socket_comm_test_teardown() +{ + socket_comm_session_teardown(test_session); + test_session = NULL; +} + + +/* + * Test cases + */ + +void test_pcep_socket_comm_initialize() +{ + test_session = socket_comm_session_initialize( + test_message_received_handler, NULL, NULL, + test_connection_except_notifier, &test_host_ip, test_port, + connect_timeout_millis, NULL, false, NULL); + CU_ASSERT_PTR_NOT_NULL(test_session); + CU_ASSERT_FALSE(test_session->is_ipv6); +} + + +void test_pcep_socket_comm_initialize_ipv6() +{ + test_session = socket_comm_session_initialize_ipv6( + test_message_received_handler, NULL, NULL, + test_connection_except_notifier, &test_host_ipv6, test_port, + connect_timeout_millis, NULL, false, NULL); + CU_ASSERT_PTR_NOT_NULL(test_session); + CU_ASSERT_TRUE(test_session->is_ipv6); +} + + +void test_pcep_socket_comm_initialize_with_src() +{ + /* Test that INADDR_ANY will be used when src_ip is NULL */ + test_session = socket_comm_session_initialize_with_src( + test_message_received_handler, NULL, NULL, + test_connection_except_notifier, NULL, 0, &test_host_ip, + test_port, connect_timeout_millis, NULL, false, NULL); + CU_ASSERT_PTR_NOT_NULL(test_session); + CU_ASSERT_EQUAL( + test_session->src_sock_addr.src_sock_addr_ipv4.sin_addr.s_addr, + INADDR_ANY); + CU_ASSERT_FALSE(test_session->is_ipv6); + + socket_comm_session_teardown(test_session); + test_session = socket_comm_session_initialize_with_src( + test_message_received_handler, NULL, NULL, + test_connection_except_notifier, &test_src_ip, test_src_port, + &test_host_ip, test_port, connect_timeout_millis, NULL, false, + NULL); + CU_ASSERT_PTR_NOT_NULL(test_session); + CU_ASSERT_EQUAL( + test_session->src_sock_addr.src_sock_addr_ipv4.sin_addr.s_addr, + test_src_ip.s_addr); + CU_ASSERT_EQUAL(test_session->src_sock_addr.src_sock_addr_ipv4.sin_port, + ntohs(test_src_port)); + CU_ASSERT_FALSE(test_session->is_ipv6); +} + + +void test_pcep_socket_comm_initialize_with_src_ipv6() +{ + /* Test that INADDR6_ANY will be used when src_ip is NULL */ + test_session = socket_comm_session_initialize_with_src_ipv6( + test_message_received_handler, NULL, NULL, + test_connection_except_notifier, NULL, 0, &test_host_ipv6, + test_port, connect_timeout_millis, NULL, false, NULL); + CU_ASSERT_PTR_NOT_NULL(test_session); + CU_ASSERT_EQUAL(memcmp(&test_session->src_sock_addr.src_sock_addr_ipv6 + .sin6_addr, + &in6addr_any, sizeof(struct in6_addr)), + 0); + CU_ASSERT_TRUE(test_session->is_ipv6); + + socket_comm_session_teardown(test_session); + test_session = socket_comm_session_initialize_with_src_ipv6( + test_message_received_handler, NULL, NULL, + test_connection_except_notifier, &test_src_ipv6, test_src_port, + &test_host_ipv6, test_port, connect_timeout_millis, NULL, false, + NULL); + CU_ASSERT_PTR_NOT_NULL(test_session); + CU_ASSERT_EQUAL(memcmp(&test_session->src_sock_addr.src_sock_addr_ipv6 + .sin6_addr, + &test_src_ipv6, sizeof(struct in6_addr)), + 0); + CU_ASSERT_EQUAL( + test_session->src_sock_addr.src_sock_addr_ipv6.sin6_port, + ntohs(test_src_port)); + CU_ASSERT_TRUE(test_session->is_ipv6); +} + + +void test_pcep_socket_comm_initialize_tcpmd5() +{ + char tcp_md5_str[] = "hello"; + int tcp_md5_strlen = strlen(tcp_md5_str); + + test_session = socket_comm_session_initialize( + test_message_received_handler, NULL, NULL, + test_connection_except_notifier, &test_host_ip, test_port, 1, + tcp_md5_str, true, NULL); + CU_ASSERT_PTR_NOT_NULL(test_session); + CU_ASSERT_EQUAL(0, strncmp(tcp_md5_str, + test_session->tcp_authentication_str, + tcp_md5_strlen)); + CU_ASSERT_TRUE(test_session->is_tcp_auth_md5); + CU_ASSERT_FALSE(socket_comm_session_connect_tcp(test_session)); + /* This call does not work, it returns errno=92, Protocol not available + getsockopt(test_session->socket_fd, SOL_SOCKET, TCP_MD5SIG, &sig, + &siglen);*/ + + socket_comm_session_teardown(test_session); + test_session = socket_comm_session_initialize( + test_message_received_handler, NULL, NULL, + test_connection_except_notifier, &test_host_ip, test_port, 1, + tcp_md5_str, false, NULL); + CU_ASSERT_PTR_NOT_NULL(test_session); + CU_ASSERT_EQUAL(0, strncmp(tcp_md5_str, + test_session->tcp_authentication_str, + tcp_md5_strlen)); + CU_ASSERT_FALSE(test_session->is_tcp_auth_md5); + CU_ASSERT_FALSE(socket_comm_session_connect_tcp(test_session)); +} + + +void test_pcep_socket_comm_initialize_ipv6_tcpmd5() +{ + char tcp_md5_str[] = "hello"; + int tcp_md5_strlen = strlen(tcp_md5_str); + + test_session = socket_comm_session_initialize_ipv6( + test_message_received_handler, NULL, NULL, + test_connection_except_notifier, &test_host_ipv6, test_port, 1, + tcp_md5_str, true, NULL); + CU_ASSERT_PTR_NOT_NULL(test_session); + CU_ASSERT_EQUAL(0, strncmp(tcp_md5_str, + test_session->tcp_authentication_str, + tcp_md5_strlen)); + CU_ASSERT_TRUE(test_session->is_tcp_auth_md5); + CU_ASSERT_FALSE(socket_comm_session_connect_tcp(test_session)); + /* This call does not work, it returns errno=92, Protocol not available + getsockopt(test_session->socket_fd, SOL_SOCKET, TCP_MD5SIG, &sig, + &siglen);*/ + + socket_comm_session_teardown(test_session); + test_session = socket_comm_session_initialize_ipv6( + test_message_received_handler, NULL, NULL, + test_connection_except_notifier, &test_host_ipv6, test_port, 1, + tcp_md5_str, false, NULL); + CU_ASSERT_PTR_NOT_NULL(test_session); + CU_ASSERT_EQUAL(0, strncmp(tcp_md5_str, + test_session->tcp_authentication_str, + tcp_md5_strlen)); + CU_ASSERT_FALSE(test_session->is_tcp_auth_md5); + CU_ASSERT_FALSE(socket_comm_session_connect_tcp(test_session)); +} + + +void test_pcep_socket_comm_initialize_handlers() +{ + /* Verify incorrect handler usage is correctly handled */ + + /* Both receive handlers cannot be NULL */ + test_session = socket_comm_session_initialize( + NULL, NULL, NULL, test_connection_except_notifier, + &test_host_ip, test_port, connect_timeout_millis, NULL, false, + NULL); + CU_ASSERT_PTR_NULL(test_session); + + /* Both receive handlers cannot be set */ + test_session = socket_comm_session_initialize( + test_message_received_handler, + test_message_ready_to_read_handler, test_message_sent_handler, + test_connection_except_notifier, &test_host_ip, test_port, + connect_timeout_millis, NULL, false, NULL); + CU_ASSERT_PTR_NULL(test_session); + + /* Only one receive handler can be set */ + test_session = socket_comm_session_initialize( + NULL, test_message_ready_to_read_handler, + test_message_sent_handler, test_connection_except_notifier, + &test_host_ip, test_port, connect_timeout_millis, NULL, false, + NULL); + CU_ASSERT_PTR_NOT_NULL(test_session); +} + + +void test_pcep_socket_comm_session_not_initialized() +{ + CU_ASSERT_FALSE(socket_comm_session_connect_tcp(NULL)); + CU_ASSERT_FALSE(socket_comm_session_close_tcp(NULL)); + CU_ASSERT_FALSE(socket_comm_session_close_tcp_after_write(NULL)); + socket_comm_session_send_message(NULL, NULL, 0, true); + CU_ASSERT_FALSE(socket_comm_session_teardown(NULL)); +} + + +void test_pcep_socket_comm_session_destroy() +{ + test_session = socket_comm_session_initialize( + test_message_received_handler, NULL, test_message_sent_handler, + test_connection_except_notifier, &test_host_ip, test_port, + connect_timeout_millis, NULL, false, NULL); + CU_ASSERT_PTR_NOT_NULL(test_session); + CU_ASSERT_PTR_NOT_NULL(socket_comm_handle_); + CU_ASSERT_EQUAL(socket_comm_handle_->num_active_sessions, 1); + + CU_ASSERT_TRUE(socket_comm_session_teardown(test_session)); + test_session = NULL; + CU_ASSERT_PTR_NOT_NULL(socket_comm_handle_); + + CU_ASSERT_TRUE(destroy_socket_comm_loop()); + CU_ASSERT_PTR_NULL(socket_comm_handle_); +} diff --git a/pceplib/test/pcep_socket_comm_test.h b/pceplib/test/pcep_socket_comm_test.h new file mode 100644 index 0000000000..f857af087a --- /dev/null +++ b/pceplib/test/pcep_socket_comm_test.h @@ -0,0 +1,42 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Javier Garcia <javier.garcia@voltanet.io> + * + */ + +/* + * Timer definitions to be used internally by the pcep_timers library. + */ + +#ifndef PCEP_SOCKET_COMM_TEST_H_ +#define PCEP_SOCKET_COMM_TEST_H_ + +void pcep_socket_comm_test_teardown(void); +void pcep_socket_comm_test_setup(void); +void test_pcep_socket_comm_initialize(void); +void test_pcep_socket_comm_initialize_ipv6(void); +void test_pcep_socket_comm_initialize_with_src(void); +void test_pcep_socket_comm_initialize_with_src_ipv6(void); +void test_pcep_socket_comm_initialize_tcpmd5(void); +void test_pcep_socket_comm_initialize_ipv6_tcpmd5(void); +void test_pcep_socket_comm_initialize_handlers(void); +void test_pcep_socket_comm_session_not_initialized(void); +void test_pcep_socket_comm_session_destroy(void); + +#endif diff --git a/pceplib/test/pcep_socket_comm_tests.c b/pceplib/test/pcep_socket_comm_tests.c new file mode 100644 index 0000000000..293678f1a7 --- /dev/null +++ b/pceplib/test/pcep_socket_comm_tests.c @@ -0,0 +1,128 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Brady Johnson <brady@voltanet.io> + * + */ + + +#include <CUnit/Basic.h> +#include <CUnit/CUnit.h> +#include <CUnit/TestDB.h> + +#include "pcep_socket_comm_loop_test.h" +#include "pcep_socket_comm_test.h" + + +int main(int argc, char **argv) +{ + /* Unused parameters cause compilation warnings */ + (void)argc; + (void)argv; + + CU_initialize_registry(); + + /* + * Tests defined in pcep_socket_comm_test.c + */ + CU_pSuite test_socket_comm_suite = CU_add_suite_with_setup_and_teardown( + "PCEP Socket Comm Test Suite", NULL, + NULL, // suite setup and cleanup function pointers + pcep_socket_comm_test_setup, // test case setup function pointer + pcep_socket_comm_test_teardown); // test case teardown function + // pointer + + CU_add_test(test_socket_comm_suite, "test_pcep_socket_comm_initialize", + test_pcep_socket_comm_initialize); + CU_add_test(test_socket_comm_suite, + "test_pcep_socket_comm_initialize_ipv6", + test_pcep_socket_comm_initialize_ipv6); + CU_add_test(test_socket_comm_suite, + "test_pcep_socket_comm_initialize_with_src", + test_pcep_socket_comm_initialize_with_src); + CU_add_test(test_socket_comm_suite, + "test_pcep_socket_comm_initialize_with_src_ipv6", + test_pcep_socket_comm_initialize_with_src_ipv6); + CU_add_test(test_socket_comm_suite, + "test_pcep_socket_comm_initialize_tcpmd5", + test_pcep_socket_comm_initialize_tcpmd5); + CU_add_test(test_socket_comm_suite, + "test_pcep_socket_comm_initialize_ipv6_tcpmd5", + test_pcep_socket_comm_initialize_ipv6_tcpmd5); + CU_add_test(test_socket_comm_suite, + "test_pcep_socket_comm_initialize_handlers", + test_pcep_socket_comm_initialize_handlers); + CU_add_test(test_socket_comm_suite, + "test_pcep_socket_comm_session_not_initialized", + test_pcep_socket_comm_session_not_initialized); + CU_add_test(test_socket_comm_suite, + "test_pcep_socket_comm_session_destroy", + test_pcep_socket_comm_session_destroy); + + /* + * Tests defined in pcep_socket_comm_loop_test.c + */ + CU_pSuite test_socket_comm_loop_suite = + CU_add_suite_with_setup_and_teardown( + "PCEP Socket Comm Loop Test Suite", NULL, NULL, + pcep_socket_comm_loop_test_setup, // suite setup + // function pointer + pcep_socket_comm_loop_test_teardown); // suite cleanup + // function + // pointer + + CU_add_test(test_socket_comm_loop_suite, + "test_socket_comm_loop_null_handle", + test_socket_comm_loop_null_handle); + CU_add_test(test_socket_comm_loop_suite, + "test_socket_comm_loop_not_active", + test_socket_comm_loop_not_active); + CU_add_test(test_socket_comm_loop_suite, "test_handle_reads_no_read", + test_handle_reads_no_read); + CU_add_test(test_socket_comm_loop_suite, + "test_handle_reads_read_message", + test_handle_reads_read_message); + CU_add_test(test_socket_comm_loop_suite, + "test_handle_reads_read_message_close", + test_handle_reads_read_message_close); + + /* + * Run the tests and cleanup. + */ + CU_basic_set_mode(CU_BRM_VERBOSE); + CU_basic_run_tests(); + CU_FailureRecord *failure_record = CU_get_failure_list(); + if (failure_record != NULL) { + printf("\nFailed tests:\n\t [Suite] [Test] [File:line-number]\n"); + do { + printf("\t [%s] [%s] [%s:%d]\n", + failure_record->pSuite->pName, + failure_record->pTest->pName, + failure_record->strFileName, + failure_record->uiLineNumber); + failure_record = failure_record->pNext; + + } while (failure_record != NULL); + } + + CU_pRunSummary run_summary = CU_get_run_summary(); + int result = run_summary->nTestsFailed; + CU_cleanup_registry(); + + return result; +} diff --git a/pceplib/test/pcep_socket_comm_tests_valgrind.sh b/pceplib/test/pcep_socket_comm_tests_valgrind.sh new file mode 100755 index 0000000000..d9e95e4c1c --- /dev/null +++ b/pceplib/test/pcep_socket_comm_tests_valgrind.sh @@ -0,0 +1,2 @@ +source pceplib/test/pcep_tests_valgrind.sh +valgrind_test pceplib/test/pcep_socket_comm_tests diff --git a/pceplib/test/pcep_tests_valgrind.sh b/pceplib/test/pcep_tests_valgrind.sh new file mode 100755 index 0000000000..ca4772cb67 --- /dev/null +++ b/pceplib/test/pcep_tests_valgrind.sh @@ -0,0 +1,15 @@ +# +# Common function definition for PCEPlib valgrind tests +# + +function valgrind_test() +{ + local test_suite=$1 + [[ -z ${test_suite} ]] && { echo "${FUNCNAME}(): test_suite not specified."; exit 1; } + [[ ! -x "${test_suite}" ]] && { echo "${test_suite} is not an executable file."; exit 1; } + + G_SLICE=always-malloc + G_DEBUG=gc-friendly + VALGRIND="valgrind -v --tool=memcheck --leak-check=full --num-callers=40 --error-exitcode=1" + ${VALGRIND} --log-file=${test_suite}.val.log ./${test_suite} || ({ echo "Valgrind memory check error"; exit 1; }) +} diff --git a/pceplib/test/pcep_timers_event_loop_test.c b/pceplib/test/pcep_timers_event_loop_test.c new file mode 100644 index 0000000000..ae63601df2 --- /dev/null +++ b/pceplib/test/pcep_timers_event_loop_test.c @@ -0,0 +1,162 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Brady Johnson <brady@voltanet.io> + * + */ + + +#include <stdlib.h> + +#include <CUnit/CUnit.h> + +#include "pcep_timers.h" +#include "pcep_utils_memory.h" +#include "pcep_timers_event_loop.h" +#include "pcep_timers_event_loop_test.h" + + +typedef struct timer_expire_handler_info_ { + bool handler_called; + void *data; + int timerId; + +} timer_expire_handler_info; + +static pcep_timers_context *test_timers_context = NULL; +static timer_expire_handler_info expire_handler_info; +#define TEST_EVENT_LOOP_TIMER_ID 500 + + +/* Called when a timer expires */ +static void test_timer_expire_handler(void *data, int timerId) +{ + expire_handler_info.handler_called = true; + expire_handler_info.data = data; + expire_handler_info.timerId = timerId; +} + + +/* Test case setup called before each test. + * Declared in pcep_timers_tests.c */ +void pcep_timers_event_loop_test_setup() +{ + test_timers_context = + pceplib_malloc(PCEPLIB_INFRA, sizeof(pcep_timers_context)); + memset(test_timers_context, 0, sizeof(pcep_timers_context)); + if (pthread_mutex_init(&(test_timers_context->timer_list_lock), NULL) + != 0) { + fprintf(stderr, + "ERROR initializing timers, cannot initialize the mutex\n"); + } + test_timers_context->active = false; + test_timers_context->expire_handler = test_timer_expire_handler; + test_timers_context->timer_list = + ordered_list_initialize(timer_list_node_timer_id_compare); + + expire_handler_info.handler_called = false; + expire_handler_info.data = NULL; + expire_handler_info.timerId = -1; +} + + +/* Test case teardown called after each test. + * Declared in pcep_timers_tests.c */ +void pcep_timers_event_loop_test_teardown() +{ + pthread_mutex_unlock(&test_timers_context->timer_list_lock); + pthread_mutex_destroy(&(test_timers_context->timer_list_lock)); + ordered_list_destroy(test_timers_context->timer_list); + pceplib_free(PCEPLIB_INFRA, test_timers_context); + test_timers_context = NULL; +} + + +/* + * Test functions + */ + +void test_walk_and_process_timers_no_timers() +{ + CU_ASSERT_EQUAL(test_timers_context->timer_list->num_entries, 0); + CU_ASSERT_PTR_NULL(test_timers_context->timer_list->head); + + walk_and_process_timers(test_timers_context); + + CU_ASSERT_FALSE(expire_handler_info.handler_called); + CU_ASSERT_EQUAL(test_timers_context->timer_list->num_entries, 0); + CU_ASSERT_PTR_NULL(test_timers_context->timer_list->head); +} + + +void test_walk_and_process_timers_timer_not_expired() +{ + pcep_timer timer; + timer.data = &timer; + // Set the timer to expire 100 seconds from now + timer.expire_time = time(NULL) + 100; + timer.timer_id = TEST_EVENT_LOOP_TIMER_ID; + ordered_list_add_node(test_timers_context->timer_list, &timer); + + walk_and_process_timers(test_timers_context); + + /* The timer should still be in the list, since it hasnt expired yet */ + CU_ASSERT_FALSE(expire_handler_info.handler_called); + CU_ASSERT_EQUAL(test_timers_context->timer_list->num_entries, 1); + CU_ASSERT_PTR_NOT_NULL(test_timers_context->timer_list->head); +} + + +void test_walk_and_process_timers_timer_expired() +{ + /* We need to alloc it, since it will be free'd in + * walk_and_process_timers */ + pcep_timer *timer = pceplib_malloc(PCEPLIB_INFRA, sizeof(pcep_timer)); + 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); + + /* Since the timer expired, the expire_handler should have been called + * and the timer should have been removed from the timer list */ + CU_ASSERT_TRUE(expire_handler_info.handler_called); + CU_ASSERT_PTR_EQUAL(expire_handler_info.data, timer); + CU_ASSERT_EQUAL(expire_handler_info.timerId, TEST_EVENT_LOOP_TIMER_ID); + CU_ASSERT_EQUAL(test_timers_context->timer_list->num_entries, 0); + CU_ASSERT_PTR_NULL(test_timers_context->timer_list->head); +} + +void test_event_loop_null_handle() +{ + /* Verify that event_loop() correctly handles a NULL timers_context */ + event_loop(NULL); +} + + +void test_event_loop_not_active() +{ + /* Verify that event_loop() correctly handles an inactive timers_context + * flag */ + test_timers_context->active = false; + event_loop(test_timers_context); +} diff --git a/pceplib/test/pcep_timers_event_loop_test.h b/pceplib/test/pcep_timers_event_loop_test.h new file mode 100644 index 0000000000..19fd264858 --- /dev/null +++ b/pceplib/test/pcep_timers_event_loop_test.h @@ -0,0 +1,38 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Javier Garcia <javier.garcia@voltanet.io> + * + */ + +/* + * Timer definitions to be used internally by the pcep_timers library. + */ + +#ifndef PCEP_TIMERS_EVENT_LOOP_TEST_H_ +#define PCEP_TIMERS_EVENT_LOOP_TEST_H_ + +void pcep_timers_event_loop_test_setup(void); +void pcep_timers_event_loop_test_teardown(void); +void test_walk_and_process_timers_no_timers(void); +void test_walk_and_process_timers_timer_not_expired(void); +void test_walk_and_process_timers_timer_expired(void); +void test_event_loop_null_handle(void); +void test_event_loop_not_active(void); + +#endif /* PCEPTIMERINTERNALS_H_ */ diff --git a/pceplib/test/pcep_timers_test.c b/pceplib/test/pcep_timers_test.c new file mode 100644 index 0000000000..9d9e0f6c1b --- /dev/null +++ b/pceplib/test/pcep_timers_test.c @@ -0,0 +1,109 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Brady Johnson <brady@voltanet.io> + * + */ + + +#include <stdbool.h> +#include <CUnit/CUnit.h> + +#include "pcep_timers.h" +#include "pcep_timers_test.h" + +/* Test case teardown called after each test. + * Declared in pcep_timers_tests.c */ +void pcep_timers_test_teardown() +{ + teardown_timers(); +} + +static void test_timer_expire_handler(void *data, int timerId) +{ + (void)data; + (void)timerId; +} + + +void test_double_initialization(void) +{ + CU_ASSERT_EQUAL(initialize_timers(test_timer_expire_handler), true); + CU_ASSERT_EQUAL(initialize_timers(test_timer_expire_handler), false); +} + + +void test_initialization_null_callback(void) +{ + CU_ASSERT_EQUAL(initialize_timers(NULL), false); +} + + +void test_not_initialized(void) +{ + /* All of these should fail if initialize_timers() hasnt been called */ + CU_ASSERT_EQUAL(create_timer(5, NULL), -1); + CU_ASSERT_EQUAL(cancel_timer(7), false); + CU_ASSERT_EQUAL(reset_timer(7), false); + CU_ASSERT_EQUAL(teardown_timers(), false); +} + + +void test_create_timer(void) +{ + CU_ASSERT_EQUAL(initialize_timers(test_timer_expire_handler), true); + + int timer_id = create_timer(0, NULL); + CU_ASSERT_TRUE(timer_id > -1); +} + + +void test_cancel_timer(void) +{ + CU_ASSERT_EQUAL(initialize_timers(test_timer_expire_handler), true); + + int timer_id = create_timer(10, NULL); + CU_ASSERT_TRUE(timer_id > -1); + + CU_ASSERT_EQUAL(cancel_timer(timer_id), true); +} + + +void test_cancel_timer_invalid(void) +{ + CU_ASSERT_EQUAL(initialize_timers(test_timer_expire_handler), true); + CU_ASSERT_EQUAL(cancel_timer(1), false); +} + + +void test_reset_timer(void) +{ + CU_ASSERT_EQUAL(initialize_timers(test_timer_expire_handler), true); + + int timer_id = create_timer(10, NULL); + CU_ASSERT_TRUE(timer_id > -1); + + CU_ASSERT_EQUAL(reset_timer(timer_id), true); +} + + +void test_reset_timer_invalid(void) +{ + CU_ASSERT_EQUAL(initialize_timers(test_timer_expire_handler), true); + CU_ASSERT_EQUAL(reset_timer(1), false); +} diff --git a/pceplib/test/pcep_timers_test.h b/pceplib/test/pcep_timers_test.h new file mode 100644 index 0000000000..6ac9a90e49 --- /dev/null +++ b/pceplib/test/pcep_timers_test.h @@ -0,0 +1,40 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Javier Garcia <javier.garcia@voltanet.io> + * + */ + +/* + * Timer definitions to be used internally by the pcep_timers library. + */ + +#ifndef PCEP_TIMERS_TEST_H_ +#define PCEP_TIMERS_TEST_H_ + +void pcep_timers_test_teardown(void); +void test_double_initialization(void); +void test_initialization_null_callback(void); +void test_not_initialized(void); +void test_create_timer(void); +void test_cancel_timer(void); +void test_cancel_timer_invalid(void); +void test_reset_timer(void); +void test_reset_timer_invalid(void); + +#endif /* PCEPTIMERINTERNALS_H_ */ diff --git a/pceplib/test/pcep_timers_tests.c b/pceplib/test/pcep_timers_tests.c new file mode 100644 index 0000000000..adfea17e29 --- /dev/null +++ b/pceplib/test/pcep_timers_tests.c @@ -0,0 +1,113 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Brady Johnson <brady@voltanet.io> + * + */ + + +#include <CUnit/Basic.h> +#include <CUnit/CUnit.h> +#include <CUnit/TestDB.h> + +#include "pcep_timers_test.h" +#include "pcep_timers_event_loop_test.h" + + +int main(int argc, char **argv) +{ + /* Unused parameters cause compilation warnings */ + (void)argc; + (void)argv; + + CU_initialize_registry(); + + /* + * Tests defined in pcep_timers_test.c + */ + CU_pSuite test_timers_suite = CU_add_suite_with_setup_and_teardown( + "PCEP Timers Test Suite", NULL, + NULL, // suite setup and cleanup function pointers + NULL, pcep_timers_test_teardown); // test case setup and + // teardown function pointers + CU_add_test(test_timers_suite, "test_double_initialization", + test_double_initialization); + CU_add_test(test_timers_suite, "test_initialization_null_callback", + test_initialization_null_callback); + CU_add_test(test_timers_suite, "test_not_initialized", + test_not_initialized); + CU_add_test(test_timers_suite, "test_create_timer", test_create_timer); + CU_add_test(test_timers_suite, "test_cancel_timer", test_cancel_timer); + CU_add_test(test_timers_suite, "test_cancel_timer_invalid", + test_cancel_timer_invalid); + CU_add_test(test_timers_suite, "test_reset_timer", test_reset_timer); + CU_add_test(test_timers_suite, "test_reset_timer_invalid", + test_reset_timer_invalid); + + /* + * Tests defined in pcep_timers_event_loop_test.c + */ + CU_pSuite test_timers_event_loop_suite = + CU_add_suite_with_setup_and_teardown( + "PCEP Timers Event Loop Test Suite", NULL, + NULL, // suite setup and cleanup function pointers + pcep_timers_event_loop_test_setup, // test case setup + // function pointer + pcep_timers_event_loop_test_teardown); // test case + // teardown + // function + // pointer + CU_add_test(test_timers_event_loop_suite, + "test_walk_and_process_timers_no_timers", + test_walk_and_process_timers_no_timers); + CU_add_test(test_timers_event_loop_suite, + "test_walk_and_process_timers_timer_not_expired", + test_walk_and_process_timers_timer_not_expired); + CU_add_test(test_timers_event_loop_suite, + "test_walk_and_process_timers_timer_expired", + test_walk_and_process_timers_timer_expired); + CU_add_test(test_timers_event_loop_suite, "test_event_loop_null_handle", + test_event_loop_null_handle); + CU_add_test(test_timers_event_loop_suite, "test_event_loop_not_active", + test_event_loop_not_active); + + /* + * Run the tests and cleanup. + */ + CU_basic_set_mode(CU_BRM_VERBOSE); + CU_basic_run_tests(); + CU_FailureRecord *failure_record = CU_get_failure_list(); + if (failure_record != NULL) { + printf("\nFailed tests:\n\t [Suite] [Test] [File:line-number]\n"); + do { + printf("\t [%s] [%s] [%s:%d]\n", + failure_record->pSuite->pName, + failure_record->pTest->pName, + failure_record->strFileName, + failure_record->uiLineNumber); + failure_record = failure_record->pNext; + + } while (failure_record != NULL); + } + + CU_pRunSummary run_summary = CU_get_run_summary(); + int result = run_summary->nTestsFailed; + CU_cleanup_registry(); + + return result; +} diff --git a/pceplib/test/pcep_timers_tests_valgrind.sh b/pceplib/test/pcep_timers_tests_valgrind.sh new file mode 100755 index 0000000000..f9bff3b2a6 --- /dev/null +++ b/pceplib/test/pcep_timers_tests_valgrind.sh @@ -0,0 +1,2 @@ +source pceplib/test/pcep_tests_valgrind.sh +valgrind_test pceplib/test/pcep_timers_tests diff --git a/pceplib/test/pcep_utils_counters_test.c b/pceplib/test/pcep_utils_counters_test.c new file mode 100644 index 0000000000..6f53e4d400 --- /dev/null +++ b/pceplib/test/pcep_utils_counters_test.c @@ -0,0 +1,254 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Brady Johnson <brady@voltanet.io> + * + */ + + +#include <stdlib.h> + +#include <CUnit/CUnit.h> + +#include "pcep_utils_counters.h" +#include "pcep_utils_counters_test.h" + + +void test_create_counters_group() +{ + const char group_name[] = "group"; + uint16_t num_subgroups = 10; + + struct counters_group *group = + create_counters_group(NULL, num_subgroups); + CU_ASSERT_PTR_NULL(group); + + group = create_counters_group(group_name, MAX_COUNTER_GROUPS + 1); + CU_ASSERT_PTR_NULL(group); + + group = create_counters_group(group_name, num_subgroups); + CU_ASSERT_PTR_NOT_NULL(group); + + CU_ASSERT_EQUAL(group->num_subgroups, 0); + CU_ASSERT_EQUAL(group->max_subgroups, num_subgroups); + CU_ASSERT_EQUAL(strcmp(group->counters_group_name, group_name), 0); + + delete_counters_group(group); +} + +void test_create_counters_subgroup() +{ + const char subgroup_name[] = "subgroup"; + uint16_t subgroup_id = 10; + uint16_t num_counters = 20; + + struct counters_subgroup *subgroup = + create_counters_subgroup(NULL, subgroup_id, num_counters); + CU_ASSERT_PTR_NULL(subgroup); + + subgroup = create_counters_subgroup( + subgroup_name, MAX_COUNTER_GROUPS + 1, num_counters); + CU_ASSERT_PTR_NULL(subgroup); + + subgroup = create_counters_subgroup(subgroup_name, subgroup_id, + MAX_COUNTERS + 1); + CU_ASSERT_PTR_NULL(subgroup); + + subgroup = create_counters_subgroup(subgroup_name, subgroup_id, + num_counters); + CU_ASSERT_PTR_NOT_NULL(subgroup); + + CU_ASSERT_EQUAL(subgroup->subgroup_id, subgroup_id); + CU_ASSERT_EQUAL(subgroup->num_counters, 0); + CU_ASSERT_EQUAL(subgroup->max_counters, num_counters); + CU_ASSERT_EQUAL(strcmp(subgroup->counters_subgroup_name, subgroup_name), + 0); + + delete_counters_subgroup(subgroup); +} + +void test_add_counters_subgroup() +{ + struct counters_group *group = create_counters_group("group", 1); + struct counters_subgroup *subgroup1 = + create_counters_subgroup("subgroup", 0, 5); + struct counters_subgroup *subgroup2 = + create_counters_subgroup("subgroup", 1, 5); + + CU_ASSERT_FALSE(add_counters_subgroup(NULL, NULL)); + CU_ASSERT_FALSE(add_counters_subgroup(NULL, subgroup1)); + CU_ASSERT_FALSE(add_counters_subgroup(group, NULL)); + + CU_ASSERT_EQUAL(group->num_subgroups, 0); + CU_ASSERT_TRUE(add_counters_subgroup(group, subgroup1)); + CU_ASSERT_EQUAL(group->num_subgroups, 1); + /* Cant add more than num_subgroups to the group */ + CU_ASSERT_FALSE(add_counters_subgroup(group, subgroup2)); + + CU_ASSERT_PTR_NOT_NULL(find_subgroup(group, 0)); + CU_ASSERT_PTR_NULL(find_subgroup(group, 1)); + + delete_counters_group(group); + delete_counters_subgroup(subgroup2); +} + +void test_create_subgroup_counter() +{ + uint16_t counter_id = 1; + char counter_name[] = "my counter"; + struct counters_subgroup *subgroup = + create_counters_subgroup("subgroup", 1, 2); + + CU_ASSERT_FALSE( + create_subgroup_counter(NULL, counter_id, counter_name)); + CU_ASSERT_FALSE(create_subgroup_counter(subgroup, counter_id + 1, + counter_name)); + CU_ASSERT_FALSE(create_subgroup_counter(subgroup, counter_id, NULL)); + CU_ASSERT_EQUAL(subgroup->num_counters, 0); + CU_ASSERT_TRUE( + create_subgroup_counter(subgroup, counter_id, counter_name)); + CU_ASSERT_EQUAL(subgroup->num_counters, 1); + + delete_counters_subgroup(subgroup); +} + +void test_delete_counters_group() +{ + struct counters_group *group = create_counters_group("group", 1); + + CU_ASSERT_FALSE(delete_counters_group(NULL)); + CU_ASSERT_TRUE(delete_counters_group(group)); +} + +void test_delete_counters_subgroup() +{ + struct counters_subgroup *subgroup = + create_counters_subgroup("subgroup", 1, 1); + + CU_ASSERT_FALSE(delete_counters_subgroup(NULL)); + CU_ASSERT_TRUE(delete_counters_subgroup(subgroup)); +} + +void test_reset_group_counters() +{ + uint16_t subgroup_id = 1; + uint16_t counter_id = 1; + struct counters_group *group = create_counters_group("group", 10); + struct counters_subgroup *subgroup = + create_counters_subgroup("subgroup", subgroup_id, 10); + create_subgroup_counter(subgroup, counter_id, "counter"); + add_counters_subgroup(group, subgroup); + + struct counter *counter = subgroup->counters[counter_id]; + counter->counter_value = 100; + + CU_ASSERT_FALSE(reset_group_counters(NULL)); + CU_ASSERT_TRUE(reset_group_counters(group)); + CU_ASSERT_EQUAL(counter->counter_value, 0); + + delete_counters_group(group); +} + +void test_reset_subgroup_counters() +{ + uint16_t counter_id = 1; + struct counters_subgroup *subgroup = + create_counters_subgroup("subgroup", 1, 10); + create_subgroup_counter(subgroup, counter_id, "counter"); + + struct counter *counter = subgroup->counters[counter_id]; + counter->counter_value = 100; + + CU_ASSERT_FALSE(reset_subgroup_counters(NULL)); + CU_ASSERT_TRUE(reset_subgroup_counters(subgroup)); + CU_ASSERT_EQUAL(counter->counter_value, 0); + + delete_counters_subgroup(subgroup); +} + +void test_increment_counter() +{ + uint16_t subgroup_id = 1; + uint16_t counter_id = 1; + struct counters_group *group = create_counters_group("group", 10); + struct counters_subgroup *subgroup = + create_counters_subgroup("subgroup", subgroup_id, 10); + create_subgroup_counter(subgroup, counter_id, "counter"); + add_counters_subgroup(group, subgroup); + + struct counter *counter = subgroup->counters[counter_id]; + counter->counter_value = 100; + + CU_ASSERT_FALSE(increment_counter(NULL, subgroup_id, counter_id)); + CU_ASSERT_FALSE(increment_counter(group, 100, counter_id)); + CU_ASSERT_FALSE(increment_counter(group, subgroup_id, 123)); + CU_ASSERT_TRUE(increment_counter(group, subgroup_id, counter_id)); + CU_ASSERT_EQUAL(counter->counter_value, 101); + CU_ASSERT_EQUAL(subgroup_counters_total(subgroup), 101); + + delete_counters_group(group); +} + +void test_increment_subgroup_counter() +{ + int counter_id = 1; + uint32_t counter_value = 100; + struct counters_subgroup *subgroup = + create_counters_subgroup("subgroup", 1, 10); + create_subgroup_counter(subgroup, counter_id, "counter"); + + struct counter *counter = subgroup->counters[counter_id]; + counter->counter_value = counter_value; + + CU_ASSERT_FALSE(increment_subgroup_counter(NULL, counter_id)); + CU_ASSERT_FALSE(increment_subgroup_counter(subgroup, counter_id + 1)); + CU_ASSERT_TRUE(increment_subgroup_counter(subgroup, counter_id)); + CU_ASSERT_EQUAL(counter->counter_value, counter_value + 1); + + delete_counters_subgroup(subgroup); +} + +void test_dump_counters_group_to_log() +{ + uint16_t subgroup_id = 1; + uint16_t counter_id = 1; + struct counters_group *group = create_counters_group("group", 10); + struct counters_subgroup *subgroup = + create_counters_subgroup("subgroup", subgroup_id, 10); + create_subgroup_counter(subgroup, counter_id, "counter"); + add_counters_subgroup(group, subgroup); + + CU_ASSERT_FALSE(dump_counters_group_to_log(NULL)); + CU_ASSERT_TRUE(dump_counters_group_to_log(group)); + + delete_counters_group(group); +} + +void test_dump_counters_subgroup_to_log() +{ + uint16_t subgroup_id = 1; + uint16_t counter_id = 1; + struct counters_subgroup *subgroup = + create_counters_subgroup("subgroup", subgroup_id, 10); + create_subgroup_counter(subgroup, counter_id, "counter"); + + CU_ASSERT_FALSE(dump_counters_subgroup_to_log(NULL)); + CU_ASSERT_TRUE(dump_counters_subgroup_to_log(subgroup)); + + delete_counters_subgroup(subgroup); +} diff --git a/pceplib/test/pcep_utils_counters_test.h b/pceplib/test/pcep_utils_counters_test.h new file mode 100644 index 0000000000..07236dcb53 --- /dev/null +++ b/pceplib/test/pcep_utils_counters_test.h @@ -0,0 +1,43 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Javier Garcia <javier.garcia@voltanet.io> + * + */ + +/* + * Timer definitions to be used internally by the pcep_timers library. + */ + +#ifndef PCEP_UTILS_COUNTERS_TEST_H_ +#define PCEP_UTILS_COUNTERS_TEST_H_ + +void test_create_counters_group(void); +void test_create_counters_subgroup(void); +void test_add_counters_subgroup(void); +void test_create_subgroup_counter(void); +void test_delete_counters_group(void); +void test_delete_counters_subgroup(void); +void test_reset_group_counters(void); +void test_reset_subgroup_counters(void); +void test_increment_counter(void); +void test_increment_subgroup_counter(void); +void test_dump_counters_group_to_log(void); +void test_dump_counters_subgroup_to_log(void); + +#endif diff --git a/pceplib/test/pcep_utils_double_linked_list_test.c b/pceplib/test/pcep_utils_double_linked_list_test.c new file mode 100644 index 0000000000..d2600e66c4 --- /dev/null +++ b/pceplib/test/pcep_utils_double_linked_list_test.c @@ -0,0 +1,297 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Brady Johnson <brady@voltanet.io> + * + */ + + +#include <CUnit/CUnit.h> + +#include "pcep_utils_double_linked_list.h" +#include "pcep_utils_double_linked_list_test.h" + +typedef struct dll_node_data_ { + int int_data; + +} dll_node_data; + +void test_empty_dl_list() +{ + double_linked_list *handle = dll_initialize(); + + CU_ASSERT_PTR_NULL(dll_delete_first_node(handle)); + CU_ASSERT_PTR_NULL(dll_delete_last_node(handle)); + CU_ASSERT_PTR_NULL(dll_delete_node(handle, NULL)); + + dll_destroy(handle); +} + +void test_null_dl_list_handle() +{ + dll_destroy(NULL); + CU_ASSERT_PTR_NULL(dll_prepend(NULL, NULL)); + CU_ASSERT_PTR_NULL(dll_append(NULL, NULL)); + CU_ASSERT_PTR_NULL(dll_delete_first_node(NULL)); + CU_ASSERT_PTR_NULL(dll_delete_last_node(NULL)); + CU_ASSERT_PTR_NULL(dll_delete_node(NULL, NULL)); +} + +void test_dll_prepend_data() +{ + dll_node_data data1, data2, data3; + data1.int_data = 1; + data2.int_data = 2; + data3.int_data = 3; + + double_linked_list *handle = dll_initialize(); + + CU_ASSERT_PTR_NOT_NULL(dll_prepend(handle, &data3)); + CU_ASSERT_PTR_NOT_NULL(dll_prepend(handle, &data2)); + CU_ASSERT_PTR_NOT_NULL(dll_prepend(handle, &data1)); + + CU_ASSERT_EQUAL(handle->num_entries, 3); + + double_linked_list_node *node = handle->head; + CU_ASSERT_PTR_EQUAL(node->data, &data1); + CU_ASSERT_PTR_NULL(node->prev_node); + CU_ASSERT_PTR_NOT_NULL(node->next_node); + + node = node->next_node; + CU_ASSERT_PTR_EQUAL(node->data, &data2); + CU_ASSERT_PTR_NOT_NULL(node->prev_node); + CU_ASSERT_PTR_NOT_NULL(node->next_node); + + node = node->next_node; + CU_ASSERT_PTR_EQUAL(node->data, &data3); + CU_ASSERT_PTR_NOT_NULL(node->prev_node); + CU_ASSERT_PTR_NULL(node->next_node); + CU_ASSERT_PTR_EQUAL(handle->tail, node); + + dll_destroy(handle); +} + + +void test_dll_append_data() +{ + dll_node_data data1, data2, data3; + data1.int_data = 1; + data2.int_data = 2; + data3.int_data = 3; + + double_linked_list *handle = dll_initialize(); + + CU_ASSERT_PTR_NOT_NULL(dll_append(handle, &data1)); + CU_ASSERT_PTR_NOT_NULL(dll_append(handle, &data2)); + CU_ASSERT_PTR_NOT_NULL(dll_append(handle, &data3)); + + CU_ASSERT_EQUAL(handle->num_entries, 3); + + double_linked_list_node *node = handle->head; + CU_ASSERT_PTR_EQUAL(node->data, &data1); + CU_ASSERT_PTR_NULL(node->prev_node); + CU_ASSERT_PTR_NOT_NULL(node->next_node); + + node = node->next_node; + CU_ASSERT_PTR_EQUAL(node->data, &data2); + CU_ASSERT_PTR_NOT_NULL(node->prev_node); + CU_ASSERT_PTR_NOT_NULL(node->next_node); + + node = node->next_node; + CU_ASSERT_PTR_EQUAL(node->data, &data3); + CU_ASSERT_PTR_NOT_NULL(node->prev_node); + CU_ASSERT_PTR_NULL(node->next_node); + CU_ASSERT_PTR_EQUAL(handle->tail, node); + + dll_destroy(handle); +} + + +void test_dll_delete_first_node() +{ + dll_node_data data1, data2; + data1.int_data = 1; + data2.int_data = 2; + + double_linked_list *handle = dll_initialize(); + + /* Test deleting with just 1 node in the list */ + CU_ASSERT_PTR_NOT_NULL(dll_append(handle, &data1)); + CU_ASSERT_EQUAL(handle->num_entries, 1); + + void *deleted_data = dll_delete_first_node(handle); + CU_ASSERT_PTR_NOT_NULL(deleted_data); + CU_ASSERT_PTR_EQUAL(&data1, deleted_data); + + CU_ASSERT_EQUAL(handle->num_entries, 0); + CU_ASSERT_PTR_NULL(handle->head); + CU_ASSERT_PTR_NULL(handle->tail); + + /* Test deleting with 2 nodes in the list */ + CU_ASSERT_PTR_NOT_NULL(dll_append(handle, &data1)); + CU_ASSERT_PTR_NOT_NULL(dll_append(handle, &data2)); + CU_ASSERT_EQUAL(handle->num_entries, 2); + + deleted_data = dll_delete_first_node(handle); + CU_ASSERT_PTR_NOT_NULL(deleted_data); + CU_ASSERT_PTR_EQUAL(&data1, deleted_data); + + CU_ASSERT_EQUAL(handle->num_entries, 1); + CU_ASSERT_PTR_EQUAL(handle->head->data, &data2); + CU_ASSERT_PTR_EQUAL(handle->head, handle->tail); + CU_ASSERT_PTR_NULL(handle->head->prev_node); + CU_ASSERT_PTR_NULL(handle->head->next_node); + + dll_destroy(handle); +} + + +void test_dll_delete_last_node() +{ + dll_node_data data1, data2; + data1.int_data = 1; + data2.int_data = 2; + + double_linked_list *handle = dll_initialize(); + + /* Test deleting with just 1 node in the list */ + CU_ASSERT_PTR_NOT_NULL(dll_append(handle, &data1)); + CU_ASSERT_EQUAL(handle->num_entries, 1); + + void *deleted_data = dll_delete_last_node(handle); + CU_ASSERT_PTR_NOT_NULL(deleted_data); + CU_ASSERT_PTR_EQUAL(&data1, deleted_data); + + CU_ASSERT_EQUAL(handle->num_entries, 0); + CU_ASSERT_PTR_NULL(handle->head); + CU_ASSERT_PTR_NULL(handle->tail); + + /* Test deleting with 2 nodes in the list */ + CU_ASSERT_PTR_NOT_NULL(dll_append(handle, &data1)); + CU_ASSERT_PTR_NOT_NULL(dll_append(handle, &data2)); + CU_ASSERT_EQUAL(handle->num_entries, 2); + + deleted_data = dll_delete_last_node(handle); + CU_ASSERT_PTR_NOT_NULL(deleted_data); + CU_ASSERT_PTR_EQUAL(&data2, deleted_data); + + CU_ASSERT_EQUAL(handle->num_entries, 1); + CU_ASSERT_PTR_EQUAL(handle->head->data, &data1); + CU_ASSERT_PTR_EQUAL(handle->head, handle->tail); + CU_ASSERT_PTR_NULL(handle->head->prev_node); + CU_ASSERT_PTR_NULL(handle->head->next_node); + + dll_destroy(handle); +} + + +void test_dll_delete_node() +{ + dll_node_data data1, data2, data3; + data1.int_data = 1; + data2.int_data = 2; + data3.int_data = 3; + double_linked_list_node *node1, *node2, *node3; + double_linked_list *handle; + + /* Test deleting with just 1 node in the list */ + handle = dll_initialize(); + node1 = dll_append(handle, &data1); + CU_ASSERT_PTR_NOT_NULL(node1); + CU_ASSERT_EQUAL(handle->num_entries, 1); + + void *deleted_data = dll_delete_node(handle, node1); + CU_ASSERT_PTR_NOT_NULL(deleted_data); + CU_ASSERT_PTR_EQUAL(&data1, deleted_data); + + CU_ASSERT_EQUAL(handle->num_entries, 0); + CU_ASSERT_PTR_NULL(handle->head); + CU_ASSERT_PTR_NULL(handle->tail); + + /* + * Test deleting the head with 2 nodes in the list + */ + node1 = dll_append(handle, &data1); + node2 = dll_append(handle, &data2); + CU_ASSERT_PTR_NOT_NULL(node1); + CU_ASSERT_PTR_NOT_NULL(node2); + CU_ASSERT_EQUAL(handle->num_entries, 2); + + /* Delete the head entry */ + deleted_data = dll_delete_node(handle, node1); + CU_ASSERT_PTR_NOT_NULL(deleted_data); + CU_ASSERT_PTR_EQUAL(&data1, deleted_data); + + CU_ASSERT_EQUAL(handle->num_entries, 1); + CU_ASSERT_PTR_EQUAL(handle->head->data, &data2); + CU_ASSERT_PTR_EQUAL(handle->head, handle->tail); + CU_ASSERT_PTR_NULL(handle->head->prev_node); + CU_ASSERT_PTR_NULL(handle->head->next_node); + dll_destroy(handle); + + /* + * Test deleting the tail with 2 nodes in the list + */ + handle = dll_initialize(); + node1 = dll_append(handle, &data1); + node2 = dll_append(handle, &data2); + CU_ASSERT_PTR_NOT_NULL(node1); + CU_ASSERT_PTR_NOT_NULL(node2); + CU_ASSERT_EQUAL(handle->num_entries, 2); + + /* Delete the tail entry */ + deleted_data = dll_delete_node(handle, node2); + CU_ASSERT_PTR_NOT_NULL(deleted_data); + CU_ASSERT_PTR_EQUAL(&data2, deleted_data); + + CU_ASSERT_EQUAL(handle->num_entries, 1); + CU_ASSERT_PTR_EQUAL(handle->head->data, &data1); + CU_ASSERT_PTR_EQUAL(handle->head, handle->tail); + CU_ASSERT_PTR_NULL(handle->head->prev_node); + CU_ASSERT_PTR_NULL(handle->head->next_node); + dll_destroy(handle); + + /* + * Test deleting in the middle with 3 nodes in the list + */ + handle = dll_initialize(); + node1 = dll_append(handle, &data1); + node2 = dll_append(handle, &data2); + node3 = dll_append(handle, &data3); + CU_ASSERT_PTR_NOT_NULL(node1); + CU_ASSERT_PTR_NOT_NULL(node2); + CU_ASSERT_PTR_NOT_NULL(node3); + CU_ASSERT_EQUAL(handle->num_entries, 3); + + /* Delete the middle entry */ + deleted_data = dll_delete_node(handle, node2); + CU_ASSERT_PTR_NOT_NULL(deleted_data); + CU_ASSERT_PTR_EQUAL(&data2, deleted_data); + + CU_ASSERT_EQUAL(handle->num_entries, 2); + CU_ASSERT_PTR_EQUAL(handle->head, node1); + CU_ASSERT_PTR_EQUAL(handle->tail, node3); + CU_ASSERT_PTR_EQUAL(node1->data, &data1); + CU_ASSERT_PTR_EQUAL(node3->data, &data3); + CU_ASSERT_PTR_EQUAL(node1->next_node, node3); + CU_ASSERT_PTR_EQUAL(node3->prev_node, node1); + CU_ASSERT_PTR_NULL(node1->prev_node); + CU_ASSERT_PTR_NULL(node3->next_node); + + dll_destroy(handle); +} diff --git a/pceplib/test/pcep_utils_double_linked_list_test.h b/pceplib/test/pcep_utils_double_linked_list_test.h new file mode 100644 index 0000000000..ddb6467cb6 --- /dev/null +++ b/pceplib/test/pcep_utils_double_linked_list_test.h @@ -0,0 +1,38 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Javier Garcia <javier.garcia@voltanet.io> + * + */ + +/* + * Timer definitions to be used internally by the pcep_timers library. + */ + +#ifndef PCEP_UTILS_DOUBLE_LINKED_LIST_TEST_H_ +#define PCEP_UTILS_DOUBLE_LINKED_LIST_TEST_H_ + +void test_empty_dl_list(void); +void test_null_dl_list_handle(void); +void test_dll_prepend_data(void); +void test_dll_append_data(void); +void test_dll_delete_first_node(void); +void test_dll_delete_last_node(void); +void test_dll_delete_node(void); + +#endif /* PCEPTIMERINTERNALS_H_ */ diff --git a/pceplib/test/pcep_utils_memory_test.c b/pceplib/test/pcep_utils_memory_test.c new file mode 100644 index 0000000000..b0b528f084 --- /dev/null +++ b/pceplib/test/pcep_utils_memory_test.c @@ -0,0 +1,241 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Brady Johnson <brady@voltanet.io> + * + */ + + +#include <stdlib.h> +#include <stdint.h> + +#include <CUnit/CUnit.h> + +#include "pcep_utils_memory.h" +#include "pcep_utils_memory_test.h" + +void *test_pceplib_malloc(void *mem_type, size_t size); +void *test_pceplib_calloc(void *mem_type, size_t size); +void *test_pceplib_realloc(void *mem_type, void *ptr, size_t size); +void *test_pceplib_strdup(void *mem_type, const char *str); +void test_pceplib_free(void *mem_type, void *ptr); +void verify_memory_type(struct pceplib_memory_type *mt, uint32_t num_alloc, + uint32_t alloc_bytes, uint32_t num_free, + uint32_t free_bytes); +void verify_ext_memory_type(void *mt, int num_malloc_calls, + int num_calloc_calls, int num_realloc_calls, + int num_strdup_calls, int num_free_calls); + +struct test_memory_type { + int num_malloc_calls; + int num_calloc_calls; + int num_realloc_calls; + int num_strdup_calls; + int num_free_calls; +}; + +void *test_pceplib_malloc(void *mem_type, size_t size) +{ + ((struct test_memory_type *)mem_type)->num_malloc_calls++; + return malloc(size); +} + +void *test_pceplib_calloc(void *mem_type, size_t size) +{ + ((struct test_memory_type *)mem_type)->num_calloc_calls++; + return calloc(1, size); +} + +void *test_pceplib_realloc(void *mem_type, void *ptr, size_t size) +{ + ((struct test_memory_type *)mem_type)->num_realloc_calls++; + return realloc(ptr, size); +} + +void *test_pceplib_strdup(void *mem_type, const char *str) +{ + ((struct test_memory_type *)mem_type)->num_strdup_calls++; + return strdup(str); +} + +void test_pceplib_free(void *mem_type, void *ptr) +{ + ((struct test_memory_type *)mem_type)->num_free_calls++; + free(ptr); +} + +void verify_memory_type(struct pceplib_memory_type *mt, uint32_t num_alloc, + uint32_t alloc_bytes, uint32_t num_free, + uint32_t free_bytes) +{ + CU_ASSERT_EQUAL(num_alloc, mt->num_allocates); + CU_ASSERT_EQUAL(alloc_bytes, mt->total_bytes_allocated); + CU_ASSERT_EQUAL(num_free, mt->num_frees); + CU_ASSERT_EQUAL(free_bytes, mt->total_bytes_freed); +} + +void verify_ext_memory_type(void *mt, int num_malloc_calls, + int num_calloc_calls, int num_realloc_calls, + int num_strdup_calls, int num_free_calls) +{ + struct test_memory_type *mt_ptr = (struct test_memory_type *)mt; + CU_ASSERT_EQUAL(num_malloc_calls, mt_ptr->num_malloc_calls); + CU_ASSERT_EQUAL(num_calloc_calls, mt_ptr->num_calloc_calls); + CU_ASSERT_EQUAL(num_realloc_calls, mt_ptr->num_realloc_calls); + CU_ASSERT_EQUAL(num_strdup_calls, mt_ptr->num_strdup_calls); + CU_ASSERT_EQUAL(num_free_calls, mt_ptr->num_free_calls); +} + +void test_memory_internal_impl() +{ + int alloc_size = 100; + struct pceplib_memory_type *pceplib_infra_ptr = + (struct pceplib_memory_type *)PCEPLIB_INFRA; + struct pceplib_memory_type *pceplib_messages_ptr = + (struct pceplib_memory_type *)PCEPLIB_MESSAGES; + int alloc_counter = 1; + int free_counter = 1; + + /* reset the memory type counters for easier testing */ + pceplib_infra_ptr->num_allocates = + pceplib_infra_ptr->total_bytes_allocated = + pceplib_infra_ptr->num_frees = + pceplib_infra_ptr->total_bytes_freed = 0; + pceplib_messages_ptr->num_allocates = + pceplib_messages_ptr->total_bytes_allocated = + pceplib_messages_ptr->num_frees = + pceplib_messages_ptr->total_bytes_freed = 0; + + /* Make sure nothing crashes when all these are set NULL, since the + * internal default values should still be used. */ + pceplib_memory_initialize(NULL, NULL, NULL, NULL, NULL, NULL, NULL); + + /* Test malloc() */ + void *ptr = pceplib_malloc(PCEPLIB_INFRA, alloc_size); + CU_ASSERT_PTR_NOT_NULL(ptr); + pceplib_free(PCEPLIB_INFRA, ptr); + verify_memory_type(pceplib_infra_ptr, alloc_counter, alloc_size, + free_counter++, 0); + + /* Test calloc() */ + ptr = pceplib_calloc(PCEPLIB_INFRA, alloc_size); + CU_ASSERT_PTR_NOT_NULL(ptr); + pceplib_free(PCEPLIB_INFRA, ptr); + alloc_counter++; + verify_memory_type(pceplib_infra_ptr, alloc_counter, + alloc_size * alloc_counter, free_counter++, 0); + + /* Test realloc() */ + ptr = pceplib_malloc(PCEPLIB_INFRA, alloc_size); + CU_ASSERT_PTR_NOT_NULL(ptr); + ptr = pceplib_realloc(PCEPLIB_INFRA, ptr, alloc_size); + CU_ASSERT_PTR_NOT_NULL(ptr); + pceplib_free(PCEPLIB_INFRA, ptr); + alloc_counter += 2; + verify_memory_type(pceplib_infra_ptr, alloc_counter, + alloc_size * alloc_counter, free_counter++, 0); + + /* Test strdup() */ + ptr = pceplib_malloc(PCEPLIB_INFRA, alloc_size); + /* Make strdup duplicate (alloc_size - 1) bytes */ + memset(ptr, 'a', alloc_size); + ((char *)ptr)[alloc_size - 1] = '\0'; + char *str = pceplib_strdup(PCEPLIB_INFRA, (char *)ptr); + CU_ASSERT_PTR_NOT_NULL(ptr); + pceplib_free(PCEPLIB_INFRA, ptr); + pceplib_free(PCEPLIB_INFRA, str); + alloc_counter += 2; + free_counter++; + verify_memory_type(pceplib_infra_ptr, alloc_counter, + (alloc_size * alloc_counter) - 1, free_counter, 0); + + /* Make sure only the pceplib_infra_ptr memory counters are incremented + */ + verify_memory_type(pceplib_messages_ptr, 0, 0, 0, 0); +} + +void test_memory_external_impl() +{ + int alloc_size = 100; + struct pceplib_memory_type *pceplib_infra_ptr = + (struct pceplib_memory_type *)PCEPLIB_INFRA; + struct pceplib_memory_type *pceplib_messages_ptr = + (struct pceplib_memory_type *)PCEPLIB_MESSAGES; + + /* reset the internal memory type counters to later verify they are NOT + * incremented since an external impl was provided */ + pceplib_infra_ptr->num_allocates = + pceplib_infra_ptr->total_bytes_allocated = + pceplib_infra_ptr->num_frees = + pceplib_infra_ptr->total_bytes_freed = 0; + pceplib_messages_ptr->num_allocates = + pceplib_messages_ptr->total_bytes_allocated = + pceplib_messages_ptr->num_frees = + pceplib_messages_ptr->total_bytes_freed = 0; + + /* Setup the external memory type */ + struct test_memory_type infra_mt, messages_mt; + void *infra_ptr = &infra_mt; + void *messages_ptr = &messages_mt; + memset(infra_ptr, 0, sizeof(struct test_memory_type)); + memset(messages_ptr, 0, sizeof(struct test_memory_type)); + int free_counter = 1; + + /* Initialize the PCEPlib memory system with an external implementation + */ + pceplib_memory_initialize(infra_ptr, messages_ptr, test_pceplib_malloc, + test_pceplib_calloc, test_pceplib_realloc, + test_pceplib_strdup, test_pceplib_free); + + /* Test malloc() */ + void *ptr = pceplib_malloc(PCEPLIB_MESSAGES, alloc_size); + CU_ASSERT_PTR_NOT_NULL(ptr); + pceplib_free(PCEPLIB_MESSAGES, ptr); + verify_ext_memory_type(messages_ptr, 1, 0, 0, 0, free_counter++); + + /* Test calloc() */ + ptr = pceplib_calloc(PCEPLIB_MESSAGES, alloc_size); + CU_ASSERT_PTR_NOT_NULL(ptr); + pceplib_free(PCEPLIB_MESSAGES, ptr); + verify_ext_memory_type(messages_ptr, 1, 1, 0, 0, free_counter++); + + /* Test realloc() */ + ptr = pceplib_malloc(PCEPLIB_MESSAGES, alloc_size); + CU_ASSERT_PTR_NOT_NULL(ptr); + ptr = pceplib_realloc(PCEPLIB_MESSAGES, ptr, alloc_size); + CU_ASSERT_PTR_NOT_NULL(ptr); + pceplib_free(PCEPLIB_MESSAGES, ptr); + verify_ext_memory_type(messages_ptr, 2, 1, 1, 0, free_counter++); + + /* Test strdup() */ + ptr = pceplib_malloc(PCEPLIB_MESSAGES, alloc_size); + /* Make strdup duplicate (alloc_size - 1) bytes */ + memset(ptr, 'a', alloc_size); + ((char *)ptr)[alloc_size - 1] = '\0'; + char *str = pceplib_strdup(PCEPLIB_MESSAGES, (char *)ptr); + CU_ASSERT_PTR_NOT_NULL(ptr); + pceplib_free(PCEPLIB_MESSAGES, ptr); + pceplib_free(PCEPLIB_MESSAGES, str); + verify_ext_memory_type(messages_ptr, 3, 1, 1, 1, free_counter + 1); + + /* Make sure the internal memory counters are NOT incremented */ + verify_memory_type(pceplib_infra_ptr, 0, 0, 0, 0); + verify_memory_type(pceplib_messages_ptr, 0, 0, 0, 0); + + verify_ext_memory_type(infra_ptr, 0, 0, 0, 0, 0); +} diff --git a/pceplib/test/pcep_utils_memory_test.h b/pceplib/test/pcep_utils_memory_test.h new file mode 100644 index 0000000000..4e0c3fadf1 --- /dev/null +++ b/pceplib/test/pcep_utils_memory_test.h @@ -0,0 +1,33 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Javier Garcia <javier.garcia@voltanet.io> + * + */ + +/* + * Timer definitions to be used internally by the pcep_timers library. + */ + +#ifndef PCEP_MEMORY_TEST_H_ +#define PCEP_MEMORY_TEST_H_ + +void test_memory_internal_impl(void); +void test_memory_external_impl(void); + +#endif /* PCEPTIMERINTERNALS_H_ */ diff --git a/pceplib/test/pcep_utils_ordered_list_test.c b/pceplib/test/pcep_utils_ordered_list_test.c new file mode 100644 index 0000000000..fe9ee58825 --- /dev/null +++ b/pceplib/test/pcep_utils_ordered_list_test.c @@ -0,0 +1,248 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Brady Johnson <brady@voltanet.io> + * + */ + + +#include <CUnit/CUnit.h> + +#include "pcep_utils_ordered_list.h" +#include "pcep_utils_ordered_list_test.h" + +typedef struct node_data_ { + int int_data; + +} node_data; + + +int node_data_compare(void *list_entry, void *new_entry) +{ + /* + * < 0 if new_entry < list_entry + * == 0 if new_entry == list_entry (new_entry will be inserted after + * list_entry) > 0 if new_entry > list_entry + */ + + return ((node_data *)new_entry)->int_data + - ((node_data *)list_entry)->int_data; +} + + +void test_empty_list() +{ + ordered_list_handle *handle = + ordered_list_initialize(node_data_compare); + + CU_ASSERT_PTR_NOT_NULL(handle); + CU_ASSERT_PTR_NULL(handle->head); + CU_ASSERT_PTR_NOT_NULL(handle->compare_function); + CU_ASSERT_EQUAL(handle->num_entries, 0); + + ordered_list_destroy(handle); +} + + +void test_null_list_handle() +{ + node_data data; + ordered_list_node node_data; + + void *ptr = ordered_list_add_node(NULL, &data); + CU_ASSERT_PTR_NULL(ptr); + + ptr = ordered_list_find(NULL, &data); + CU_ASSERT_PTR_NULL(ptr); + + ptr = ordered_list_remove_first_node(NULL); + CU_ASSERT_PTR_NULL(ptr); + + ptr = ordered_list_remove_first_node_equals(NULL, &data); + CU_ASSERT_PTR_NULL(ptr); + + ptr = ordered_list_remove_node(NULL, &node_data, &node_data); + CU_ASSERT_PTR_NULL(ptr); +} + + +void test_add_to_list() +{ + node_data data1, data2, data3; + data1.int_data = 1; + data2.int_data = 2; + data3.int_data = 3; + + ordered_list_handle *handle = + ordered_list_initialize(node_data_compare); + + ordered_list_add_node(handle, &data3); + ordered_list_add_node(handle, &data1); + ordered_list_add_node(handle, &data2); + + CU_ASSERT_EQUAL(handle->num_entries, 3); + + ordered_list_node *node = handle->head; + CU_ASSERT_PTR_EQUAL(node->data, &data1); + + node = node->next_node; + CU_ASSERT_PTR_EQUAL(node->data, &data2); + + node = node->next_node; + CU_ASSERT_PTR_EQUAL(node->data, &data3); + + node = node->next_node; + CU_ASSERT_PTR_EQUAL(node, NULL); + + ordered_list_destroy(handle); +} + + +void test_find() +{ + node_data data1, data2, data3, data_not_inList; + data1.int_data = 1; + data2.int_data = 2; + data3.int_data = 3; + data_not_inList.int_data = 5; + + ordered_list_handle *handle = + ordered_list_initialize(node_data_compare); + + ordered_list_add_node(handle, &data3); + ordered_list_add_node(handle, &data2); + ordered_list_add_node(handle, &data1); + + ordered_list_node *node = ordered_list_find(handle, &data1); + CU_ASSERT_PTR_NOT_NULL(node); + CU_ASSERT_PTR_EQUAL(node->data, &data1); + + node = ordered_list_find(handle, &data2); + CU_ASSERT_PTR_NOT_NULL(node); + CU_ASSERT_PTR_EQUAL(node->data, &data2); + + node = ordered_list_find(handle, &data3); + CU_ASSERT_PTR_NOT_NULL(node); + CU_ASSERT_PTR_EQUAL(node->data, &data3); + + node = ordered_list_find(handle, &data_not_inList); + CU_ASSERT_PTR_NULL(node); + + ordered_list_destroy(handle); +} + + +void test_remove_first_node() +{ + node_data data1, data2, data3; + data1.int_data = 1; + data2.int_data = 2; + data3.int_data = 3; + + ordered_list_handle *handle = + ordered_list_initialize(node_data_compare); + + ordered_list_add_node(handle, &data1); + ordered_list_add_node(handle, &data2); + ordered_list_add_node(handle, &data3); + + void *node_data = ordered_list_remove_first_node(handle); + CU_ASSERT_PTR_NOT_NULL(node_data); + CU_ASSERT_PTR_EQUAL(node_data, &data1); + CU_ASSERT_EQUAL(handle->num_entries, 2); + + node_data = ordered_list_remove_first_node(handle); + CU_ASSERT_PTR_NOT_NULL(node_data); + CU_ASSERT_PTR_EQUAL(node_data, &data2); + CU_ASSERT_EQUAL(handle->num_entries, 1); + + node_data = ordered_list_remove_first_node(handle); + CU_ASSERT_PTR_NOT_NULL(node_data); + CU_ASSERT_PTR_EQUAL(node_data, &data3); + CU_ASSERT_EQUAL(handle->num_entries, 0); + CU_ASSERT_PTR_NULL(handle->head); + + node_data = ordered_list_remove_first_node(handle); + CU_ASSERT_PTR_NULL(node_data); + + ordered_list_destroy(handle); +} + + +void test_remove_first_node_equals() +{ + node_data data1, data2, data3; + data1.int_data = 1; + data2.int_data = 2; + data3.int_data = 3; + + ordered_list_handle *handle = + ordered_list_initialize(node_data_compare); + + ordered_list_add_node(handle, &data1); + ordered_list_add_node(handle, &data2); + ordered_list_add_node(handle, &data3); + + void *node_data = ordered_list_remove_first_node_equals(handle, &data2); + CU_ASSERT_PTR_NOT_NULL(node_data); + CU_ASSERT_PTR_EQUAL(node_data, &data2); + CU_ASSERT_EQUAL(handle->num_entries, 2); + + node_data = ordered_list_remove_first_node_equals(handle, &data3); + CU_ASSERT_PTR_NOT_NULL(node_data); + CU_ASSERT_PTR_EQUAL(node_data, &data3); + CU_ASSERT_EQUAL(handle->num_entries, 1); + + node_data = ordered_list_remove_first_node_equals(handle, &data1); + CU_ASSERT_PTR_NOT_NULL(node_data); + CU_ASSERT_PTR_EQUAL(node_data, &data1); + CU_ASSERT_EQUAL(handle->num_entries, 0); + + node_data = ordered_list_remove_first_node_equals(handle, &data1); + CU_ASSERT_PTR_NULL(node_data); + + ordered_list_destroy(handle); +} + + +void test_remove_node() +{ + node_data data1, data2, data3; + data1.int_data = 1; + data2.int_data = 2; + data3.int_data = 3; + + ordered_list_handle *handle = + ordered_list_initialize(node_data_compare); + + ordered_list_node *node1 = ordered_list_add_node(handle, &data1); + ordered_list_node *node2 = ordered_list_add_node(handle, &data2); + ordered_list_node *node3 = ordered_list_add_node(handle, &data3); + + void *node_data = ordered_list_remove_node(handle, node2, node3); + CU_ASSERT_PTR_NOT_NULL(node_data); + CU_ASSERT_PTR_EQUAL(node_data, &data3); + CU_ASSERT_EQUAL(handle->num_entries, 2); + + node_data = ordered_list_remove_node(handle, node1, node2); + CU_ASSERT_PTR_NOT_NULL(node_data); + CU_ASSERT_PTR_EQUAL(node_data, &data2); + CU_ASSERT_EQUAL(handle->num_entries, 1); + + ordered_list_destroy(handle); +} diff --git a/pceplib/test/pcep_utils_ordered_list_test.h b/pceplib/test/pcep_utils_ordered_list_test.h new file mode 100644 index 0000000000..3686848b69 --- /dev/null +++ b/pceplib/test/pcep_utils_ordered_list_test.h @@ -0,0 +1,39 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Javier Garcia <javier.garcia@voltanet.io> + * + */ + +/* + * Timer definitions to be used internally by the pcep_timers library. + */ + +#ifndef PCEP_UTILS_ORDERED_LIST_TEST_H_ +#define PCEP_UTILS_ORDERED_LIST_TEST_H_ + +void test_empty_list(void); +void test_null_list_handle(void); +void test_add_to_list(void); +void test_find(void); +void test_remove_first_node(void); +void test_remove_first_node_equals(void); +void test_remove_node(void); +int node_data_compare(void *list_entry, void *new_entry); + +#endif /* PCEPTIMERINTERNALS_H_ */ diff --git a/pceplib/test/pcep_utils_queue_test.c b/pceplib/test/pcep_utils_queue_test.c new file mode 100644 index 0000000000..1731457789 --- /dev/null +++ b/pceplib/test/pcep_utils_queue_test.c @@ -0,0 +1,157 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Brady Johnson <brady@voltanet.io> + * + */ + + +#include <CUnit/CUnit.h> + +#include "pcep_utils_queue.h" +#include "pcep_utils_queue_test.h" + +typedef struct node_data_ { + int int_data; + +} node_data; + + +void test_empty_queue() +{ + queue_handle *handle = queue_initialize(); + + CU_ASSERT_PTR_NOT_NULL(handle); + CU_ASSERT_PTR_NULL(handle->head); + CU_ASSERT_EQUAL(handle->num_entries, 0); + + queue_destroy(handle); +} + + +void test_null_queue_handle() +{ + /* test each method handles a NULL handle without crashing */ + node_data data; + queue_destroy(NULL); + void *ptr = queue_enqueue(NULL, &data); + CU_ASSERT_PTR_NULL(ptr); + + ptr = queue_dequeue(NULL); + CU_ASSERT_PTR_NULL(ptr); +} + + +void test_enqueue() +{ + node_data data1, data2, data3; + data1.int_data = 1; + data2.int_data = 2; + data3.int_data = 3; + + queue_handle *handle = queue_initialize(); + + queue_enqueue(handle, &data1); + queue_enqueue(handle, &data2); + queue_enqueue(handle, &data3); + + CU_ASSERT_EQUAL(handle->num_entries, 3); + + queue_node *node = handle->head; + CU_ASSERT_PTR_EQUAL(node->data, &data1); + + node = node->next_node; + CU_ASSERT_PTR_EQUAL(node->data, &data2); + + node = node->next_node; + CU_ASSERT_PTR_EQUAL(node->data, &data3); + + node = node->next_node; + CU_ASSERT_PTR_NULL(node); + + queue_destroy(handle); +} + + +void test_enqueue_with_limit() +{ + node_data data1, data2, data3; + data1.int_data = 1; + data2.int_data = 2; + data3.int_data = 3; + + queue_handle *handle = queue_initialize_with_size(2); + + queue_node *node = queue_enqueue(handle, &data1); + CU_ASSERT_PTR_NOT_NULL(node); + + node = queue_enqueue(handle, &data2); + CU_ASSERT_PTR_NOT_NULL(node); + + node = queue_enqueue(handle, &data3); + CU_ASSERT_PTR_NULL(node); + + CU_ASSERT_EQUAL(handle->num_entries, 2); + + node = handle->head; + CU_ASSERT_PTR_EQUAL(node->data, &data1); + + node = node->next_node; + CU_ASSERT_PTR_EQUAL(node->data, &data2); + + node = node->next_node; + CU_ASSERT_PTR_NULL(node); + + queue_destroy(handle); +} + + +void test_dequeue() +{ + node_data data1, data2, data3; + data1.int_data = 1; + data2.int_data = 2; + data3.int_data = 3; + + queue_handle *handle = queue_initialize(); + + /* first test dequeue handles an empty queue */ + void *node_data = queue_dequeue(handle); + CU_ASSERT_PTR_NULL(node_data); + + queue_enqueue(handle, &data1); + queue_enqueue(handle, &data2); + queue_enqueue(handle, &data3); + + node_data = queue_dequeue(handle); + CU_ASSERT_PTR_EQUAL(node_data, &data1); + CU_ASSERT_EQUAL(handle->num_entries, 2); + + node_data = queue_dequeue(handle); + CU_ASSERT_PTR_EQUAL(node_data, &data2); + CU_ASSERT_EQUAL(handle->num_entries, 1); + + node_data = queue_dequeue(handle); + CU_ASSERT_PTR_EQUAL(node_data, &data3); + CU_ASSERT_EQUAL(handle->num_entries, 0); + + node_data = queue_dequeue(handle); + CU_ASSERT_PTR_NULL(node_data); + + queue_destroy(handle); +} diff --git a/pceplib/test/pcep_utils_queue_test.h b/pceplib/test/pcep_utils_queue_test.h new file mode 100644 index 0000000000..16236d0d9d --- /dev/null +++ b/pceplib/test/pcep_utils_queue_test.h @@ -0,0 +1,36 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Javier Garcia <javier.garcia@voltanet.io> + * + */ + +/* + * Timer definitions to be used internally by the pcep_timers library. + */ + +#ifndef PCEP_UTILS_QUEUE_TEST_H_ +#define PCEP_UTILS_QUEUE_TEST_H_ + +void test_empty_queue(void); +void test_null_queue_handle(void); +void test_enqueue(void); +void test_enqueue_with_limit(void); +void test_dequeue(void); + +#endif /* PCEPTIMERINTERNALS_H_ */ diff --git a/pceplib/test/pcep_utils_tests.c b/pceplib/test/pcep_utils_tests.c new file mode 100644 index 0000000000..452b9fa09c --- /dev/null +++ b/pceplib/test/pcep_utils_tests.c @@ -0,0 +1,136 @@ +/* + * This file is part of the PCEPlib, a PCEP protocol library. + * + * Copyright (C) 2020 Volta Networks https://voltanet.io/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Author : Brady Johnson <brady@voltanet.io> + * + */ + + +#include <CUnit/Basic.h> +#include <CUnit/CUnit.h> +#include <CUnit/TestDB.h> +#include "pcep_utils_ordered_list_test.h" +#include "pcep_utils_queue_test.h" +#include "pcep_utils_double_linked_list_test.h" +#include "pcep_utils_counters_test.h" +#include "pcep_utils_memory_test.h" + + +int main(int argc, char **argv) +{ + /* Unused parameters cause compilation warnings */ + (void)argc; + (void)argv; + + CU_initialize_registry(); + + CU_pSuite test_queue_suite = + CU_add_suite("PCEP Utils Queue Test Suite", NULL, NULL); + CU_add_test(test_queue_suite, "test_empty_queue", test_empty_queue); + CU_add_test(test_queue_suite, "test_null_queue_handle", + test_null_queue_handle); + CU_add_test(test_queue_suite, "test_enqueue", test_enqueue); + CU_add_test(test_queue_suite, "test_enqueue_with_limit", + test_enqueue_with_limit); + CU_add_test(test_queue_suite, "test_dequeue", test_dequeue); + + CU_pSuite test_list_suite = + CU_add_suite("PCEP Utils Ordered List Test Suite", NULL, NULL); + CU_add_test(test_list_suite, "test_empty_list", test_empty_list); + CU_add_test(test_list_suite, "test_null_handle", test_null_list_handle); + CU_add_test(test_list_suite, "test_add_toList", test_add_to_list); + CU_add_test(test_list_suite, "test_find", test_find); + CU_add_test(test_list_suite, "test_remove_first_node", + test_remove_first_node); + CU_add_test(test_list_suite, "test_remove_first_node_equals", + test_remove_first_node_equals); + CU_add_test(test_list_suite, "test_remove_node", test_remove_node); + + CU_pSuite test_dl_list_suite = CU_add_suite( + "PCEP Utils Double Linked List Test Suite", NULL, NULL); + CU_add_test(test_dl_list_suite, "test_empty_dl_list", + test_empty_dl_list); + CU_add_test(test_dl_list_suite, "test_null_dl_handle", + test_null_dl_list_handle); + CU_add_test(test_dl_list_suite, "test_dll_prepend_data", + test_dll_prepend_data); + CU_add_test(test_dl_list_suite, "test_dll_append_data", + test_dll_append_data); + CU_add_test(test_dl_list_suite, "test_dll_delete_first_node", + test_dll_delete_first_node); + CU_add_test(test_dl_list_suite, "test_dll_delete_last_node", + test_dll_delete_last_node); + CU_add_test(test_dl_list_suite, "test_dll_delete_node", + test_dll_delete_node); + + CU_pSuite test_counters_suite = + CU_add_suite("PCEP Utils Counters Test Suite", NULL, NULL); + CU_add_test(test_counters_suite, "test_create_counters_group", + test_create_counters_group); + CU_add_test(test_counters_suite, "test_create_counters_subgroup", + test_create_counters_subgroup); + CU_add_test(test_counters_suite, "test_add_counters_subgroup", + test_add_counters_subgroup); + CU_add_test(test_counters_suite, "test_create_subgroup_counter", + test_create_subgroup_counter); + CU_add_test(test_counters_suite, "test_delete_counters_group", + test_delete_counters_group); + CU_add_test(test_counters_suite, "test_delete_counters_subgroup", + test_delete_counters_subgroup); + CU_add_test(test_counters_suite, "test_reset_group_counters", + test_reset_group_counters); + CU_add_test(test_counters_suite, "test_reset_subgroup_counters", + test_reset_subgroup_counters); + CU_add_test(test_counters_suite, "test_increment_counter", + test_increment_counter); + CU_add_test(test_counters_suite, "test_increment_subgroup_counter", + test_increment_subgroup_counter); + CU_add_test(test_counters_suite, "test_dump_counters_group_to_log", + test_dump_counters_group_to_log); + CU_add_test(test_counters_suite, "test_dump_counters_subgroup_to_log", + test_dump_counters_subgroup_to_log); + + CU_pSuite test_memory_suite = + CU_add_suite("PCEP Utils Memory Test Suite", NULL, NULL); + CU_add_test(test_memory_suite, "test_memory_internal_impl", + test_memory_internal_impl); + CU_add_test(test_memory_suite, "test_memory_external_impl", + test_memory_external_impl); + + CU_basic_set_mode(CU_BRM_VERBOSE); + CU_basic_run_tests(); + CU_FailureRecord *failure_record = CU_get_failure_list(); + if (failure_record != NULL) { + printf("\nFailed tests:\n\t [Suite] [Test] [File:line-number]\n"); + do { + printf("\t [%s] [%s] [%s:%d]\n", + failure_record->pSuite->pName, + failure_record->pTest->pName, + failure_record->strFileName, + failure_record->uiLineNumber); + failure_record = failure_record->pNext; + + } while (failure_record != NULL); + } + + CU_pRunSummary run_summary = CU_get_run_summary(); + int result = run_summary->nTestsFailed; + CU_cleanup_registry(); + + return result; +} diff --git a/pceplib/test/pcep_utils_tests_valgrind.sh b/pceplib/test/pcep_utils_tests_valgrind.sh new file mode 100755 index 0000000000..6348d82708 --- /dev/null +++ b/pceplib/test/pcep_utils_tests_valgrind.sh @@ -0,0 +1,2 @@ +source pceplib/test/pcep_tests_valgrind.sh +valgrind_test pceplib/test/pcep_utils_tests diff --git a/pceplib/test/subdir.am b/pceplib/test/subdir.am new file mode 100644 index 0000000000..0ae61d1bce --- /dev/null +++ b/pceplib/test/subdir.am @@ -0,0 +1,122 @@ +if PATHD_PCEP +if PATHD_PCEP_TEST + +# The default Automake target is check, add a test target to call check. +# Also make sure the binaries are current before running the tests. +test: pceplib/test/pcep_msg_tests pceplib/test/pcep_pcc_api_tests pceplib/test/pcep_session_logic_tests pceplib/test/pcep_socket_comm_tests pceplib/test/pcep_timers_tests pceplib/test/pcep_utils_tests + +check_SCRIPTS = pceplib/test/pcep_msg_tests pceplib/test/pcep_pcc_api_tests pceplib/test/pcep_session_logic_tests pceplib/test/pcep_socket_comm_tests pceplib/test/pcep_timers_tests pceplib/test/pcep_utils_tests +TESTS = $(check_SCRIPTS) + + +# Definitions to build the Unit Test binaries with CUnit +noinst_PROGRAMS += pceplib/test/pcep_msg_tests \ + pceplib/test/pcep_pcc_api_tests \ + pceplib/test/pcep_session_logic_tests \ + pceplib/test/pcep_socket_comm_tests \ + pceplib/test/pcep_timers_tests \ + pceplib/test/pcep_utils_tests + +noinst_HEADERS += pceplib/test/pcep_msg_messages_test.h \ + pceplib/test/pcep_msg_object_error_types_test.h \ + pceplib/test/pcep_msg_objects_test.h \ + pceplib/test/pcep_msg_tlvs_test.h \ + pceplib/test/pcep_msg_tools_test.h \ + pceplib/test/pcep_pcc_api_test.h \ + pceplib/test/pcep_session_logic_loop_test.h \ + pceplib/test/pcep_session_logic_states_test.h \ + pceplib/test/pcep_session_logic_test.h \ + pceplib/test/pcep_socket_comm_loop_test.h \ + pceplib/test/pcep_socket_comm_test.h \ + pceplib/test/pcep_timers_event_loop_test.h \ + pceplib/test/pcep_timers_test.h \ + pceplib/test/pcep_utils_counters_test.h \ + pceplib/test/pcep_utils_double_linked_list_test.h \ + pceplib/test/pcep_utils_memory_test.h \ + pceplib/test/pcep_utils_ordered_list_test.h \ + pceplib/test/pcep_utils_queue_test.h + +pceplib_test_pcep_msg_tests_CFLAGS = -I$(top_srcdir)/pceplib +pceplib_test_pcep_msg_tests_LDADD = $(top_builddir)/pceplib/libpcep_pcc.la lib/libfrr.la -lcunit -lpthread +pceplib_test_pcep_msg_tests_SOURCES = pceplib/test/pcep_msg_messages_test.c \ + pceplib/test/pcep_msg_messages_tests.c \ + pceplib/test/pcep_msg_object_error_types_test.c \ + pceplib/test/pcep_msg_objects_test.c \ + pceplib/test/pcep_msg_tlvs_test.c \ + pceplib/test/pcep_msg_tools_test.c + +# The pcc_api_tests and pcep_session_logic_tests use the +# socket_comm_mock, so the LDADD variable needs to be modified +pceplib_test_pcep_pcc_api_tests_CFLAGS = -I$(top_srcdir)/pceplib +pceplib_test_pcep_pcc_api_tests_LDADD = $(top_builddir)/pceplib/libsocket_comm_mock.la $(top_builddir)/pceplib/libpcep_pcc.la lib/libfrr.la -lcunit -lpthread +pceplib_test_pcep_pcc_api_tests_SOURCES = pceplib/test/pcep_pcc_api_test.c pceplib/test/pcep_pcc_api_tests.c + +pceplib_test_pcep_session_logic_tests_CFLAGS = -I$(top_srcdir)/pceplib +pceplib_test_pcep_session_logic_tests_LDADD = $(top_builddir)/pceplib/libsocket_comm_mock.la $(top_builddir)/pceplib/libpcep_pcc.la lib/libfrr.la -lcunit -lpthread +pceplib_test_pcep_session_logic_tests_SOURCES = pceplib/test/pcep_session_logic_loop_test.c \ + pceplib/test/pcep_session_logic_states_test.c \ + pceplib/test/pcep_session_logic_test.c \ + pceplib/test/pcep_session_logic_tests.c + +pceplib_test_pcep_socket_comm_tests_CFLAGS = -I$(top_srcdir)/pceplib +pceplib_test_pcep_socket_comm_tests_LDADD = $(top_builddir)/pceplib/libpcep_pcc.la lib/libfrr.la -lcunit -lpthread +pceplib_test_pcep_socket_comm_tests_SOURCES = pceplib/test/pcep_socket_comm_loop_test.c \ + pceplib/test/pcep_socket_comm_test.c \ + pceplib/test/pcep_socket_comm_tests.c + +pceplib_test_pcep_timers_tests_CFLAGS = -I$(top_srcdir)/pceplib +pceplib_test_pcep_timers_tests_LDADD = $(top_builddir)/pceplib/libpcep_pcc.la lib/libfrr.la -lcunit -lpthread +pceplib_test_pcep_timers_tests_SOURCES = pceplib/test/pcep_timers_event_loop_test.c \ + pceplib/test/pcep_timers_test.c \ + pceplib/test/pcep_timers_tests.c + +pceplib_test_pcep_utils_tests_CFLAGS = -I$(top_srcdir)/pceplib +pceplib_test_pcep_utils_tests_LDADD = $(top_builddir)/pceplib/libpcep_pcc.la lib/libfrr.la -lcunit -lpthread +pceplib_test_pcep_utils_tests_SOURCES = pceplib/test/pcep_utils_counters_test.c \ + pceplib/test/pcep_utils_double_linked_list_test.c \ + pceplib/test/pcep_utils_memory_test.c \ + pceplib/test/pcep_utils_ordered_list_test.c \ + pceplib/test/pcep_utils_queue_test.c \ + pceplib/test/pcep_utils_tests.c + +# These test scripts will call the test binaries +# defined above in noinst_PROGRAMS with Valgrind +if HAVE_VALGRIND_PCEP + +dist_noinst_SCRIPTS = pceplib/test/pcep_pcc_api_tests_valgrind.sh \ + pceplib/test/pcep_session_logic_tests_valgrind.sh \ + pceplib/test/pcep_socket_comm_tests_valgrind.sh \ + pceplib/test/pcep_timers_tests_valgrind.sh \ + pceplib/test/pcep_utils_tests_valgrind.sh \ + pceplib/test/pcep_msg_tests_valgrind.sh \ + pceplib/test/pcep_tests_valgrind.sh + +check_SCRIPTS += pceplib/test/pcep_msg_tests_valgrind.sh \ + pceplib/test/pcep_pcc_api_tests_valgrind.sh \ + pceplib/test/pcep_session_logic_tests_valgrind.sh \ + pceplib/test/pcep_socket_comm_tests_valgrind.sh \ + pceplib/test/pcep_timers_tests_valgrind.sh \ + pceplib/test/pcep_utils_tests_valgrind.sh + +TESTS += $(check_SCRIPTS) + + + +pceplib/test/pcep_msg_tests_valgrind.sh: + chmod +x pceplib/test/pcep_msg_tests_valgrind.sh +pceplib/test/pcep_pcc_api_tests_valgrind.sh: + chmod +x pceplib/test/pcep_pcc_api_tests_valgrind.sh +pceplib/test/pcep_session_logic_tests_valgrind.sh: + chmod +x pceplib/test/pcep_session_logic_tests_valgrind.sh +pceplib/test/pcep_socket_comm_tests_valgrind.sh: + chmod +x pceplib/test/pcep_socket_comm_tests_valgrind.sh +pceplib/test/pcep_timers_tests_valgrind.sh: + chmod +x pceplib/test/pcep_timers_tests_valgrind.sh +pceplib/test/pcep_utils_tests_valgrind.sh: + chmod +x pceplib/test/pcep_utils_tests_valgrind.sh + + +endif + +endif +endif 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 714d6e8e1d..ae5b7940e9 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -6057,7 +6057,7 @@ static void show_mroute(struct pim_instance *pim, struct vty *vty, vty_out(vty, " R - SGRpt Pruned, F - Register flag, T - SPT-bit set\n"); vty_out(vty, - "\nSource Group Flags Proto Input Output TTL Uptime\n"); + "\nSource Group Flags Proto Input Output TTL Uptime\n"); } now = pim_time_monotonic_sec(); @@ -6247,7 +6247,7 @@ static void show_mroute(struct pim_instance *pim, struct vty *vty, } vty_out(vty, - "%-15s %-15s %-15s %-6s %-16s %-16s %-3d %8s\n", + "%-15s %-15s %-8s %-6s %-16s %-16s %-3d %8s\n", src_str, grp_str, state_str, proto, in_ifname, out_ifname, ttl, mroute_uptime); diff --git a/pimd/pim_igmp_mtrace.c b/pimd/pim_igmp_mtrace.c index 941d067619..d36a275f85 100644 --- a/pimd/pim_igmp_mtrace.c +++ b/pimd/pim_igmp_mtrace.c @@ -66,7 +66,6 @@ static bool mtrace_fwd_info_weak(struct pim_instance *pim, struct pim_nexthop nexthop; struct interface *ifp_in; struct in_addr nh_addr; - char nexthop_str[INET_ADDRSTRLEN]; nh_addr.s_addr = INADDR_ANY; @@ -82,10 +81,8 @@ static bool mtrace_fwd_info_weak(struct pim_instance *pim, zlog_debug("mtrace pim_nexthop_lookup OK"); if (PIM_DEBUG_MTRACE) - zlog_debug("mtrace next_hop=%s", - inet_ntop(nexthop.mrib_nexthop_addr.family, - &nexthop.mrib_nexthop_addr.u.prefix, - nexthop_str, sizeof(nexthop_str))); + zlog_debug("mtrace next_hop=%pI4", + &nexthop.mrib_nexthop_addr.u.prefix4); if (nexthop.mrib_nexthop_addr.family == AF_INET) nh_addr = nexthop.mrib_nexthop_addr.u.prefix4; @@ -114,7 +111,6 @@ static bool mtrace_fwd_info(struct pim_instance *pim, struct interface *ifp_in; struct in_addr nh_addr; uint32_t total; - char up_str[INET_ADDRSTRLEN]; memset(&sg, 0, sizeof(struct prefix_sg)); sg.src = mtracep->src_addr; @@ -142,9 +138,7 @@ static bool mtrace_fwd_info(struct pim_instance *pim, total = htonl(MTRACE_UNKNOWN_COUNT); if (PIM_DEBUG_MTRACE) - zlog_debug("fwd_info: upstream next hop=%s", - inet_ntop(AF_INET, &(nh_addr), up_str, - sizeof(up_str))); + zlog_debug("fwd_info: upstream next hop=%pI4", &nh_addr); if (up->channel_oil) total = up->channel_oil->cc.pktcnt; @@ -198,31 +192,19 @@ static void mtrace_rsp_init(struct igmp_mtrace_rsp *mtrace_rspp) static void mtrace_rsp_debug(uint32_t qry_id, int rsp, struct igmp_mtrace_rsp *mrspp) { - char inc_str[INET_ADDRSTRLEN]; - char out_str[INET_ADDRSTRLEN]; - char prv_str[INET_ADDRSTRLEN]; + struct in_addr incoming = mrspp->incoming; + struct in_addr outgoing = mrspp->outgoing; + struct in_addr prev_hop = mrspp->prev_hop; zlog_debug( - "Rx mt(%d) qid=%ud arr=%x in=%s out=%s prev=%s proto=%d fwd=%d", - rsp, ntohl(qry_id), mrspp->arrival, - inet_ntop(AF_INET, &(mrspp->incoming), inc_str, - sizeof(inc_str)), - inet_ntop(AF_INET, &(mrspp->outgoing), out_str, - sizeof(out_str)), - inet_ntop(AF_INET, &(mrspp->prev_hop), prv_str, - sizeof(prv_str)), - mrspp->rtg_proto, mrspp->fwd_code); + "Rx mt(%d) qid=%ud arr=%x in=%pI4 out=%pI4 prev=%pI4 proto=%d fwd=%d", + rsp, ntohl(qry_id), mrspp->arrival, &incoming, &outgoing, + &prev_hop, mrspp->rtg_proto, mrspp->fwd_code); } static void mtrace_debug(struct pim_interface *pim_ifp, struct igmp_mtrace *mtracep, int mtrace_len) { - char inc_str[INET_ADDRSTRLEN]; - char grp_str[INET_ADDRSTRLEN]; - char src_str[INET_ADDRSTRLEN]; - char dst_str[INET_ADDRSTRLEN]; - char rsp_str[INET_ADDRSTRLEN]; - struct in_addr ga, sa, da, ra; ga = mtracep->grp_addr; @@ -231,19 +213,10 @@ static void mtrace_debug(struct pim_interface *pim_ifp, ra = mtracep->rsp_addr; zlog_debug( - "Rx mtrace packet incoming on %s: hops=%d type=%d size=%d, grp=%s, src=%s, dst=%s rsp=%s ttl=%d qid=%ud", - inet_ntop(AF_INET, &(pim_ifp->primary_address), inc_str, - sizeof(inc_str)), - mtracep->hops, mtracep->type, mtrace_len, - inet_ntop(AF_INET, &ga, grp_str, - sizeof(grp_str)), - inet_ntop(AF_INET, &sa, src_str, - sizeof(src_str)), - inet_ntop(AF_INET, &da, dst_str, - sizeof(dst_str)), - inet_ntop(AF_INET, &ra, rsp_str, - sizeof(rsp_str)), - mtracep->rsp_ttl, ntohl(mtracep->qry_id)); + "Rx mtrace packet incoming on %pI4: hops=%d type=%d size=%d, grp=%pI4, src=%pI4, dst=%pI4 rsp=%pI4 ttl=%d qid=%ud", + &pim_ifp->primary_address, mtracep->hops, mtracep->type, + mtrace_len, &ga, &sa, &da, &ra, mtracep->rsp_ttl, + ntohl(mtracep->qry_id)); if (mtrace_len > (int)sizeof(struct igmp_mtrace)) { int i; @@ -290,8 +263,6 @@ static int mtrace_send_packet(struct interface *ifp, ssize_t sent; int ret; int fd; - char if_str[INET_ADDRSTRLEN]; - char rsp_str[INET_ADDRSTRLEN]; uint8_t ttl; memset(&to, 0, sizeof(to)); @@ -301,13 +272,11 @@ static int mtrace_send_packet(struct interface *ifp, if (PIM_DEBUG_MTRACE) { struct in_addr if_addr; + struct in_addr rsp_addr = mtracep->rsp_addr; if_addr = mtrace_primary_address(ifp); - zlog_debug( - "Sending mtrace packet to %s on %s", - inet_ntop(AF_INET, &mtracep->rsp_addr, rsp_str, - sizeof(rsp_str)), - inet_ntop(AF_INET, &if_addr, if_str, sizeof(if_str))); + zlog_debug("Sending mtrace packet to %pI4 on %pI4", &rsp_addr, + &if_addr); } fd = pim_socket_raw(IPPROTO_IGMP); @@ -514,7 +483,6 @@ static int mtrace_send_mc_response(struct pim_instance *pim, struct listnode *chnextnode; struct pim_ifchannel *ch = NULL; int ret = -1; - char buf[PREFIX_STRLEN]; memset(&sg, 0, sizeof(struct prefix_sg)); sg.grp = mtracep->rsp_addr; @@ -523,11 +491,11 @@ static int mtrace_send_mc_response(struct pim_instance *pim, if (c_oil == NULL) { if (PIM_DEBUG_MTRACE) { + struct in_addr rsp_addr = mtracep->rsp_addr; + zlog_debug( - "Dropping mtrace multicast response packet len=%u to %s", - (unsigned int)mtrace_len, - inet_ntop(AF_INET, &mtracep->rsp_addr, - buf, sizeof(buf))); + "Dropping mtrace multicast response packet len=%u to %pI4", + (unsigned int)mtrace_len, &rsp_addr); } return -1; } @@ -562,7 +530,6 @@ static int mtrace_send_response(struct pim_instance *pim, if (IPV4_CLASS_DE(ntohl(mtracep->rsp_addr.s_addr))) { struct pim_rpf *p_rpf; - char grp_str[INET_ADDRSTRLEN]; if (pim_rp_i_am_rp(pim, mtracep->rsp_addr)) return mtrace_send_mc_response(pim, mtracep, @@ -571,11 +538,11 @@ static int mtrace_send_response(struct pim_instance *pim, p_rpf = pim_rp_g(pim, mtracep->rsp_addr); if (p_rpf == NULL) { - if (PIM_DEBUG_MTRACE) - zlog_debug("mtrace no RP for %s", - inet_ntop(AF_INET, - &(mtracep->rsp_addr), - grp_str, sizeof(grp_str))); + if (PIM_DEBUG_MTRACE) { + struct in_addr rsp_addr = mtracep->rsp_addr; + + zlog_debug("mtrace no RP for %pI4", &rsp_addr); + } return -1; } nexthop = p_rpf->source_nexthop; 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 ddd8dc6bf9..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) { @@ -67,7 +69,6 @@ static int pim_msdp_sock_accept(struct thread *thread) int accept_sock; int msdp_sock; struct pim_msdp_peer *mp; - char buf[SU_ADDRSTRLEN]; sockunion_init(&su); @@ -96,8 +97,7 @@ static int pim_msdp_sock_accept(struct thread *thread) ++pim->msdp.rejected_accepts; if (PIM_DEBUG_MSDP_EVENTS) { flog_err(EC_PIM_MSDP_PACKET, - "msdp peer connection refused from %s", - sockunion2str(&su, buf, SU_ADDRSTRLEN)); + "msdp peer connection refused from %pSU", &su); } close(msdp_sock); return -1; @@ -113,8 +113,8 @@ static int pim_msdp_sock_accept(struct thread *thread) if (mp->fd >= 0) { if (PIM_DEBUG_MSDP_EVENTS) { zlog_notice( - "msdp peer new connection from %s stop old connection", - sockunion2str(&su, buf, SU_ADDRSTRLEN)); + "msdp peer new connection from %pSU stop old connection", + &su); } pim_msdp_peer_stop_tcp_conn(mp, true /* chg_state */); } @@ -196,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); @@ -274,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 4bc78529a8..a7d7551cbd 100644 --- a/pimd/pim_nb_config.c +++ b/pimd/pim_nb_config.c @@ -1181,7 +1181,7 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ms case NB_EV_APPLY: vrf = nb_running_get_entry(args->dnode, NULL, true); pim = vrf->info; - mesh_group_name = yang_dnode_get_string(args->dnode, "."); + mesh_group_name = yang_dnode_get_string(args->dnode, "mesh-group-name"); result = ip_no_msdp_mesh_group_cmd_worker(pim, mesh_group_name, args->errmsg, @@ -2394,6 +2394,13 @@ 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"); @@ -2402,18 +2409,20 @@ int lib_interface_pim_address_family_mroute_oif_modify( "%% Enable PIM and/or IGMP on this interface first"); return NB_ERR_VALIDATION; } + +#ifdef PIM_ENFORCE_LOOPFREE_MFC + if (oif && (iif->ifindex == oif->ifindex)) { + strlcpy(args->errmsg, + "% IIF same as OIF and loopfree enforcement is enabled; rejecting", + args->errmsg_len); + return NB_ERR_VALIDATION; + } +#endif break; case NB_EV_PREPARE: 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", @@ -2707,11 +2716,11 @@ int lib_interface_igmp_igmp_enable_modify(struct nb_cb_modify_args *args) switch (args->event) { case NB_EV_VALIDATE: if_dnode = yang_dnode_get_parent(args->dnode, "interface"); - ifp_name = yang_dnode_get_string(if_dnode, "."); mcast_if_count = yang_get_list_elements_count(if_dnode); /* Limiting mcast interfaces to number of VIFs */ if (mcast_if_count == MAXVIFS) { + ifp_name = yang_dnode_get_string(if_dnode, "name"); snprintf(args->errmsg, args->errmsg_len, "Max multicast interfaces(%d) Reached. Could not enable IGMP on interface %s", MAXVIFS, ifp_name); @@ -2982,7 +2991,7 @@ int lib_interface_igmp_address_family_static_group_create( case NB_EV_VALIDATE: if_dnode = yang_dnode_get_parent(args->dnode, "interface"); if (!is_pim_interface(if_dnode)) { - ifp_name = yang_dnode_get_string(if_dnode, "."); + ifp_name = yang_dnode_get_string(if_dnode, "name"); snprintf(args->errmsg, args->errmsg_len, "multicast not enabled on interface %s", ifp_name); 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/python/clippy/__init__.py b/python/clippy/__init__.py index d6865ff484..344a1c91ee 100644 --- a/python/clippy/__init__.py +++ b/python/clippy/__init__.py @@ -21,6 +21,8 @@ import _clippy from _clippy import parse, Graph, GraphNode +frr_top_src = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) + def graph_iterate(graph): """iterator yielding all nodes of a graph diff --git a/python/clippy/elf.py b/python/clippy/elf.py new file mode 100644 index 0000000000..4ed334f0c4 --- /dev/null +++ b/python/clippy/elf.py @@ -0,0 +1,574 @@ +# FRR libelf wrapper +# +# Copyright (C) 2020 David Lamparter for 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 + +''' +Wrapping layer and additional utility around _clippy.ELFFile. + +Essentially, the C bits have the low-level ELF access bits that should be +fast while this has the bits that string everything together (and would've +been a PITA to do in C.) + +Surprisingly - or maybe through proper engineering - this actually works +across architecture, word size and even endianness boundaries. Both the C +module (through GElf_*) and this code (cf. struct.unpack format mangling +in ELFDissectStruct) will take appropriate measures to flip and resize +fields as needed. +''' + +import struct +from collections import OrderedDict +from weakref import WeakValueDictionary + +from _clippy import ELFFile, ELFAccessError + +# +# data access +# + +class ELFNull(object): + ''' + NULL pointer, returned instead of ELFData + ''' + def __init__(self): + self.symname = None + self._dstsect = None + + def __repr__(self): + return '<ptr: NULL>' + + def __hash__(self): + return hash(None) + + def get_string(self): + return None + +class ELFUnresolved(object): + ''' + Reference to an unresolved external symbol, returned instead of ELFData + + :param symname: name of the referenced symbol + :param addend: offset added to the symbol, normally zero + ''' + def __init__(self, symname, addend): + self.addend = addend + self.symname = symname + self._dstsect = None + + def __repr__(self): + return '<unresolved: %s+%d>' % (self.symname, self.addend) + + def __hash__(self): + return hash((self.symname, self.addend)) + +class ELFData(object): + ''' + Actual data somewhere in the ELF file. + + :type dstsect: ELFSubset + :param dstsect: container data area (section or entire file) + :param dstoffs: byte offset into dstsect + :param dstlen: byte size of object, or None if unknown, open-ended or string + ''' + def __init__(self, dstsect, dstoffs, dstlen): + self._dstsect = dstsect + self._dstoffs = dstoffs + self._dstlen = dstlen + self.symname = None + + def __repr__(self): + return '<ptr: %s+0x%05x/%d>' % (self._dstsect.name, self._dstoffs, self._dstlen or -1) + + def __hash__(self): + return hash((self._dstsect, self._dstoffs)) + + def get_string(self): + ''' + Interpret as C string / null terminated UTF-8 and get the actual text. + ''' + try: + return self._dstsect[self._dstoffs:str].decode('UTF-8') + except: + import pdb; pdb.set_trace() + + def get_data(self, reflen): + ''' + Interpret as some structure (and check vs. expected length) + + :param reflen: expected size of the object, compared against actual + size (which is only known in rare cases, mostly when directly + accessing a symbol since symbols have their destination object + size recorded) + ''' + if self._dstlen is not None and self._dstlen != reflen: + raise ValueError('symbol size mismatch (got %d, expected %d)' % (self._dstlen, reflen)) + return self._dstsect[self._dstoffs:self._dstoffs+reflen] + + def offset(self, offs, within_symbol=False): + ''' + Get another ELFData at an offset + + :param offs: byte offset, can be negative (e.g. in container_of) + :param within_symbol: retain length information + ''' + if self._dstlen is None or not within_symbol: + return ELFData(self._dstsect, self._dstoffs + offs, None) + else: + return ELFData(self._dstsect, self._dstoffs + offs, self._dstlen - offs) + +# +# dissection data items +# + +class ELFDissectData(object): + ''' + Common bits for ELFDissectStruct and ELFDissectUnion + ''' + + def __len__(self): + ''' + Used for boolean evaluation, e.g. "if struct: ..." + ''' + return not (isinstance(self._data, ELFNull) or isinstance(self._data, ELFUnresolved)) + + def container_of(self, parent, fieldname): + ''' + Assume this struct is embedded in a larger struct and get at the larger + + Python ``self.container_of(a, b)`` = C ``container_of(self, a, b)`` + + :param parent: class (not instance) of the larger struct + :param fieldname: fieldname that refers back to this + :returns: instance of parent, with fieldname set to this object + ''' + offset = 0 + if not hasattr(parent, '_efields'): + parent._setup_efields() + + for field in parent._efields[self.elfclass]: + if field[0] == fieldname: + break + offset += struct.calcsize(field[1]) + else: + raise AttributeError('%r not found in %r.fields' % (fieldname, parent)) + + return parent(self._data.offset(-offset), replace = {fieldname: self}) + +class ELFDissectStruct(ELFDissectData): + ''' + Decode and provide access to a struct somewhere in the ELF file + + Handles pointers and strings somewhat nicely. Create a subclass for each + struct that is to be accessed, and give a field list in a "fields" + class-member. + + :param dataptr: ELFData referring to the data bits to decode. + :param parent: where this was instantiated from; only for reference, has + no functional impact. + :param replace: substitute data values for specific fields. Used by + `container_of` to replace the inner struct when creating the outer + one. + + .. attribute:: fields + + List of tuples describing the struct members. Items can be: + - ``('name', ELFDissectData)`` - directly embed another struct + - ``('name', 'I')`` - simple data types; second item for struct.unpack + - ``('name', 'I', None)`` - field to ignore + - ``('name', 'P', str)`` - pointer to string + - ``('name', 'P', ELFDissectData)`` - pointer to another struct + + ``P`` is added as unpack format for pointers (sized appropriately for + the ELF file.) + + Refer to tiabwarfo.py for extracting this from ``pahole``. + + TBD: replace tuples with a class. + + .. attribute:: fieldrename + + Dictionary to rename fields, useful if fields comes from tiabwarfo.py. + ''' + + class Pointer(object): + ''' + Quick wrapper for pointers to further structs + + This is just here to avoid going into infinite loops when loading + structs that have pointers to each other (e.g. struct xref <--> + struct xrefdata.) The pointer destination is only instantiated when + actually accessed. + ''' + def __init__(self, cls, ptr): + self.cls = cls + self.ptr = ptr + + def __repr__(self): + return '<Pointer:%s %r>' % (self.cls.__name__, self.ptr) + + def __call__(self): + if isinstance(self.ptr, ELFNull): + return None + return self.cls(self.ptr) + + def __new__(cls, dataptr, parent = None, replace = None): + if dataptr._dstsect is None: + return super().__new__(cls) + + obj = dataptr._dstsect._pointers.get((cls, dataptr)) + if obj is not None: + return obj + obj = super().__new__(cls) + dataptr._dstsect._pointers[(cls, dataptr)] = obj + return obj + + replacements = 'lLnN' + + @classmethod + def _preproc_structspec(cls, elfclass, spec): + elfbits = elfclass + + if hasattr(spec, 'calcsize'): + spec = '%ds' % (spec.calcsize(elfclass),) + + if elfbits == 32: + repl = ['i', 'I'] + else: + repl = ['q', 'Q'] + for c in cls.replacements: + spec = spec.replace(c, repl[int(c.isupper())]) + return spec + + @classmethod + def _setup_efields(cls): + cls._efields = {} + cls._esize = {} + for elfclass in [32, 64]: + cls._efields[elfclass] = [] + size = 0 + for f in cls.fields: + newf = (f[0], cls._preproc_structspec(elfclass, f[1])) + f[2:] + cls._efields[elfclass].append(newf) + size += struct.calcsize(newf[1]) + cls._esize[elfclass] = size + + def __init__(self, dataptr, parent = None, replace = None): + if not hasattr(self.__class__, '_efields'): + self._setup_efields() + + self._fdata = None + self._data = dataptr + self._parent = parent + self.symname = dataptr.symname + if isinstance(dataptr, ELFNull) or isinstance(dataptr, ELFUnresolved): + self._fdata = {} + return + + self._elfsect = dataptr._dstsect + self.elfclass = self._elfsect._elffile.elfclass + self.offset = dataptr._dstoffs + + pspecl = [f[1] for f in self._efields[self.elfclass]] + + # need to correlate output from struct.unpack with extra metadata + # about the particular fields, so note down byte offsets (in locs) + # and tuple indices of pointers (in ptrs) + pspec = '' + locs = {} + ptrs = set() + + for idx, spec in enumerate(pspecl): + if spec == 'P': + ptrs.add(idx) + spec = self._elfsect.ptrtype + + locs[idx] = struct.calcsize(pspec) + pspec = pspec + spec + + self._total_size = struct.calcsize(pspec) + + def replace_ptrs(v): + idx, val = v[0], v[1] + if idx not in ptrs: + return val + return self._elfsect.pointer(self.offset + locs[idx]) + + data = dataptr.get_data(struct.calcsize(pspec)) + unpacked = struct.unpack(self._elfsect.endian + pspec, data) + unpacked = list(map(replace_ptrs, enumerate(unpacked))) + self._fraw = unpacked + self._fdata = OrderedDict() + replace = replace or {} + + for i, item in enumerate(unpacked): + name = self.fields[i][0] + if name is None: + continue + + if name in replace: + self._fdata[name] = replace[name] + continue + + if isinstance(self.fields[i][1], type) and issubclass(self.fields[i][1], ELFDissectData): + dataobj = self.fields[i][1](dataptr.offset(locs[i]), self) + self._fdata[name] = dataobj + continue + if len(self.fields[i]) == 3: + if self.fields[i][2] == str: + self._fdata[name] = item.get_string() + continue + elif self.fields[i][2] is None: + pass + elif issubclass(self.fields[i][2], ELFDissectData): + cls = self.fields[i][2] + dataobj = self.Pointer(cls, item) + self._fdata[name] = dataobj + continue + + self._fdata[name] = item + + def __getattr__(self, attrname): + if attrname not in self._fdata: + raise AttributeError(attrname) + if isinstance(self._fdata[attrname], self.Pointer): + self._fdata[attrname] = self._fdata[attrname]() + return self._fdata[attrname] + + def __repr__(self): + if not isinstance(self._data, ELFData): + return '<%s: %r>' % (self.__class__.__name__, self._data) + return '<%s: %s>' % (self.__class__.__name__, + ', '.join(['%s=%r' % t for t in self._fdata.items()])) + + @classmethod + def calcsize(cls, elfclass): + ''' + Sum up byte size of this struct + + Wraps struct.calcsize with some extra features. + ''' + if not hasattr(cls, '_efields'): + cls._setup_efields() + + pspec = ''.join([f[1] for f in cls._efields[elfclass]]) + + ptrtype = 'I' if elfclass == 32 else 'Q' + pspec = pspec.replace('P', ptrtype) + + return struct.calcsize(pspec) + +class ELFDissectUnion(ELFDissectData): + ''' + Decode multiple structs in the same place. + + Not currently used (and hence not tested.) Worked at some point but not + needed anymore and may be borked now. Remove this comment when using. + ''' + def __init__(self, dataptr, parent = None): + self._dataptr = dataptr + self._parent = parent + self.members = [] + for name, membercls in self.__class__.members: + item = membercls(dataptr, parent) + self.members.append(item) + setattr(self, name, item) + + def __repr__(self): + return '<%s: %s>' % (self.__class__.__name__, ', '.join([repr(i) for i in self.members])) + + @classmethod + def calcsize(cls, elfclass): + return max([member.calcsize(elfclass) for name, member in cls.members]) + +# +# wrappers for spans of ELF data +# + +class ELFSubset(object): + ''' + Common abstract base for section-level and file-level access. + ''' + + def __init__(self): + super().__init__() + + self._pointers = WeakValueDictionary() + + def __hash__(self): + return hash(self.name) + + def __getitem__(self, k): + ''' + Read data from slice + + Subscript **must** be a slice; a simple index will not return a byte + but rather throw an exception. Valid slice syntaxes are defined by + the C module: + + - `this[123:456]` - extract specific range + - `this[123:str]` - extract until null byte. The slice stop value is + the `str` type (or, technically, `unicode`.) + ''' + return self._obj[k] + + def getreloc(self, offset): + ''' + Check for a relocation record at the specified offset. + ''' + return self._obj.getreloc(offset) + + def iter_data(self, scls, slice_ = slice(None)): + ''' + Assume an array of structs present at a particular slice and decode + + :param scls: ELFDissectData subclass for the struct + :param slice_: optional range specification + ''' + size = scls.calcsize(self._elffile.elfclass) + + offset = slice_.start or 0 + stop = slice_.stop or self._obj.len + if stop < 0: + stop = self._obj.len - stop + + while offset < stop: + yield scls(ELFData(self, offset, size)) + offset += size + + def pointer(self, offset): + ''' + Try to dereference a pointer value + + This checks whether there's a relocation at the given offset and + uses that; otherwise (e.g. in a non-PIE executable where the pointer + is already resolved by the linker) the data at the location is used. + + :param offset: byte offset from beginning of section, + or virtual address in file + :returns: ELFData wrapping pointed-to object + ''' + + ptrsize = struct.calcsize(self.ptrtype) + data = struct.unpack(self.endian + self.ptrtype, self[offset:offset + ptrsize])[0] + + reloc = self.getreloc(offset) + dstsect = None + if reloc: + # section won't be available in whole-file operation + dstsect = reloc.getsection(data) + addend = reloc.r_addend + + if reloc.relative: + # old-style ELF REL instead of RELA, not well-tested + addend += data + + if reloc.unresolved and reloc.symvalid: + return ELFUnresolved(reloc.symname, addend) + elif reloc.symvalid: + data = addend + reloc.st_value + else: + data = addend + + # 0 could technically be a valid pointer for a shared library, + # since libraries may use 0 as default virtual start address (it'll + # be adjusted on loading) + # That said, if the library starts at 0, that's where the ELF header + # would be so it's still an invalid pointer. + if data == 0 and dstsect == None: + return ELFNull() + + # wrap_data is different between file & section + return self._wrap_data(data, dstsect) + +class ELFDissectSection(ELFSubset): + ''' + Access the contents of an ELF section like ``.text`` or ``.data`` + + :param elfwrap: ELFDissectFile wrapper for the file + :param idx: section index in section header table + :param section: section object from C module + ''' + + def __init__(self, elfwrap, idx, section): + super().__init__() + + self._elfwrap = elfwrap + self._elffile = elfwrap._elffile + self._idx = idx + self._section = self._obj = section + self.name = section.name + self.ptrtype = elfwrap.ptrtype + self.endian = elfwrap.endian + + def _wrap_data(self, data, dstsect): + if dstsect is None: + dstsect = self._elfwrap._elffile.get_section_addr(data) + offs = data - dstsect.sh_addr + dstsect = self._elfwrap.get_section(dstsect.idx) + return ELFData(dstsect, offs, None) + +class ELFDissectFile(ELFSubset): + ''' + Access the contents of an ELF file. + + Note that offsets for array subscript and relocation/pointer access are + based on the file's virtual address space and are NOT offsets to the + start of the file on disk! + + (Shared libraries frequently have a virtual address space starting at 0, + but non-PIE executables have an architecture specific default loading + address like 0x400000 on x86. + + :param filename: ELF file to open + ''' + + def __init__(self, filename): + super().__init__() + + self.name = filename + self._elffile = self._obj = ELFFile(filename) + self._sections = {} + + self.ptrtype = 'I' if self._elffile.elfclass == 32 else 'Q' + self.endian = '>' if self._elffile.bigendian else '<' + + @property + def _elfwrap(self): + return self + + def _wrap_data(self, data, dstsect): + return ELFData(self, data, None) + + def get_section(self, secname): + ''' + Look up section by name or index + ''' + if isinstance(secname, int): + sh_idx = secname + section = self._elffile.get_section_idx(secname) + else: + section = self._elffile.get_section(secname) + + if section is None: + return None + + sh_idx = section.idx + + if sh_idx not in self._sections: + self._sections[sh_idx] = ELFDissectSection(self, sh_idx, section) + + return self._sections[sh_idx] diff --git a/python/clippy/uidhash.py b/python/clippy/uidhash.py new file mode 100644 index 0000000000..bf994d389e --- /dev/null +++ b/python/clippy/uidhash.py @@ -0,0 +1,71 @@ +# xref unique ID hash calculation +# +# Copyright (C) 2020 David Lamparter for 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 + +import struct +from hashlib import sha256 + +def bititer(data, bits, startbit = True): + ''' + just iterate the individual bits out from a bytes object + + if startbit is True, an '1' bit is inserted at the very beginning + goes <bits> at a time, starts at LSB. + ''' + bitavail, v = 0, 0 + if startbit and len(data) > 0: + v = data.pop(0) + yield (v & ((1 << bits) - 1)) | (1 << (bits - 1)) + bitavail = 9 - bits + v >>= bits - 1 + + while len(data) > 0: + while bitavail < bits: + v |= data.pop(0) << bitavail + bitavail += 8 + yield v & ((1 << bits) - 1) + bitavail -= bits + v >>= bits + +def base32c(data): + ''' + Crockford base32 with extra dashes + ''' + chs = "0123456789ABCDEFGHJKMNPQRSTVWXYZ" + o = '' + if type(data) == str: + data = [ord(v) for v in data] + else: + data = list(data) + for i, bits in enumerate(bititer(data, 5)): + if i == 5: + o = o + '-' + elif i == 10: + break + o = o + chs[bits] + return o + +def uidhash(filename, hashstr, hashu32a, hashu32b): + ''' + xref Unique ID hash used in FRRouting + ''' + filename = '/'.join(filename.rsplit('/')[-2:]) + + hdata = filename.encode('UTF-8') + hashstr.encode('UTF-8') + hdata += struct.pack('>II', hashu32a, hashu32b) + i = sha256(hdata).digest() + return base32c(i) diff --git a/python/makefile.py b/python/makefile.py index 10c73df72d..44658013b3 100644 --- a/python/makefile.py +++ b/python/makefile.py @@ -31,6 +31,10 @@ clippy_scan = mv["clippy_scan"].strip().split() for clippy_file in clippy_scan: assert clippy_file.endswith(".c") +xref_targets = [] +for varname in ["bin_PROGRAMS", "sbin_PROGRAMS", "lib_LTLIBRARIES", "module_LTLIBRARIES"]: + xref_targets.extend(mv[varname].strip().split()) + # check for files using clippy but not listed in clippy_scan if args.dev_build: basepath = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) @@ -125,6 +129,14 @@ for clippy_file in clippy_scan: out_lines.append(clippydep.substitute(clippybase=clippy_file[:-2])) out_lines.append("") +out_lines.append("xrefs = %s" % (" ".join(["%s.xref" % target for target in xref_targets]))) +out_lines.append("frr.xref: $(xrefs)") +out_lines.append("") + +#frr.xref: $(bin_PROGRAMS) $(sbin_PROGRAMS) $(lib_LTLIBRARIES) $(module_LTLIBRARIES) +# $(AM_V_XRELFO) $(CLIPPY) $(top_srcdir)/python/xrelfo.py -o $@ $^ + +out_lines.append("") out_lines.extend(bcdeps) out_lines.append("") bc_targets = [] diff --git a/python/runtests.py b/python/runtests.py new file mode 100644 index 0000000000..bcf650b329 --- /dev/null +++ b/python/runtests.py @@ -0,0 +1,14 @@ +import pytest +import sys +import os + +try: + import _clippy +except ImportError: + sys.stderr.write('''these tests need to be run with the _clippy C extension +module available. Try running "clippy runtests.py ...". +''') + sys.exit(1) + +os.chdir(os.path.dirname(os.path.abspath(__file__))) +raise SystemExit(pytest.main(sys.argv[1:])) diff --git a/python/test_xrelfo.py b/python/test_xrelfo.py new file mode 100644 index 0000000000..3ae24ea7b3 --- /dev/null +++ b/python/test_xrelfo.py @@ -0,0 +1,65 @@ +# some basic tests for xrelfo & the python ELF machinery +# +# Copyright (C) 2020 David Lamparter for 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 + +import sys +import os +import pytest +from pprint import pprint + +root = os.path.dirname(os.path.dirname(__file__)) +sys.path.append(os.path.join(root, 'python')) + +import xrelfo +from clippy import elf, uidhash + +def test_uidhash(): + assert uidhash.uidhash("lib/test_xref.c", "logging call", 3, 0) \ + == 'H7KJB-67TBH' + +def test_xrelfo_other(): + for data in [ + elf.ELFNull(), + elf.ELFUnresolved('somesym', 0), + ]: + + dissect = xrelfo.XrefPtr(data) + print(repr(dissect)) + + with pytest.raises(AttributeError): + dissect.xref + +def test_xrelfo_obj(): + xrelfo_ = xrelfo.Xrelfo() + edf = xrelfo_.load_elf(os.path.join(root, 'lib/.libs/zclient.o'), 'zclient.lo') + xrefs = xrelfo_._xrefs + + with pytest.raises(elf.ELFAccessError): + edf[0:4] + + pprint(xrefs[0]) + pprint(xrefs[0]._data) + +def test_xrelfo_bin(): + xrelfo_ = xrelfo.Xrelfo() + edf = xrelfo_.load_elf(os.path.join(root, 'lib/.libs/libfrr.so'), 'libfrr.la') + xrefs = xrelfo_._xrefs + + assert edf[0:4] == b'\x7fELF' + + pprint(xrefs[0]) + pprint(xrefs[0]._data) diff --git a/python/tiabwarfo.py b/python/tiabwarfo.py new file mode 100644 index 0000000000..265173e314 --- /dev/null +++ b/python/tiabwarfo.py @@ -0,0 +1,203 @@ +# FRR DWARF structure definition extractor +# +# Copyright (C) 2020 David Lamparter for 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 + +import sys +import os +import subprocess +import re +import argparse +import subprocess +import json + +structs = ['xref', 'xref_logmsg', 'xref_threadsched', 'xref_install_element', 'xrefdata', 'xrefdata_logmsg', 'cmd_element'] + +def extract(filename='lib/.libs/libfrr.so'): + ''' + Convert output from "pahole" to JSON. + + Example pahole output: + $ pahole -C xref lib/.libs/libfrr.so + struct xref { + struct xrefdata * xrefdata; /* 0 8 */ + enum xref_type type; /* 8 4 */ + int line; /* 12 4 */ + const char * file; /* 16 8 */ + const char * func; /* 24 8 */ + + /* size: 32, cachelines: 1, members: 5 */ + /* last cacheline: 32 bytes */ + }; + ''' + pahole = subprocess.check_output(['pahole', '-C', ','.join(structs), filename]).decode('UTF-8') + + struct_re = re.compile(r'^struct ([^ ]+) \{([^\}]+)};', flags=re.M | re.S) + field_re = re.compile(r'^\s*(?P<type>[^;\(]+)\s+(?P<name>[^;\[\]]+)(?:\[(?P<array>\d+)\])?;\s*\/\*(?P<comment>.*)\*\/\s*$') + comment_re = re.compile(r'^\s*\/\*.*\*\/\s*$') + + pastructs = struct_re.findall(pahole) + out = {} + + for sname, data in pastructs: + this = out.setdefault(sname, {}) + fields = this.setdefault('fields', []) + + lines = data.strip().splitlines() + + next_offs = 0 + + for line in lines: + if line.strip() == '': + continue + m = comment_re.match(line) + if m is not None: + continue + + m = field_re.match(line) + if m is not None: + offs, size = m.group('comment').strip().split() + offs = int(offs) + size = int(size) + typ_ = m.group('type').strip() + name = m.group('name') + + if name.startswith('(*'): + # function pointer + typ_ = typ_ + ' *' + name = name[2:].split(')')[0] + + data = { + 'name': name, + 'type': typ_, + # 'offset': offs, + # 'size': size, + } + if m.group('array'): + data['array'] = int(m.group('array')) + + fields.append(data) + if offs != next_offs: + raise ValueError('%d padding bytes before struct %s.%s' % (offs - next_offs, sname, name)) + next_offs = offs + size + continue + + raise ValueError('cannot process line: %s' % line) + + return out + +class FieldApplicator(object): + ''' + Fill ELFDissectStruct fields list from pahole/JSON + + Uses the JSON file created by the above code to fill in the struct fields + in subclasses of ELFDissectStruct. + ''' + + # only what we really need. add more as needed. + packtypes = { + 'int': 'i', + 'uint8_t': 'B', + 'uint16_t': 'H', + 'uint32_t': 'I', + 'char': 's', + } + + def __init__(self, data): + self.data = data + self.classes = [] + self.clsmap = {} + + def add(self, cls): + self.classes.append(cls) + self.clsmap[cls.struct] = cls + + def resolve(self, cls): + out = [] + #offset = 0 + + fieldrename = getattr(cls, 'fieldrename', {}) + def mkname(n): + return (fieldrename.get(n, n),) + + for field in self.data[cls.struct]['fields']: + typs = field['type'].split() + typs = [i for i in typs if i not in ['const']] + + # this will break reuse of xrefstructs.json across 32bit & 64bit + # platforms + + #if field['offset'] != offset: + # assert offset < field['offset'] + # out.append(('_pad', '%ds' % (field['offset'] - offset,))) + + # pretty hacky C types handling, but covers what we need + + ptrlevel = 0 + while typs[-1] == '*': + typs.pop(-1) + ptrlevel += 1 + + if ptrlevel > 0: + packtype = ('P', None) + if ptrlevel == 1: + if typs[0] == 'char': + packtype = ('P', str) + elif typs[0] == 'struct' and typs[1] in self.clsmap: + packtype = ('P', self.clsmap[typs[1]]) + elif typs[0] == 'enum': + packtype = ('I',) + elif typs[0] in self.packtypes: + packtype = (self.packtypes[typs[0]],) + elif typs[0] == 'struct': + if typs[1] in self.clsmap: + packtype = (self.clsmap[typs[1]],) + else: + raise ValueError('embedded struct %s not in extracted data' % (typs[1],)) + else: + raise ValueError('cannot decode field %s in struct %s (%s)' % ( + cls.struct, field['name'], field['type'])) + + if 'array' in field and typs[0] == 'char': + packtype = ('%ds' % field['array'],) + out.append(mkname(field['name']) + packtype) + elif 'array' in field: + for i in range(0, field['array']): + out.append(mkname('%s_%d' % (field['name'], i)) + packtype) + else: + out.append(mkname(field['name']) + packtype) + + #offset = field['offset'] + field['size'] + + cls.fields = out + + def __call__(self): + for cls in self.classes: + self.resolve(cls) + +def main(): + argp = argparse.ArgumentParser(description = 'FRR DWARF structure extractor') + argp.add_argument('-o', dest='output', type=str, help='write JSON output', default='python/xrefstructs.json') + argp.add_argument('-i', dest='input', type=str, help='ELF file to read', default='lib/.libs/libfrr.so') + args = argp.parse_args() + + out = extract(args.input) + with open(args.output + '.tmp', 'w') as fd: + json.dump(out, fd, indent=2, sort_keys=True) + os.rename(args.output + '.tmp', args.output) + +if __name__ == '__main__': + main() diff --git a/python/xrefstructs.json b/python/xrefstructs.json new file mode 100644 index 0000000000..25c48c9d56 --- /dev/null +++ b/python/xrefstructs.json @@ -0,0 +1,140 @@ +{ + "cmd_element": { + "fields": [ + { + "name": "string", + "type": "const char *" + }, + { + "name": "doc", + "type": "const char *" + }, + { + "name": "daemon", + "type": "int" + }, + { + "name": "attr", + "type": "uint32_t" + }, + { + "name": "func", + "type": "int *" + }, + { + "name": "name", + "type": "const char *" + }, + { + "name": "xref", + "type": "struct xref" + } + ] + }, + "xref": { + "fields": [ + { + "name": "xrefdata", + "type": "struct xrefdata *" + }, + { + "name": "type", + "type": "enum xref_type" + }, + { + "name": "line", + "type": "int" + }, + { + "name": "file", + "type": "const char *" + }, + { + "name": "func", + "type": "const char *" + } + ] + }, + "xref_install_element": { + "fields": [ + { + "name": "xref", + "type": "struct xref" + }, + { + "name": "cmd_element", + "type": "const struct cmd_element *" + }, + { + "name": "node_type", + "type": "enum node_type" + } + ] + }, + "xref_logmsg": { + "fields": [ + { + "name": "xref", + "type": "struct xref" + }, + { + "name": "fmtstring", + "type": "const char *" + }, + { + "name": "priority", + "type": "uint32_t" + }, + { + "name": "ec", + "type": "uint32_t" + }, + { + "name": "args", + "type": "const char *" + } + ] + }, + "xref_threadsched": { + "fields": [ + { + "name": "xref", + "type": "struct xref" + }, + { + "name": "funcname", + "type": "const char *" + }, + { + "name": "dest", + "type": "const char *" + }, + { + "name": "thread_type", + "type": "uint32_t" + } + ] + }, + "xrefdata": { + "fields": [ + { + "name": "xref", + "type": "const struct xref *" + }, + { + "array": 16, + "name": "uid", + "type": "char" + }, + { + "name": "hashstr", + "type": "const char *" + }, + { + "array": 2, + "name": "hashu32", + "type": "uint32_t" + } + ] + } +}
\ No newline at end of file diff --git a/python/xrelfo.py b/python/xrelfo.py new file mode 100644 index 0000000000..0ecd008579 --- /dev/null +++ b/python/xrelfo.py @@ -0,0 +1,424 @@ +# FRR ELF xref extractor +# +# Copyright (C) 2020 David Lamparter for 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 + +import sys +import os +import struct +import re +import traceback +import json +import argparse + +from clippy.uidhash import uidhash +from clippy.elf import * +from clippy import frr_top_src +from tiabwarfo import FieldApplicator + +try: + with open(os.path.join(frr_top_src, 'python', 'xrefstructs.json'), 'r') as fd: + xrefstructs = json.load(fd) +except FileNotFoundError: + sys.stderr.write(''' +The "xrefstructs.json" file (created by running tiabwarfo.py with the pahole +tool available) could not be found. It should be included with the sources. +''') + sys.exit(1) + +# constants, need to be kept in sync manually... + +XREFT_THREADSCHED = 0x100 +XREFT_LOGMSG = 0x200 +XREFT_DEFUN = 0x300 +XREFT_INSTALL_ELEMENT = 0x301 + +# LOG_* +priovals = {} +prios = ['0', '1', '2', 'E', 'W', 'N', 'I', 'D'] + + +class XrelfoJson(object): + def dump(self): + pass + + def check(self, wopt): + yield from [] + + def to_dict(self, refs): + pass + +class Xref(ELFDissectStruct, XrelfoJson): + struct = 'xref' + fieldrename = {'type': 'typ'} + containers = {} + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + self._container = None + if self.xrefdata: + self.xrefdata.ref_from(self, self.typ) + + def container(self): + if self._container is None: + if self.typ in self.containers: + self._container = self.container_of(self.containers[self.typ], 'xref') + return self._container + + def check(self, *args, **kwargs): + if self._container: + yield from self._container.check(*args, **kwargs) + + +class Xrefdata(ELFDissectStruct): + struct = 'xrefdata' + + # uid is all zeroes in the data loaded from ELF + fieldrename = {'uid': '_uid'} + + def ref_from(self, xref, typ): + self.xref = xref + + @property + def uid(self): + if self.hashstr is None: + return None + return uidhash(self.xref.file, self.hashstr, self.hashu32_0, self.hashu32_1) + +class XrefPtr(ELFDissectStruct): + fields = [ + ('xref', 'P', Xref), + ] + +class XrefThreadSched(ELFDissectStruct, XrelfoJson): + struct = 'xref_threadsched' +Xref.containers[XREFT_THREADSCHED] = XrefThreadSched + +class XrefLogmsg(ELFDissectStruct, XrelfoJson): + struct = 'xref_logmsg' + + def _warn_fmt(self, text): + lines = text.split('\n') + yield ((self.xref.file, self.xref.line), '%s:%d: %s (in %s())%s\n' % (self.xref.file, self.xref.line, lines[0], self.xref.func, ''.join(['\n' + l for l in lines[1:]]))) + + fmt_regexes = [ + (re.compile(r'([\n\t]+)'), 'error: log message contains tab or newline'), + # (re.compile(r'^(\s+)'), 'warning: log message starts with whitespace'), + (re.compile(r'^((?:warn(?:ing)?|error):\s*)', re.I), 'warning: log message starts with severity'), + ] + arg_regexes = [ + # the (?<![\?:] ) avoids warning for x ? inet_ntop(...) : "(bla)" + (re.compile(r'((?<![\?:] )inet_ntop\s*\(\s*(?:[AP]F_INET|2)\s*,)'), 'cleanup: replace inet_ntop(AF_INET, ...) with %pI4', lambda s: True), + (re.compile(r'((?<![\?:] )inet_ntop\s*\(\s*(?:[AP]F_INET6|10)\s*,)'), 'cleanup: replace inet_ntop(AF_INET6, ...) with %pI6', lambda s: True), + (re.compile(r'((?<![\?:] )inet_ntoa)'), 'cleanup: replace inet_ntoa(...) with %pI4', lambda s: True), + (re.compile(r'((?<![\?:] )ipaddr2str)'), 'cleanup: replace ipaddr2str(...) with %pIA', lambda s: True), + (re.compile(r'((?<![\?:] )prefix2str)'), 'cleanup: replace prefix2str(...) with %pFX', lambda s: True), + (re.compile(r'((?<![\?:] )prefix_mac2str)'), 'cleanup: replace prefix_mac2str(...) with %pEA', lambda s: True), + (re.compile(r'((?<![\?:] )sockunion2str)'), 'cleanup: replace sockunion2str(...) with %pSU', lambda s: True), + + # (re.compile(r'^(\s*__(?:func|FUNCTION|PRETTY_FUNCTION)__\s*)'), 'error: debug message starts with __func__', lambda s: (s.priority & 7 == 7) ), + ] + + def check(self, wopt): + def fmt_msg(rex, itext): + if sys.stderr.isatty(): + items = rex.split(itext) + out = [] + for i, text in enumerate(items): + if (i % 2) == 1: + out.append('\033[41;37;1m%s\033[m' % repr(text)[1:-1]) + else: + out.append(repr(text)[1:-1]) + + excerpt = ''.join(out) + else: + excerpt = repr(itext)[1:-1] + return excerpt + + if wopt.Wlog_format: + for rex, msg in self.fmt_regexes: + if not rex.search(self.fmtstring): + continue + + excerpt = fmt_msg(rex, self.fmtstring) + yield from self._warn_fmt('%s: "%s"' % (msg, excerpt)) + + if wopt.Wlog_args: + for rex, msg, cond in self.arg_regexes: + if not cond(self): + continue + if not rex.search(self.args): + continue + + excerpt = fmt_msg(rex, self.args) + yield from self._warn_fmt('%s:\n\t"%s",\n\t%s' % (msg, repr(self.fmtstring)[1:-1], excerpt)) + + def dump(self): + print('%-60s %s%s %-25s [EC %d] %s' % ( + '%s:%d %s()' % (self.xref.file, self.xref.line, self.xref.func), + prios[self.priority & 7], + priovals.get(self.priority & 0x30, ' '), + self.xref.xrefdata.uid, self.ec, self.fmtstring)) + + def to_dict(self, xrelfo): + jsobj = dict([(i, getattr(self.xref, i)) for i in ['file', 'line', 'func']]) + if self.ec != 0: + jsobj['ec'] = self.ec + jsobj['fmtstring'] = self.fmtstring + jsobj['args'] = self.args + jsobj['priority'] = self.priority & 7 + jsobj['type'] = 'logmsg' + jsobj['binary'] = self._elfsect._elfwrap.orig_filename + + if self.priority & 0x10: + jsobj.setdefault('flags', []).append('errno') + if self.priority & 0x20: + jsobj.setdefault('flags', []).append('getaddrinfo') + + xrelfo['refs'].setdefault(self.xref.xrefdata.uid, []).append(jsobj) + +Xref.containers[XREFT_LOGMSG] = XrefLogmsg + +class CmdElement(ELFDissectStruct, XrelfoJson): + struct = 'cmd_element' + + cmd_attrs = { 0: None, 1: 'deprecated', 2: 'hidden'} + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + def to_dict(self, xrelfo): + jsobj = xrelfo['cli'].setdefault(self.name, {}).setdefault(self._elfsect._elfwrap.orig_filename, {}) + + jsobj.update({ + 'string': self.string, + 'doc': self.doc, + 'attr': self.cmd_attrs.get(self.attr, self.attr), + }) + if jsobj['attr'] is None: + del jsobj['attr'] + + jsobj['defun'] = dict([(i, getattr(self.xref, i)) for i in ['file', 'line', 'func']]) + +Xref.containers[XREFT_DEFUN] = CmdElement + +class XrefInstallElement(ELFDissectStruct, XrelfoJson): + struct = 'xref_install_element' + + def to_dict(self, xrelfo): + jsobj = xrelfo['cli'].setdefault(self.cmd_element.name, {}).setdefault(self._elfsect._elfwrap.orig_filename, {}) + nodes = jsobj.setdefault('nodes', []) + + nodes.append({ + 'node': self.node_type, + 'install': dict([(i, getattr(self.xref, i)) for i in ['file', 'line', 'func']]), + }) + +Xref.containers[XREFT_INSTALL_ELEMENT] = XrefInstallElement + +# shove in field defs +fieldapply = FieldApplicator(xrefstructs) +fieldapply.add(Xref) +fieldapply.add(Xrefdata) +fieldapply.add(XrefLogmsg) +fieldapply.add(XrefThreadSched) +fieldapply.add(CmdElement) +fieldapply.add(XrefInstallElement) +fieldapply() + + +class Xrelfo(dict): + def __init__(self): + super().__init__({ + 'refs': {}, + 'cli': {}, + }) + self._xrefs = [] + + def load_file(self, filename): + orig_filename = filename + if filename.endswith('.la') or filename.endswith('.lo'): + with open(filename, 'r') as fd: + for line in fd: + line = line.strip() + if line.startswith('#') or line == '' or '=' not in line: + continue + + var, val = line.split('=', 1) + if var not in ['library_names', 'pic_object']: + continue + if val.startswith("'") or val.startswith('"'): + val = val[1:-1] + + if var == 'pic_object': + filename = os.path.join(os.path.dirname(filename), val) + break + + val = val.strip().split()[0] + filename = os.path.join(os.path.dirname(filename), '.libs', val) + break + else: + raise ValueError('could not process libtool file "%s"' % orig_filename) + + while True: + with open(filename, 'rb') as fd: + hdr = fd.read(4) + + if hdr == b'\x7fELF': + self.load_elf(filename, orig_filename) + return + + if hdr[:2] == b'#!': + path, name = os.path.split(filename) + filename = os.path.join(path, '.libs', name) + continue + + if hdr[:1] == b'{': + with open(filename, 'r') as fd: + self.load_json(fd) + return + + raise ValueError('cannot determine file type for %s' % (filename)) + + def load_elf(self, filename, orig_filename): + edf = ELFDissectFile(filename) + edf.orig_filename = orig_filename + + note = edf._elffile.find_note('FRRouting', 'XREF') + if note is not None: + endian = '>' if edf._elffile.bigendian else '<' + mem = edf._elffile[note] + if edf._elffile.elfclass == 64: + start, end = struct.unpack(endian + 'QQ', mem) + start += note.start + end += note.start + 8 + else: + start, end = struct.unpack(endian + 'II', mem) + start += note.start + end += note.start + 4 + + ptrs = edf.iter_data(XrefPtr, slice(start, end)) + + else: + xrefarray = edf.get_section('xref_array') + if xrefarray is None: + raise ValueError('file has neither xref note nor xref_array section') + + ptrs = xrefarray.iter_data(XrefPtr) + + for ptr in ptrs: + if ptr.xref is None: + print('NULL xref') + continue + self._xrefs.append(ptr.xref) + + container = ptr.xref.container() + if container is None: + continue + container.to_dict(self) + + return edf + + def load_json(self, fd): + data = json.load(fd) + for uid, items in data['refs'].items(): + myitems = self['refs'].setdefault(uid, []) + for item in items: + if item in myitems: + continue + myitems.append(item) + + for cmd, items in data['cli'].items(): + self['cli'].setdefault(cmd, {}).update(items) + + return data + + def check(self, checks): + for xref in self._xrefs: + yield from xref.check(checks) + +def main(): + argp = argparse.ArgumentParser(description = 'FRR xref ELF extractor') + argp.add_argument('-o', dest='output', type=str, help='write JSON output') + argp.add_argument('--out-by-file', type=str, help='write by-file JSON output') + argp.add_argument('-Wlog-format', action='store_const', const=True) + argp.add_argument('-Wlog-args', action='store_const', const=True) + argp.add_argument('--profile', action='store_const', const=True) + argp.add_argument('binaries', metavar='BINARY', nargs='+', type=str, help='files to read (ELF files or libtool objects)') + args = argp.parse_args() + + if args.profile: + import cProfile + cProfile.runctx('_main(args)', globals(), {'args': args}, sort='cumtime') + else: + _main(args) + +def _main(args): + errors = 0 + xrelfo = Xrelfo() + + for fn in args.binaries: + try: + xrelfo.load_file(fn) + except: + errors += 1 + sys.stderr.write('while processing %s:\n' % (fn)) + traceback.print_exc() + + for option in dir(args): + if option.startswith('W'): + checks = sorted(xrelfo.check(args)) + sys.stderr.write(''.join([c[-1] for c in checks])) + break + + + refs = xrelfo['refs'] + + counts = {} + for k, v in refs.items(): + strs = set([i['fmtstring'] for i in v]) + if len(strs) != 1: + print('\033[31;1m%s\033[m' % k) + counts[k] = len(v) + + out = xrelfo + outbyfile = {} + for uid, locs in refs.items(): + for loc in locs: + filearray = outbyfile.setdefault(loc['file'], []) + loc = dict(loc) + del loc['file'] + filearray.append(loc) + + for k in outbyfile.keys(): + outbyfile[k] = sorted(outbyfile[k], key=lambda x: x['line']) + + if errors: + sys.exit(1) + + if args.output: + with open(args.output + '.tmp', 'w') as fd: + json.dump(out, fd, indent=2, sort_keys=True) + os.rename(args.output + '.tmp', args.output) + + if args.out_by_file: + with open(args.out_by_file + '.tmp', 'w') as fd: + json.dump(outbyfile, fd, indent=2, sort_keys=True) + os.rename(args.out_by_file + '.tmp', args.out_by_file) + +if __name__ == '__main__': + main() diff --git a/redhat/frr.spec.in b/redhat/frr.spec.in index 02c272f47c..b6d7ab2416 100644 --- a/redhat/frr.spec.in +++ b/redhat/frr.spec.in @@ -698,6 +698,7 @@ fi %endif %if %{with_pathd} %{_sbindir}/pathd + %{_libdir}/frr/modules/pathd_pcep.so %endif %{_libdir}/libfrr.so* %{_libdir}/libfrrcares* 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..37bce7484c 100644 --- a/ripd/rip_snmp.c +++ b/ripd/rip_snmp.c @@ -589,4 +589,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 a276dedec8..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, @@ -698,7 +698,6 @@ static void rip_packet_dump(struct rip_packet *packet, int size, caddr_t lim; struct rte *rte; const char *command_str; - char pbuf[BUFSIZ], nbuf[BUFSIZ]; uint8_t netmask = 0; uint8_t *p; @@ -766,24 +765,18 @@ static void rip_packet_dump(struct rip_packet *packet, int size, } } else zlog_debug( - " %s/%d -> %s family %d tag %" ROUTE_TAG_PRI + " %pI4/%d -> %pI4 family %d tag %" ROUTE_TAG_PRI " metric %ld", - inet_ntop(AF_INET, &rte->prefix, pbuf, - BUFSIZ), - netmask, - inet_ntop(AF_INET, &rte->nexthop, nbuf, - BUFSIZ), + &rte->prefix, netmask, &rte->nexthop, ntohs(rte->family), (route_tag_t)ntohs(rte->tag), (unsigned long)ntohl(rte->metric)); } else { - zlog_debug( - " %s family %d tag %" ROUTE_TAG_PRI - " metric %ld", - inet_ntop(AF_INET, &rte->prefix, pbuf, BUFSIZ), - ntohs(rte->family), - (route_tag_t)ntohs(rte->tag), - (unsigned long)ntohl(rte->metric)); + zlog_debug(" %pI4 family %d tag %" ROUTE_TAG_PRI + " metric %ld", + &rte->prefix, ntohs(rte->family), + (route_tag_t)ntohs(rte->tag), + (unsigned long)ntohl(rte->metric)); } } } 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..479fcaeb54 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) { 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 a9f570598f..749feaca6c 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, @@ -351,8 +351,6 @@ void ripng_packet_dump(struct ripng_packet *packet, int size, static void ripng_nexthop_rte(struct rte *rte, struct sockaddr_in6 *from, struct ripng_nexthop *nexthop) { - char buf[INET6_BUFSIZ]; - /* Logging before checking RTE. */ if (IS_RIPNG_DEBUG_RECV) zlog_debug("RIPng nexthop RTE address %s tag %" ROUTE_TAG_PRI @@ -398,9 +396,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 %s", - inet6_ntoa(rte->addr), - inet_ntop(AF_INET6, &from->sin6_addr, buf, INET6_BUFSIZ)); + zlog_warn("RIPng nexthop RTE with non link-local address %s from %pI6", + inet6_ntoa(rte->addr), &from->sin6_addr); nexthop->flag = RIPNG_NEXTHOP_UNSPEC; memset(&nexthop->address, 0, sizeof(struct in6_addr)); 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..ecb7053fd6 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 */ diff --git a/sharpd/sharp_main.c b/sharpd/sharp_main.c index fe7f9851f9..a1216247c0 100644 --- a/sharpd/sharp_main.c +++ b/sharpd/sharp_main.c @@ -49,7 +49,7 @@ #include "sharp_globals.h" #include "sharp_nht.h" -DEFINE_MGROUP(SHARPD, "sharpd") +DEFINE_MGROUP(SHARPD, "sharpd"); zebra_capabilities_t _caps_p[] = { }; @@ -129,7 +129,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; 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_zebra.c b/sharpd/sharp_zebra.c index fed732b843..73bbaf0bc0 100644 --- a/sharpd/sharp_zebra.c +++ b/sharpd/sharp_zebra.c @@ -638,7 +638,6 @@ void sharp_zebra_nexthop_watch(struct prefix *p, vrf_id_t vrf_id, bool import, static int sharp_debug_nexthops(struct zapi_route *api) { int i; - char buf[PREFIX_STRLEN]; if (api->nexthop_num == 0) { zlog_debug( @@ -653,20 +652,16 @@ static int sharp_debug_nexthops(struct zapi_route *api) case NEXTHOP_TYPE_IPV4_IFINDEX: case NEXTHOP_TYPE_IPV4: zlog_debug( - " Nexthop %s, type: %d, ifindex: %d, vrf: %d, label_num: %d", - inet_ntop(AF_INET, &znh->gate.ipv4.s_addr, buf, - sizeof(buf)), - znh->type, znh->ifindex, znh->vrf_id, - znh->label_num); + " Nexthop %pI4, type: %d, ifindex: %d, vrf: %d, label_num: %d", + &znh->gate.ipv4.s_addr, znh->type, znh->ifindex, + znh->vrf_id, znh->label_num); break; case NEXTHOP_TYPE_IPV6_IFINDEX: case NEXTHOP_TYPE_IPV6: zlog_debug( - " Nexthop %s, type: %d, ifindex: %d, vrf: %d, label_num: %d", - inet_ntop(AF_INET6, &znh->gate.ipv6, buf, - sizeof(buf)), - znh->type, znh->ifindex, znh->vrf_id, - znh->label_num); + " Nexthop %pI6, type: %d, ifindex: %d, vrf: %d, label_num: %d", + &znh->gate.ipv6, znh->type, znh->ifindex, + znh->vrf_id, znh->label_num); break; case NEXTHOP_TYPE_IFINDEX: zlog_debug(" Nexthop IFINDEX: %d, ifindex: %d", @@ -690,7 +685,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; 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_memory.h b/staticd/static_memory.h deleted file mode 100644 index 077cd0f32b..0000000000 --- a/staticd/static_memory.h +++ /dev/null @@ -1,30 +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 - */ -#ifndef __STATIC_MEMORY_H__ - -#include "memory.h" - -DECLARE_MGROUP(STATIC) - -DECLARE_MTYPE(STATIC_ROUTE); -DECLARE_MTYPE(STATIC_NEXTHOP); -DECLARE_MTYPE(STATIC_PATH); - -#endif diff --git a/staticd/static_nb_config.c b/staticd/static_nb_config.c index 3f1d0aa496..db154992f9 100644 --- a/staticd/static_nb_config.c +++ b/staticd/static_nb_config.c @@ -103,10 +103,32 @@ static void static_path_list_tag_modify(struct nb_cb_modify_args *args, static_install_path(rn, pn, info->safi, info->svrf); } +struct nexthop_iter { + int count; + bool blackhole; +}; + +static int nexthop_iter_cb(const struct lyd_node *dnode, void *arg) +{ + struct nexthop_iter *iter = arg; + int nh_type; + + nh_type = yang_dnode_get_enum(dnode, "./nh-type"); + + if (nh_type == STATIC_BLACKHOLE) + iter->blackhole = true; + + iter->count++; + + return YANG_ITER_CONTINUE; +} + static bool static_nexthop_create(struct nb_cb_create_args *args, const struct lyd_node *rn_dnode, struct stable_info *info) { + const struct lyd_node *pn_dnode; + struct nexthop_iter iter; struct route_node *rn; struct static_path *pn; struct ipaddr ipaddr; @@ -128,6 +150,20 @@ static bool static_nexthop_create(struct nb_cb_create_args *args, return NB_ERR_VALIDATION; } } + + iter.count = 0; + iter.blackhole = false; + + pn_dnode = yang_dnode_get_parent(args->dnode, "path-list"); + yang_dnode_iterate(nexthop_iter_cb, &iter, pn_dnode, + "./frr-nexthops/nexthop"); + + if (iter.blackhole && iter.count > 1) { + snprintf( + args->errmsg, args->errmsg_len, + "Route can not have blackhole and non-blackhole nexthops simultaneously"); + return NB_ERR_VALIDATION; + } break; case NB_EV_PREPARE: case NB_EV_ABORT: diff --git a/staticd/static_routes.c b/staticd/static_routes.c index 9f7e19660d..739c08b09e 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, 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..ba1367b877 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; diff --git a/staticd/static_vty.c b/staticd/static_vty.c index 1488cc1775..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" @@ -294,8 +293,11 @@ static int static_route_leak(struct vty *vty, const char *svrf, buf_gate_str, ifname); dnode = yang_dnode_get(vty->candidate_config->dnode, ab_xpath); - if (!dnode) + if (!dnode) { + vty_out(vty, + "%% Refusing to remove a non-existent route\n"); return ret; + } dnode = yang_get_subtree_with_no_sibling(dnode); assert(dnode); 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/bgpd/test_aspath.c b/tests/bgpd/test_aspath.c index 936ffaaad5..1a9183c472 100644 --- a/tests/bgpd/test_aspath.c +++ b/tests/bgpd/test_aspath.c @@ -892,7 +892,7 @@ static int validate(struct aspath *as, const struct test_spec *sp) /* Excercise AS4 parsing a bit, with a dogfood test */ if (!s) - s = stream_new(4096); + s = stream_new(BGP_MAX_EXTENDED_MESSAGE_PACKET_SIZE); bytes4 = aspath_put(s, as, 1); as4 = make_aspath(STREAM_DATA(s), bytes4, 1); @@ -1201,12 +1201,13 @@ static int handle_attr_test(struct aspath_tests *t) asp = make_aspath(t->segment->asdata, t->segment->len, 0); - peer.curr = stream_new(BGP_MAX_PACKET_SIZE); + peer.curr = stream_new(BGP_MAX_EXTENDED_MESSAGE_PACKET_SIZE); peer.obuf = stream_fifo_new(); peer.bgp = &bgp; peer.host = (char *)"none"; peer.fd = -1; peer.cap = t->cap; + peer.max_packet_size = BGP_MAX_PACKET_SIZE; stream_write(peer.curr, t->attrheader, t->len); datalen = aspath_put(peer.curr, asp, t->as4 == AS4_DATA); diff --git a/tests/bgpd/test_capability.c b/tests/bgpd/test_capability.c index 153b83897d..91c0cce80c 100644 --- a/tests/bgpd/test_capability.c +++ b/tests/bgpd/test_capability.c @@ -935,7 +935,7 @@ int main(void) peer->afc_adv[i][j] = 1; } - peer->curr = stream_new(BGP_MAX_PACKET_SIZE); + peer->curr = stream_new(BGP_MAX_EXTENDED_MESSAGE_PACKET_SIZE); i = 0; while (mp_segments[i].name) diff --git a/tests/bgpd/test_mp_attr.c b/tests/bgpd/test_mp_attr.c index f510760913..8de0604c45 100644 --- a/tests/bgpd/test_mp_attr.c +++ b/tests/bgpd/test_mp_attr.c @@ -1100,7 +1100,7 @@ int main(void) peer = peer_create_accept(bgp); peer->host = (char *)"foo"; peer->status = Established; - peer->curr = stream_new(BGP_MAX_PACKET_SIZE); + peer->curr = stream_new(BGP_MAX_EXTENDED_MESSAGE_PACKET_SIZE); ifp.ifindex = 0; peer->nexthop.ifp = &ifp; diff --git a/tests/isisd/test_isis_spf.refout b/tests/isisd/test_isis_spf.refout index 024f7256e0..bdd5b2e439 100644 --- a/tests/isisd/test_isis_spf.refout +++ b/tests/isisd/test_isis_spf.refout @@ -3146,9 +3146,9 @@ rt3 TE-IS 50 rt5 - rt5(4) IS-IS L1 IPv4 routing table:
- Prefix Metric Interface Nexthop Label(s)
- -----------------------------------------------------------
- 10.0.255.3/32 60 - rt5 16050/18/16030
+ Prefix Metric Interface Nexthop Label(s)
+ -----------------------------------------------------
+ 10.0.255.3/32 60 - rt5 16050/18
P-space (self):
rt2
@@ -3194,9 +3194,9 @@ rt3 TE-IS 50 rt5 - rt5(4) IS-IS L1 IPv6 routing table:
- Prefix Metric Interface Nexthop Label(s)
- -------------------------------------------------------------
- 2001:db8::3/128 60 - rt5 16051/19/16031
+ Prefix Metric Interface Nexthop Label(s)
+ -------------------------------------------------------
+ 2001:db8::3/128 60 - rt5 16051/19
test# test isis topology 2 root rt1 ti-lfa system-id rt1 pseudonode-id 1
P-space (self):
@@ -3236,7 +3236,7 @@ IS-IS L1 IPv4 routing table: Prefix Metric Interface Nexthop Label(s)
-----------------------------------------------------------
- 10.0.255.4/32 65 - rt2 16020/18/16040
+ 10.0.255.4/32 65 - rt2 16020/18
10.0.255.5/32 75 - rt2 16020/18/16050
10.0.255.6/32 75 - rt2 16020/18/16060
@@ -3277,7 +3277,7 @@ IS-IS L1 IPv6 routing table: Prefix Metric Interface Nexthop Label(s)
-------------------------------------------------------------
- 2001:db8::4/128 65 - rt2 16021/19/16041
+ 2001:db8::4/128 65 - rt2 16021/19
2001:db8::5/128 75 - rt2 16021/19/16051
2001:db8::6/128 75 - rt2 16021/19/16061
@@ -3508,7 +3508,7 @@ IS-IS L1 IPv4 routing table: -----------------------------------------------------------
10.0.255.2/32 100 - rt3 16050/17/16020
10.0.255.4/32 90 - rt3 16050/17/16040
- 10.0.255.6/32 80 - rt3 16050/17/16060
+ 10.0.255.6/32 80 - rt3 16050/17
10.0.255.8/32 90 - rt3 16050/17/16080
test# test isis topology 4 root rt4 ti-lfa system-id rt6 ipv4-only
@@ -3553,7 +3553,7 @@ IS-IS L1 IPv4 routing table: Prefix Metric Interface Nexthop Label(s)
-----------------------------------------------------------
- 10.0.255.6/32 100 - rt2 16050/17/16060
+ 10.0.255.6/32 100 - rt2 16050/17
10.0.255.8/32 110 - rt2 16050/17/16080
test# test isis topology 5 root rt1 ti-lfa system-id rt2 ipv4-only
@@ -3865,7 +3865,7 @@ IS-IS L1 IPv4 routing table: 10.0.255.1/32 100 - rt5 16110/17/16010
10.0.255.4/32 90 - rt5 16110/17/16040
10.0.255.7/32 80 - rt5 16110/17/16070
- 10.0.255.10/32 70 - rt5 16110/17/16100
+ 10.0.255.10/32 70 - rt5 16110/17
test# test isis topology 8 root rt2 ti-lfa system-id rt5 ipv4-only
P-space (self):
@@ -3979,9 +3979,9 @@ rt3 TE-IS 120 rt2 - rt4(4) IS-IS L1 IPv4 routing table:
- Prefix Metric Interface Nexthop Label(s)
- -----------------------------------------------------------
- 10.0.255.3/32 130 - rt2 16040/18/16030
+ Prefix Metric Interface Nexthop Label(s)
+ -----------------------------------------------------
+ 10.0.255.3/32 130 - rt2 16040/18
P-space (self):
rt2
@@ -4030,9 +4030,9 @@ rt3 TE-IS 120 rt2 - rt4(4) IS-IS L1 IPv6 routing table:
- Prefix Metric Interface Nexthop Label(s)
- -------------------------------------------------------------
- 2001:db8::3/128 130 - rt2 16041/19/16031
+ Prefix Metric Interface Nexthop Label(s)
+ -------------------------------------------------------
+ 2001:db8::3/128 130 - rt2 16041/19
test# test isis topology 9 root rt1 ti-lfa system-id rt2
P-space (self):
@@ -4079,7 +4079,7 @@ IS-IS L1 IPv4 routing table: Prefix Metric Interface Nexthop Label(s)
-----------------------------------------------------------
10.0.255.2/32 130 - rt3 16030/18/16020
- 10.0.255.4/32 120 - rt3 16030/18/16040
+ 10.0.255.4/32 120 - rt3 16030/18
10.0.255.5/32 130 - rt3 16030/18/16050
10.0.255.6/32 150 - rt3 16030/18/16060
10.0.255.7/32 150 - rt3 16030/18/16070
@@ -4130,7 +4130,7 @@ IS-IS L1 IPv6 routing table: Prefix Metric Interface Nexthop Label(s)
-------------------------------------------------------------
2001:db8::2/128 130 - rt3 16031/19/16021
- 2001:db8::4/128 120 - rt3 16031/19/16041
+ 2001:db8::4/128 120 - rt3 16031/19
2001:db8::5/128 130 - rt3 16031/19/16051
2001:db8::6/128 150 - rt3 16031/19/16061
2001:db8::7/128 150 - rt3 16031/19/16071
@@ -4213,9 +4213,9 @@ IS-IS L1 IPv4 routing table: 10.0.255.3/32 80 - rt6 16060/16/16030
- rt7 16070/16/16030
- rt8 16080/16/16030
- 10.0.255.4/32 50 - rt6 16060/16/16040
- - rt7 16070/16/16040
- - rt8 16080/16/16040
+ 10.0.255.4/32 50 - rt6 16060/16
+ - rt7 16070/16
+ - rt8 16080/16
10.0.255.5/32 60 - rt6 16060/16/16050
- rt7 16070/16/16050
- rt8 16080/16/16050
@@ -4295,9 +4295,9 @@ IS-IS L1 IPv6 routing table: 2001:db8::3/128 80 - rt6 16061/17/16031
- rt7 16071/17/16031
- rt8 16081/17/16031
- 2001:db8::4/128 50 - rt6 16061/17/16041
- - rt7 16071/17/16041
- - rt8 16081/17/16041
+ 2001:db8::4/128 50 - rt6 16061/17
+ - rt7 16071/17
+ - rt8 16081/17
2001:db8::5/128 60 - rt6 16061/17/16051
- rt7 16071/17/16051
- rt8 16081/17/16051
@@ -4351,9 +4351,9 @@ rt3 TE-IS 50 rt5 - rt1(4) IS-IS L1 IPv4 routing table:
- Prefix Metric Interface Nexthop Label(s)
- -----------------------------------------------------------
- 10.0.255.8/32 60 - rt5 16040/26/16080
+ Prefix Metric Interface Nexthop Label(s)
+ -----------------------------------------------------
+ 10.0.255.8/32 60 - rt5 16040/26
P-space (self):
rt1
@@ -4403,9 +4403,9 @@ rt3 TE-IS 50 rt5 - rt1(4) IS-IS L1 IPv6 routing table:
- Prefix Metric Interface Nexthop Label(s)
- -------------------------------------------------------------
- 2001:db8::8/128 60 - rt5 16041/27/16081
+ Prefix Metric Interface Nexthop Label(s)
+ -------------------------------------------------------
+ 2001:db8::8/128 60 - rt5 16041/27
test# test isis topology 10 root rt1 ti-lfa system-id rt2
P-space (self):
@@ -4460,8 +4460,8 @@ IS-IS L1 IPv4 routing table: - rt4 16070/18/16020
10.0.255.5/32 100 - rt3 20060/18/16050
- rt4 16070/18/16050
- 10.0.255.8/32 90 - rt3 20060/18/16080
- - rt4 16070/18/16080
+ 10.0.255.8/32 90 - rt3 20060/18
+ - rt4 16070/18
P-space (self):
rt3
@@ -4515,8 +4515,8 @@ IS-IS L1 IPv6 routing table: - rt4 16071/19/16021
2001:db8::5/128 100 - rt3 20061/19/16051
- rt4 16071/19/16051
- 2001:db8::8/128 90 - rt3 20061/19/16081
- - rt4 16071/19/16081
+ 2001:db8::8/128 90 - rt3 20061/19
+ - rt4 16071/19
test# test isis topology 10 root rt1 ti-lfa system-id rt4
P-space (self):
@@ -4563,7 +4563,7 @@ IS-IS L1 IPv4 routing table: Prefix Metric Interface Nexthop Label(s)
-----------------------------------------------------------
10.0.255.4/32 100 - rt2 16080/20/16040
- 10.0.255.7/32 90 - rt2 16080/20/16070
+ 10.0.255.7/32 90 - rt2 16080/20
P-space (self):
rt2
@@ -4609,7 +4609,7 @@ IS-IS L1 IPv6 routing table: Prefix Metric Interface Nexthop Label(s)
-------------------------------------------------------------
2001:db8::4/128 100 - rt2 16081/21/16041
- 2001:db8::7/128 90 - rt2 16081/21/16071
+ 2001:db8::7/128 90 - rt2 16081/21
test# test isis topology 11 root rt2 ti-lfa system-id rt4
P-space (self):
@@ -4747,12 +4747,12 @@ rt3 TE-IS 740 rt2 - rt5(4) IS-IS L1 IPv4 routing table:
- Prefix Metric Interface Nexthop Label(s)
- -----------------------------------------------------------------
- 10.0.255.3/32 750 - rt2 16080/17/16/16/16030
- 10.0.255.5/32 350 - rt2 16080/17/16/16050
- 10.0.255.7/32 150 - rt2 16080/17/16070
- 10.0.255.9/32 160 - rt2 16080/17/18/16090
+ Prefix Metric Interface Nexthop Label(s)
+ -----------------------------------------------------------
+ 10.0.255.3/32 750 - rt2 16080/17/16/16
+ 10.0.255.5/32 350 - rt2 16080/17/16
+ 10.0.255.7/32 150 - rt2 16080/17
+ 10.0.255.9/32 160 - rt2 16080/17/18
test# test isis topology 13 root rt1 ti-lfa system-id rt3 ipv4-only
P-space (self):
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_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/Dockerfile b/tests/topotests/Dockerfile index b7042d84c6..c9110d2db9 100644 --- a/tests/topotests/Dockerfile +++ b/tests/topotests/Dockerfile @@ -23,6 +23,7 @@ RUN export DEBIAN_FRONTEND=noninteractive \ libreadline-dev \ libc-ares-dev \ libcap-dev \ + libelf-dev \ man \ mininet \ pkg-config \ diff --git a/tests/topotests/all-protocol-startup/test_all_protocol_startup.py b/tests/topotests/all-protocol-startup/test_all_protocol_startup.py index f7ed29782d..c858571254 100644 --- a/tests/topotests/all-protocol-startup/test_all_protocol_startup.py +++ b/tests/topotests/all-protocol-startup/test_all_protocol_startup.py @@ -346,13 +346,15 @@ def test_converge_protocols(): print("Show that v4 routes are right\n") v4_routesFile = "%s/r%s/ipv4_routes.ref" % (thisDir, i) - expected = open(v4_routesFile).read().rstrip() + expected = net["r%s" % i].cmd( + "sort {} 2> /dev/null".format(v4_routesFile) + ).rstrip() expected = ("\n".join(expected.splitlines()) + "\n").splitlines(1) actual = ( net["r%s" % i] .cmd( - 'vtysh -c "show ip route" | sed -e \'/^Codes: /,/^\s*$/d\' | env LC_ALL=en_US.UTF-8 sort 2> /dev/null' + "vtysh -c \"show ip route\" | sed -e '/^Codes: /,/^\s*$/d' | sort 2> /dev/null" ) .rstrip() ) @@ -377,13 +379,15 @@ def test_converge_protocols(): print("Show that v6 routes are right\n") v6_routesFile = "%s/r%s/ipv6_routes.ref" % (thisDir, i) - expected = open(v6_routesFile).read().rstrip() + expected = net["r%s" % i].cmd( + "sort {} 2> /dev/null".format(v6_routesFile) + ).rstrip() expected = ("\n".join(expected.splitlines()) + "\n").splitlines(1) actual = ( net["r%s" % i] .cmd( - 'vtysh -c "show ipv6 route" | sed -e \'/^Codes: /,/^\s*$/d\' | env LC_ALL=en_US.UTF-8 sort 2> /dev/null' + "vtysh -c \"show ipv6 route\" | sed -e '/^Codes: /,/^\s*$/d' | sort 2> /dev/null" ) .rstrip() ) diff --git a/tests/topotests/bfd-bgp-cbit-topo3/r1/peers.json b/tests/topotests/bfd-bgp-cbit-topo3/r1/peers.json index d1927ae49a..b436d5562e 100644 --- a/tests/topotests/bfd-bgp-cbit-topo3/r1/peers.json +++ b/tests/topotests/bfd-bgp-cbit-topo3/r1/peers.json @@ -8,9 +8,10 @@ "remote-diagnostic":"ok", "receive-interval":300, "transmit-interval":300, - "echo-interval":0, + "echo-receive-interval":50, + "echo-transmit-interval":0, "remote-receive-interval":300, "remote-transmit-interval":300, - "remote-echo-interval":50 + "remote-echo-receive-interval":50 } ] diff --git a/tests/topotests/bfd-bgp-cbit-topo3/r1/peers_down.json b/tests/topotests/bfd-bgp-cbit-topo3/r1/peers_down.json index 25b47f18ec..c7c7b96ee7 100644 --- a/tests/topotests/bfd-bgp-cbit-topo3/r1/peers_down.json +++ b/tests/topotests/bfd-bgp-cbit-topo3/r1/peers_down.json @@ -6,9 +6,10 @@ "status":"up", "receive-interval":300, "transmit-interval":300, - "echo-interval":0, + "echo-receive-interval":50, + "echo-transmit-interval":0, "remote-receive-interval":300, "remote-transmit-interval":300, - "remote-echo-interval":50 + "remote-echo-receive-interval":50 } ] diff --git a/tests/topotests/bfd-bgp-cbit-topo3/r3/peers.json b/tests/topotests/bfd-bgp-cbit-topo3/r3/peers.json index 5193f2a6e2..fc9e145340 100644 --- a/tests/topotests/bfd-bgp-cbit-topo3/r3/peers.json +++ b/tests/topotests/bfd-bgp-cbit-topo3/r3/peers.json @@ -8,9 +8,10 @@ "remote-diagnostic":"ok", "receive-interval":300, "transmit-interval":300, - "echo-interval":0, + "echo-receive-interval":50, + "echo-transmit-interval":0, "remote-receive-interval":300, "remote-transmit-interval":300, - "remote-echo-interval":50 + "remote-echo-receive-interval":50 } ] diff --git a/tests/topotests/bfd-bgp-cbit-topo3/r3/peers_down.json b/tests/topotests/bfd-bgp-cbit-topo3/r3/peers_down.json index 9e4bd2633f..620c6ddcd4 100644 --- a/tests/topotests/bfd-bgp-cbit-topo3/r3/peers_down.json +++ b/tests/topotests/bfd-bgp-cbit-topo3/r3/peers_down.json @@ -6,9 +6,10 @@ "status":"down", "receive-interval":300, "transmit-interval":300, - "echo-interval":0, + "echo-receive-interval":50, + "echo-transmit-interval":0, "remote-receive-interval":300, "remote-transmit-interval":300, - "remote-echo-interval":50 + "remote-echo-receive-interval":50 } ] diff --git a/tests/topotests/bfd-bgp-cbit-topo3/test_bfd_bgp_cbit_topo3.py b/tests/topotests/bfd-bgp-cbit-topo3/test_bfd_bgp_cbit_topo3.py index 4c3bad1280..560d6eebec 100644 --- a/tests/topotests/bfd-bgp-cbit-topo3/test_bfd_bgp_cbit_topo3.py +++ b/tests/topotests/bfd-bgp-cbit-topo3/test_bfd_bgp_cbit_topo3.py @@ -44,7 +44,8 @@ from lib.topolog import logger # Required to instantiate the topology builder class. from mininet.topo import Topo -pytestmark = [pytest.mark.bfdd] +pytestmark = [pytest.mark.bgpd, pytest.mark.bfdd] + class BFDTopo(Topo): "Test topology builder" @@ -65,6 +66,7 @@ class BFDTopo(Topo): switch.add_link(tgen.gears["r2"]) switch.add_link(tgen.gears["r3"]) + def setup_module(mod): "Sets up the pytest environment" tgen = Topogen(BFDTopo, mod.__name__) diff --git a/tests/topotests/bfd-isis-topo1/test_bfd_isis_topo1.py b/tests/topotests/bfd-isis-topo1/test_bfd_isis_topo1.py index bb930141ac..fcb5672dce 100644 --- a/tests/topotests/bfd-isis-topo1/test_bfd_isis_topo1.py +++ b/tests/topotests/bfd-isis-topo1/test_bfd_isis_topo1.py @@ -92,6 +92,7 @@ from mininet.topo import Topo pytestmark = [pytest.mark.bfdd, pytest.mark.isisd] + class TemplateTopo(Topo): "Test topology builder" diff --git a/tests/topotests/bfd-ospf-topo1/test_bfd_ospf_topo1.py b/tests/topotests/bfd-ospf-topo1/test_bfd_ospf_topo1.py index 9ce14dd75e..ae148f948c 100755 --- a/tests/topotests/bfd-ospf-topo1/test_bfd_ospf_topo1.py +++ b/tests/topotests/bfd-ospf-topo1/test_bfd_ospf_topo1.py @@ -92,6 +92,7 @@ from mininet.topo import Topo pytestmark = [pytest.mark.bfdd, pytest.mark.ospfd] + class TemplateTopo(Topo): "Test topology builder" 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/bfdd.conf b/tests/topotests/bfd-profiles-topo1/r1/bfdd.conf index 4d636ab052..688f2e839c 100644 --- a/tests/topotests/bfd-profiles-topo1/r1/bfdd.conf +++ b/tests/topotests/bfd-profiles-topo1/r1/bfdd.conf @@ -6,6 +6,7 @@ bfd profile slowtx receive-interval 800 transmit-interval 800 + echo receive-interval 400 ! peer 172.16.0.1 interface r1-eth0 profile slowtx 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/r2/bfd-peers-initial.json b/tests/topotests/bfd-profiles-topo1/r2/bfd-peers-initial.json index 3df9ec9c9d..503f776aec 100644 --- a/tests/topotests/bfd-profiles-topo1/r2/bfd-peers-initial.json +++ b/tests/topotests/bfd-profiles-topo1/r2/bfd-peers-initial.json @@ -12,6 +12,7 @@ "remote-id": "*", "remote-receive-interval": 800, "remote-transmit-interval": 800, + "remote-echo-receive-interval": 400, "status": "up", "transmit-interval": 800, "uptime": "*", @@ -27,7 +28,7 @@ "receive-interval": 250, "remote-detect-multiplier": 3, "remote-diagnostic": "ok", - "remote-echo-interval": 50, + "remote-echo-receive-interval": 50, "remote-id": "*", "remote-receive-interval": 300, "remote-transmit-interval": 300, diff --git a/tests/topotests/bfd-profiles-topo1/r2/bfdd.conf b/tests/topotests/bfd-profiles-topo1/r2/bfdd.conf index 23a39a6ee0..700c46ba1e 100644 --- a/tests/topotests/bfd-profiles-topo1/r2/bfdd.conf +++ b/tests/topotests/bfd-profiles-topo1/r2/bfdd.conf @@ -10,6 +10,7 @@ bfd profile fasttx receive-interval 250 transmit-interval 250 + echo receive-interval disabled ! peer 172.16.0.2 interface r2-eth0 profile slowtx diff --git a/tests/topotests/bfd-profiles-topo1/r3/bfd-peers-initial.json b/tests/topotests/bfd-profiles-topo1/r3/bfd-peers-initial.json index d2d0c601c3..d987a0ae7d 100644 --- a/tests/topotests/bfd-profiles-topo1/r3/bfd-peers-initial.json +++ b/tests/topotests/bfd-profiles-topo1/r3/bfd-peers-initial.json @@ -12,6 +12,7 @@ "remote-id": "*", "remote-receive-interval": 250, "remote-transmit-interval": 250, + "remote-echo-receive-interval": 0, "status": "up", "transmit-interval": 300, "uptime": "*", diff --git a/tests/topotests/bfd-profiles-topo1/r4/bfd-peers-initial.json b/tests/topotests/bfd-profiles-topo1/r4/bfd-peers-initial.json index 2c2e136abf..c73296ac97 100644 --- a/tests/topotests/bfd-profiles-topo1/r4/bfd-peers-initial.json +++ b/tests/topotests/bfd-profiles-topo1/r4/bfd-peers-initial.json @@ -29,7 +29,7 @@ "receive-interval": 300, "remote-detect-multiplier": 3, "remote-diagnostic": "ok", - "remote-echo-interval": 50, + "remote-echo-receive-interval": 50, "remote-id": "*", "remote-receive-interval": 300, "remote-transmit-interval": 300, 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/bfd-profiles-topo1/test_bfd_profiles_topo1.py b/tests/topotests/bfd-profiles-topo1/test_bfd_profiles_topo1.py index 76e9ef247f..4a2c8ee002 100644 --- a/tests/topotests/bfd-profiles-topo1/test_bfd_profiles_topo1.py +++ b/tests/topotests/bfd-profiles-topo1/test_bfd_profiles_topo1.py @@ -45,7 +45,8 @@ from lib.topolog import logger # Required to instantiate the topology builder class. from mininet.topo import Topo -pytestmark = [pytest.mark.bfdd, pytest.mark.isisd, pytest.mark.ospfd] +pytestmark = [pytest.mark.bfdd, pytest.mark.bgpd, pytest.mark.isisd, pytest.mark.ospfd] + class BFDProfTopo(Topo): "Test topology builder" diff --git a/tests/topotests/bfd-topo1/r2/peers.json b/tests/topotests/bfd-topo1/r2/peers.json index 5035d643c5..267459c7a8 100644 --- a/tests/topotests/bfd-topo1/r2/peers.json +++ b/tests/topotests/bfd-topo1/r2/peers.json @@ -4,7 +4,7 @@ "status": "up" }, { - "remote-echo-interval": 100, + "remote-echo-receive-interval": 100, "peer": "192.168.1.1", "status": "up" }, diff --git a/tests/topotests/bfd-topo1/test_bfd_topo1.py b/tests/topotests/bfd-topo1/test_bfd_topo1.py index 76078b5d7d..86bdcfed04 100644 --- a/tests/topotests/bfd-topo1/test_bfd_topo1.py +++ b/tests/topotests/bfd-topo1/test_bfd_topo1.py @@ -45,7 +45,8 @@ from lib.topolog import logger # Required to instantiate the topology builder class. from mininet.topo import Topo -pytestmark = [pytest.mark.bfdd] +pytestmark = [pytest.mark.bfdd, pytest.mark.bgpd] + class BFDTopo(Topo): "Test topology builder" diff --git a/tests/topotests/bfd-topo2/r1/peers.json b/tests/topotests/bfd-topo2/r1/peers.json index b14351cd81..9bce991d0d 100644 --- a/tests/topotests/bfd-topo2/r1/peers.json +++ b/tests/topotests/bfd-topo2/r1/peers.json @@ -8,10 +8,11 @@ "remote-diagnostic":"ok", "receive-interval":300, "transmit-interval":300, - "echo-interval":0, + "echo-receive-interval":50, + "echo-transmit-interval":0, "remote-receive-interval":300, "remote-transmit-interval":300, - "remote-echo-interval":50 + "remote-echo-receive-interval":50 }, { "multihop":false, @@ -21,9 +22,10 @@ "remote-diagnostic":"ok", "receive-interval":300, "transmit-interval":300, - "echo-interval":0, + "echo-receive-interval":50, + "echo-transmit-interval":0, "remote-receive-interval":300, "remote-transmit-interval":300, - "remote-echo-interval":50 + "remote-echo-receive-interval":50 } ] diff --git a/tests/topotests/bfd-topo2/r2/peers.json b/tests/topotests/bfd-topo2/r2/peers.json index 29075fcc80..ec2135ce37 100644 --- a/tests/topotests/bfd-topo2/r2/peers.json +++ b/tests/topotests/bfd-topo2/r2/peers.json @@ -3,39 +3,42 @@ "status": "up", "transmit-interval": 300, "remote-receive-interval": 300, - "echo-interval": 0, + "echo-receive-interval": 50, + "echo-transmit-interval": 0, "diagnostic": "ok", "multihop": false, "interface": "r2-eth0", "remote-transmit-interval": 300, "receive-interval": 300, - "remote-echo-interval": 50, + "remote-echo-receive-interval": 50, "remote-diagnostic": "ok" }, { "status": "up", "transmit-interval": 300, "remote-receive-interval": 300, - "echo-interval": 0, + "echo-receive-interval": 50, + "echo-transmit-interval": 0, "diagnostic": "ok", "multihop": false, "interface": "r2-eth2", "remote-transmit-interval": 300, "receive-interval": 300, - "remote-echo-interval": 50, + "remote-echo-receive-interval": 50, "remote-diagnostic": "ok" }, { "status": "up", "transmit-interval": 300, "remote-receive-interval": 300, - "echo-interval": 0, + "echo-receive-interval": 50, + "echo-transmit-interval": 0, "diagnostic": "ok", "multihop": false, "interface": "r2-eth1", "remote-transmit-interval": 300, "receive-interval": 300, - "remote-echo-interval": 50, + "remote-echo-receive-interval": 50, "remote-diagnostic": "ok", "peer": "10.0.3.1" } diff --git a/tests/topotests/bfd-topo2/r3/peers.json b/tests/topotests/bfd-topo2/r3/peers.json index 6698bff201..c19c980338 100644 --- a/tests/topotests/bfd-topo2/r3/peers.json +++ b/tests/topotests/bfd-topo2/r3/peers.json @@ -3,13 +3,14 @@ "status": "up", "transmit-interval": 300, "remote-receive-interval": 300, - "echo-interval": 0, + "echo-receive-interval": 50, + "echo-transmit-interval": 0, "diagnostic": "ok", "multihop": false, "interface": "r3-eth0", "remote-transmit-interval": 300, "receive-interval": 300, - "remote-echo-interval": 50, + "remote-echo-receive-interval": 50, "remote-diagnostic": "ok", "peer": "10.0.3.2" } diff --git a/tests/topotests/bfd-topo2/r4/peers.json b/tests/topotests/bfd-topo2/r4/peers.json index 83101eb47f..dd26b9b580 100644 --- a/tests/topotests/bfd-topo2/r4/peers.json +++ b/tests/topotests/bfd-topo2/r4/peers.json @@ -8,10 +8,11 @@ "remote-diagnostic":"ok", "receive-interval":300, "transmit-interval":300, - "echo-interval":0, + "echo-receive-interval": 50, + "echo-transmit-interval":0, "remote-receive-interval":300, "remote-transmit-interval":300, - "remote-echo-interval":50 + "remote-echo-receive-interval":50 }, { "multihop":false, @@ -21,9 +22,10 @@ "remote-diagnostic":"ok", "receive-interval":300, "transmit-interval":300, - "echo-interval":0, + "echo-receive-interval": 50, + "echo-transmit-interval":0, "remote-receive-interval":300, "remote-transmit-interval":300, - "remote-echo-interval":50 + "remote-echo-receive-interval":50 } ] diff --git a/tests/topotests/bfd-topo2/test_bfd_topo2.py b/tests/topotests/bfd-topo2/test_bfd_topo2.py index c31cc02b3a..e85b2644dd 100644 --- a/tests/topotests/bfd-topo2/test_bfd_topo2.py +++ b/tests/topotests/bfd-topo2/test_bfd_topo2.py @@ -46,7 +46,8 @@ from lib.topolog import logger # Required to instantiate the topology builder class. from mininet.topo import Topo -pytestmark = [pytest.mark.bfdd, pytest.mark.ospfd] +pytestmark = [pytest.mark.bfdd, pytest.mark.bgpd, pytest.mark.ospfd] + class BFDTopo(Topo): "Test topology builder" diff --git a/tests/topotests/bfd-topo3/r1/bfd-peers.json b/tests/topotests/bfd-topo3/r1/bfd-peers.json index 56205d538b..f8a354fc20 100644 --- a/tests/topotests/bfd-topo3/r1/bfd-peers.json +++ b/tests/topotests/bfd-topo3/r1/bfd-peers.json @@ -2,7 +2,8 @@ { "detect-multiplier": 3, "diagnostic": "ok", - "echo-interval": 0, + "echo-receive-interval": 50, + "echo-transmit-interval": 0, "id": "*", "local": "2001:db8:1::1", "minimum-ttl": 253, @@ -12,7 +13,7 @@ "receive-interval": 2000, "remote-detect-multiplier": 3, "remote-diagnostic": "ok", - "remote-echo-interval": 50, + "remote-echo-receive-interval": 50, "remote-id": "*", "remote-receive-interval": 2000, "remote-transmit-interval": 2000, @@ -24,7 +25,8 @@ { "detect-multiplier": 3, "diagnostic": "ok", - "echo-interval": 0, + "echo-receive-interval": 50, + "echo-transmit-interval": 0, "id": "*", "interface": "r1-eth0", "local": "2001:db8:1::1", @@ -34,7 +36,7 @@ "receive-interval": 600, "remote-detect-multiplier": 3, "remote-diagnostic": "ok", - "remote-echo-interval": 50, + "remote-echo-receive-interval": 50, "remote-id": "*", "remote-receive-interval": 600, "remote-transmit-interval": 600, @@ -46,7 +48,8 @@ { "detect-multiplier": 3, "diagnostic": "ok", - "echo-interval": 0, + "echo-receive-interval": 50, + "echo-transmit-interval": 0, "id": "*", "local": "192.168.1.1", "minimum-ttl": 254, @@ -56,7 +59,7 @@ "receive-interval": 2000, "remote-detect-multiplier": 3, "remote-diagnostic": "ok", - "remote-echo-interval": 50, + "remote-echo-receive-interval": 50, "remote-id": "*", "remote-receive-interval": 2000, "remote-transmit-interval": 2000, diff --git a/tests/topotests/bfd-topo3/r2/bfd-peers.json b/tests/topotests/bfd-topo3/r2/bfd-peers.json index cb8985b13e..786d66dbe3 100644 --- a/tests/topotests/bfd-topo3/r2/bfd-peers.json +++ b/tests/topotests/bfd-topo3/r2/bfd-peers.json @@ -2,7 +2,8 @@ { "detect-multiplier": 3, "diagnostic": "ok", - "echo-interval": 0, + "echo-receive-interval": 50, + "echo-transmit-interval": 0, "id": "*", "interface": "r2-eth0", "local": "2001:db8:1::2", @@ -12,7 +13,7 @@ "receive-interval": 600, "remote-detect-multiplier": 3, "remote-diagnostic": "ok", - "remote-echo-interval": 50, + "remote-echo-receive-interval": 50, "remote-id": "*", "remote-receive-interval": 600, "remote-transmit-interval": 600, @@ -24,7 +25,8 @@ { "detect-multiplier": 3, "diagnostic": "ok", - "echo-interval": 0, + "echo-receive-interval": 50, + "echo-transmit-interval": 0, "id": "*", "interface": "r2-eth1", "local": "2001:db8:2::2", @@ -34,7 +36,7 @@ "receive-interval": 2000, "remote-detect-multiplier": 3, "remote-diagnostic": "ok", - "remote-echo-interval": 50, + "remote-echo-receive-interval": 50, "remote-id": "*", "remote-receive-interval": 2000, "remote-transmit-interval": 2000, diff --git a/tests/topotests/bfd-topo3/r3/bfd-peers.json b/tests/topotests/bfd-topo3/r3/bfd-peers.json index 8be35fd084..1f58663a4e 100644 --- a/tests/topotests/bfd-topo3/r3/bfd-peers.json +++ b/tests/topotests/bfd-topo3/r3/bfd-peers.json @@ -2,7 +2,8 @@ { "detect-multiplier": 3, "diagnostic": "ok", - "echo-interval": 0, + "echo-receive-interval": 50, + "echo-transmit-interval": 0, "id": "*", "interface": "r3-eth1", "local": "2001:db8:3::2", @@ -12,7 +13,7 @@ "receive-interval": 2000, "remote-detect-multiplier": 3, "remote-diagnostic": "ok", - "remote-echo-interval": 50, + "remote-echo-receive-interval": 50, "remote-id": "*", "remote-receive-interval": 2000, "remote-transmit-interval": 2000, @@ -24,7 +25,8 @@ { "detect-multiplier": 3, "diagnostic": "ok", - "echo-interval": 0, + "echo-receive-interval": 50, + "echo-transmit-interval": 0, "id": "*", "interface": "r3-eth0", "local": "2001:db8:2::1", @@ -34,7 +36,7 @@ "receive-interval": 2000, "remote-detect-multiplier": 3, "remote-diagnostic": "ok", - "remote-echo-interval": 50, + "remote-echo-receive-interval": 50, "remote-id": "*", "remote-receive-interval": 2000, "remote-transmit-interval": 2000, @@ -46,7 +48,8 @@ { "detect-multiplier": 3, "diagnostic": "ok", - "echo-interval": 0, + "echo-receive-interval": 50, + "echo-transmit-interval": 0, "id": "*", "local": "192.168.2.1", "minimum-ttl": 254, @@ -56,7 +59,7 @@ "receive-interval": 2000, "remote-detect-multiplier": 3, "remote-diagnostic": "ok", - "remote-echo-interval": 50, + "remote-echo-receive-interval": 50, "remote-id": "*", "remote-receive-interval": 2000, "remote-transmit-interval": 2000, diff --git a/tests/topotests/bfd-topo3/r4/bfd-peers.json b/tests/topotests/bfd-topo3/r4/bfd-peers.json index e2e6722ef4..5477f39120 100644 --- a/tests/topotests/bfd-topo3/r4/bfd-peers.json +++ b/tests/topotests/bfd-topo3/r4/bfd-peers.json @@ -2,7 +2,8 @@ { "detect-multiplier": 3, "diagnostic": "ok", - "echo-interval": 0, + "echo-receive-interval": 50, + "echo-transmit-interval": 0, "id": "*", "local": "2001:db8:3::1", "minimum-ttl": 253, @@ -12,7 +13,7 @@ "receive-interval": 2000, "remote-detect-multiplier": 3, "remote-diagnostic": "ok", - "remote-echo-interval": 50, + "remote-echo-receive-interval": 50, "remote-id": "*", "remote-receive-interval": 2000, "remote-transmit-interval": 2000, @@ -24,7 +25,8 @@ { "detect-multiplier": 3, "diagnostic": "ok", - "echo-interval": 0, + "echo-receive-interval": 50, + "echo-transmit-interval": 0, "id": "*", "interface": "r4-eth0", "local": "2001:db8:3::1", @@ -34,7 +36,7 @@ "receive-interval": 2000, "remote-detect-multiplier": 3, "remote-diagnostic": "ok", - "remote-echo-interval": 50, + "remote-echo-receive-interval": 50, "remote-id": "*", "remote-receive-interval": 2000, "remote-transmit-interval": 2000, diff --git a/tests/topotests/bfd-topo3/test_bfd_topo3.py b/tests/topotests/bfd-topo3/test_bfd_topo3.py index f473b67108..6bb223e203 100644 --- a/tests/topotests/bfd-topo3/test_bfd_topo3.py +++ b/tests/topotests/bfd-topo3/test_bfd_topo3.py @@ -45,6 +45,8 @@ from lib.topolog import logger # Required to instantiate the topology builder class. from mininet.topo import Topo +pytestmark = [pytest.mark.bfdd, pytest.mark.bgpd] + class BFDTopo(Topo): "Test topology builder" diff --git a/tests/topotests/bfd-vrf-topo1/r2/peers.json b/tests/topotests/bfd-vrf-topo1/r2/peers.json index 5035d643c5..267459c7a8 100644 --- a/tests/topotests/bfd-vrf-topo1/r2/peers.json +++ b/tests/topotests/bfd-vrf-topo1/r2/peers.json @@ -4,7 +4,7 @@ "status": "up" }, { - "remote-echo-interval": 100, + "remote-echo-receive-interval": 100, "peer": "192.168.1.1", "status": "up" }, diff --git a/tests/topotests/bfd-vrf-topo1/test_bfd_vrf_topo1.py b/tests/topotests/bfd-vrf-topo1/test_bfd_vrf_topo1.py index a238ff8da3..8a1ffe085d 100644 --- a/tests/topotests/bfd-vrf-topo1/test_bfd_vrf_topo1.py +++ b/tests/topotests/bfd-vrf-topo1/test_bfd_vrf_topo1.py @@ -46,7 +46,8 @@ from lib.topolog import logger # Required to instantiate the topology builder class. from mininet.topo import Topo -pytestmark = [pytest.mark.bfdd] +pytestmark = [pytest.mark.bfdd, pytest.mark.bgpd] + class BFDTopo(Topo): "Test topology builder" diff --git a/tests/topotests/bgp-aggregator-zero/test_bgp_aggregator_zero.py b/tests/topotests/bgp-aggregator-zero/test_bgp_aggregator_zero.py index 0db47da3f2..c4bbdce2c3 100644 --- a/tests/topotests/bgp-aggregator-zero/test_bgp_aggregator_zero.py +++ b/tests/topotests/bgp-aggregator-zero/test_bgp_aggregator_zero.py @@ -40,6 +40,8 @@ from lib.topogen import Topogen, TopoRouter, get_topogen from lib.topolog import logger from mininet.topo import Topo +pytestmark = [pytest.mark.bgpd] + class BgpAggregatorAsnZero(Topo): def build(self, *_args, **_opts): diff --git a/tests/topotests/bgp-basic-functionality-topo1/test_bgp_basic_functionality.py b/tests/topotests/bgp-basic-functionality-topo1/test_bgp_basic_functionality.py index b701a0d61e..374cce21f6 100644 --- a/tests/topotests/bgp-basic-functionality-topo1/test_bgp_basic_functionality.py +++ b/tests/topotests/bgp-basic-functionality-topo1/test_bgp_basic_functionality.py @@ -91,6 +91,9 @@ from lib.bgp import ( ) from lib.topojson import build_topo_from_json, build_config_from_json +pytestmark = [pytest.mark.bgpd, pytest.mark.staticd] + + # Reading the data from JSON File for topology creation jsonFile = "{}/bgp_basic_functionality.json".format(CWD) try: 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-ecmp-topo2/test_ebgp_ecmp_topo2.py b/tests/topotests/bgp-ecmp-topo2/test_ebgp_ecmp_topo2.py index 353df0684b..dfe6a8074d 100644 --- a/tests/topotests/bgp-ecmp-topo2/test_ebgp_ecmp_topo2.py +++ b/tests/topotests/bgp-ecmp-topo2/test_ebgp_ecmp_topo2.py @@ -324,6 +324,7 @@ def test_modify_ecmp_max_paths(request, ecmp_num, test_type): write_test_footer(tc_name) + @pytest.mark.parametrize("ecmp_num", ["8", "16", "32"]) @pytest.mark.parametrize("test_type", ["redist_static", "advertise_nw"]) def test_ecmp_after_clear_bgp(request, ecmp_num, test_type): @@ -349,7 +350,7 @@ def test_ecmp_after_clear_bgp(request, ecmp_num, test_type): addr_type, dut, input_dict_1, - next_hop=NEXT_HOPS[addr_type][:int(ecmp_num)], + next_hop=NEXT_HOPS[addr_type][: int(ecmp_num)], protocol=protocol, ) assert result is True, "Testcase {} : Failed \n Error: {}".format( @@ -372,7 +373,7 @@ def test_ecmp_after_clear_bgp(request, ecmp_num, test_type): addr_type, dut, input_dict_1, - next_hop=NEXT_HOPS[addr_type][:int(ecmp_num)], + next_hop=NEXT_HOPS[addr_type][: int(ecmp_num)], protocol=protocol, ) assert result is True, "Testcase {} : Failed \n Error: {}".format( diff --git a/tests/topotests/bgp-ecmp-topo2/test_ibgp_ecmp_topo2.py b/tests/topotests/bgp-ecmp-topo2/test_ibgp_ecmp_topo2.py index 2f73bdb1b8..2bde52af1d 100644 --- a/tests/topotests/bgp-ecmp-topo2/test_ibgp_ecmp_topo2.py +++ b/tests/topotests/bgp-ecmp-topo2/test_ibgp_ecmp_topo2.py @@ -325,6 +325,7 @@ def test_modify_ecmp_max_paths(request, ecmp_num, test_type): write_test_footer(tc_name) + @pytest.mark.parametrize("ecmp_num", ["8", "16", "32"]) @pytest.mark.parametrize("test_type", ["redist_static", "advertise_nw"]) def test_ecmp_after_clear_bgp(request, ecmp_num, test_type): @@ -350,7 +351,7 @@ def test_ecmp_after_clear_bgp(request, ecmp_num, test_type): addr_type, dut, input_dict_1, - next_hop=NEXT_HOPS[addr_type][:int(ecmp_num)], + next_hop=NEXT_HOPS[addr_type][: int(ecmp_num)], protocol=protocol, ) assert result is True, "Testcase {} : Failed \n Error: {}".format( @@ -373,7 +374,7 @@ def test_ecmp_after_clear_bgp(request, ecmp_num, test_type): addr_type, dut, input_dict_1, - next_hop=NEXT_HOPS[addr_type][:int(ecmp_num)], + next_hop=NEXT_HOPS[addr_type][: int(ecmp_num)], protocol=protocol, ) assert result is True, "Testcase {} : Failed \n Error: {}".format( diff --git a/tests/topotests/bgp-evpn-mh/test_evpn_mh.py b/tests/topotests/bgp-evpn-mh/test_evpn_mh.py index aec78179ff..2744920272 100644 --- a/tests/topotests/bgp-evpn-mh/test_evpn_mh.py +++ b/tests/topotests/bgp-evpn-mh/test_evpn_mh.py @@ -482,7 +482,7 @@ def check_es(dut): curr_es_set.append(esi) types = es["type"] vtep_ips = [] - for vtep in es["vteps"]: + for vtep in es.get("vteps", []): vtep_ips.append(vtep["vtep_ip"]) if "local" in types: @@ -513,7 +513,7 @@ def check_one_es(dut, esi, down_vteps): esi = es["esi"] types = es["type"] vtep_ips = [] - for vtep in es["vteps"]: + for vtep in es.get("vteps", []): vtep_ips.append(vtep["vtep_ip"]) if "local" in types: @@ -593,11 +593,25 @@ def test_evpn_ead_update(): # tgen.mininet_cli() -def check_mac(dut, vni, mac, m_type, esi, intf): +def ping_anycast_gw(tgen): + local_host = tgen.gears["hostd11"] + remote_host = tgen.gears["hostd21"] + + # ping the anycast gw from the local and remote hosts to populate + # the mac address on the PEs + cmd_str = "arping -I torbond -c 1 45.0.0.1" + local_host.run(cmd_str) + remote_host.run(cmd_str) + + +def check_mac(dut, vni, mac, m_type, esi, intf, ping_gw=False, tgen=None): """ checks if mac is present and if desination matches the one provided """ + if ping_gw: + ping_anycast_gw(tgen) + out = dut.vtysh_cmd("show evpn mac vni %d mac %s json" % (vni, mac)) mac_js = json.loads(out) @@ -627,11 +641,6 @@ def test_evpn_mac(): tors.append(tgen.gears["torm11"]) tors.append(tgen.gears["torm12"]) - # ping the anycast gw from the local and remote hosts to populate - # the mac address on the PEs - local_host.run("arping -I torbond -c 1 45.0.0.1") - remote_host.run("arping -I torbond -c 1 45.0.0.1") - vni = 1000 # check if the rack-1 host MAC is present on all rack-1 PEs @@ -642,7 +651,7 @@ def test_evpn_mac(): intf = "hostbond1" for tor in tors: - test_fn = partial(check_mac, tor, vni, mac, m_type, esi, intf) + test_fn = partial(check_mac, tor, vni, mac, m_type, esi, intf, True, tgen) _, result = topotest.run_and_expect(test_fn, None, count=20, wait=3) assertmsg = '"{}" local MAC content incorrect'.format(tor.name) assert result is None, assertmsg diff --git a/tests/topotests/bgp-evpn-vxlan_topo1/test_bgp_evpn_vxlan.py b/tests/topotests/bgp-evpn-vxlan_topo1/test_bgp_evpn_vxlan.py index 785a3acbf9..086bad6481 100755 --- a/tests/topotests/bgp-evpn-vxlan_topo1/test_bgp_evpn_vxlan.py +++ b/tests/topotests/bgp-evpn-vxlan_topo1/test_bgp_evpn_vxlan.py @@ -47,6 +47,7 @@ from mininet.topo import Topo pytestmark = [pytest.mark.bgpd, pytest.mark.ospfd] + class TemplateTopo(Topo): "Test topology builder" diff --git a/tests/topotests/bgp-snmp-mplsl3vpn/test_bgp_snmp_mplsvpn.py b/tests/topotests/bgp-snmp-mplsl3vpn/test_bgp_snmp_mplsvpn.py index 5eb1738632..db4eab9d3d 100755 --- a/tests/topotests/bgp-snmp-mplsl3vpn/test_bgp_snmp_mplsvpn.py +++ b/tests/topotests/bgp-snmp-mplsl3vpn/test_bgp_snmp_mplsvpn.py @@ -47,6 +47,8 @@ from lib.snmptest import SnmpTester # Required to instantiate the topology builder class. from mininet.topo import Topo +pytestmark = [pytest.mark.bgpd, pytest.mark.isisd, pytest.mark.snmp] + class TemplateTopo(Topo): "Test topology builder" @@ -266,7 +268,7 @@ def test_pe1_converge_evpn(): break count += 1 sleep(1) - #tgen.mininet_cli() + # tgen.mininet_cli() assertmsg = "BGP Peer 10.4.4.4 did not connect" assert passed, assertmsg @@ -620,7 +622,7 @@ rte_table_test = { "unknown(0)", "ipv4(1)", "unknown(0)", - ], + ], "mplsL3VpnVrfRteInetCidrNextHop": [ "C0 A8 64 0A", "C0 A8 C8 0A", @@ -630,7 +632,6 @@ rte_table_test = { "C0 A8 C8 0A", '""', ], - "mplsL3VpnVrfRteInetCidrIfIndex": ["5", "6", "4", "5", "0", "6", "0"], "mplsL3VpnVrfRteInetCidrType": [ "local(3)", "local(3)", @@ -649,7 +650,15 @@ rte_table_test = { "bgp(14)", "local(2)", ], - "mplsL3VpnVrfRteInetCidrNextHopAS": ["65001", "65001", "0", "65001", "0", "65001", "0"], + "mplsL3VpnVrfRteInetCidrNextHopAS": [ + "65001", + "65001", + "0", + "65001", + "0", + "65001", + "0", + ], "mplsL3VpnVrfRteInetCidrMetric1": ["0", "0", "20", "0", "0", "0", "0"], "mplsL3VpnVrfRteInetCidrMetric2": ["-1", "-1", "-1", "-1", "-1", "-1", "-1"], "mplsL3VpnVrfRteInetCidrMetric3": ["-1", "-1", "-1", "-1", "-1", "-1", "-1"], @@ -663,7 +672,7 @@ rte_table_test = { "active(1)", "active(1)", "active(1)", - "active(1)", + "active(1)", ], } @@ -720,6 +729,22 @@ def test_r1_mplsvpn_rte_table(): ) if passed: break + # generate ifindex row grabbing ifindices from vtysh + if passed: + ifindex_row = [ + router_interface_get_ifindex(r1r, "eth3"), + router_interface_get_ifindex(r1r, "eth4"), + router_interface_get_ifindex(r1r, "eth2"), + router_interface_get_ifindex(r1r, "eth3"), + "0", + router_interface_get_ifindex(r1r, "eth4"), + "0", + ] + if not r1_snmp.test_oid_walk( + "mplsL3VpnVrfRteInetCidrIfIndex", ifindex_row, oid_list + ): + passed = False + print("passed {}".format(passed)) assert passed, assertmsg diff --git a/tests/topotests/bgp_aggregate-address_origin/test_bgp_aggregate-address_origin.py b/tests/topotests/bgp_aggregate-address_origin/test_bgp_aggregate-address_origin.py index 86fd4b601f..be07fab87b 100644 --- a/tests/topotests/bgp_aggregate-address_origin/test_bgp_aggregate-address_origin.py +++ b/tests/topotests/bgp_aggregate-address_origin/test_bgp_aggregate-address_origin.py @@ -47,6 +47,8 @@ from lib.topogen import Topogen, TopoRouter, get_topogen from lib.topolog import logger from mininet.topo import Topo +pytestmark = [pytest.mark.bgpd] + class TemplateTopo(Topo): def build(self, *_args, **_opts): diff --git a/tests/topotests/bgp_aggregate-address_route-map/test_bgp_aggregate-address_route-map.py b/tests/topotests/bgp_aggregate-address_route-map/test_bgp_aggregate-address_route-map.py index c7d9f13f3f..484f40251f 100644 --- a/tests/topotests/bgp_aggregate-address_route-map/test_bgp_aggregate-address_route-map.py +++ b/tests/topotests/bgp_aggregate-address_route-map/test_bgp_aggregate-address_route-map.py @@ -50,6 +50,8 @@ from lib.topogen import Topogen, TopoRouter, get_topogen from lib.topolog import logger from mininet.topo import Topo +pytestmark = [pytest.mark.bgpd] + class TemplateTopo(Topo): def build(self, *_args, **_opts): diff --git a/tests/topotests/bgp_as_allow_in/test_bgp_as_allow_in.py b/tests/topotests/bgp_as_allow_in/test_bgp_as_allow_in.py index 544bda145c..4d41c7a321 100644 --- a/tests/topotests/bgp_as_allow_in/test_bgp_as_allow_in.py +++ b/tests/topotests/bgp_as_allow_in/test_bgp_as_allow_in.py @@ -76,6 +76,9 @@ from lib.bgp import ( ) from lib.topojson import build_topo_from_json, build_config_from_json +pytestmark = [pytest.mark.bgpd, pytest.mark.staticd] + + # Reading the data from JSON File for topology creation jsonFile = "{}/bgp_as_allow_in.json".format(CWD) try: diff --git a/tests/topotests/bgp_as_wide_bgp_identifier/test_bgp_as_wide_bgp_identifier.py b/tests/topotests/bgp_as_wide_bgp_identifier/test_bgp_as_wide_bgp_identifier.py index 02edb62ca0..a736463927 100644 --- a/tests/topotests/bgp_as_wide_bgp_identifier/test_bgp_as_wide_bgp_identifier.py +++ b/tests/topotests/bgp_as_wide_bgp_identifier/test_bgp_as_wide_bgp_identifier.py @@ -45,6 +45,8 @@ from lib.topogen import Topogen, TopoRouter, get_topogen from lib.topolog import logger from mininet.topo import Topo +pytestmark = [pytest.mark.bgpd] + class TemplateTopo(Topo): def build(self, *_args, **_opts): diff --git a/tests/topotests/bgp_blackhole_community/test_bgp_blackhole_community.py b/tests/topotests/bgp_blackhole_community/test_bgp_blackhole_community.py index a856c9278f..6512e4d4c6 100644 --- a/tests/topotests/bgp_blackhole_community/test_bgp_blackhole_community.py +++ b/tests/topotests/bgp_blackhole_community/test_bgp_blackhole_community.py @@ -40,6 +40,8 @@ from lib.topolog import logger from mininet.topo import Topo from lib.common_config import step +pytestmark = [pytest.mark.bgpd] + class TemplateTopo(Topo): def build(self, *_args, **_opts): diff --git a/tests/topotests/bgp_comm-list_delete/test_bgp_comm-list_delete.py b/tests/topotests/bgp_comm-list_delete/test_bgp_comm-list_delete.py index fe7052b80f..81bf8da31a 100644 --- a/tests/topotests/bgp_comm-list_delete/test_bgp_comm-list_delete.py +++ b/tests/topotests/bgp_comm-list_delete/test_bgp_comm-list_delete.py @@ -45,6 +45,8 @@ from lib.topogen import Topogen, TopoRouter, get_topogen from lib.topolog import logger from mininet.topo import Topo +pytestmark = [pytest.mark.bgpd] + class TemplateTopo(Topo): def build(self, *_args, **_opts): diff --git a/tests/topotests/bgp_communities_topo1/test_bgp_communities.py b/tests/topotests/bgp_communities_topo1/test_bgp_communities.py index f2e54b24d6..6d4a7d82e5 100644 --- a/tests/topotests/bgp_communities_topo1/test_bgp_communities.py +++ b/tests/topotests/bgp_communities_topo1/test_bgp_communities.py @@ -66,6 +66,9 @@ from lib.bgp import ( from lib.topojson import build_topo_from_json, build_config_from_json from copy import deepcopy +pytestmark = [pytest.mark.bgpd, pytest.mark.staticd] + + # Reading the data from JSON File for topology creation jsonFile = "{}/bgp_communities.json".format(CWD) try: diff --git a/tests/topotests/bgp_communities_topo1/test_bgp_communities_topo2.py b/tests/topotests/bgp_communities_topo1/test_bgp_communities_topo2.py index c0842148f1..3415789068 100644 --- a/tests/topotests/bgp_communities_topo1/test_bgp_communities_topo2.py +++ b/tests/topotests/bgp_communities_topo1/test_bgp_communities_topo2.py @@ -70,6 +70,9 @@ from lib.bgp import ( from lib.topojson import build_topo_from_json, build_config_from_json from copy import deepcopy +pytestmark = [pytest.mark.bgpd, pytest.mark.staticd] + + # Reading the data from JSON File for topology creation jsonFile = "{}/bgp_communities_topo2.json".format(CWD) try: diff --git a/tests/topotests/bgp_community_change_update/test_bgp_community_change_update.py b/tests/topotests/bgp_community_change_update/test_bgp_community_change_update.py index 5fc4310266..95e63c617e 100644 --- a/tests/topotests/bgp_community_change_update/test_bgp_community_change_update.py +++ b/tests/topotests/bgp_community_change_update/test_bgp_community_change_update.py @@ -59,6 +59,8 @@ from mininet.topo import Topo from lib.common_config import step from time import sleep +pytestmark = [pytest.mark.bgpd, pytest.mark.bgpd] + class TemplateTopo(Topo): def build(self, *_args, **_opts): diff --git a/tests/topotests/bgp_features/peer1/exa_readpipe.py b/tests/topotests/bgp_features/peer1/exa_readpipe.py index dba1536388..9e689a27e3 100644 --- a/tests/topotests/bgp_features/peer1/exa_readpipe.py +++ b/tests/topotests/bgp_features/peer1/exa_readpipe.py @@ -8,7 +8,7 @@ if len(sys.argv) != 2: fifo = sys.argv[1] while True: - pipe = open(fifo, 'r') + pipe = open(fifo, "r") with pipe: line = pipe.readline().strip() if line != "": diff --git a/tests/topotests/bgp_features/peer2/exa_readpipe.py b/tests/topotests/bgp_features/peer2/exa_readpipe.py index dba1536388..9e689a27e3 100644 --- a/tests/topotests/bgp_features/peer2/exa_readpipe.py +++ b/tests/topotests/bgp_features/peer2/exa_readpipe.py @@ -8,7 +8,7 @@ if len(sys.argv) != 2: fifo = sys.argv[1] while True: - pipe = open(fifo, 'r') + pipe = open(fifo, "r") with pipe: line = pipe.readline().strip() if line != "": diff --git a/tests/topotests/bgp_features/peer3/exa_readpipe.py b/tests/topotests/bgp_features/peer3/exa_readpipe.py index dba1536388..9e689a27e3 100644 --- a/tests/topotests/bgp_features/peer3/exa_readpipe.py +++ b/tests/topotests/bgp_features/peer3/exa_readpipe.py @@ -8,7 +8,7 @@ if len(sys.argv) != 2: fifo = sys.argv[1] while True: - pipe = open(fifo, 'r') + pipe = open(fifo, "r") with pipe: line = pipe.readline().strip() if line != "": diff --git a/tests/topotests/bgp_features/peer4/exa_readpipe.py b/tests/topotests/bgp_features/peer4/exa_readpipe.py index dba1536388..9e689a27e3 100644 --- a/tests/topotests/bgp_features/peer4/exa_readpipe.py +++ b/tests/topotests/bgp_features/peer4/exa_readpipe.py @@ -8,7 +8,7 @@ if len(sys.argv) != 2: fifo = sys.argv[1] while True: - pipe = open(fifo, 'r') + pipe = open(fifo, "r") with pipe: line = pipe.readline().strip() if line != "": 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 3a2d283025..a6338d0c70 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 @@ -1317,18 +1317,20 @@ def test_BGP_GR_TC_4_p0(request): result = verify_bgp_rib( tgen, addr_type, dut, input_topo, next_hop, expected=False ) - assert result is not True, "Testcase {} : Failed \n Error {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r1: routes are still present in BGP RIB\n Error: {}".format( tc_name, result - ) + )) logger.info(" Expected behavior: {}".format(result)) # Verifying RIB routes result = verify_rib( tgen, addr_type, dut, input_topo, next_hop, protocol, expected=False ) - assert result is not True, "Testcase {} : Failed \n Error {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r1: routes are still present in ZEBRA\n Error: {}".format( tc_name, result - ) + )) logger.info(" Expected behavior: {}".format(result)) logger.info("[Phase 5] : R2 is about to come up now ") @@ -1788,9 +1790,10 @@ def test_BGP_GR_TC_6_1_2_p1(request): result = verify_r_bit( tgen, topo, addr_type, input_dict, dut="r2", peer="r1", expected=False ) - assert result is not True, "Testcase {} : Failed \n Error {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r2: R-bit is set to True\n Error: {}".format( tc_name, result - ) + )) logger.info("Restart BGPd on R2 ") kill_router_daemons(tgen, "r2", ["bgpd"]) @@ -1808,9 +1811,10 @@ def test_BGP_GR_TC_6_1_2_p1(request): result = verify_r_bit( tgen, topo, addr_type, input_dict, dut="r2", peer="r1", expected=False ) - assert result is not True, "Testcase {} : Failed \n Error {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r2: R-bit is set to True\n Error: {}".format( tc_name, result - ) + )) write_test_footer(tc_name) @@ -2092,18 +2096,20 @@ def test_BGP_GR_TC_17_p1(request): result = verify_bgp_rib( tgen, addr_type, dut, input_topo, next_hop, expected=False ) - assert result is not True, "Testcase {} : Failed \n Error {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r1: routes are still present in BGP RIB\n Error: {}".format( tc_name, result - ) + )) logger.info(" Expected behavior: {}".format(result)) # Verifying RIB routes result = verify_rib( tgen, addr_type, dut, input_topo, next_hop, protocol, expected=False ) - assert result is not True, "Testcase {} : Failed \n Error {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r1: routes are still present in ZEBRA\n Error: {}".format( tc_name, result - ) + )) logger.info(" Expected behavior: {}".format(result)) logger.info("[Phase 5] : R2 is about to come up now ") @@ -2122,9 +2128,10 @@ def test_BGP_GR_TC_17_p1(request): result = verify_r_bit( tgen, topo, addr_type, input_dict, dut="r1", peer="r2", expected=False ) - assert result is not True, "Testcase {} : Failed \n Error {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r1: R-bit is set to True\n Error: {}".format( tc_name, result - ) + )) # Verifying BGP RIB routes next_hop = next_hop_per_address_family( @@ -2450,18 +2457,20 @@ def test_BGP_GR_TC_20_p1(request): result = verify_bgp_rib( tgen, addr_type, dut, input_topo, next_hop, expected=False ) - assert result is not True, "Testcase {} : Failed \n Error {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r1: routes are still present in BGP RIB\n Error: {}".format( tc_name, result - ) + )) logger.info(" Expected behavior: {}".format(result)) # Verifying RIB routes result = verify_rib( tgen, addr_type, dut, input_topo, next_hop, protocol, expected=False ) - assert result is not True, "Testcase {} : Failed \n Error {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r1: routes are still present in ZEBRA\n Error: {}".format( tc_name, result - ) + )) logger.info(" Expected behavior: {}".format(result)) logger.info("[Phase 5] : R2 is about to come up now ") @@ -2734,9 +2743,10 @@ def test_BGP_GR_TC_31_1_p1(request): result = verify_rib( tgen, addr_type, dut, input_topo, next_hop, protocol, expected=False ) - assert result is not True, "Testcase {} : Failed \n Error {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r1: routes are still present in ZEBRA\n Error: {}".format( tc_name, result - ) + )) logger.info("[Phase 4] : R1 is about to come up now ") start_router_daemons(tgen, "r1", ["bgpd"]) @@ -3215,9 +3225,10 @@ def test_BGP_GR_TC_9_p1(request): result = verify_bgp_rib( tgen, addr_type, dut, input_topo, next_hop, expected=False ) - assert result is not True, "Testcase {} :Failed \n Error {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r1: routes are still present in BGP RIB\n Error: {}".format( tc_name, result - ) + )) logger.info(" Expected behavior: {}".format(result)) # Verifying RIB routes @@ -3225,9 +3236,10 @@ def test_BGP_GR_TC_9_p1(request): result = verify_rib( tgen, addr_type, dut, input_topo, next_hop, protocol, expected=False ) - assert result is not True, "Testcase {} :Failed \n Error {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r1: routes are still present in ZEBRA\n Error: {}".format( tc_name, result - ) + )) logger.info(" Expected behavior: {}".format(result)) logger.info("[Phase 5] : R2 is about to come up now ") @@ -3257,9 +3269,10 @@ def test_BGP_GR_TC_9_p1(request): result = verify_f_bit( tgen, topo, addr_type, input_dict, dut="r1", peer="r2", expected=False ) - assert result is not True, "Testcase {} :Failed \n Error {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r1: F-bit is set to True\n Error: {}".format( tc_name, result - ) + )) write_test_footer(tc_name) @@ -3391,9 +3404,10 @@ def test_BGP_GR_TC_17_p1(request): result = verify_bgp_rib( tgen, addr_type, dut, input_topo, next_hop, expected=False ) - assert result is not True, "Testcase {} :Failed \n Error {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r1: routes are still present in BGP RIB\n Error: {}".format( tc_name, result - ) + )) logger.info(" Expected behavior: {}".format(result)) # Verifying RIB routes @@ -3401,9 +3415,10 @@ def test_BGP_GR_TC_17_p1(request): result = verify_rib( tgen, addr_type, dut, input_topo, next_hop, protocol, expected=False ) - assert result is not True, "Testcase {} :Failed \n Error {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r1: routes are still present in ZEBRA\n Error: {}".format( tc_name, result - ) + )) logger.info(" Expected behavior: {}".format(result)) logger.info("[Phase 5] : R2 is about to come up now ") @@ -3425,9 +3440,10 @@ def test_BGP_GR_TC_17_p1(request): result = verify_r_bit( tgen, topo, addr_type, input_dict, dut="r1", peer="r2", expected=False ) - assert result is not True, "Testcase {} :Failed \n Error {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r1: R-bit is set to True\n Error: {}".format( tc_name, result - ) + )) # Verifying BGP RIB routes next_hop = next_hop_per_address_family( @@ -3647,9 +3663,10 @@ def test_BGP_GR_TC_43_p1(request): result = verify_bgp_rib( tgen, addr_type, dut, input_topo, next_hop, expected=False ) - assert result is not True, "Testcase {} :Failed \n Error {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r2: routes are still present in BGP RIB\n Error: {}".format( tc_name, result - ) + )) protocol = "bgp" result = verify_rib( tgen, addr_type, dut, input_topo, next_hop, protocol, expected=False @@ -3954,9 +3971,10 @@ def test_BGP_GR_TC_44_p1(request): result = verify_bgp_rib( tgen, addr_type, dut, input_topo, next_hop, expected=False ) - assert result is not True, "Testcase {} :Failed \n Error {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r1: routes are still present in BGP RIB\n Error: {}".format( tc_name, result - ) + )) result = verify_rib( tgen, addr_type, dut, input_topo, next_hop, protocol, expected=False ) @@ -4981,9 +4999,10 @@ def test_BGP_GR_TC_48_p1(request): result = verify_rib( tgen, addr_type, dut, input_topo, next_hop, protocol, expected=False ) - assert result is not True, "Testcase {} :Failed \n Error {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r1: routes are still present in ZEBRA\n Error: {}".format( tc_name, result - ) + )) dut = "r2" peer = "r1" @@ -4994,15 +5013,17 @@ def test_BGP_GR_TC_48_p1(request): result = verify_bgp_rib( tgen, addr_type, dut, input_topo, next_hop, expected=False ) - assert result is not True, "Testcase {} :Failed \n Error {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r2: routes are still present in BGP RIB\n Error: {}".format( tc_name, result - ) + )) result = verify_rib( tgen, addr_type, dut, input_topo, next_hop, protocol, expected=False ) - assert result is not True, "Testcase {} :Failed \n Error {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r2: routes are still present in ZEBRA\n Error: {}".format( tc_name, result - ) + )) step("Bring up BGP on R1 and remove Peer-level GR config from R1") @@ -5361,15 +5382,17 @@ def test_BGP_GR_TC_52_p1(request): result = verify_bgp_rib( tgen, addr_type, dut, input_topo, next_hop, expected=False ) - assert result is not True, "Testcase {} :Failed \n Error {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r1: routes are still present in BGP RIB\n Error: {}".format( tc_name, result - ) + )) result = verify_rib( tgen, addr_type, dut, input_topo, next_hop, protocol, expected=False ) - assert result is not True, "Testcase {} :Failed \n Error {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r1: routes are still present in ZEBRA\n Error: {}".format( tc_name, result - ) + )) step("Bring up BGP on R2 and remove Peer-level GR config from R1") 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 2ddeab13f6..2c5dd92f54 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 @@ -555,9 +555,10 @@ def test_BGP_GR_TC_3_p0(request): result = verify_eor( tgen, topo, addr_type, input_dict, dut="r2", peer="r1", expected=False ) - assert result is not True, ( - "Testcase " + tc_name + " : Failed \n Error: {}".format(result) - ) + assert result is not True, ("Testcase {} : Failed \n " + "r2: EOR is set to True\n Error: {}".format( + tc_name, result + )) logger.info( "Waiting for selection deferral timer({} sec)..".format(GR_SELECT_DEFER_TIMER) @@ -700,9 +701,10 @@ def test_BGP_GR_TC_11_p0(request): result = verify_eor( tgen, topo, addr_type, input_dict, dut="r1", peer="r3", expected=False ) - assert result is not True, ( - "Testcase " + tc_name + " : Failed \n Error: {}".format(result) - ) + assert result is not True, ("Testcase {} : Failed \n " + "r1: EOR is set to True\n Error: {}".format( + tc_name, result + )) logger.info( "Waiting for selection deferral timer({} sec).. ".format( @@ -729,9 +731,10 @@ def test_BGP_GR_TC_11_p0(request): result = verify_eor( tgen, topo, addr_type, input_dict, dut="r3", peer="r1", expected=False ) - assert result is not True, "Testcase {} : Failed \n Error {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r3: EOR is set to True\n Error: {}".format( tc_name, result - ) + )) write_test_footer(tc_name) @@ -1465,31 +1468,35 @@ def test_BGP_GR_18_p1(request): dut = "r6" input_dict_1 = {key: topo["routers"][key] for key in ["r1"]} result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1, expected=False) - assert result is not True, "Testcase {} : Failed \n Error {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r6: routes are still present in BGP RIB\n Error: {}".format( tc_name, result - ) + )) logger.info(" Expected behavior: {}".format(result)) # Verifying RIB routes before shutting down BGPd daemon result = verify_rib(tgen, addr_type, dut, input_dict_1, expected=False) - assert result is not True, "Testcase {} : Failed \n Error {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r6: routes are still present in ZEBRA\n Error: {}".format( tc_name, result - ) + )) logger.info(" Expected behavior: {}".format(result)) # Verifying BGP RIB routes dut = "r2" result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1, expected=False) - assert result is not True, "Testcase {} : Failed \n Error {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r2: routes are still present in BGP RIB\n Error: {}".format( tc_name, result - ) + )) logger.info(" Expected behavior: {}".format(result)) # Verifying RIB routes before shutting down BGPd daemon result = verify_rib(tgen, addr_type, dut, input_dict_1, expected=False) - assert result is not True, "Testcase {} : Failed \n Error {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r6: routes are still present in ZEBRA\n Error: {}".format( tc_name, result - ) + )) logger.info(" Expected behavior: {}".format(result)) write_test_footer(tc_name) @@ -1950,16 +1957,18 @@ def test_BGP_GR_chaos_29_p1(request): # Verifying BGP RIB routes before shutting down BGPd daemon input_dict = {key: topo["routers"][key] for key in ["r1"]} result = verify_bgp_rib(tgen, addr_type, dut, input_dict, expected=False) - assert result is not True, "Testcase {} : Failed \n Error {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r3: routes are still present in BGP RIB\n Error: {}".format( tc_name, result - ) + )) logger.info(" Expected behavior: {}".format(result)) # Verifying RIB routes before shutting down BGPd daemon result = verify_rib(tgen, addr_type, dut, input_dict, expected=False) - assert result is not True, "Testcase {} : Failed \n Error {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r3: routes are still present in ZEBRA\n Error: {}".format( tc_name, result - ) + )) logger.info(" Expected behavior: {}".format(result)) logger.info("[Step 4] : Start BGPd daemon on R1..") @@ -2201,9 +2210,10 @@ def test_BGP_GR_chaos_33_p1(request): result = verify_rib( tgen, addr_type, dut, input_dict_2, next_hop_4, expected=False ) - assert result is not True, "Testcase {} : Failed \n Error {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r3: routes are still present in BGP RIB\n Error: {}".format( tc_name, result - ) + )) logger.info(" Expected behavior: {}".format(result)) if addr_type == "ipv6": @@ -2215,9 +2225,10 @@ def test_BGP_GR_chaos_33_p1(request): result = verify_rib( tgen, addr_type, dut, input_dict_2, next_hop_6, expected=False ) - assert result is not True, "Testcase {} :Failed \n Error {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r3: routes are still present in ZEBRA\n Error: {}".format( tc_name, result - ) + )) logger.info(" Expected behavior: {}".format(result)) logger.info("[Step 4] : Start BGPd daemon on R1 and R4..") @@ -2398,24 +2409,27 @@ def test_BGP_GR_chaos_34_2_p1(request): result = verify_f_bit( tgen, topo, addr_type, input_dict, "r3", "r1", expected=False ) - assert result is not True, "Testcase {} : Failed \n Error {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r3: F-bit is set to True\n Error: {}".format( tc_name, result - ) + )) logger.info(" Expected behavior: {}".format(result)) # Verifying BGP RIB routes after starting BGPd daemon input_dict_1 = {key: topo["routers"][key] for key in ["r1"]} result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1, expected=False) - assert result is not True, "Testcase {} : Failed \n Error {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r3: routes are still present in BGP RIB\n Error: {}".format( tc_name, result - ) + )) logger.info(" Expected behavior: {}".format(result)) # Verifying RIB routes result = verify_rib(tgen, addr_type, dut, input_dict_1, expected=False) - assert result is not True, "Testcase {} : Failed \n Error {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r3: routes are still present in ZEBRA\n Error: {}".format( tc_name, result - ) + )) logger.info(" Expected behavior: {}".format(result)) write_test_footer(tc_name) @@ -2552,9 +2566,10 @@ def test_BGP_GR_chaos_34_1_p1(request): result = verify_f_bit( tgen, topo, addr_type, input_dict_2, "r3", "r1", expected=False ) - assert result is not True, "Testcase {} : Failed \n Error {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r3: F-bit is set to True\n Error: {}".format( tc_name, result - ) + )) logger.info(" Expected behavior: {}".format(result)) logger.info("[Step 3] : Kill BGPd daemon on R1..") @@ -2570,16 +2585,18 @@ def test_BGP_GR_chaos_34_1_p1(request): # Verifying BGP RIB routes input_dict = {key: topo["routers"][key] for key in ["r1"]} result = verify_bgp_rib(tgen, addr_type, dut, input_dict, expected=False) - assert result is not True, "Testcase {} : Failed \n Error {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r3: routes are still present in BGP RIB\n Error: {}".format( tc_name, result - ) + )) logger.info(" Expected behavior: {}".format(result)) # Verifying RIB routes result = verify_rib(tgen, addr_type, dut, input_dict, expected=False) - assert result is not True, "Testcase {} : Failed \n Error {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r3: routes are still present in ZEBRA\n Error: {}".format( tc_name, result - ) + )) logger.info(" Expected behavior: {}".format(result)) # Start BGPd daemon on R1 @@ -2753,24 +2770,27 @@ def test_BGP_GR_chaos_32_p1(request): result = verify_eor( tgen, topo, addr_type, input_dict_3, dut="r5", peer="r1", expected=False ) - assert result is not True, "Testcase {} : Failed \n Error {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r5: EOR is set to TRUE\n Error: {}".format( tc_name, result - ) + )) logger.info(" Expected behavior: {}".format(result)) # Verifying BGP RIB routes after starting BGPd daemon input_dict_1 = {key: topo["routers"][key] for key in ["r5"]} result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1, expected=False) - assert result is not True, "Testcase {} : Failed \n Error {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r3: routes are still present in BGP RIB\n Error: {}".format( tc_name, result - ) + )) logger.info(" Expected behavior: {}".format(result)) # Verifying RIB routes result = verify_rib(tgen, addr_type, dut, input_dict_1, expected=False) - assert result is not True, "Testcase {} : Failed \n Error {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r3: routes are still present in ZEBRA\n Error: {}".format( tc_name, result - ) + )) logger.info(" Expected behavior: {}".format(result)) write_test_footer(tc_name) @@ -2876,9 +2896,10 @@ def test_BGP_GR_chaos_37_p1(request): result = verify_eor( tgen, topo, addr_type, input_dict, dut="r3", peer="r1", expected=False ) - assert result is not True, "Testcase {} : Failed \n Error {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r3: EOR is set to True\n Error: {}".format( tc_name, result - ) + )) logger.info(" Expected behavior: {}".format(result)) # Verifying BGP RIB routes after starting BGPd daemon @@ -2941,9 +2962,10 @@ def test_BGP_GR_chaos_37_p1(request): result = verify_eor( tgen, topo, addr_type, input_dict_3, dut="r1", peer="r3", expected=False ) - assert result is not True, "Testcase {} : Failed \n Error {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r1: EOR is set to True\n Error: {}".format( tc_name, result - ) + )) write_test_footer(tc_name) @@ -3095,16 +3117,18 @@ def test_BGP_GR_chaos_30_p1(request): # Verifying BGP RIB routes before shutting down BGPd daemon input_dict = {key: topo["routers"][key] for key in ["r3"]} result = verify_bgp_rib(tgen, addr_type, dut, input_dict, expected=False) - assert result is not True, "Testcase {} : Failed \n Error {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r1: routes are still present in BGP RIB\n Error: {}".format( tc_name, result - ) + )) logger.info(" Expected behavior: {}".format(result)) # Verifying RIB routes before shutting down BGPd daemon result = verify_rib(tgen, addr_type, dut, input_dict, expected=False) - assert result is not True, "Testcase {} : Failed \n Error {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r1: routes are still present in ZEBRA\n Error: {}".format( tc_name, result - ) + )) logger.info(" Expected behavior: {}".format(result)) write_test_footer(tc_name) @@ -3506,9 +3530,10 @@ def BGP_GR_TC_7_p1(request): dut = "r1" input_dict_1 = {key: topo["routers"][key] for key in ["r3"]} result = verify_rib(tgen, addr_type, dut, input_dict_1, expected=False) - assert result is not True, "Testcase {} :Failed \n Error {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r1: routes are still present in ZEBRA\n Error: {}".format( tc_name, result - ) + )) write_test_footer(tc_name) @@ -3682,9 +3707,10 @@ def test_BGP_GR_TC_23_p1(request): result = verify_eor( tgen, topo, addr_type, input_dict, dut="r1", peer="r2", expected=False ) - assert result is not True, ( - "Testcase " + tc_name + " :Failed \n Error: {}".format(result) - ) + assert result is not True, ("Testcase {} : Failed \n " + "r1: EOR is set to True\n Error: {}".format( + tc_name, result + )) # Verifying BGP RIB routes received from router R1 dut = "r1" @@ -3805,16 +3831,18 @@ def test_BGP_GR_20_p1(request): dut = "r3" input_dict_1 = {key: topo["routers"][key] for key in ["r1"]} result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1, expected=False) - assert result is not True, "Testcase {} :Failed \n Error {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r3: routes are still present in BGP RIB\n Error: {}".format( tc_name, result - ) + )) logger.info(" Expected behavior: {}".format(result)) # Verifying RIB routes before shutting down BGPd daemon result = verify_rib(tgen, addr_type, dut, input_dict_1, expected=False) - assert result is not True, "Testcase {} :Failed \n Error {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r3: routes are still present in ZEBRA\n Error: {}".format( tc_name, result - ) + )) logger.info(" Expected behavior: {}".format(result)) # Start BGPd daemon on R1 diff --git a/tests/topotests/bgp_l3vpn_to_bgp_direct/test_bgp_l3vpn_to_bgp_direct.py b/tests/topotests/bgp_l3vpn_to_bgp_direct/test_bgp_l3vpn_to_bgp_direct.py index d863f9c3ed..be12cfde37 100755 --- a/tests/topotests/bgp_l3vpn_to_bgp_direct/test_bgp_l3vpn_to_bgp_direct.py +++ b/tests/topotests/bgp_l3vpn_to_bgp_direct/test_bgp_l3vpn_to_bgp_direct.py @@ -31,6 +31,7 @@ from lib.ltemplate import * pytestmark = [pytest.mark.bgpd, pytest.mark.ospfd] + def test_adjacencies(): CliOnFail = None # For debugging, uncomment the next line diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/test_bgp_l3vpn_to_bgp_vrf.py b/tests/topotests/bgp_l3vpn_to_bgp_vrf/test_bgp_l3vpn_to_bgp_vrf.py index d2e40037a6..8bb700235c 100755 --- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/test_bgp_l3vpn_to_bgp_vrf.py +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/test_bgp_l3vpn_to_bgp_vrf.py @@ -31,6 +31,7 @@ from lib.ltemplate import * pytestmark = [pytest.mark.bgpd, pytest.mark.ospfd] + def test_check_linux_vrf(): CliOnFail = None # For debugging, uncomment the next line diff --git a/tests/topotests/bgp_large_community/test_bgp_large_community_topo_2.py b/tests/topotests/bgp_large_community/test_bgp_large_community_topo_2.py index c2858a4bd0..8e5ffe10be 100644 --- a/tests/topotests/bgp_large_community/test_bgp_large_community_topo_2.py +++ b/tests/topotests/bgp_large_community/test_bgp_large_community_topo_2.py @@ -598,9 +598,10 @@ def test_large_community_lists_with_rmap_apply_and_remove(request): result = verify_bgp_community( tgen, adt, dut, NETWORKS[adt], input_dict_4, expected=False ) - assert result is not True, "Testcase {} : Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "largeCommunity is still present after deleting route-map \n Error: {}".format( tc_name, result - ) + )) write_test_footer(tc_name) @@ -898,9 +899,10 @@ def test_large_community_lists_with_rmap_set_none(request): dut = "r6" for adt in ADDR_TYPES: result = verify_bgp_community(tgen, adt, dut, NETWORKS[adt], expected=False) - assert result is not True, "Testcase {} : Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "Community-list is still present \n Error: {}".format( tc_name, result - ) + )) write_test_footer(tc_name) @@ -2236,9 +2238,10 @@ def test_large_community_lists_with_rmap_match_regex(request): result = verify_bgp_community( tgen, adt, dut, NETWORKS[adt], input_dict_7, expected=False ) - assert result is not True, "Testcase {} : Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "largeCommunity is still present \n Error: {}".format( tc_name, result - ) + )) write_test_footer(tc_name) diff --git a/tests/topotests/bgp_listen_on_multiple_addresses/test_bgp_listen_on_multiple_addresses.py b/tests/topotests/bgp_listen_on_multiple_addresses/test_bgp_listen_on_multiple_addresses.py index d773e87ef6..a3ca1408e2 100755 --- a/tests/topotests/bgp_listen_on_multiple_addresses/test_bgp_listen_on_multiple_addresses.py +++ b/tests/topotests/bgp_listen_on_multiple_addresses/test_bgp_listen_on_multiple_addresses.py @@ -142,7 +142,7 @@ def _bgp_converge_initial(router_name, peer_address, timeout=180): """ Waits for the BGP connection between a given router and a given peer (specified by its IP address) to be established. If the connection is - not established within a given timeout, then an exception is raised. + not established within a given timeout, then an exception is raised. """ tgen = get_topogen() router = tgen.routers()[router_name] diff --git a/tests/topotests/bgp_lu_topo1/test_bgp_lu.py b/tests/topotests/bgp_lu_topo1/test_bgp_lu.py index 61418d7a79..d550c38a2f 100644 --- a/tests/topotests/bgp_lu_topo1/test_bgp_lu.py +++ b/tests/topotests/bgp_lu_topo1/test_bgp_lu.py @@ -45,17 +45,18 @@ from lib.topolog import logger # Required to instantiate the topology builder class. from mininet.topo import Topo -#Basic scenario for BGP-LU. Nodes are directly connected. -#Node 3 is advertising many routes to 2, which advertises them -#as BGP-LU to 1; this way we get routes with actual labels, as -#opposed to implicit-null routes in the 2-node case. +# Basic scenario for BGP-LU. Nodes are directly connected. +# Node 3 is advertising many routes to 2, which advertises them +# as BGP-LU to 1; this way we get routes with actual labels, as +# opposed to implicit-null routes in the 2-node case. # # AS1 BGP-LU AS2 iBGP AS2 -#+-----+ +-----+ +-----+ -#| |.1 .2| |.2 .3| | -#| 1 +----------------+ 2 +-----------------+ 3 | -#| | 10.0.0.0/24 | | 10.0.1.0/24 | | -#+-----+ +-----+ +-----+ +# +-----+ +-----+ +-----+ +# | |.1 .2| |.2 .3| | +# | 1 +----------------+ 2 +-----------------+ 3 | +# | | 10.0.0.0/24 | | 10.0.1.0/24 | | +# +-----+ +-----+ +-----+ + class TemplateTopo(Topo): "Test topology builder" @@ -84,7 +85,6 @@ class TemplateTopo(Topo): switch.add_link(tgen.gears["R3"]) - def setup_module(mod): "Sets up the pytest environment" # This function initiates the topology build with Topogen... @@ -115,15 +115,19 @@ def teardown_module(mod): # This function tears down the whole topology. tgen.stop_topology() + def check_labelpool(router): json_file = "{}/{}/labelpool.summ.json".format(CWD, router.name) expected = json.loads(open(json_file).read()) - test_func = partial(topotest.router_json_cmp, router, "show bgp labelpool summary json", expected) + test_func = partial( + topotest.router_json_cmp, router, "show bgp labelpool summary json", expected + ) _, result = topotest.run_and_expect(test_func, None, count=20, wait=1) assertmsg = '"{}" JSON output mismatches - Did not converge'.format(router.name) assert result is None, assertmsg - + + def test_converge_bgplu(): "Wait for protocol convergence" @@ -132,13 +136,14 @@ def test_converge_bgplu(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - #tgen.mininet_cli(); + # tgen.mininet_cli(); r1 = tgen.gears["R1"] r2 = tgen.gears["R2"] check_labelpool(r1) check_labelpool(r2) + def test_clear_bgplu(): "Wait for protocol convergence" @@ -147,7 +152,7 @@ def test_clear_bgplu(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - #tgen.mininet_cli(); + # tgen.mininet_cli(); r1 = tgen.gears["R1"] r2 = tgen.gears["R2"] @@ -164,6 +169,7 @@ def test_clear_bgplu(): check_labelpool(r1) check_labelpool(r2) + def test_memory_leak(): "Run the memory leak test and report results." tgen = get_topogen() 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 cf6b7cc53f..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) @@ -504,9 +508,10 @@ def test_ambiguous_overlapping_addresses_in_different_vrfs_p0(request): ) result = verify_rib(tgen, addr_type, dut, input_dict_1, tag=500, expected=False) - assert result is not True, "Testcase {} : Failed \n Error {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "Routes are present with tag value 500 \n Error: {}".format( tc_name, result - ) + )) logger.info("Expected Behavior: {}".format(result)) step( @@ -1142,9 +1147,10 @@ def test_prefixes_leaking_p0(request): result = verify_rib( tgen, addr_type, dut, input_dict_1, metric=123, expected=False ) - assert result is not True, "Testcase {} : Failed \n Error {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "Routes are present with metric value 123 \n Error: {}".format( tc_name, result - ) + )) logger.info("Expected Behavior: {}".format(result)) result = verify_rib(tgen, addr_type, dut, input_dict_2, metric=123) @@ -1155,9 +1161,10 @@ def test_prefixes_leaking_p0(request): result = verify_rib( tgen, addr_type, dut, input_dict_2, metric=0, expected=False ) - assert result is not True, "Testcase {} : Failed \n Error {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "Routes are present with metric value 0 \n Error: {}".format( tc_name, result - ) + )) logger.info("Expected Behavior: {}".format(result)) write_test_footer(tc_name) 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 19a9140c13..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) @@ -2214,14 +2218,16 @@ def test_restart_bgpd_daemon_p1(request): } result = verify_rib(tgen, addr_type, dut, input_dict_1, expected=False) - assert result is not True, "Testcase {} :Failed \n Error {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "Routes are still present in VRF RED_A and RED_B \n Error: {}".format( tc_name, result - ) + )) result = verify_rib(tgen, addr_type, dut, input_dict_2, expected=False) - assert result is not True, "Testcase {} :Failed \n Error {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "Routes are still present in VRF BLUE_A and BLUE_B \n Error: {}".format( tc_name, result - ) + )) step("Bring up BGPd daemon on R1.") start_router_daemons(tgen, "r1", ["bgpd"]) diff --git a/tests/topotests/bgp_recursive_route_ebgp_multi_hop/test_bgp_recursive_route_ebgp_multi_hop.py b/tests/topotests/bgp_recursive_route_ebgp_multi_hop/test_bgp_recursive_route_ebgp_multi_hop.py index 3f9009967d..4764ff8945 100644 --- a/tests/topotests/bgp_recursive_route_ebgp_multi_hop/test_bgp_recursive_route_ebgp_multi_hop.py +++ b/tests/topotests/bgp_recursive_route_ebgp_multi_hop/test_bgp_recursive_route_ebgp_multi_hop.py @@ -20,7 +20,7 @@ # """ -Following tests are covered to test bgp recursive route and ebgp +Following tests are covered to test bgp recursive route and ebgp multi-hop functionality: 1. Verify that BGP routes are installed in iBGP peer, only when there @@ -365,9 +365,10 @@ def test_recursive_routes_iBGP_peer_p1(request): protocol="bgp", expected=False, ) - assert result is not True, "Testcase : Failed \n Error : {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "Routes are still present \n Error: {}".format( tc_name, result - ) + )) step("Reconfigure the same static route on R2 again") dut = "r2" @@ -485,9 +486,10 @@ def test_recursive_routes_iBGP_peer_p1(request): result = verify_rib( tgen, addr_type, "r2", input_dict_4, protocol="bgp", expected=False ) - assert result is not True, "Testcase {} : Failed \n Error : {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "Routes are still present \n Error: {}".format( tc_name, result - ) + )) write_test_footer(tc_name) @@ -596,9 +598,10 @@ def test_next_hop_as_self_ip_p1(request): next_hop=topo["routers"]["r2"]["links"]["r4"][addr_type].split("/")[0], expected=False, ) - assert result is not True, "Testcase : Failed \n Error : {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "Routes are still present \n Error: {}".format( tc_name, result - ) + )) step("Shut interface on R2 that has IP from the subnet as BGP next-hop") intf_r2_r4 = topo["routers"]["r2"]["links"]["r4"]["interface"] @@ -673,9 +676,10 @@ def test_next_hop_as_self_ip_p1(request): next_hop=topo["routers"]["r2"]["links"]["r4"][addr_type].split("/")[0], expected=False, ) - assert result is not True, "Testcase : Failed \n Error : {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "Routes are still present \n Error: {}".format( tc_name, result - ) + )) write_test_footer(tc_name) @@ -1618,9 +1622,10 @@ def test_BGP_peering_bw_loopback_and_physical_p1(request): step("Verify that once eBGP multi-hop is removed, BGP session goes down") result = verify_bgp_convergence_from_running_config(tgen, expected=False) - assert result is not True, "Testcase {} : Failed \n Error : {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "BGP is converged \n Error: {}".format( tc_name, result - ) + )) step("Add ebgp-multihop command on R3 again") for addr_type in ADDR_TYPES: @@ -1658,9 +1663,10 @@ def test_BGP_peering_bw_loopback_and_physical_p1(request): step("Verify that BGP session goes down, when update-source is removed") result = verify_bgp_convergence_from_running_config(tgen, expected=False) - assert result is not True, "Testcase {} : Failed \n Error : {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "BGP is converged \n Error: {}".format( tc_name, result - ) + )) step("Add update-source command on R1 again") for addr_type in ADDR_TYPES: @@ -1709,16 +1715,18 @@ def test_BGP_peering_bw_loopback_and_physical_p1(request): next_hop=topo["routers"]["r1"]["links"]["r3"][addr_type].split("/")[0], expected=False, ) - assert result is not True, "Testcase {} : Failed \n Error : {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "Routes are still present \n Error: {}".format( tc_name, result - ) + )) sleep(3) step("Verify that BGP session goes down, when static route is removed") result = verify_bgp_convergence_from_running_config(tgen, expected=False) - assert result is not True, "Testcase {} : Failed \n Error : {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "BGP is converged \n Error: {}".format( tc_name, result - ) + )) step("Add static route on R3 again") for addr_type in ADDR_TYPES: @@ -1760,9 +1768,10 @@ def test_BGP_peering_bw_loopback_and_physical_p1(request): sleep(3) step("Verify that BGP neighborship between R1 and R3 goes down") result = verify_bgp_convergence_from_running_config(tgen, expected=False) - assert result is not True, "Testcase {} : Failed \n Error : {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "BGP is converged \n Error: {}".format( tc_name, result - ) + )) intf_r1_r3 = topo["routers"]["r1"]["links"]["r3"]["interface"] shutdown_bringup_interface(tgen, "r1", intf_r1_r3, True) @@ -2078,9 +2087,10 @@ def test_BGP_active_standby_preemption_and_ecmp_p1(request): ], expected=False, ) - assert result is not True, "Testcase {} : Failed \n Error : {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "Routes are still present \n Error: {}".format( tc_name, result - ) + )) step("Reconfigure multipath-relax command on R4") result = create_router_bgp(tgen, topo, maxpath_relax) @@ -2137,9 +2147,10 @@ def test_BGP_active_standby_preemption_and_ecmp_p1(request): ], expected=False, ) - assert result is not True, "Testcase {} : Failed \n Error : {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "Routes are still present \n Error: {}".format( tc_name, result - ) + )) step("Re-configure maximum-path 2 command on R4") input_dict_8 = { @@ -2327,9 +2338,10 @@ def test_password_authentication_for_eBGP_and_iBGP_peers_p1(request): "configured but not peer routers" ) result = verify_bgp_convergence(tgen, topo, expected=False) - assert result is not True, "Testcase {} : Failed \n Error : {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "BGP is converged \n Error: {}".format( tc_name, result - ) + )) step("configure same password on R2 and R3") for routerN in ["r2", "r3"]: @@ -2356,9 +2368,10 @@ def test_password_authentication_for_eBGP_and_iBGP_peers_p1(request): "strings are in CAPs on R2 and R3" ) result = verify_bgp_convergence(tgen, topo, expected=False) - assert result is not True, "Testcase {} : Failed \n Error : {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "BGP is converged \n Error: {}".format( tc_name, result - ) + )) step("Configure same password on R2 and R3 without CAPs") for routerN in ["r2", "r3"]: @@ -2382,9 +2395,10 @@ def test_password_authentication_for_eBGP_and_iBGP_peers_p1(request): step("Verify if password is removed from R1, both sessions go down again") result = verify_bgp_convergence(tgen, topo, expected=False) - assert result is not True, "Testcase {} : Failed \n Error : {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "BGP is converged \n Error: {}".format( tc_name, result - ) + )) step("Configure alphanumeric password on R1 and peer routers R2,R3") for bgp_neighbor in ["r2", "r3"]: diff --git a/tests/topotests/bgp_rfapi_basic_sanity/test_bgp_rfapi_basic_sanity.py b/tests/topotests/bgp_rfapi_basic_sanity/test_bgp_rfapi_basic_sanity.py index ce69f28aba..fa04aaf366 100755 --- a/tests/topotests/bgp_rfapi_basic_sanity/test_bgp_rfapi_basic_sanity.py +++ b/tests/topotests/bgp_rfapi_basic_sanity/test_bgp_rfapi_basic_sanity.py @@ -31,6 +31,7 @@ from lib.ltemplate import * pytestmark = [pytest.mark.bgpd, pytest.mark.ospfd] + def test_add_routes(): CliOnFail = None # For debugging, uncomment the next line diff --git a/tests/topotests/bgp_suppress_fib/r3/v4_route.json b/tests/topotests/bgp_suppress_fib/r3/v4_route.json index 19294eb492..e255d07599 100644 --- a/tests/topotests/bgp_suppress_fib/r3/v4_route.json +++ b/tests/topotests/bgp_suppress_fib/r3/v4_route.json @@ -19,7 +19,6 @@ "fib":true, "ip":"10.0.0.9", "afi":"ipv4", - "interfaceIndex":2, "interfaceName":"r3-eth0", "active":true } diff --git a/tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo1.py b/tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo1.py index 63db393178..b99f1a7418 100644 --- a/tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo1.py +++ b/tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo1.py @@ -498,7 +498,6 @@ def disable_route_map_to_prefer_global_next_hop(tgen, topo): # ##################################################### - def test_dynamic_imported_routes_advertised_to_iBGP_peer_p0(request): """ TC5_FUNC_5: @@ -761,6 +760,29 @@ def test_dynamic_imported_routes_advertised_to_iBGP_peer_p0(request): tc_name, result ) + for addr_type in ADDR_TYPES: + + step( + "On router R1 delete static routes in vrf ISR to LOOPBACK_1" + ) + + input_routes_r1 = { + "r1": { + "static_routes": [ + { + "network": [NETWORK1_3[addr_type], NETWORK1_4[addr_type]], + "next_hop": (intf_r2_r1[addr_type]).split("/")[0], + "delete": True + } + ] + } + } + + result = create_static_routes(tgen, input_routes_r1) + assert result is True, "Testcase {} :Failed \n Error: {}".format( + tc_name, result + ) + write_test_footer(tc_name) diff --git a/tests/topotests/docker/frr-topotests.sh b/tests/topotests/docker/frr-topotests.sh index d25856ea62..9ef59b3bbc 100755 --- a/tests/topotests/docker/frr-topotests.sh +++ b/tests/topotests/docker/frr-topotests.sh @@ -132,6 +132,7 @@ if [ -z "$TOPOTEST_FRR" ]; then echo "frr-topotests only works if you have your tree in git." >&2 exit 1 fi + git -C "$TOPOTEST_FRR" ls-files -z > "${TOPOTEST_LOGS}/git-ls-files" fi if [ -z "$TOPOTEST_BUILDCACHE" ]; then diff --git a/tests/topotests/docker/inner/compile_frr.sh b/tests/topotests/docker/inner/compile_frr.sh index dee0ec8118..495beaf3cc 100755 --- a/tests/topotests/docker/inner/compile_frr.sh +++ b/tests/topotests/docker/inner/compile_frr.sh @@ -34,19 +34,15 @@ CDIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" if [ "${TOPOTEST_CLEAN}" != "0" ]; then log_info "Cleaning FRR builddir..." - rm -rf $FRR_SYNC_DIR $FRR_BUILD_DIR &> /dev/null + rm -rf $FRR_BUILD_DIR &> /dev/null fi log_info "Syncing FRR source with host..." -mkdir -p $FRR_SYNC_DIR +mkdir -p $FRR_BUILD_DIR rsync -a --info=progress2 \ - --exclude '*.o' \ - --exclude '*.lo'\ + --from0 --files-from=/tmp/git-ls-files \ --chown root:root \ - $FRR_HOST_DIR/. $FRR_SYNC_DIR/ -(cd $FRR_SYNC_DIR && git clean -xdf > /dev/null) -mkdir -p $FRR_BUILD_DIR -rsync -a --info=progress2 --chown root:root $FRR_SYNC_DIR/. $FRR_BUILD_DIR/ + $FRR_HOST_DIR/. $FRR_BUILD_DIR/ cd "$FRR_BUILD_DIR" || \ log_fatal "failed to find frr directory" diff --git a/tests/topotests/docker/inner/funcs.sh b/tests/topotests/docker/inner/funcs.sh index acb8b55e97..d78d5006bc 100755 --- a/tests/topotests/docker/inner/funcs.sh +++ b/tests/topotests/docker/inner/funcs.sh @@ -23,7 +23,6 @@ # SOFTWARE. FRR_HOST_DIR=/root/host-frr -FRR_SYNC_DIR=/root/persist/frr-sync FRR_BUILD_DIR=/root/persist/frr-build if [ ! -L "/root/frr" ]; then diff --git a/tests/topotests/evpn_type5_test_topo1/test_evpn_type5_topo1.py b/tests/topotests/evpn_type5_test_topo1/test_evpn_type5_topo1.py index 87f391ae49..1a399ab32e 100644 --- a/tests/topotests/evpn_type5_test_topo1/test_evpn_type5_topo1.py +++ b/tests/topotests/evpn_type5_test_topo1/test_evpn_type5_topo1.py @@ -1312,14 +1312,14 @@ def test_evpn_routes_from_VNFs_p1(request): ) for addr_type in ADDR_TYPES: input_routes = {key: topo["routers"][key] for key in ["r1"]} - result = verify_rib(tgen, addr_type, "d2", input_routes, expected=False) + result = verify_rib(tgen, addr_type, "d2", input_routes) assert result is True, "Testcase {} :Failed \n Error: {}".format( tc_name, result ) for addr_type in ADDR_TYPES: input_routes = {key: topo["routers"][key] for key in ["r2"]} - result = verify_rib(tgen, addr_type, "d2", input_routes, expected=False) + result = verify_rib(tgen, addr_type, "d2", input_routes) assert result is True, "Testcase {} :Failed \n Error: {}".format( tc_name, result ) @@ -1475,8 +1475,8 @@ def test_evpn_routes_from_VNFs_p1(request): tgen, dut, intf_name, intf_ipv6, vrf, create=False ) - logger.info("Wait for 60 sec.") - sleep(60) + result = verify_bgp_convergence(tgen, topo, dut) + assert result is True, "Failed to converge on {}".format(dut) step( "Verify that DCG-2 receives EVPN routes corresponding to " diff --git a/tests/topotests/example-test/test_template.py b/tests/topotests/example-test/test_template.py index 973303b830..0265dbe796 100644 --- a/tests/topotests/example-test/test_template.py +++ b/tests/topotests/example-test/test_template.py @@ -44,7 +44,7 @@ from lib.topolog import logger from mininet.topo import Topo -#TODO: select markers based on daemons used during test +# TODO: select markers based on daemons used during test # pytest module level markers """ pytestmark = pytest.mark.bfdd # single marker diff --git a/tests/topotests/example-topojson-test/test_topo_json_multiple_links/test_example_topojson_multiple_links.py b/tests/topotests/example-topojson-test/test_topo_json_multiple_links/test_example_topojson_multiple_links.py index cd48716905..09ac9f2fa4 100755 --- a/tests/topotests/example-topojson-test/test_topo_json_multiple_links/test_example_topojson_multiple_links.py +++ b/tests/topotests/example-topojson-test/test_topo_json_multiple_links/test_example_topojson_multiple_links.py @@ -54,7 +54,7 @@ from lib.bgp import verify_bgp_convergence from lib.topojson import build_topo_from_json, build_config_from_json -#TODO: select markers based on daemons used during test +# TODO: select markers based on daemons used during test # pytest module level markers """ pytestmark = pytest.mark.bfdd # single marker diff --git a/tests/topotests/example-topojson-test/test_topo_json_single_link/test_example_topojson.py b/tests/topotests/example-topojson-test/test_topo_json_single_link/test_example_topojson.py index 0c72e30044..26336d5de1 100755 --- a/tests/topotests/example-topojson-test/test_topo_json_single_link/test_example_topojson.py +++ b/tests/topotests/example-topojson-test/test_topo_json_single_link/test_example_topojson.py @@ -53,7 +53,7 @@ from lib.bgp import verify_bgp_convergence from lib.topojson import build_topo_from_json, build_config_from_json -#TODO: select markers based on daemons used during test +# TODO: select markers based on daemons used during test # pytest module level markers """ pytestmark = pytest.mark.bfdd # single marker diff --git a/tests/topotests/example-topojson-test/test_topo_json_single_link_loopback/test_example_topojson.py b/tests/topotests/example-topojson-test/test_topo_json_single_link_loopback/test_example_topojson.py index d05ad6db21..012b05d376 100755 --- a/tests/topotests/example-topojson-test/test_topo_json_single_link_loopback/test_example_topojson.py +++ b/tests/topotests/example-topojson-test/test_topo_json_single_link_loopback/test_example_topojson.py @@ -55,7 +55,7 @@ from lib.bgp import verify_bgp_convergence from lib.topojson import build_topo_from_json, build_config_from_json -#TODO: select markers based on daemons used during test +# TODO: select markers based on daemons used during test # pytest module level markers """ pytestmark = pytest.mark.bfdd # single marker diff --git a/tests/topotests/isis-lfa-topo1/test_isis_lfa_topo1.py b/tests/topotests/isis-lfa-topo1/test_isis_lfa_topo1.py index ab15c3542f..dcfcd11435 100755 --- a/tests/topotests/isis-lfa-topo1/test_isis_lfa_topo1.py +++ b/tests/topotests/isis-lfa-topo1/test_isis_lfa_topo1.py @@ -165,6 +165,7 @@ class TemplateTopo(Topo): f_in.close() f_out.close() + def setup_module(mod): "Sets up the pytest environment" tgen = Topogen(TemplateTopo, mod.__name__) diff --git a/tests/topotests/isis-lsp-bits-topo1/rt5/step1/show_ip_route.ref b/tests/topotests/isis-lsp-bits-topo1/rt5/step1/show_ip_route.ref index fe34b03890..358d0a230c 100644 --- a/tests/topotests/isis-lsp-bits-topo1/rt5/step1/show_ip_route.ref +++ b/tests/topotests/isis-lsp-bits-topo1/rt5/step1/show_ip_route.ref @@ -49,7 +49,6 @@ { "ip":"10.0.4.3", "afi":"ipv4", - "interfaceIndex":2, "interfaceName":"eth-rt3" } ] @@ -65,7 +64,6 @@ { "ip":"10.0.6.4", "afi":"ipv4", - "interfaceIndex":3, "interfaceName":"eth-rt4" } ] diff --git a/tests/topotests/isis-lsp-bits-topo1/rt6/step1/show_ip_route.ref b/tests/topotests/isis-lsp-bits-topo1/rt6/step1/show_ip_route.ref index 2840514e6e..40375792a4 100644 --- a/tests/topotests/isis-lsp-bits-topo1/rt6/step1/show_ip_route.ref +++ b/tests/topotests/isis-lsp-bits-topo1/rt6/step1/show_ip_route.ref @@ -98,7 +98,6 @@ { "ip":"10.0.8.5", "afi":"ipv4", - "interfaceIndex":3, "interfaceName":"eth-rt5" } ] diff --git a/tests/topotests/isis-lsp-bits-topo1/rt6/step2/show_ip_route.ref b/tests/topotests/isis-lsp-bits-topo1/rt6/step2/show_ip_route.ref index 61efcb9e98..8083be4cfb 100644 --- a/tests/topotests/isis-lsp-bits-topo1/rt6/step2/show_ip_route.ref +++ b/tests/topotests/isis-lsp-bits-topo1/rt6/step2/show_ip_route.ref @@ -91,7 +91,6 @@ { "ip":"10.0.8.5", "afi":"ipv4", - "interfaceIndex":3, "interfaceName":"eth-rt5" } ] diff --git a/tests/topotests/isis-lsp-bits-topo1/rt6/step3/show_ip_route.ref b/tests/topotests/isis-lsp-bits-topo1/rt6/step3/show_ip_route.ref index 8fecf14687..1ba8c8cda8 100644 --- a/tests/topotests/isis-lsp-bits-topo1/rt6/step3/show_ip_route.ref +++ b/tests/topotests/isis-lsp-bits-topo1/rt6/step3/show_ip_route.ref @@ -71,7 +71,6 @@ { "ip":"10.0.8.5", "afi":"ipv4", - "interfaceIndex":3, "interfaceName":"eth-rt5" } ] diff --git a/tests/topotests/isis-lsp-bits-topo1/rt6/step4/show_ip_route.ref b/tests/topotests/isis-lsp-bits-topo1/rt6/step4/show_ip_route.ref index 2840514e6e..40375792a4 100644 --- a/tests/topotests/isis-lsp-bits-topo1/rt6/step4/show_ip_route.ref +++ b/tests/topotests/isis-lsp-bits-topo1/rt6/step4/show_ip_route.ref @@ -98,7 +98,6 @@ { "ip":"10.0.8.5", "afi":"ipv4", - "interfaceIndex":3, "interfaceName":"eth-rt5" } ] diff --git a/tests/topotests/isis-lsp-bits-topo1/test_isis_lsp_bits_topo1.py b/tests/topotests/isis-lsp-bits-topo1/test_isis_lsp_bits_topo1.py index 95a0d87c33..27dc1073c6 100755 --- a/tests/topotests/isis-lsp-bits-topo1/test_isis_lsp_bits_topo1.py +++ b/tests/topotests/isis-lsp-bits-topo1/test_isis_lsp_bits_topo1.py @@ -73,7 +73,7 @@ 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, '../')) +sys.path.append(os.path.join(CWD, "../")) # pylint: disable=C0413 # Import topogen and topotest helpers @@ -87,8 +87,10 @@ from mininet.topo import Topo # Global multi-dimensional dictionary containing all expected outputs outputs = {} + class TemplateTopo(Topo): "Test topology builder" + def build(self, *_args, **_opts): "Build function" tgen = get_topogen(self) @@ -96,36 +98,36 @@ class TemplateTopo(Topo): # # Define FRR Routers # - for router in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']: + for router in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: tgen.add_router(router) # # Define connections # - switch = tgen.add_switch('s1') - switch.add_link(tgen.gears['rt1'], nodeif="eth-sw1") - switch.add_link(tgen.gears['rt2'], nodeif="eth-sw1") - switch.add_link(tgen.gears['rt3'], nodeif="eth-sw1") + switch = tgen.add_switch("s1") + switch.add_link(tgen.gears["rt1"], nodeif="eth-sw1") + switch.add_link(tgen.gears["rt2"], nodeif="eth-sw1") + switch.add_link(tgen.gears["rt3"], nodeif="eth-sw1") - switch = tgen.add_switch('s2') - switch.add_link(tgen.gears['rt2'], nodeif="eth-rt4") - switch.add_link(tgen.gears['rt4'], nodeif="eth-rt2") + switch = tgen.add_switch("s2") + switch.add_link(tgen.gears["rt2"], nodeif="eth-rt4") + switch.add_link(tgen.gears["rt4"], nodeif="eth-rt2") - switch = tgen.add_switch('s4') - switch.add_link(tgen.gears['rt3'], nodeif="eth-rt5") - switch.add_link(tgen.gears['rt5'], nodeif="eth-rt3") + switch = tgen.add_switch("s4") + switch.add_link(tgen.gears["rt3"], nodeif="eth-rt5") + switch.add_link(tgen.gears["rt5"], nodeif="eth-rt3") - switch = tgen.add_switch('s6') - switch.add_link(tgen.gears['rt4'], nodeif="eth-rt5") - switch.add_link(tgen.gears['rt5'], nodeif="eth-rt4") + switch = tgen.add_switch("s6") + switch.add_link(tgen.gears["rt4"], nodeif="eth-rt5") + switch.add_link(tgen.gears["rt5"], nodeif="eth-rt4") - switch = tgen.add_switch('s7') - switch.add_link(tgen.gears['rt4'], nodeif="eth-rt6") - switch.add_link(tgen.gears['rt6'], nodeif="eth-rt4") + switch = tgen.add_switch("s7") + switch.add_link(tgen.gears["rt4"], nodeif="eth-rt6") + switch.add_link(tgen.gears["rt6"], nodeif="eth-rt4") - switch = tgen.add_switch('s8') - switch.add_link(tgen.gears['rt5'], nodeif="eth-rt6") - switch.add_link(tgen.gears['rt6'], nodeif="eth-rt5") + switch = tgen.add_switch("s8") + switch.add_link(tgen.gears["rt5"], nodeif="eth-rt6") + switch.add_link(tgen.gears["rt6"], nodeif="eth-rt5") def setup_module(mod): @@ -138,16 +140,15 @@ def setup_module(mod): # For all registered routers, load the zebra configuration file for rname, router in router_list.items(): router.load_config( - TopoRouter.RD_ZEBRA, - os.path.join(CWD, '{}/zebra.conf'.format(rname)) + TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) router.load_config( - TopoRouter.RD_ISIS, - os.path.join(CWD, '{}/isisd.conf'.format(rname)) + TopoRouter.RD_ISIS, os.path.join(CWD, "{}/isisd.conf".format(rname)) ) tgen.start_router() + def teardown_module(mod): "Teardown the pytest environment" tgen = get_topogen() @@ -155,6 +156,7 @@ def teardown_module(mod): # This function tears down the whole topology. tgen.stop_topology() + def router_compare_json_output(rname, command, reference): "Compare router JSON output" @@ -170,6 +172,7 @@ def router_compare_json_output(rname, command, reference): assertmsg = '"{}" JSON output mismatches the expected result'.format(rname) assert diff is None, assertmsg + # # Step 1 # @@ -184,13 +187,14 @@ def test_isis_adjacencies_step1(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']: + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: router_compare_json_output( - rname, + rname, "show yang operational-data /frr-interface:lib isisd", "step1/show_yang_interface_isis_adjacencies.ref", ) + def test_rib_ipv4_step1(): logger.info("Test (step 1): verify IPv4 RIB") tgen = get_topogen() @@ -199,11 +203,12 @@ def test_rib_ipv4_step1(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']: + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: router_compare_json_output( rname, "show ip route isis json", "step1/show_ip_route.ref" ) + def test_rib_ipv6_step1(): logger.info("Test (step 1): verify IPv6 RIB") tgen = get_topogen() @@ -212,11 +217,12 @@ def test_rib_ipv6_step1(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']: + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: router_compare_json_output( rname, "show ipv6 route isis json", "step1/show_ipv6_route.ref" ) + # # Step 2 # @@ -235,15 +241,20 @@ def test_rib_ipv4_step2(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - logger.info('Disabling setting the attached-bit on RT2 and RT4') - tgen.net['rt2'].cmd('vtysh -c "conf t" -c "router isis 1" -c "no attached-bit send"') - tgen.net['rt4'].cmd('vtysh -c "conf t" -c "router isis 1" -c "no attached-bit send"') + logger.info("Disabling setting the attached-bit on RT2 and RT4") + tgen.net["rt2"].cmd( + 'vtysh -c "conf t" -c "router isis 1" -c "no attached-bit send"' + ) + tgen.net["rt4"].cmd( + 'vtysh -c "conf t" -c "router isis 1" -c "no attached-bit send"' + ) - for rname in ['rt1', 'rt6']: + for rname in ["rt1", "rt6"]: router_compare_json_output( rname, "show ip route isis json", "step2/show_ip_route.ref" ) + def test_rib_ipv6_step2(): logger.info("Test (step 2): verify IPv6 RIB") tgen = get_topogen() @@ -252,11 +263,12 @@ def test_rib_ipv6_step2(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - for rname in ['rt1', 'rt6']: + for rname in ["rt1", "rt6"]: router_compare_json_output( rname, "show ipv6 route isis json", "step2/show_ipv6_route.ref" ) + # # Step 3 # @@ -265,7 +277,7 @@ def test_rib_ipv6_step2(): # -disble processing a LSP with attach bit set # # Expected changes: -# -RT1 and RT6 should not install a default route +# -RT1 and RT6 should not install a default route # def test_rib_ipv4_step3(): logger.info("Test (step 3): verify IPv4 RIB") @@ -275,19 +287,24 @@ def test_rib_ipv4_step3(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - logger.info('Enable setting the attached-bit on RT2 and RT4') - tgen.net['rt2'].cmd('vtysh -c "conf t" -c "router isis 1" -c "attached-bit send"') - tgen.net['rt4'].cmd('vtysh -c "conf t" -c "router isis 1" -c "attached-bit send"') + logger.info("Enable setting the attached-bit on RT2 and RT4") + tgen.net["rt2"].cmd('vtysh -c "conf t" -c "router isis 1" -c "attached-bit send"') + tgen.net["rt4"].cmd('vtysh -c "conf t" -c "router isis 1" -c "attached-bit send"') - logger.info('Disable processing received attached-bit in LSP on RT1 and RT6') - tgen.net['rt1'].cmd('vtysh -c "conf t" -c "router isis 1" -c "attached-bit receive ignore"') - tgen.net['rt6'].cmd('vtysh -c "conf t" -c "router isis 1" -c "attached-bit receive ignore"') + logger.info("Disable processing received attached-bit in LSP on RT1 and RT6") + tgen.net["rt1"].cmd( + 'vtysh -c "conf t" -c "router isis 1" -c "attached-bit receive ignore"' + ) + tgen.net["rt6"].cmd( + 'vtysh -c "conf t" -c "router isis 1" -c "attached-bit receive ignore"' + ) - for rname in ['rt1', 'rt6']: + for rname in ["rt1", "rt6"]: router_compare_json_output( rname, "show ip route isis json", "step3/show_ip_route.ref" ) + def test_rib_ipv6_step3(): logger.info("Test (step 3): verify IPv6 RIB") tgen = get_topogen() @@ -296,11 +313,12 @@ def test_rib_ipv6_step3(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - for rname in ['rt1', 'rt6']: + for rname in ["rt1", "rt6"]: router_compare_json_output( rname, "show ipv6 route isis json", "step3/show_ipv6_route.ref" ) + # # Step 4 # @@ -319,13 +337,21 @@ def test_rib_ipv4_step4(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - logger.info('restore default processing on received attached-bit in LSP on RT1 and RT6') - tgen.net['rt1'].cmd('vtysh -c "conf t" -c "router isis 1" -c "no attached-bit receive ignore"') - tgen.net['rt6'].cmd('vtysh -c "conf t" -c "router isis 1" -c "no attached-bit receive ignore"') - - for rname in ['rt1', 'rt6']: + logger.info( + "restore default processing on received attached-bit in LSP on RT1 and RT6" + ) + tgen.net["rt1"].cmd( + 'vtysh -c "conf t" -c "router isis 1" -c "no attached-bit receive ignore"' + ) + tgen.net["rt6"].cmd( + 'vtysh -c "conf t" -c "router isis 1" -c "no attached-bit receive ignore"' + ) + + for rname in ["rt1", "rt6"]: router_compare_json_output( - rname, "show ip route isis json", "step4/show_ip_route.ref") + rname, "show ip route isis json", "step4/show_ip_route.ref" + ) + def test_rib_ipv6_step4(): logger.info("Test (step 4): verify IPv6 RIB") @@ -335,19 +361,22 @@ def test_rib_ipv6_step4(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - for rname in ['rt1', 'rt6']: + for rname in ["rt1", "rt6"]: router_compare_json_output( - rname, "show ipv6 route isis json", "step4/show_ipv6_route.ref") + rname, "show ipv6 route isis json", "step4/show_ipv6_route.ref" + ) + # Memory leak test template 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') + pytest.skip("Memory leak test/report is disabled") tgen.report_memory_leaks() -if __name__ == '__main__': + +if __name__ == "__main__": args = ["-s"] + sys.argv[1:] sys.exit(pytest.main(args)) diff --git a/tests/topotests/isis-rlfa-topo1/test_isis_rlfa_topo1.py b/tests/topotests/isis-rlfa-topo1/test_isis_rlfa_topo1.py index 4c692841ac..9ad41c5934 100755 --- a/tests/topotests/isis-rlfa-topo1/test_isis_rlfa_topo1.py +++ b/tests/topotests/isis-rlfa-topo1/test_isis_rlfa_topo1.py @@ -167,6 +167,7 @@ class TemplateTopo(Topo): f_in.close() f_out.close() + def setup_module(mod): "Sets up the pytest environment" tgen = Topogen(TemplateTopo, mod.__name__) diff --git a/tests/topotests/isis-snmp/ce3/zebra.conf b/tests/topotests/isis-snmp/ce3/zebra.conf new file mode 100644 index 0000000000..c6a5824d15 --- /dev/null +++ b/tests/topotests/isis-snmp/ce3/zebra.conf @@ -0,0 +1,12 @@ +log file zebra.log +! +hostname ce3 +! +interface ce3-eth0 + ip address 172.16.1.3/24 + no link-detect +! +ip forwarding +! +line vty +! diff --git a/tests/topotests/isis-snmp/r1/isisd.conf b/tests/topotests/isis-snmp/r1/isisd.conf new file mode 100644 index 0000000000..dd32d3b8a5 --- /dev/null +++ b/tests/topotests/isis-snmp/r1/isisd.conf @@ -0,0 +1,24 @@ +hostname r1 +log file isisd.log +debug isis adj-packets +debug isis events +debug isis update-packets +agentx +! +router isis 1 + net 10.0000.0000.0000.0000.0000.0000.0000.0000.0001.00 + metric-style wide + redistribute ipv4 connected level-1 + redistribute ipv6 connected level-1 +! +interface r1-eth0 + ip router isis 1 + ipv6 router isis 1 + isis circuit-type level-1 +! +interface r1-eth1 + ip router isis 1 + ipv6 router isis 1 + isis network point-to-point + isis circuit-type level-1 +! diff --git a/tests/topotests/isis-snmp/r1/ldpd.conf b/tests/topotests/isis-snmp/r1/ldpd.conf new file mode 100644 index 0000000000..4ec296ca5a --- /dev/null +++ b/tests/topotests/isis-snmp/r1/ldpd.conf @@ -0,0 +1,26 @@ +hostname r1 +log file ldpd.log +! +debug mpls ldp zebra +debug mpls ldp event +debug mpls ldp errors +debug mpls ldp sync +agentx +! +mpls ldp + router-id 1.1.1.1 + ! + address-family ipv4 + discovery transport-address 1.1.1.1 + label local allocate host-routes + ! + ttl-security disable + ! + interface r1-eth0 + ! + interface r1-eth1 + ! + ! +! +line vty +! diff --git a/tests/topotests/isis-snmp/r1/show_ip_route.ref b/tests/topotests/isis-snmp/r1/show_ip_route.ref new file mode 100644 index 0000000000..dc8f19dad0 --- /dev/null +++ b/tests/topotests/isis-snmp/r1/show_ip_route.ref @@ -0,0 +1,143 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"connected", + "selected":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceIndex":1, + "interfaceName":"lo", + "active":true + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "distance":115, + "metric":10, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceIndex":3, + "interfaceName":"r1-eth1", + "active":true + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "distance":115, + "metric":10, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.3", + "afi":"ipv4", + "interfaceIndex":4, + "interfaceName":"r1-eth2", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "distance":115, + "metric":10, + "nexthops":[ + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceIndex":3, + "interfaceName":"r1-eth1" + } + ] + }, + { + "prefix":"10.0.1.0\/24", + "protocol":"connected", + "selected":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceIndex":3, + "interfaceName":"r1-eth1", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "distance":115, + "metric":10, + "nexthops":[ + { + "ip":"10.0.2.3", + "afi":"ipv4", + "interfaceIndex":4, + "interfaceName":"r1-eth2" + } + ] + }, + { + "prefix":"10.0.2.0\/24", + "protocol":"connected", + "selected":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceIndex":4, + "interfaceName":"r1-eth2", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "selected":true, + "distance":115, + "metric":10, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceIndex":3, + "interfaceName":"r1-eth1", + "active":true + }, + { + "fib":true, + "ip":"10.0.2.3", + "afi":"ipv4", + "interfaceIndex":4, + "interfaceName":"r1-eth2", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis-snmp/r1/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-snmp/r1/show_yang_interface_isis_adjacencies.ref new file mode 100644 index 0000000000..390fda749e --- /dev/null +++ b/tests/topotests/isis-snmp/r1/show_yang_interface_isis_adjacencies.ref @@ -0,0 +1,40 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "r1-eth0", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0004", + "state": "up" + } + ] + } + } + } + }, + { + "name": "r1-eth1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0003", + "state": "up" + } + ] + } + } + } + } + ] + } +} diff --git a/tests/topotests/isis-snmp/r1/snmpd.conf b/tests/topotests/isis-snmp/r1/snmpd.conf new file mode 100644 index 0000000000..b37911da36 --- /dev/null +++ b/tests/topotests/isis-snmp/r1/snmpd.conf @@ -0,0 +1,15 @@ +agentAddress udp:1.1.1.1:161 + +com2sec public 1.1.1.1 public + +group public_group v1 public +group public_group v2c public + +access public_group "" any noauth prefix all all none + +view all included .1 + +iquerySecName frr +rouser frr + +master agentx diff --git a/tests/topotests/isis-snmp/r1/zebra.conf b/tests/topotests/isis-snmp/r1/zebra.conf new file mode 100644 index 0000000000..6ac341e431 --- /dev/null +++ b/tests/topotests/isis-snmp/r1/zebra.conf @@ -0,0 +1,24 @@ +log file zebra.log +! +hostname r1 +! +debug zebra kernel +debug zebra rib detailed +debug zebra dplane detailed +debug zebra nht +! +interface lo + ip address 1.1.1.1/32 +! +interface r1-eth0 + description to rt4 + ip address 14.0.0.1/24 +! +interface r1-eth1 + description to rt3 + ip address 13.0.0.1/24 +! +ip forwarding +! +line vty +! diff --git a/tests/topotests/isis-snmp/r2/isisd.conf b/tests/topotests/isis-snmp/r2/isisd.conf new file mode 100644 index 0000000000..4403d8913b --- /dev/null +++ b/tests/topotests/isis-snmp/r2/isisd.conf @@ -0,0 +1,25 @@ +hostname r2 +log file isisd.log +debug isis adj-packets +debug isis events +debug isis update-packets +agentx +! +router isis 1 + net 10.0000.0000.0000.0000.0000.0000.0000.0000.0002.00 + metric-style wide + redistribute ipv4 connected level-1 + redistribute ipv6 connected level-1 +! +interface r2-eth0 + ip router isis 1 + ipv6 router isis 1 + isis network point-to-point + isis circuit-type level-1 +! +interface r2-eth1 + ip router isis 1 + ipv6 router isis 1 + isis network point-to-point + isis circuit-type level-1 +! diff --git a/tests/topotests/isis-snmp/r2/ldpd.conf b/tests/topotests/isis-snmp/r2/ldpd.conf new file mode 100644 index 0000000000..eb963fe41c --- /dev/null +++ b/tests/topotests/isis-snmp/r2/ldpd.conf @@ -0,0 +1,25 @@ +hostname r2 +log file ldpd.log +! +debug mpls ldp zebra +debug mpls ldp event +debug mpls ldp errors +debug mpls ldp sync +! +mpls ldp + router-id 2.2.2.2 + ! + address-family ipv4 + discovery transport-address 2.2.2.2 + label local allocate host-routes + ! + ttl-security disable + ! + interface r2-eth0 + ! + interface r2-eth1 + ! + ! +! +line vty +! diff --git a/tests/topotests/isis-snmp/r2/show_ip_route.ref b/tests/topotests/isis-snmp/r2/show_ip_route.ref new file mode 100644 index 0000000000..2bcee96064 --- /dev/null +++ b/tests/topotests/isis-snmp/r2/show_ip_route.ref @@ -0,0 +1,143 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "distance":115, + "metric":10, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceIndex":3, + "interfaceName":"r2-eth1", + "active":true + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"connected", + "selected":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceIndex":1, + "interfaceName":"lo", + "active":true + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "distance":115, + "metric":10, + "nexthops":[ + { + "fib":true, + "ip":"10.0.3.3", + "afi":"ipv4", + "interfaceIndex":4, + "interfaceName":"r2-eth2", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "distance":115, + "metric":10, + "nexthops":[ + { + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceIndex":3, + "interfaceName":"r2-eth1" + } + ] + }, + { + "prefix":"10.0.1.0\/24", + "protocol":"connected", + "selected":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceIndex":3, + "interfaceName":"r2-eth1", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "selected":true, + "distance":115, + "metric":10, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceIndex":3, + "interfaceName":"r2-eth1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.3", + "afi":"ipv4", + "interfaceIndex":4, + "interfaceName":"r2-eth2", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "distance":115, + "metric":10, + "nexthops":[ + { + "ip":"10.0.3.3", + "afi":"ipv4", + "interfaceIndex":4, + "interfaceName":"r2-eth2" + } + ] + }, + { + "prefix":"10.0.3.0\/24", + "protocol":"connected", + "selected":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceIndex":4, + "interfaceName":"r2-eth2", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis-snmp/r2/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-snmp/r2/show_yang_interface_isis_adjacencies.ref new file mode 100644 index 0000000000..52550daf14 --- /dev/null +++ b/tests/topotests/isis-snmp/r2/show_yang_interface_isis_adjacencies.ref @@ -0,0 +1,40 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "r2-eth0", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0005", + "state": "up" + } + ] + } + } + } + }, + { + "name": "r2-eth1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0003", + "state": "up" + } + ] + } + } + } + } + ] + } +} diff --git a/tests/topotests/isis-snmp/r2/snmpd.conf b/tests/topotests/isis-snmp/r2/snmpd.conf new file mode 100644 index 0000000000..0f779b8b91 --- /dev/null +++ b/tests/topotests/isis-snmp/r2/snmpd.conf @@ -0,0 +1,15 @@ +agentAddress udp:2.2.2.2:161 + +com2sec public 2.2.2.2 public + +group public_group v1 public +group public_group v2c public + +access public_group "" any noauth prefix all all none + +view all included .1 + +iquerySecName frr +rouser frr + +master agentx diff --git a/tests/topotests/isis-snmp/r2/zebra.conf b/tests/topotests/isis-snmp/r2/zebra.conf new file mode 100644 index 0000000000..4aa7440c33 --- /dev/null +++ b/tests/topotests/isis-snmp/r2/zebra.conf @@ -0,0 +1,24 @@ +log file zebra.log +! +hostname r2 +! +debug zebra rib detailed +debug zebra dplane detailed +debug zebra kernel +debug zebra nht +! +interface lo + ip address 2.2.2.2/32 +! +interface r2-eth0 + description to rt5 + ip address 25.0.0.2/24 +! +interface r2-eth1 + description to rt3 + ip address 23.0.0.2/24 +! +ip forwarding +! +line vty +! diff --git a/tests/topotests/isis-snmp/r3/isisd.conf b/tests/topotests/isis-snmp/r3/isisd.conf new file mode 100644 index 0000000000..e06fe8c1f9 --- /dev/null +++ b/tests/topotests/isis-snmp/r3/isisd.conf @@ -0,0 +1,25 @@ +hostname r3 +log file isisd.log +debug isis adj-packets +debug isis events +debug isis update-packets +agentx +! +router isis 1 + net 10.0000.0000.0000.0000.0000.0000.0000.0000.0003.00 + metric-style wide + redistribute ipv4 connected level-1 + redistribute ipv6 connected level-1 +! +interface r3-eth1 + ip router isis 1 + ipv6 router isis 1 + isis network point-to-point + isis circuit-type level-1 +! +interface r3-eth2 + ip router isis 1 + ipv6 router isis 1 + isis network point-to-point + isis circuit-type level-1 +! diff --git a/tests/topotests/isis-snmp/r3/ldpd.conf b/tests/topotests/isis-snmp/r3/ldpd.conf new file mode 100644 index 0000000000..2935caf13b --- /dev/null +++ b/tests/topotests/isis-snmp/r3/ldpd.conf @@ -0,0 +1,25 @@ +hostname r3 +log file ldpd.log +! +debug mpls ldp zebra +debug mpls ldp event +debug mpls ldp errors +debug mpls ldp sync +! +mpls ldp + router-id 3.3.3.3 + ! + address-family ipv4 + discovery transport-address 3.3.3.3 + label local allocate host-routes + ! + ttl-security disable + ! + interface r3-eth1 + ! + interface r3-eth2 + ! + ! +! +line vty +! diff --git a/tests/topotests/isis-snmp/r3/show_ip_route.ref b/tests/topotests/isis-snmp/r3/show_ip_route.ref new file mode 100644 index 0000000000..da46f1dfe2 --- /dev/null +++ b/tests/topotests/isis-snmp/r3/show_ip_route.ref @@ -0,0 +1,143 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "distance":115, + "metric":10, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.1", + "afi":"ipv4", + "interfaceIndex":3, + "interfaceName":"r3-eth1", + "active":true + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "distance":115, + "metric":10, + "nexthops":[ + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceIndex":4, + "interfaceName":"r3-eth2", + "active":true + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"connected", + "selected":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceIndex":1, + "interfaceName":"lo", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "selected":true, + "distance":115, + "metric":10, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.1", + "afi":"ipv4", + "interfaceIndex":3, + "interfaceName":"r3-eth1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceIndex":4, + "interfaceName":"r3-eth2", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "distance":115, + "metric":10, + "nexthops":[ + { + "ip":"10.0.2.1", + "afi":"ipv4", + "interfaceIndex":3, + "interfaceName":"r3-eth1" + } + ] + }, + { + "prefix":"10.0.2.0\/24", + "protocol":"connected", + "selected":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceIndex":3, + "interfaceName":"r3-eth1", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "distance":115, + "metric":10, + "nexthops":[ + { + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceIndex":4, + "interfaceName":"r3-eth2" + } + ] + }, + { + "prefix":"10.0.3.0\/24", + "protocol":"connected", + "selected":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceIndex":4, + "interfaceName":"r3-eth2", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis-snmp/r3/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-snmp/r3/show_yang_interface_isis_adjacencies.ref new file mode 100644 index 0000000000..3aafab4e2e --- /dev/null +++ b/tests/topotests/isis-snmp/r3/show_yang_interface_isis_adjacencies.ref @@ -0,0 +1,40 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "r3-eth1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0001", + "state": "up" + } + ] + } + } + } + }, + { + "name": "r3-eth2", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0002", + "state": "up" + } + ] + } + } + } + } + ] + } +} diff --git a/tests/topotests/isis-snmp/r3/snmpd.conf b/tests/topotests/isis-snmp/r3/snmpd.conf new file mode 100644 index 0000000000..3f3501a6fd --- /dev/null +++ b/tests/topotests/isis-snmp/r3/snmpd.conf @@ -0,0 +1,15 @@ +agentAddress udp:3.3.3.3:161 + +com2sec public 3.3.3.3 public + +group public_group v1 public +group public_group v2c public + +access public_group "" any noauth prefix all all none + +view all included .1 + +iquerySecName frr +rouser frr + +master agentx diff --git a/tests/topotests/isis-snmp/r3/zebra.conf b/tests/topotests/isis-snmp/r3/zebra.conf new file mode 100644 index 0000000000..6b76114d4d --- /dev/null +++ b/tests/topotests/isis-snmp/r3/zebra.conf @@ -0,0 +1,28 @@ +log file zebra.log +! +hostname r3 +! +debug zebra rib detailed +debug zebra dplane detailed +debug zebra kernel +debug zebra nht +! +interface lo + ip address 3.3.3.3/32 +! +interface r3-eth0 + description to ce3 + ip address 172.16.1.3/24 +! +interface r3-eth1 + description to rt2 + ip address 13.0.0.3/24 +! +interface r3-eth2 + description to rt1 + ip address 23.0.0.3/24 +! +ip forwarding +! +line vty +! diff --git a/tests/topotests/isis-snmp/r4/isisd.conf b/tests/topotests/isis-snmp/r4/isisd.conf new file mode 100644 index 0000000000..1256141da9 --- /dev/null +++ b/tests/topotests/isis-snmp/r4/isisd.conf @@ -0,0 +1,24 @@ +hostname r4 +log file isisd.log +debug isis adj-packets +debug isis events +debug isis update-packets +agentx +! +router isis 1 + net 10.0000.0000.0000.0000.0000.0000.0000.0000.0004.00 + metric-style wide + redistribute ipv4 connected level-1 + redistribute ipv6 connected level-1 +! +interface r4-eth0 + ip router isis 1 + ipv6 router isis 1 + isis circuit-type level-1 +! +interface r4-eth1 + ip router isis 1 + ipv6 router isis 1 + isis network point-to-point + isis circuit-type level-1 +! diff --git a/tests/topotests/isis-snmp/r4/ldpd.conf b/tests/topotests/isis-snmp/r4/ldpd.conf new file mode 100644 index 0000000000..b27952514b --- /dev/null +++ b/tests/topotests/isis-snmp/r4/ldpd.conf @@ -0,0 +1,25 @@ +hostname r4 +log file ldpd.log +! +debug mpls ldp zebra +debug mpls ldp event +debug mpls ldp errors +debug mpls ldp sync +! +mpls ldp + router-id 4.4.4.4 + ! + address-family ipv4 + discovery transport-address 4.4.4.4 + label local allocate host-routes + ! + ttl-security disable + ! + interface r4-eth0 + ! + interface r4-eth1 + ! + ! +! +line vty +! diff --git a/tests/topotests/isis-snmp/r4/show_ip_route.ref b/tests/topotests/isis-snmp/r4/show_ip_route.ref new file mode 100644 index 0000000000..da46f1dfe2 --- /dev/null +++ b/tests/topotests/isis-snmp/r4/show_ip_route.ref @@ -0,0 +1,143 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "distance":115, + "metric":10, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.1", + "afi":"ipv4", + "interfaceIndex":3, + "interfaceName":"r3-eth1", + "active":true + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "distance":115, + "metric":10, + "nexthops":[ + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceIndex":4, + "interfaceName":"r3-eth2", + "active":true + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"connected", + "selected":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceIndex":1, + "interfaceName":"lo", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "selected":true, + "distance":115, + "metric":10, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.1", + "afi":"ipv4", + "interfaceIndex":3, + "interfaceName":"r3-eth1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceIndex":4, + "interfaceName":"r3-eth2", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "distance":115, + "metric":10, + "nexthops":[ + { + "ip":"10.0.2.1", + "afi":"ipv4", + "interfaceIndex":3, + "interfaceName":"r3-eth1" + } + ] + }, + { + "prefix":"10.0.2.0\/24", + "protocol":"connected", + "selected":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceIndex":3, + "interfaceName":"r3-eth1", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "distance":115, + "metric":10, + "nexthops":[ + { + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceIndex":4, + "interfaceName":"r3-eth2" + } + ] + }, + { + "prefix":"10.0.3.0\/24", + "protocol":"connected", + "selected":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceIndex":4, + "interfaceName":"r3-eth2", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis-snmp/r4/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-snmp/r4/show_yang_interface_isis_adjacencies.ref new file mode 100644 index 0000000000..86fcfea1a6 --- /dev/null +++ b/tests/topotests/isis-snmp/r4/show_yang_interface_isis_adjacencies.ref @@ -0,0 +1,40 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "r4-eth0", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0001", + "state": "up" + } + ] + } + } + } + }, + { + "name": "r4-eth1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0005", + "state": "up" + } + ] + } + } + } + } + ] + } +} diff --git a/tests/topotests/isis-snmp/r4/snmpd.conf b/tests/topotests/isis-snmp/r4/snmpd.conf new file mode 100644 index 0000000000..e5e336d888 --- /dev/null +++ b/tests/topotests/isis-snmp/r4/snmpd.conf @@ -0,0 +1,15 @@ +agentAddress udp:4.4.4.4:161 + +com2sec public 4.4.4.4 public + +group public_group v1 public +group public_group v2c public + +access public_group "" any noauth prefix all all none + +view all included .1 + +iquerySecName frr +rouser frr + +master agentx diff --git a/tests/topotests/isis-snmp/r4/zebra.conf b/tests/topotests/isis-snmp/r4/zebra.conf new file mode 100644 index 0000000000..fa13601164 --- /dev/null +++ b/tests/topotests/isis-snmp/r4/zebra.conf @@ -0,0 +1,24 @@ +log file zebra.log +! +hostname r4 +! +debug zebra rib detailed +debug zebra dplane detailed +debug zebra kernel +debug zebra nht +! +interface lo + ip address 4.4.4.4/32 +! +interface r4-eth0 + description to rt1 + ip address 14.0.0.4/24 +! +interface r4-eth1 + description to rt5 + ip address 45.0.0.4/24 +! +ip forwarding +! +line vty +! diff --git a/tests/topotests/isis-snmp/r5/isisd.conf b/tests/topotests/isis-snmp/r5/isisd.conf new file mode 100644 index 0000000000..58859041a9 --- /dev/null +++ b/tests/topotests/isis-snmp/r5/isisd.conf @@ -0,0 +1,25 @@ +hostname r5 +log file isisd.log +debug isis adj-packets +debug isis events +debug isis update-packets +agentx +! +router isis 1 + net 10.0000.0000.0000.0000.0000.0000.0000.0000.0005.00 + metric-style wide + redistribute ipv4 connected level-1 + redistribute ipv6 connected level-1 +! +interface r5-eth0 + ip router isis 1 + ipv6 router isis 1 + isis network point-to-point + isis circuit-type level-1 +! +interface r5-eth1 + ip router isis 1 + ipv6 router isis 1 + isis network point-to-point + isis circuit-type level-1 +! diff --git a/tests/topotests/isis-snmp/r5/ldpd.conf b/tests/topotests/isis-snmp/r5/ldpd.conf new file mode 100644 index 0000000000..f3ba867a9f --- /dev/null +++ b/tests/topotests/isis-snmp/r5/ldpd.conf @@ -0,0 +1,25 @@ +hostname r5 +log file ldpd.log +! +debug mpls ldp zebra +debug mpls ldp event +debug mpls ldp errors +debug mpls ldp sync +! +mpls ldp + router-id 5.5.5.5 + ! + address-family ipv4 + discovery transport-address 5.5.5.5 + label local allocate host-routes + ! + ttl-security disable + ! + interface r5-eth0 + ! + interface r5-eth1 + ! + ! +! +line vty +! diff --git a/tests/topotests/isis-snmp/r5/ldpdconf b/tests/topotests/isis-snmp/r5/ldpdconf new file mode 100644 index 0000000000..fc700608b5 --- /dev/null +++ b/tests/topotests/isis-snmp/r5/ldpdconf @@ -0,0 +1,25 @@ +hostname r5 +log file ldpd.log +! +debug mpls ldp zebra +debug mpls ldp event +debug mpls ldp errors +debug mpls ldp sync +! +mpls ldp + router-id 3.3.3.3 + ! + address-family ipv4 + discovery transport-address 5.5.5.5 + label local allocate host-routes + ! + ttl-security disable + ! + interface r5-eth0 + ! + interface r5-eth1 + ! + ! +! +line vty +! diff --git a/tests/topotests/isis-snmp/r5/show_ip_route.ref b/tests/topotests/isis-snmp/r5/show_ip_route.ref new file mode 100644 index 0000000000..da46f1dfe2 --- /dev/null +++ b/tests/topotests/isis-snmp/r5/show_ip_route.ref @@ -0,0 +1,143 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "distance":115, + "metric":10, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.1", + "afi":"ipv4", + "interfaceIndex":3, + "interfaceName":"r3-eth1", + "active":true + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "distance":115, + "metric":10, + "nexthops":[ + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceIndex":4, + "interfaceName":"r3-eth2", + "active":true + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"connected", + "selected":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceIndex":1, + "interfaceName":"lo", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "selected":true, + "distance":115, + "metric":10, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.1", + "afi":"ipv4", + "interfaceIndex":3, + "interfaceName":"r3-eth1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceIndex":4, + "interfaceName":"r3-eth2", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "distance":115, + "metric":10, + "nexthops":[ + { + "ip":"10.0.2.1", + "afi":"ipv4", + "interfaceIndex":3, + "interfaceName":"r3-eth1" + } + ] + }, + { + "prefix":"10.0.2.0\/24", + "protocol":"connected", + "selected":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceIndex":3, + "interfaceName":"r3-eth1", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "distance":115, + "metric":10, + "nexthops":[ + { + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceIndex":4, + "interfaceName":"r3-eth2" + } + ] + }, + { + "prefix":"10.0.3.0\/24", + "protocol":"connected", + "selected":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceIndex":4, + "interfaceName":"r3-eth2", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis-snmp/r5/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-snmp/r5/show_yang_interface_isis_adjacencies.ref new file mode 100644 index 0000000000..994e8166ce --- /dev/null +++ b/tests/topotests/isis-snmp/r5/show_yang_interface_isis_adjacencies.ref @@ -0,0 +1,40 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "r5-eth0", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0002", + "state": "up" + } + ] + } + } + } + }, + { + "name": "r5-eth1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0004", + "state": "up" + } + ] + } + } + } + } + ] + } +} diff --git a/tests/topotests/isis-snmp/r5/snmpd.conf b/tests/topotests/isis-snmp/r5/snmpd.conf new file mode 100644 index 0000000000..5bebbdebd4 --- /dev/null +++ b/tests/topotests/isis-snmp/r5/snmpd.conf @@ -0,0 +1,15 @@ +agentAddress udp:5.5.5.5:161 + +com2sec public 5.5.5.5 public + +group public_group v1 public +group public_group v2c public + +access public_group "" any noauth prefix all all none + +view all included .1 + +iquerySecName frr +rouser frr + +master agentx diff --git a/tests/topotests/isis-snmp/r5/zebra.conf b/tests/topotests/isis-snmp/r5/zebra.conf new file mode 100644 index 0000000000..7230129f22 --- /dev/null +++ b/tests/topotests/isis-snmp/r5/zebra.conf @@ -0,0 +1,24 @@ +log file zebra.log +! +hostname r5 +! +debug zebra rib detailed +debug zebra dplane detailed +debug zebra kernel +debug zebra nht +! +interface lo + ip address 5.5.5.5/32 +! +interface r5-eth0 + description to rt2 + ip address 25.0.0.5/24 +! +interface r5-eth1 + description to rt4 + ip address 45.0.0.5/24 +! +ip forwarding +! +line vty +! diff --git a/tests/topotests/isis-snmp/test_isis_snmp.dot b/tests/topotests/isis-snmp/test_isis_snmp.dot new file mode 100644 index 0000000000..6d8c893712 --- /dev/null +++ b/tests/topotests/isis-snmp/test_isis_snmp.dot @@ -0,0 +1,114 @@ +## 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="Test Topology - LDP-VPLS 1"; + + # Routers + ce3 [ + shape=doubleoctagon + label="ce3", + fillcolor="#f08080", + style=filled, + ]; + 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, + ]; + + r4 [ + shape=doubleoctagon + label="r4", + fillcolor="#f08080", + style=filled, + ]; + r5 [ + shape=doubleoctagon + label="r5", + fillcolor="#f08080", + style=filled, + ]; + + + + # Switches + s1 [ + shape=oval, + label="s1\n14.0.0/24", + fillcolor="#d0e0d0", + style=filled, + ]; + s2 [ + shape=oval, + label="s2\n25.0.0.0/24", + fillcolor="#d0e0d0", + style=filled, + ]; + s3 [ + shape=oval, + label="s3\n172.16.1.0/24", + fillcolor="#d0e0d0", + style=filled, + ]; + s4 [ + shape=oval, + label="s4\n45.0.0.0/24", + fillcolor="#d0e0d0", + style=filled, + ]; + s5 [ + shape=oval, + label="s5\n13.0.0.0/24", + fillcolor="#d0e0d0", + style=filled, + ]; + s6 [ + shape=oval, + label="s6\n23.0.0.0/24", + fillcolor="#d0e0d0", + style=filled, + ]; + + # Connections + ce3 -- s3 [label="eth0\n.3"]; + + r1 -- s1 [label="eth1\n.1"]; + r1 -- s5 [label="eth2\n.1"]; + + r2 -- s2 [label="eth1\n.2"]; + r2 -- s6 [label="eth2\n.2"]; + + r3 -- s5 [label="eth1\n.3"]; + r3 -- s6 [label="eth2\n.3"]; + + r4 -- s1 [label="eth1\n.4"]; + r4 -- s4 [label="eth2\n.4"]; + + r5 -- s2 [label="eth1\n.5"]; + r5 -- s4 [label="eth2\n.5"]; +} diff --git a/tests/topotests/isis-snmp/test_isis_snmp.py b/tests/topotests/isis-snmp/test_isis_snmp.py new file mode 100755 index 0000000000..1bcd0eefc6 --- /dev/null +++ b/tests/topotests/isis-snmp/test_isis_snmp.py @@ -0,0 +1,369 @@ +#!/usr/bin/env python + +# +# test_isis_snmp.py +# Part of NetDEF Topology Tests +# +# Copyright (c) 2020 by Volta Networks +# +# 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_isis_snmp.py: + + +---------+ 45.0.0.0/24 +---------+ + | | rt4-eth1 | | + | RT4 +----------------+ RT5 | + | | rt5-eth1| | + +---------+ +---------+ + rt4-eth0| |rt5-eth0 + | | + 14.0.0.0/24| |25.0.0.0/24 + | | + rt1-eth0| |rt2-eth0 + +---------+ +---------+ + | | | | + | RT1 | | RT2 | + | 1.1.1.1 | | 2.2.2.2 | + | | | | + +---------+ +---------+ + rt1-eth1| |rt2-eth1 + | | + | | + 13.0.0.0/24| +---------+ |23.0.0.0/24 + | | | | + | | RT3 | | + +--------+ 3.3.3.3 +-------+ + rt3-eth1| |rt3-eth2 + +---------+ + |rt3-eth0 + | + | + ce3-eth0 (172.16.1.3/24)| + +---------+ + | | + | CE3 | + | | + +---------+ +""" + +import os +import re +import sys +import pytest +import json +from time import sleep +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 +# Import topogen and topotest helpers +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger +from lib.snmptest import SnmpTester + +# Required to instantiate the topology builder class. +from mininet.topo import Topo + + +class TemplateTopo(Topo): + "Test topology builder" + + def build(self, *_args, **_opts): + "Build function" + tgen = get_topogen(self) + + # + # Define FRR Routers + # + for router in ["ce3", "r1", "r2", "r3", "r4", "r5"]: + tgen.add_router(router) + + # + # Define connections + # + switch = tgen.add_switch("s1") + switch.add_link(tgen.gears["r1"]) + switch.add_link(tgen.gears["r4"]) + + switch = tgen.add_switch("s2") + switch.add_link(tgen.gears["r5"]) + switch.add_link(tgen.gears["r2"]) + + switch = tgen.add_switch("s3") + switch.add_link(tgen.gears["ce3"]) + switch.add_link(tgen.gears["r3"]) + + switch = tgen.add_switch("s4") + switch.add_link(tgen.gears["r4"]) + switch.add_link(tgen.gears["r5"]) + + switch = tgen.add_switch("s5") + switch.add_link(tgen.gears["r1"]) + switch.add_link(tgen.gears["r3"]) + + switch = tgen.add_switch("s6") + switch.add_link(tgen.gears["r2"]) + switch.add_link(tgen.gears["r3"]) + + + +def setup_module(mod): + "Sets up the pytest environment" + + # skip tests is SNMP not installed + if not os.path.isfile("/usr/sbin/snmpd"): + error_msg = "SNMP not installed - skipping" + pytest.skip(error_msg) + + # This function initiates the topology build with Topogen... + tgen = Topogen(TemplateTopo, mod.__name__) + # ... and here it calls Mininet initialization functions. + tgen.start_topology() + + router_list = tgen.routers() + + # For all registered routers, load the zebra configuration file + for rname, router in router_list.iteritems(): + router.load_config( + TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) + ) + # Don't start the following in the CE nodes + if router.name[0] == "r": + router.load_config( + TopoRouter.RD_ISIS, os.path.join(CWD, "{}/isisd.conf".format(rname)), + "-M snmp", + ) + router.load_config( + TopoRouter.RD_LDP, os.path.join(CWD, "{}/ldpd.conf".format(rname)), + ) + router.load_config( + TopoRouter.RD_SNMP, os.path.join(CWD, "{}/snmpd.conf".format(rname)), + "-Le -Ivacm_conf,usmConf,iquery -V -DAgentX,trap", + ) + + # After loading the configurations, this function loads configured daemons. + tgen.start_router() + +def teardown_module(mod): + "Teardown the pytest environment" + tgen = get_topogen() + + # This function tears down the whole topology. + tgen.stop_topology() + +def router_compare_json_output(rname, command, reference): + "Compare router JSON output" + + logger.info('Comparing router "%s" "%s" output', rname, command) + + tgen = get_topogen() + filename = "{}/{}/{}".format(CWD, rname, reference) + expected = json.loads(open(filename).read()) + + # Run test function until we get an result. Wait at most 80 seconds. + test_func = partial(topotest.router_json_cmp, tgen.gears[rname], command, expected) + _, diff = topotest.run_and_expect(test_func, None, count=160, wait=0.5) + assertmsg = '"{}" JSON output mismatches the expected result'.format(rname) + assert diff is None, assertmsg + +def generate_oid(numoids, index1, index2): + if numoids == 1: + oid = "{}".format(index1) + else: + oid = "{}.{}".format(index1, index2) + return oid + + +def test_isis_convergence(): + logger.info("Test: check ISIS adjacencies") + tgen = get_topogen() + + for rname in ["r1", "r2", "r3", "r4", "r5"]: + router_compare_json_output( + rname, + "show yang operational-data /frr-interface:lib isisd", + "show_yang_interface_isis_adjacencies.ref") + +def test_r1_scalar_snmp(): + "Wait for protocol convergence" + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.net.get("r1") + r1_snmp = SnmpTester(r1, "1.1.1.1", "public", "2c") + + assert r1_snmp.test_oid('isisSysVersion', "one(1)") + assert r1_snmp.test_oid('isisSysLevelType', "level1and2(3)") + assert r1_snmp.test_oid('isisSysID',"00 00 00 00 00 01") + assert r1_snmp.test_oid('isisSysMaxPathSplits',"32") + assert r1_snmp.test_oid('isisSysMaxLSPGenInt',"900 seconds") + assert r1_snmp.test_oid('isisSysAdminState',"on(1)") + assert r1_snmp.test_oid('isisSysMaxAge',"1200 seconds") + assert r1_snmp.test_oid('isisSysProtSupported',"07 5 6 7") + + r2 = tgen.net.get("r2") + r2_snmp = SnmpTester(r2, "2.2.2.2", "public", "2c") + + assert r2_snmp.test_oid('isisSysVersion', "one(1)") + assert r2_snmp.test_oid('isisSysLevelType', "level1and2(3)") + assert r2_snmp.test_oid('isisSysID',"00 00 00 00 00 02") + assert r2_snmp.test_oid('isisSysMaxPathSplits',"32") + assert r2_snmp.test_oid('isisSysMaxLSPGenInt',"900 seconds") + assert r2_snmp.test_oid('isisSysAdminState',"on(1)") + assert r2_snmp.test_oid('isisSysMaxAge',"1200 seconds") + assert r2_snmp.test_oid('isisSysProtSupported',"07 5 6 7") + + +circtable_test = { + "isisCircAdminState": ["on(1)", "on(1)", "on(1)"], + "isisCircExistState": ["active(1)", "active(1)", "active(1)"], + "isisCircType": ["broadcast(1)", "ptToPt(2)", "staticIn(3)"], + "isisCircExtDomain": ["false(2)", "false(2)", "false(2)"], + "isisCircLevelType": ["level1(1)", "level1(1)", "level1and2(3)"], + "isisCircPassiveCircuit": ["false(2)", "false(2)", "true(1)"], + "isisCircMeshGroupEnabled": ["inactive(1)", "inactive(1)", "inactive(1)"], + "isisCircSmallHellos": ["false(2)", "false(2)", "false(2)"], + "isisCirc3WayEnabled": ["false(2)", "false(2)", "false(2)"], + } + +def test_r1_isisCircTable(): + tgen = get_topogen() + + r1 = tgen.net.get("r1") + r1r = tgen.gears["r1"] + + r1_snmp = SnmpTester(r1, "1.1.1.1", "public", "2c") + + oids = [] + oids.append(generate_oid(1,1,0)) + oids.append(generate_oid(1,2,0)) + oids.append(generate_oid(1,3,0)) + + # check items + for item in circtable_test.keys(): + assertmsg = "{} should be {} oids {} full dict {}:".format( + item, circtable_test[item], oids, r1_snmp.walk(item) + ) + assert r1_snmp.test_oid_walk(item, circtable_test[item], oids), assertmsg + +circleveltable_test = { + "isisCircLevelMetric": ["10", "10", "10", "10"], + "isisCircLevelWideMetric": ["10", "10", "0", "0"], + "isisCircLevelISPriority": ["64", "64", "64", "64"], + "isisCircLevelHelloMultiplier": ["10", "10", "10", "10"], + "isisCircLevelHelloTimer": ["3000 milliseconds", "3000 milliseconds", "3000 milliseconds", "3000 milliseconds"], + "isisCircLevelMinLSPRetransInt": ["1 seconds", "1 seconds", "0 seconds", "0 seconds"], + } + +def test_r1_isislevelCircTable(): + tgen = get_topogen() + + r1 = tgen.net.get("r1") + r1r = tgen.gears["r1"] + + r1_snmp = SnmpTester(r1, "1.1.1.1", "public", "2c") + + oids = [] + oids.append(generate_oid(2,1,"area")) + oids.append(generate_oid(2,2,"area")) + oids.append(generate_oid(2,3,"area")) + oids.append(generate_oid(2,3,"domain")) + + # check items + for item in circleveltable_test.keys(): + assertmsg = "{} should be {} oids {} full dict {}:".format( + item, circleveltable_test[item], oids, r1_snmp.walk(item) + ) + assert r1_snmp.test_oid_walk(item, circleveltable_test[item], oids), assertmsg + + +adjtable_test = { + "isisISAdjState": ["up(3)", "up(3)"], + "isisISAdj3WayState": ["down(2)", "up(0)"], + "isisISAdjNeighSysType": ["l1IntermediateSystem(1)", "l1IntermediateSystem(1)"], + "isisISAdjNeighSysID": ["00 00 00 00 00 04", "00 00 00 00 00 03"], + "isisISAdjUsage": ["0", "level1(1)"], + "isisISAdjNeighPriority": ["64", "0"], +} + +adjtable_down_test = { + "isisISAdjState": ["up(3)"], + "isisISAdj3WayState": ["down(2)"], + "isisISAdjNeighSysType": ["l1IntermediateSystem(1)"], + "isisISAdjNeighSysID": ["00 00 00 00 00 04"], + "isisISAdjUsage": ["0"], + "isisISAdjNeighPriority": ["64"], +} + +def test_r1_isisAdjTable(): + "check ISIS Adjacency Table" + tgen = get_topogen() + r1 = tgen.net.get("r1") + r1_cmd = tgen.gears["r1"] + r1_snmp = SnmpTester(r1, "1.1.1.1", "public", "2c") + + oids = [] + oids.append(generate_oid(2,1,1)) + oids.append(generate_oid(2,2,1)) + + oids_down = [] + oids_down.append(generate_oid(2,1,1)) + + # check items + for item in adjtable_test.keys(): + assertmsg = "{} should be {} oids {} full dict {}:".format( + item, adjtable_test[item], oids, r1_snmp.walk(item) + ) + assert r1_snmp.test_oid_walk(item, adjtable_test[item], oids), assertmsg + + + # shutdown interface and one adjacency should be removed + "check ISIS adjacency is removed when interface is shutdown" + r1_cmd.vtysh_cmd("conf t\ninterface r1-eth1\nshutdown") + r1_snmp = SnmpTester(r1, "1.1.1.1", "public", "2c") + + for item in adjtable_down_test.keys(): + assertmsg = "{} should be {} oids {} full dict {}:".format( + item, adjtable_down_test[item], oids_down, r1_snmp.walk(item) + ) + assert r1_snmp.test_oid_walk(item, adjtable_down_test[item], oids_down), assertmsg + + # no shutdown interface and adjacency should be restored + r1_cmd.vtysh_cmd("conf t\ninterface r1-eth1\nno shutdown") + + +# Memory leak test template +# disabling memory leak +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/isis-sr-te-topo1/test_isis_sr_te_topo1.py b/tests/topotests/isis-sr-te-topo1/test_isis_sr_te_topo1.py index da59cfe772..6bbb570267 100755 --- a/tests/topotests/isis-sr-te-topo1/test_isis_sr_te_topo1.py +++ b/tests/topotests/isis-sr-te-topo1/test_isis_sr_te_topo1.py @@ -85,7 +85,7 @@ 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, '../')) +sys.path.append(os.path.join(CWD, "../")) # pylint: disable=C0413 # Import topogen and topotest helpers @@ -101,6 +101,7 @@ pytestmark = [pytest.mark.bgpd, pytest.mark.isisd, pytest.mark.pathd] class TemplateTopo(Topo): "Test topology builder" + def build(self, *_args, **_opts): "Build function" tgen = get_topogen(self) @@ -108,48 +109,49 @@ class TemplateTopo(Topo): # # Define FRR Routers # - for router in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6', 'dst']: + for router in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6", "dst"]: tgen.add_router(router) # # Define connections # - switch = tgen.add_switch('s1') - switch.add_link(tgen.gears['rt1'], nodeif="eth-sw1") - switch.add_link(tgen.gears['rt2'], nodeif="eth-sw1") - switch.add_link(tgen.gears['rt3'], nodeif="eth-sw1") + switch = tgen.add_switch("s1") + switch.add_link(tgen.gears["rt1"], nodeif="eth-sw1") + switch.add_link(tgen.gears["rt2"], nodeif="eth-sw1") + switch.add_link(tgen.gears["rt3"], nodeif="eth-sw1") + + switch = tgen.add_switch("s2") + switch.add_link(tgen.gears["rt2"], nodeif="eth-rt4-1") + switch.add_link(tgen.gears["rt4"], nodeif="eth-rt2-1") - switch = tgen.add_switch('s2') - switch.add_link(tgen.gears['rt2'], nodeif="eth-rt4-1") - switch.add_link(tgen.gears['rt4'], nodeif="eth-rt2-1") + switch = tgen.add_switch("s3") + switch.add_link(tgen.gears["rt2"], nodeif="eth-rt4-2") + switch.add_link(tgen.gears["rt4"], nodeif="eth-rt2-2") - switch = tgen.add_switch('s3') - switch.add_link(tgen.gears['rt2'], nodeif="eth-rt4-2") - switch.add_link(tgen.gears['rt4'], nodeif="eth-rt2-2") + switch = tgen.add_switch("s4") + switch.add_link(tgen.gears["rt3"], nodeif="eth-rt5-1") + switch.add_link(tgen.gears["rt5"], nodeif="eth-rt3-1") - switch = tgen.add_switch('s4') - switch.add_link(tgen.gears['rt3'], nodeif="eth-rt5-1") - switch.add_link(tgen.gears['rt5'], nodeif="eth-rt3-1") + switch = tgen.add_switch("s5") + switch.add_link(tgen.gears["rt3"], nodeif="eth-rt5-2") + switch.add_link(tgen.gears["rt5"], nodeif="eth-rt3-2") - switch = tgen.add_switch('s5') - switch.add_link(tgen.gears['rt3'], nodeif="eth-rt5-2") - switch.add_link(tgen.gears['rt5'], nodeif="eth-rt3-2") + switch = tgen.add_switch("s6") + switch.add_link(tgen.gears["rt4"], nodeif="eth-rt5") + switch.add_link(tgen.gears["rt5"], nodeif="eth-rt4") - switch = tgen.add_switch('s6') - switch.add_link(tgen.gears['rt4'], nodeif="eth-rt5") - switch.add_link(tgen.gears['rt5'], nodeif="eth-rt4") + switch = tgen.add_switch("s7") + switch.add_link(tgen.gears["rt4"], nodeif="eth-rt6") + switch.add_link(tgen.gears["rt6"], nodeif="eth-rt4") - switch = tgen.add_switch('s7') - switch.add_link(tgen.gears['rt4'], nodeif="eth-rt6") - switch.add_link(tgen.gears['rt6'], nodeif="eth-rt4") + switch = tgen.add_switch("s8") + switch.add_link(tgen.gears["rt5"], nodeif="eth-rt6") + switch.add_link(tgen.gears["rt6"], nodeif="eth-rt5") - switch = tgen.add_switch('s8') - switch.add_link(tgen.gears['rt5'], nodeif="eth-rt6") - switch.add_link(tgen.gears['rt6'], nodeif="eth-rt5") + switch = tgen.add_switch("s9") + switch.add_link(tgen.gears["rt6"], nodeif="eth-dst") + switch.add_link(tgen.gears["dst"], nodeif="eth-rt6") - switch = tgen.add_switch('s9') - switch.add_link(tgen.gears['rt6'], nodeif="eth-dst") - switch.add_link(tgen.gears['dst'], nodeif="eth-rt6") def setup_module(mod): "Sets up the pytest environment" @@ -167,24 +169,21 @@ def setup_module(mod): # For all registered routers, load the zebra configuration file for rname, router in router_list.iteritems(): router.load_config( - TopoRouter.RD_ZEBRA, - os.path.join(CWD, '{}/zebra.conf'.format(rname)) + TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) router.load_config( - TopoRouter.RD_ISIS, - os.path.join(CWD, '{}/isisd.conf'.format(rname)) + TopoRouter.RD_ISIS, os.path.join(CWD, "{}/isisd.conf".format(rname)) ) router.load_config( - TopoRouter.RD_PATH, - os.path.join(CWD, '{}/pathd.conf'.format(rname)) + TopoRouter.RD_PATH, os.path.join(CWD, "{}/pathd.conf".format(rname)) ) router.load_config( - TopoRouter.RD_BGP, - os.path.join(CWD, '{}/bgpd.conf'.format(rname)) + TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname)) ) tgen.start_router() + def teardown_module(mod): "Teardown the pytest environment" tgen = get_topogen() @@ -192,6 +191,7 @@ def teardown_module(mod): # This function tears down the whole topology. tgen.stop_topology() + def setup_testcase(msg): logger.info(msg) tgen = get_topogen() @@ -202,9 +202,11 @@ def setup_testcase(msg): return tgen + def print_cmd_result(rname, command): print(get_topogen().gears[rname].vtysh_cmd(command, isjson=False)) + def compare_json_test(router, command, reference, exact): output = router.vtysh_cmd(command, isjson=True) result = topotest.json_cmp(output, reference) @@ -212,9 +214,10 @@ def compare_json_test(router, command, reference, exact): # Note: topotest.json_cmp() just checks on inclusion of keys. # For exact matching also compare the other way around. if not result and exact: - return topotest.json_cmp(reference, output) + return topotest.json_cmp(reference, output) else: - return result + return result + def cmp_json_output(rname, command, reference, exact=False): "Compare router JSON output" @@ -222,78 +225,136 @@ def cmp_json_output(rname, command, reference, exact=False): logger.info('Comparing router "%s" "%s" output', rname, command) tgen = get_topogen() - filename = '{}/{}/{}'.format(CWD, rname, reference) + filename = "{}/{}/{}".format(CWD, rname, reference) expected = json.loads(open(filename).read()) # Run test function until we get an result. Wait at most 60 seconds. - test_func = partial(compare_json_test, - tgen.gears[rname], command, expected, exact) + test_func = partial(compare_json_test, tgen.gears[rname], command, expected, exact) _, diff = topotest.run_and_expect(test_func, None, count=120, wait=0.5) assertmsg = '"{}" JSON output mismatches the expected result'.format(rname) assert diff is None, assertmsg + def cmp_json_output_exact(rname, command, reference): return cmp_json_output(rname, command, reference, True) -def add_candidate_path(rname, endpoint, pref, name, segment_list='default'): - get_topogen().net[rname].cmd(''' \ + +def add_candidate_path(rname, endpoint, pref, name, segment_list="default"): + get_topogen().net[rname].cmd( + """ \ vtysh -c "conf t" \ -c "segment-routing" \ -c "traffic-eng" \ - -c "policy color 1 endpoint ''' + endpoint + '''" \ - -c "candidate-path preference ''' + str(pref) + ''' name ''' + name + ''' explicit segment-list ''' + segment_list + '''"''') + -c "policy color 1 endpoint """ + + endpoint + + """" \ + -c "candidate-path preference """ + + str(pref) + + """ name """ + + name + + """ explicit segment-list """ + + segment_list + + '''"''' + ) + def delete_candidate_path(rname, endpoint, pref): - get_topogen().net[rname].cmd(''' \ + get_topogen().net[rname].cmd( + """ \ vtysh -c "conf t" \ -c "segment-routing" \ -c "traffic-eng" \ - -c "policy color 1 endpoint ''' + endpoint + '''" \ - -c "no candidate-path preference ''' + str(pref) + '''"''') + -c "policy color 1 endpoint """ + + endpoint + + """" \ + -c "no candidate-path preference """ + + str(pref) + + '''"''' + ) + def add_segment(rname, name, index, label): - get_topogen().net[rname].cmd(''' \ + get_topogen().net[rname].cmd( + """ \ vtysh -c "conf t" \ -c "segment-routing" \ -c "traffic-eng" \ - -c "segment-list ''' + name + '''" \ - -c "index ''' + str(index) + ''' mpls label ''' + str(label) + '''"''') + -c "segment-list """ + + name + + """" \ + -c "index """ + + str(index) + + """ mpls label """ + + str(label) + + '''"''' + ) + def delete_segment(rname, name, index): - get_topogen().net[rname].cmd(''' \ + get_topogen().net[rname].cmd( + """ \ vtysh -c "conf t" \ -c "segment-routing" \ -c "traffic-eng" \ - -c "segment-list ''' + name + '''" \ - -c "no index ''' + str(index) + '''"''') + -c "segment-list """ + + name + + """" \ + -c "no index """ + + str(index) + + '''"''' + ) + def create_sr_policy(rname, endpoint, bsid): - get_topogen().net[rname].cmd(''' \ + get_topogen().net[rname].cmd( + """ \ vtysh -c "conf t" \ -c "segment-routing" \ -c "traffic-eng" \ - -c "policy color 1 endpoint ''' + endpoint + '''" \ + -c "policy color 1 endpoint """ + + endpoint + + """" \ -c "name default" \ - -c "binding-sid ''' + str(bsid) + '''"''') + -c "binding-sid """ + + str(bsid) + + '''"''' + ) + def delete_sr_policy(rname, endpoint): - get_topogen().net[rname].cmd(''' \ + get_topogen().net[rname].cmd( + """ \ vtysh -c "conf t" \ -c "segment-routing" \ -c "traffic-eng" \ - -c "no policy color 1 endpoint ''' + endpoint + '''"''') + -c "no policy color 1 endpoint """ + + endpoint + + '''"''' + ) + def create_prefix_sid(rname, prefix, sid): - get_topogen().net[rname].cmd(''' \ + get_topogen().net[rname].cmd( + """ \ vtysh -c "conf t" \ -c "router isis 1" \ - -c "segment-routing prefix ''' + prefix + " index " + str(sid) + '''"''') + -c "segment-routing prefix """ + + prefix + + " index " + + str(sid) + + '''"''' + ) + def delete_prefix_sid(rname, prefix): - get_topogen().net[rname].cmd(''' \ + get_topogen().net[rname].cmd( + ''' \ vtysh -c "conf t" \ -c "router isis 1" \ - -c "no segment-routing prefix "''' + prefix) + -c "no segment-routing prefix "''' + + prefix + ) + # # Step 1 @@ -303,37 +364,42 @@ def delete_prefix_sid(rname, prefix): def test_srte_init_step1(): setup_testcase("Test (step 1): wait for IS-IS convergence / label distribution") - for rname in ['rt1', 'rt6']: - cmp_json_output(rname, - "show mpls table json", - "step1/show_mpls_table_without_candidate.ref") + for rname in ["rt1", "rt6"]: + cmp_json_output( + rname, "show mpls table json", "step1/show_mpls_table_without_candidate.ref" + ) + def test_srte_add_candidate_check_mpls_table_step1(): setup_testcase("Test (step 1): check MPLS table regarding the added Candidate Path") - for rname, endpoint in [('rt1', '6.6.6.6'), ('rt6', '1.1.1.1')]: - add_candidate_path(rname, endpoint, 100, 'default') - cmp_json_output(rname, - "show mpls table json", - "step1/show_mpls_table_with_candidate.ref") + for rname, endpoint in [("rt1", "6.6.6.6"), ("rt6", "1.1.1.1")]: + add_candidate_path(rname, endpoint, 100, "default") + cmp_json_output( + rname, "show mpls table json", "step1/show_mpls_table_with_candidate.ref" + ) delete_candidate_path(rname, endpoint, 100) + def test_srte_reinstall_sr_policy_check_mpls_table_step1(): - setup_testcase("Test (step 1): check MPLS table after the SR Policy was removed and reinstalled") + setup_testcase( + "Test (step 1): check MPLS table after the SR Policy was removed and reinstalled" + ) - for rname, endpoint, bsid in [('rt1', '6.6.6.6', 1111), ('rt6', '1.1.1.1', 6666)]: - add_candidate_path(rname, endpoint, 100, 'default') + for rname, endpoint, bsid in [("rt1", "6.6.6.6", 1111), ("rt6", "1.1.1.1", 6666)]: + add_candidate_path(rname, endpoint, 100, "default") delete_sr_policy(rname, endpoint) - cmp_json_output(rname, - "show mpls table json", - "step1/show_mpls_table_without_candidate.ref") + cmp_json_output( + rname, "show mpls table json", "step1/show_mpls_table_without_candidate.ref" + ) create_sr_policy(rname, endpoint, bsid) - add_candidate_path(rname, endpoint, 100, 'default') - cmp_json_output(rname, - "show mpls table json", - "step1/show_mpls_table_with_candidate.ref") + add_candidate_path(rname, endpoint, 100, "default") + cmp_json_output( + rname, "show mpls table json", "step1/show_mpls_table_with_candidate.ref" + ) delete_candidate_path(rname, endpoint, 100) + # # Step 2 # @@ -342,28 +408,41 @@ def test_srte_reinstall_sr_policy_check_mpls_table_step1(): def test_srte_bare_policy_step2(): setup_testcase("Test (step 2): bare SR Policy should not be operational") - for rname in ['rt1', 'rt6']: - cmp_json_output_exact(rname, - "show yang operational-data /frr-pathd:pathd pathd", - "step2/show_operational_data.ref") + for rname in ["rt1", "rt6"]: + cmp_json_output_exact( + rname, + "show yang operational-data /frr-pathd:pathd pathd", + "step2/show_operational_data.ref", + ) + def test_srte_add_candidate_check_operational_data_step2(): - setup_testcase("Test (step 2): add single Candidate Path, SR Policy should be operational") + setup_testcase( + "Test (step 2): add single Candidate Path, SR Policy should be operational" + ) + + for rname, endpoint in [("rt1", "6.6.6.6"), ("rt6", "1.1.1.1")]: + add_candidate_path(rname, endpoint, 100, "default") + cmp_json_output( + rname, + "show yang operational-data /frr-pathd:pathd pathd", + "step2/show_operational_data_with_candidate.ref", + ) - for rname, endpoint in [('rt1', '6.6.6.6'), ('rt6', '1.1.1.1')]: - add_candidate_path(rname, endpoint, 100, 'default') - cmp_json_output(rname, - "show yang operational-data /frr-pathd:pathd pathd", - "step2/show_operational_data_with_candidate.ref") def test_srte_config_remove_candidate_check_operational_data_step2(): - setup_testcase("Test (step 2): remove single Candidate Path, SR Policy should not be operational anymore") + setup_testcase( + "Test (step 2): remove single Candidate Path, SR Policy should not be operational anymore" + ) - for rname, endpoint in [('rt1', '6.6.6.6'), ('rt6', '1.1.1.1')]: + for rname, endpoint in [("rt1", "6.6.6.6"), ("rt6", "1.1.1.1")]: delete_candidate_path(rname, endpoint, 100) - cmp_json_output_exact(rname, - "show yang operational-data /frr-pathd:pathd pathd", - "step2/show_operational_data.ref") + cmp_json_output_exact( + rname, + "show yang operational-data /frr-pathd:pathd pathd", + "step2/show_operational_data.ref", + ) + # # Step 3 @@ -373,53 +452,62 @@ def test_srte_config_remove_candidate_check_operational_data_step2(): def test_srte_add_two_candidates_step3(): setup_testcase("Test (step 3): second Candidate Path has higher Priority") - for rname, endpoint in [('rt1', '6.6.6.6'), ('rt6', '1.1.1.1')]: - for pref, cand_name in [('100', 'first'), ('200', 'second')]: + for rname, endpoint in [("rt1", "6.6.6.6"), ("rt6", "1.1.1.1")]: + for pref, cand_name in [("100", "first"), ("200", "second")]: add_candidate_path(rname, endpoint, pref, cand_name) - cmp_json_output(rname, - "show yang operational-data /frr-pathd:pathd pathd", - "step3/show_operational_data_with_two_candidates.ref") + cmp_json_output( + rname, + "show yang operational-data /frr-pathd:pathd pathd", + "step3/show_operational_data_with_two_candidates.ref", + ) # cleanup - for rname, endpoint in [('rt1', '6.6.6.6'), ('rt6', '1.1.1.1')]: - for pref in ['100', '200']: + for rname, endpoint in [("rt1", "6.6.6.6"), ("rt6", "1.1.1.1")]: + for pref in ["100", "200"]: delete_candidate_path(rname, endpoint, pref) + def test_srte_add_two_candidates_with_reverse_priority_step3(): setup_testcase("Test (step 3): second Candidate Path has lower Priority") # Use reversed priorities here - for rname, endpoint in [('rt1', '6.6.6.6'), ('rt6', '1.1.1.1')]: - for pref, cand_name in [('200', 'first'), ('100', 'second')]: + for rname, endpoint in [("rt1", "6.6.6.6"), ("rt6", "1.1.1.1")]: + for pref, cand_name in [("200", "first"), ("100", "second")]: add_candidate_path(rname, endpoint, pref, cand_name) - cmp_json_output(rname, - "show yang operational-data /frr-pathd:pathd pathd", - "step3/show_operational_data_with_two_candidates.ref") + cmp_json_output( + rname, + "show yang operational-data /frr-pathd:pathd pathd", + "step3/show_operational_data_with_two_candidates.ref", + ) # cleanup - for rname, endpoint in [('rt1', '6.6.6.6'), ('rt6', '1.1.1.1')]: - for pref in ['100', '200']: + for rname, endpoint in [("rt1", "6.6.6.6"), ("rt6", "1.1.1.1")]: + for pref in ["100", "200"]: delete_candidate_path(rname, endpoint, pref) + def test_srte_remove_best_candidate_step3(): setup_testcase("Test (step 3): delete the Candidate Path with higher priority") - for rname, endpoint in [('rt1', '6.6.6.6'), ('rt6', '1.1.1.1')]: - for pref, cand_name in [('100', 'first'), ('200', 'second')]: + for rname, endpoint in [("rt1", "6.6.6.6"), ("rt6", "1.1.1.1")]: + for pref, cand_name in [("100", "first"), ("200", "second")]: add_candidate_path(rname, endpoint, pref, cand_name) # Delete candidate with higher priority - for rname, endpoint in [('rt1', '6.6.6.6'), ('rt6', '1.1.1.1')]: + for rname, endpoint in [("rt1", "6.6.6.6"), ("rt6", "1.1.1.1")]: delete_candidate_path(rname, endpoint, 200) # Candidate with lower priority should get active now - for rname, endpoint in [('rt1', '6.6.6.6'), ('rt6', '1.1.1.1')]: - cmp_json_output(rname, - "show yang operational-data /frr-pathd:pathd pathd", - "step3/show_operational_data_with_single_candidate.ref") + for rname, endpoint in [("rt1", "6.6.6.6"), ("rt6", "1.1.1.1")]: + cmp_json_output( + rname, + "show yang operational-data /frr-pathd:pathd pathd", + "step3/show_operational_data_with_single_candidate.ref", + ) # cleanup delete_candidate_path(rname, endpoint, 100) + # # Step 4 # @@ -428,38 +516,38 @@ def test_srte_remove_best_candidate_step3(): def test_srte_change_segment_list_check_mpls_table_step4(): setup_testcase("Test (step 4): check MPLS table for changed Segment List") - for rname, endpoint in [('rt1', '6.6.6.6'), ('rt6', '1.1.1.1')]: - add_candidate_path(rname, endpoint, 100, 'default') - # now change the segment list name - add_candidate_path(rname, endpoint, 100, 'default', 'test') - cmp_json_output(rname, - "show mpls table json", - "step4/show_mpls_table.ref") + for rname, endpoint in [("rt1", "6.6.6.6"), ("rt6", "1.1.1.1")]: + add_candidate_path(rname, endpoint, 100, "default") + # now change the segment list name + add_candidate_path(rname, endpoint, 100, "default", "test") + cmp_json_output(rname, "show mpls table json", "step4/show_mpls_table.ref") delete_candidate_path(rname, endpoint, 100) + def test_srte_segment_list_add_segment_check_mpls_table_step4(): - setup_testcase("Test (step 4): check MPLS table for added (then changed and finally deleted) segment") + setup_testcase( + "Test (step 4): check MPLS table for added (then changed and finally deleted) segment" + ) - add_candidate_path('rt1', '6.6.6.6', 100, 'default', 'test') + add_candidate_path("rt1", "6.6.6.6", 100, "default", "test") # first add a new segment - add_segment('rt1', 'test', 25, 16050) - cmp_json_output('rt1', - "show mpls table json", - "step4/show_mpls_table_add_segment.ref") + add_segment("rt1", "test", 25, 16050) + cmp_json_output( + "rt1", "show mpls table json", "step4/show_mpls_table_add_segment.ref" + ) # ... then change it ... - add_segment('rt1', 'test', 25, 16030) - cmp_json_output('rt1', - "show mpls table json", - "step4/show_mpls_table_change_segment.ref") + add_segment("rt1", "test", 25, 16030) + cmp_json_output( + "rt1", "show mpls table json", "step4/show_mpls_table_change_segment.ref" + ) # ... and finally delete it - delete_segment('rt1', 'test', 25) - cmp_json_output('rt1', - "show mpls table json", - "step4/show_mpls_table.ref") - delete_candidate_path('rt1', '6.6.6.6', 100) + delete_segment("rt1", "test", 25) + cmp_json_output("rt1", "show mpls table json", "step4/show_mpls_table.ref") + delete_candidate_path("rt1", "6.6.6.6", 100) + # # Step 5 @@ -467,68 +555,81 @@ def test_srte_segment_list_add_segment_check_mpls_table_step4(): # Checking the nexthop using a single SR Policy and a Candidate Path with configured route-map # def test_srte_route_map_with_sr_policy_check_nextop_step5(): - setup_testcase("Test (step 5): recursive nexthop learned through BGP neighbour should be aligned with SR Policy from route-map") + setup_testcase( + "Test (step 5): recursive nexthop learned through BGP neighbour should be aligned with SR Policy from route-map" + ) # (re-)build the SR Policy two times to ensure that reinstalling still works - for i in [1,2]: - cmp_json_output('rt1', - "show ip route bgp json", - "step5/show_ip_route_bgp_inactive_srte.ref") + for i in [1, 2]: + cmp_json_output( + "rt1", "show ip route bgp json", "step5/show_ip_route_bgp_inactive_srte.ref" + ) - delete_sr_policy('rt1', '6.6.6.6') - cmp_json_output('rt1', - "show ip route bgp json", - "step5/show_ip_route_bgp_inactive_srte.ref") + delete_sr_policy("rt1", "6.6.6.6") + cmp_json_output( + "rt1", "show ip route bgp json", "step5/show_ip_route_bgp_inactive_srte.ref" + ) - create_sr_policy('rt1', '6.6.6.6', 1111) - cmp_json_output('rt1', - "show ip route bgp json", - "step5/show_ip_route_bgp_inactive_srte.ref") + create_sr_policy("rt1", "6.6.6.6", 1111) + cmp_json_output( + "rt1", "show ip route bgp json", "step5/show_ip_route_bgp_inactive_srte.ref" + ) + + add_candidate_path("rt1", "6.6.6.6", 100, "default") + cmp_json_output( + "rt1", "show ip route bgp json", "step5/show_ip_route_bgp_active_srte.ref" + ) - add_candidate_path('rt1', '6.6.6.6', 100, 'default') - cmp_json_output('rt1', - "show ip route bgp json", - "step5/show_ip_route_bgp_active_srte.ref") + delete_candidate_path("rt1", "6.6.6.6", 100) - delete_candidate_path('rt1', '6.6.6.6', 100) def test_srte_route_map_with_sr_policy_reinstall_prefix_sid_check_nextop_step5(): - setup_testcase("Test (step 5): remove and re-install prefix SID on fist path element and check SR Policy activity") + setup_testcase( + "Test (step 5): remove and re-install prefix SID on fist path element and check SR Policy activity" + ) # first add a candidate path so the SR Policy is active - add_candidate_path('rt1', '6.6.6.6', 100, 'default') - cmp_json_output('rt1', - "show yang operational-data /frr-pathd:pathd pathd", - "step5/show_operational_data_active.ref") + add_candidate_path("rt1", "6.6.6.6", 100, "default") + cmp_json_output( + "rt1", + "show yang operational-data /frr-pathd:pathd pathd", + "step5/show_operational_data_active.ref", + ) # delete prefix SID from first element of the configured path and check # if the SR Policy is inactive since the label can't be resolved anymore - delete_prefix_sid('rt5', "5.5.5.5/32") - cmp_json_output('rt1', - "show yang operational-data /frr-pathd:pathd pathd", - "step5/show_operational_data_inactive.ref") - cmp_json_output('rt1', - "show ip route bgp json", - "step5/show_ip_route_bgp_inactive_srte.ref") + delete_prefix_sid("rt5", "5.5.5.5/32") + cmp_json_output( + "rt1", + "show yang operational-data /frr-pathd:pathd pathd", + "step5/show_operational_data_inactive.ref", + ) + cmp_json_output( + "rt1", "show ip route bgp json", "step5/show_ip_route_bgp_inactive_srte.ref" + ) # re-create the prefix SID and check if the SR Policy is active - create_prefix_sid('rt5', "5.5.5.5/32", 50) - cmp_json_output('rt1', - "show yang operational-data /frr-pathd:pathd pathd", - "step5/show_operational_data_active.ref") - cmp_json_output('rt1', - "show ip route bgp json", - "step5/show_ip_route_bgp_active_srte.ref") + create_prefix_sid("rt5", "5.5.5.5/32", 50) + cmp_json_output( + "rt1", + "show yang operational-data /frr-pathd:pathd pathd", + "step5/show_operational_data_active.ref", + ) + cmp_json_output( + "rt1", "show ip route bgp json", "step5/show_ip_route_bgp_active_srte.ref" + ) + # Memory leak test template 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') + pytest.skip("Memory leak test/report is disabled") tgen.report_memory_leaks() -if __name__ == '__main__': + +if __name__ == "__main__": args = ["-s"] + sys.argv[1:] sys.exit(pytest.main(args)) diff --git a/tests/topotests/isis-sr-topo1/test_isis_sr_topo1.py b/tests/topotests/isis-sr-topo1/test_isis_sr_topo1.py index 8a7d6ee882..148a89474e 100644 --- a/tests/topotests/isis-sr-topo1/test_isis_sr_topo1.py +++ b/tests/topotests/isis-sr-topo1/test_isis_sr_topo1.py @@ -86,6 +86,7 @@ from mininet.topo import Topo pytestmark = [pytest.mark.isisd] + class TemplateTopo(Topo): "Test topology builder" diff --git a/tests/topotests/isis-tilfa-topo1/test_isis_tilfa_topo1.py b/tests/topotests/isis-tilfa-topo1/test_isis_tilfa_topo1.py index 39b3299603..00cb623999 100755 --- a/tests/topotests/isis-tilfa-topo1/test_isis_tilfa_topo1.py +++ b/tests/topotests/isis-tilfa-topo1/test_isis_tilfa_topo1.py @@ -179,6 +179,7 @@ class TemplateTopo(Topo): f_in.close() f_out.close() + def setup_module(mod): "Sets up the pytest environment" tgen = Topogen(TemplateTopo, mod.__name__) 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 7bc694cbb0..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,11 +40,14 @@ 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 pytestmark = [pytest.mark.isisd] + class ISISTopo1(Topo): "Simple two layer ISIS vrf topology" @@ -139,15 +142,6 @@ def setup_module(mod): # After loading the configurations, this function loads configured daemons. tgen.start_router() - has_version_20 = False - for router in tgen.routers().values(): - if router.has_version("<", "4"): - has_version_20 = True - - if has_version_20: - logger.info("Skipping ISIS vrf tests for FRR 2.0") - tgen.set_error("ISIS has convergence problems with IPv6") - def teardown_module(mod): "Teardown the pytest environment" @@ -196,47 +190,32 @@ def test_isis_route_installation(): actual = router.vtysh_cmd( "show ip route vrf {0}-cust1 json".format(rname), isjson=True ) - # Older FRR versions don't list interfaces in some ISIS routes - if router.has_version("<", "3.1"): - for network, routes in expected.items(): - for route in routes: - if route["protocol"] != "isis": - continue - - for nexthop in route["nexthops"]: - nexthop.pop("interfaceIndex", None) - nexthop.pop("interfaceName", None) - assertmsg = "Router '{}' routes mismatch".format(rname) assert topotest.json_cmp(actual, expected) is None, assertmsg 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(): filename = "{0}/{1}/{1}_route_linux.json".format(CWD, rname) expected = json.loads(open(filename, "r").read()) actual = topotest.ip4_vrf_route(router) - - # Older FRR versions install routes using different proto - if router.has_version("<", "3.1"): - for network, netoptions in expected.items(): - if "proto" in netoptions and netoptions["proto"] == "187": - netoptions["proto"] = "zebra" - assertmsg = "Router '{}' OS routes mismatch".format(rname) assert topotest.json_cmp(actual, expected) is None, assertmsg @@ -257,47 +236,32 @@ def test_isis_route6_installation(): "show ipv6 route vrf {}-cust1 json".format(rname), isjson=True ) - # Older FRR versions don't list interfaces in some ISIS routes - if router.has_version("<", "3.1"): - for network, routes in expected.items(): - for route in routes: - if route["protocol"] != "isis": - continue - - for nexthop in route["nexthops"]: - nexthop.pop("interfaceIndex", None) - nexthop.pop("interfaceName", None) - assertmsg = "Router '{}' routes mismatch".format(rname) assert topotest.json_cmp(actual, expected) is None, assertmsg 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(): filename = "{0}/{1}/{1}_route6_linux.json".format(CWD, rname) expected = json.loads(open(filename, "r").read()) actual = topotest.ip6_vrf_route(router) - - # Older FRR versions install routes using different proto - if router.has_version("<", "3.1"): - for network, netoptions in expected.items(): - if "proto" in netoptions and netoptions["proto"] == "187": - netoptions["proto"] = "zebra" - assertmsg = "Router '{}' OS routes mismatch".format(rname) assert topotest.json_cmp(actual, expected) is None, assertmsg diff --git a/tests/topotests/isis-topo1/test_isis_topo1.py b/tests/topotests/isis-topo1/test_isis_topo1.py index 6963429288..e7618c7bce 100644 --- a/tests/topotests/isis-topo1/test_isis_topo1.py +++ b/tests/topotests/isis-topo1/test_isis_topo1.py @@ -47,6 +47,7 @@ from mininet.topo import Topo pytestmark = [pytest.mark.isisd] + class ISISTopo1(Topo): "Simple two layer ISIS topology" @@ -103,15 +104,6 @@ def setup_module(mod): # After loading the configurations, this function loads configured daemons. tgen.start_router() - has_version_20 = False - for router in tgen.routers().values(): - if router.has_version("<", "3"): - has_version_20 = True - - if has_version_20: - logger.info("Skipping ISIS tests for FRR 2.0") - tgen.set_error("ISIS has convergence problems with IPv6") - def teardown_module(mod): "Teardown the pytest environment" @@ -163,18 +155,6 @@ def test_isis_route_installation(): filename = "{0}/{1}/{1}_route.json".format(CWD, rname) expected = json.loads(open(filename, "r").read()) actual = router.vtysh_cmd("show ip route json", isjson=True) - - # Older FRR versions don't list interfaces in some ISIS routes - if router.has_version("<", "3.1"): - for network, routes in expected.items(): - for route in routes: - if route["protocol"] != "isis": - continue - - for nexthop in route["nexthops"]: - nexthop.pop("interfaceIndex", None) - nexthop.pop("interfaceName", None) - assertmsg = "Router '{}' routes mismatch".format(rname) assert topotest.json_cmp(actual, expected) is None, assertmsg @@ -193,13 +173,6 @@ def test_isis_linux_route_installation(): filename = "{0}/{1}/{1}_route_linux.json".format(CWD, rname) expected = json.loads(open(filename, "r").read()) actual = topotest.ip4_route(router) - - # Older FRR versions install routes using different proto - if router.has_version("<", "3.1"): - for network, netoptions in expected.items(): - if "proto" in netoptions and netoptions["proto"] == "187": - netoptions["proto"] = "zebra" - assertmsg = "Router '{}' OS routes mismatch".format(rname) assert topotest.json_cmp(actual, expected) is None, assertmsg @@ -218,21 +191,6 @@ def test_isis_route6_installation(): filename = "{0}/{1}/{1}_route6.json".format(CWD, rname) expected = json.loads(open(filename, "r").read()) actual = router.vtysh_cmd("show ipv6 route json", isjson=True) - - # Older FRR versions don't list interfaces in some ISIS routes - if router.has_version("<", "3.1"): - for network, routes in expected.items(): - for route in routes: - # Older versions display different metrics for IPv6 routes - route.pop("metric", None) - - if route["protocol"] != "isis": - continue - - for nexthop in route["nexthops"]: - nexthop.pop("interfaceIndex", None) - nexthop.pop("interfaceName", None) - assertmsg = "Router '{}' routes mismatch".format(rname) assert topotest.json_cmp(actual, expected) is None, assertmsg @@ -251,13 +209,6 @@ def test_isis_linux_route6_installation(): filename = "{0}/{1}/{1}_route6_linux.json".format(CWD, rname) expected = json.loads(open(filename, "r").read()) actual = topotest.ip6_route(router) - - # Older FRR versions install routes using different proto - if router.has_version("<", "3.1"): - for network, netoptions in expected.items(): - if "proto" in netoptions and netoptions["proto"] == "187": - netoptions["proto"] = "zebra" - assertmsg = "Router '{}' OS routes mismatch".format(rname) assert topotest.json_cmp(actual, expected) is None, assertmsg diff --git a/tests/topotests/ldp-oc-acl-topo1/test_ldp_oc_acl_topo1.py b/tests/topotests/ldp-oc-acl-topo1/test_ldp_oc_acl_topo1.py index a74e80dd80..9aa4024598 100644 --- a/tests/topotests/ldp-oc-acl-topo1/test_ldp_oc_acl_topo1.py +++ b/tests/topotests/ldp-oc-acl-topo1/test_ldp_oc_acl_topo1.py @@ -80,6 +80,7 @@ from mininet.topo import Topo pytestmark = [pytest.mark.ldpd, pytest.mark.ospfd] + class TemplateTopo(Topo): "Test topology builder" diff --git a/tests/topotests/ldp-oc-topo1/test_ldp_oc_topo1.py b/tests/topotests/ldp-oc-topo1/test_ldp_oc_topo1.py index 97790487f2..aef22c395d 100644 --- a/tests/topotests/ldp-oc-topo1/test_ldp_oc_topo1.py +++ b/tests/topotests/ldp-oc-topo1/test_ldp_oc_topo1.py @@ -80,6 +80,7 @@ from mininet.topo import Topo pytestmark = [pytest.mark.ldpd, pytest.mark.ospfd] + class TemplateTopo(Topo): "Test topology builder" diff --git a/tests/topotests/ldp-snmp/ce1/zebra.conf b/tests/topotests/ldp-snmp/ce1/zebra.conf new file mode 100644 index 0000000000..6f165e2724 --- /dev/null +++ b/tests/topotests/ldp-snmp/ce1/zebra.conf @@ -0,0 +1,12 @@ +log file zebra.log +! +hostname ce1 +! +interface ce1-eth0 + ip address 172.16.1.1/24 + no link-detect +! +ip forwarding +! +line vty +! diff --git a/tests/topotests/ldp-snmp/ce2/zebra.conf b/tests/topotests/ldp-snmp/ce2/zebra.conf new file mode 100644 index 0000000000..ac02d0f9a4 --- /dev/null +++ b/tests/topotests/ldp-snmp/ce2/zebra.conf @@ -0,0 +1,12 @@ +log file zebra.log +! +hostname ce2 +! +interface ce2-eth0 + ip address 172.16.1.2/24 + no link-detect +! +ip forwarding +! +line vty +! diff --git a/tests/topotests/ldp-snmp/ce3/zebra.conf b/tests/topotests/ldp-snmp/ce3/zebra.conf new file mode 100644 index 0000000000..c6a5824d15 --- /dev/null +++ b/tests/topotests/ldp-snmp/ce3/zebra.conf @@ -0,0 +1,12 @@ +log file zebra.log +! +hostname ce3 +! +interface ce3-eth0 + ip address 172.16.1.3/24 + no link-detect +! +ip forwarding +! +line vty +! diff --git a/tests/topotests/ldp-snmp/r1/isisd.conf b/tests/topotests/ldp-snmp/r1/isisd.conf new file mode 100644 index 0000000000..da2970d94e --- /dev/null +++ b/tests/topotests/ldp-snmp/r1/isisd.conf @@ -0,0 +1,27 @@ +hostname r1 +log file isisd.log +debug isis adj-packets +debug isis events +debug isis update-packets +debug isis ldp-sync +! +router isis 1 + lsp-gen-interval 2 + net 10.0000.0000.0000.0000.0000.0000.0000.0000.0001.00 + metric-style wide + redistribute ipv4 connected level-1 + redistribute ipv6 connected level-1 + mpls ldp-sync +! +interface r1-eth1 + ip router isis 1 + ipv6 router isis 1 + isis network point-to-point + isis circuit-type level-1 +! +interface r1-eth2 + ip router isis 1 + ipv6 router isis 1 + isis network point-to-point + isis circuit-type level-1 +! diff --git a/tests/topotests/ldp-snmp/r1/ldpd.conf b/tests/topotests/ldp-snmp/r1/ldpd.conf new file mode 100644 index 0000000000..01fc039b09 --- /dev/null +++ b/tests/topotests/ldp-snmp/r1/ldpd.conf @@ -0,0 +1,35 @@ +hostname r1 +log file ldpd.log +! +debug mpls ldp zebra +debug mpls ldp event +debug mpls ldp errors +debug mpls ldp sync +! +mpls ldp + router-id 1.1.1.1 + ! + address-family ipv4 + discovery transport-address 1.1.1.1 + label local allocate host-routes + ! + ttl-security disable + ! + interface r1-eth1 + ! + interface r1-eth2 + ! + ! +! +l2vpn CUST_A type vpls + member interface r1-eth0 + ! + member pseudowire r1-mpw0 + neighbor lsr-id 2.2.2.2 + pw-id 100 + ! +! +line vty +! +agentx +! diff --git a/tests/topotests/ldp-snmp/r1/show_ip_route.ref b/tests/topotests/ldp-snmp/r1/show_ip_route.ref new file mode 100644 index 0000000000..b1a55ba103 --- /dev/null +++ b/tests/topotests/ldp-snmp/r1/show_ip_route.ref @@ -0,0 +1,134 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"connected", + "selected":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"lo", + "active":true + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "distance":115, + "metric":10, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"r1-eth1", + "active":true + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "distance":115, + "metric":10, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.3", + "afi":"ipv4", + "interfaceName":"r1-eth2", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "distance":115, + "metric":10, + "nexthops":[ + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"r1-eth1" + } + ] + }, + { + "prefix":"10.0.1.0\/24", + "protocol":"connected", + "selected":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"r1-eth1", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "distance":115, + "metric":10, + "nexthops":[ + { + "ip":"10.0.2.3", + "afi":"ipv4", + "interfaceName":"r1-eth2" + } + ] + }, + { + "prefix":"10.0.2.0\/24", + "protocol":"connected", + "selected":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"r1-eth2", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "selected":true, + "distance":115, + "metric":10, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"r1-eth1", + "active":true + }, + { + "fib":true, + "ip":"10.0.2.3", + "afi":"ipv4", + "interfaceName":"r1-eth2", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/ldp-snmp/r1/show_isis_interface_detail.ref b/tests/topotests/ldp-snmp/r1/show_isis_interface_detail.ref new file mode 100644 index 0000000000..d8fb27af8c --- /dev/null +++ b/tests/topotests/ldp-snmp/r1/show_isis_interface_detail.ref @@ -0,0 +1,16 @@ +{ + "1": { + "r1-eth1": [ + { + "level": "Level-1", + "metric": "10" + } + ], + "r1-eth2": [ + { + "level": "Level-1", + "metric": "10" + } + ] + } +} diff --git a/tests/topotests/ldp-snmp/r1/show_isis_interface_detail_r1_eth1_shutdown.ref b/tests/topotests/ldp-snmp/r1/show_isis_interface_detail_r1_eth1_shutdown.ref new file mode 100644 index 0000000000..f77d65ebc1 --- /dev/null +++ b/tests/topotests/ldp-snmp/r1/show_isis_interface_detail_r1_eth1_shutdown.ref @@ -0,0 +1,16 @@ +{ + "1": { + "r1-eth1": [ + { + "level": "Level-1", + "metric": "16777214" + } + ], + "r1-eth2": [ + { + "level": "Level-1", + "metric": "10" + } + ] + } +} diff --git a/tests/topotests/ldp-snmp/r1/show_isis_interface_detail_r2_eth1_shutdown.ref b/tests/topotests/ldp-snmp/r1/show_isis_interface_detail_r2_eth1_shutdown.ref new file mode 100644 index 0000000000..f77d65ebc1 --- /dev/null +++ b/tests/topotests/ldp-snmp/r1/show_isis_interface_detail_r2_eth1_shutdown.ref @@ -0,0 +1,16 @@ +{ + "1": { + "r1-eth1": [ + { + "level": "Level-1", + "metric": "16777214" + } + ], + "r1-eth2": [ + { + "level": "Level-1", + "metric": "10" + } + ] + } +} diff --git a/tests/topotests/ldp-snmp/r1/show_isis_ldp_sync.ref b/tests/topotests/ldp-snmp/r1/show_isis_ldp_sync.ref new file mode 100644 index 0000000000..b699e8c145 --- /dev/null +++ b/tests/topotests/ldp-snmp/r1/show_isis_ldp_sync.ref @@ -0,0 +1,13 @@ +{ + "r1-eth1":{ + "ldpIgpSyncEnabled":true, + "holdDownTimeInSec":0, + "ldpIgpSyncState":"Sync achieved" + }, + "r1-eth2":{ + "ldpIgpSyncEnabled":true, + "holdDownTimeInSec":0, + "ldpIgpSyncState":"Sync achieved" + } + +} diff --git a/tests/topotests/ldp-snmp/r1/show_isis_ldp_sync_r1_eth1_shutdown.ref b/tests/topotests/ldp-snmp/r1/show_isis_ldp_sync_r1_eth1_shutdown.ref new file mode 100644 index 0000000000..c28cd4cc7d --- /dev/null +++ b/tests/topotests/ldp-snmp/r1/show_isis_ldp_sync_r1_eth1_shutdown.ref @@ -0,0 +1,11 @@ +{ + "r1-eth1":{ + "Interface":true + }, + "r1-eth2":{ + "ldpIgpSyncEnabled":true, + "holdDownTimeInSec":0, + "ldpIgpSyncState":"Sync achieved" + } + +} diff --git a/tests/topotests/ldp-snmp/r1/show_isis_ldp_sync_r2_eth1_shutdown.ref b/tests/topotests/ldp-snmp/r1/show_isis_ldp_sync_r2_eth1_shutdown.ref new file mode 100644 index 0000000000..c63bbea77f --- /dev/null +++ b/tests/topotests/ldp-snmp/r1/show_isis_ldp_sync_r2_eth1_shutdown.ref @@ -0,0 +1,13 @@ +{ + "r1-eth1":{ + "ldpIgpSyncEnabled":true, + "holdDownTimeInSec":0, + "ldpIgpSyncState":"Sync not achieved" + }, + "r1-eth2":{ + "ldpIgpSyncEnabled":true, + "holdDownTimeInSec":0, + "ldpIgpSyncState":"Sync achieved" + } + +} diff --git a/tests/topotests/ldp-snmp/r1/show_l2vpn_binding.ref b/tests/topotests/ldp-snmp/r1/show_l2vpn_binding.ref new file mode 100644 index 0000000000..b3de7e2c66 --- /dev/null +++ b/tests/topotests/ldp-snmp/r1/show_l2vpn_binding.ref @@ -0,0 +1,16 @@ +{ + "2.2.2.2: 100":{ + "destination":"2.2.2.2", + "vcId":100, + "localLabel":16, + "localControlWord":1, + "localVcType":"Ethernet", + "localGroupID":0, + "localIfMtu":1500, + "remoteLabel":16, + "remoteControlWord":1, + "remoteVcType":"Ethernet", + "remoteGroupID":0, + "remoteIfMtu":1500 + } +} diff --git a/tests/topotests/ldp-snmp/r1/show_l2vpn_vc.ref b/tests/topotests/ldp-snmp/r1/show_l2vpn_vc.ref new file mode 100644 index 0000000000..29e9df1089 --- /dev/null +++ b/tests/topotests/ldp-snmp/r1/show_l2vpn_vc.ref @@ -0,0 +1,8 @@ +{ + "r1-mpw0":{ + "peerId":"2.2.2.2", + "vcId":100, + "VpnName":"CUST_A", + "status":"up" + } +} diff --git a/tests/topotests/ldp-snmp/r1/show_ldp_binding.ref b/tests/topotests/ldp-snmp/r1/show_ldp_binding.ref new file mode 100644 index 0000000000..b3a12ec53f --- /dev/null +++ b/tests/topotests/ldp-snmp/r1/show_ldp_binding.ref @@ -0,0 +1,44 @@ +{ + "bindings":[ + { + "addressFamily":"ipv4", + "prefix":"1.1.1.1/32", + "neighborId":"2.2.2.2", + "localLabel":"imp-null", + "inUse":0 + }, + { + "addressFamily":"ipv4", + "prefix":"1.1.1.1/32", + "neighborId":"3.3.3.3", + "localLabel":"imp-null", + "inUse":0 + }, + { + "addressFamily":"ipv4", + "prefix":"2.2.2.2/32", + "neighborId":"2.2.2.2", + "remoteLabel":"imp-null", + "inUse":1 + }, + { + "addressFamily":"ipv4", + "prefix":"2.2.2.2/32", + "neighborId":"3.3.3.3", + "inUse":0 + }, + { + "addressFamily":"ipv4", + "prefix":"3.3.3.3/32", + "neighborId":"2.2.2.2", + "inUse":0 + }, + { + "addressFamily":"ipv4", + "prefix":"3.3.3.3/32", + "neighborId":"3.3.3.3", + "remoteLabel":"imp-null", + "inUse":1 + } + ] +} diff --git a/tests/topotests/ldp-snmp/r1/show_ldp_discovery.ref b/tests/topotests/ldp-snmp/r1/show_ldp_discovery.ref new file mode 100644 index 0000000000..9301e60c67 --- /dev/null +++ b/tests/topotests/ldp-snmp/r1/show_ldp_discovery.ref @@ -0,0 +1,25 @@ +{ + "adjacencies":[ + { + "addressFamily":"ipv4", + "neighborId":"2.2.2.2", + "type":"link", + "interface":"r1-eth1", + "helloHoldtime":15 + }, + { + "addressFamily":"ipv4", + "neighborId":"2.2.2.2", + "type":"targeted", + "peer":"2.2.2.2", + "helloHoldtime":45 + }, + { + "addressFamily":"ipv4", + "neighborId":"3.3.3.3", + "type":"link", + "interface":"r1-eth2", + "helloHoldtime":15 + } + ] +} diff --git a/tests/topotests/ldp-snmp/r1/show_ldp_igp_sync.ref b/tests/topotests/ldp-snmp/r1/show_ldp_igp_sync.ref new file mode 100644 index 0000000000..54d015fef9 --- /dev/null +++ b/tests/topotests/ldp-snmp/r1/show_ldp_igp_sync.ref @@ -0,0 +1,16 @@ +{ + "r1-eth1":{ + "state":"labelExchangeComplete", + "waitTime":10, + "waitTimeRemaining":0, + "timerRunning":false, + "peerLdpId":"2.2.2.2" + }, + "r1-eth2":{ + "state":"labelExchangeComplete", + "waitTime":10, + "waitTimeRemaining":0, + "timerRunning":false, + "peerLdpId":"3.3.3.3" + } +} diff --git a/tests/topotests/ldp-snmp/r1/show_ldp_igp_sync_r1_eth1_shutdown.ref b/tests/topotests/ldp-snmp/r1/show_ldp_igp_sync_r1_eth1_shutdown.ref new file mode 100644 index 0000000000..2232069f68 --- /dev/null +++ b/tests/topotests/ldp-snmp/r1/show_ldp_igp_sync_r1_eth1_shutdown.ref @@ -0,0 +1,16 @@ +{ + "r1-eth1":{ + "state":"labelExchangeNotComplete", + "waitTime":10, + "waitTimeRemaining":0, + "timerRunning":false, + "peerLdpId":"" + }, + "r1-eth2":{ + "state":"labelExchangeComplete", + "waitTime":10, + "waitTimeRemaining":0, + "timerRunning":false, + "peerLdpId":"3.3.3.3" + } +} diff --git a/tests/topotests/ldp-snmp/r1/show_ldp_neighbor.ref b/tests/topotests/ldp-snmp/r1/show_ldp_neighbor.ref new file mode 100644 index 0000000000..40d8ebeb90 --- /dev/null +++ b/tests/topotests/ldp-snmp/r1/show_ldp_neighbor.ref @@ -0,0 +1,16 @@ +{ + "neighbors":[ + { + "addressFamily":"ipv4", + "neighborId":"2.2.2.2", + "state":"OPERATIONAL", + "transportAddress":"2.2.2.2" + }, + { + "addressFamily":"ipv4", + "neighborId":"3.3.3.3", + "state":"OPERATIONAL", + "transportAddress":"3.3.3.3" + } + ] +} diff --git a/tests/topotests/ldp-snmp/r1/show_yang_interface_isis_adjacencies.ref b/tests/topotests/ldp-snmp/r1/show_yang_interface_isis_adjacencies.ref new file mode 100644 index 0000000000..6138d03672 --- /dev/null +++ b/tests/topotests/ldp-snmp/r1/show_yang_interface_isis_adjacencies.ref @@ -0,0 +1,42 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "r1-eth1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0002", + "neighbor-extended-circuit-id": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "r1-eth2", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0003", + "neighbor-extended-circuit-id": 0, + "state": "up" + } + ] + } + } + } + } + ] + } +} diff --git a/tests/topotests/ldp-snmp/r1/snmpd.conf b/tests/topotests/ldp-snmp/r1/snmpd.conf new file mode 100644 index 0000000000..b37911da36 --- /dev/null +++ b/tests/topotests/ldp-snmp/r1/snmpd.conf @@ -0,0 +1,15 @@ +agentAddress udp:1.1.1.1:161 + +com2sec public 1.1.1.1 public + +group public_group v1 public +group public_group v2c public + +access public_group "" any noauth prefix all all none + +view all included .1 + +iquerySecName frr +rouser frr + +master agentx diff --git a/tests/topotests/ldp-snmp/r1/zebra.conf b/tests/topotests/ldp-snmp/r1/zebra.conf new file mode 100644 index 0000000000..ea047355ad --- /dev/null +++ b/tests/topotests/ldp-snmp/r1/zebra.conf @@ -0,0 +1,29 @@ +log file zebra.log +! +hostname r1 +! +debug zebra kernel +debug zebra rib detailed +debug zebra dplane detailed +debug zebra nht +debug zebra pseudowires +debug zebra mpls +! +interface lo + ip address 1.1.1.1/32 +! +interface r1-eth0 + description to s1 +! +interface r1-eth1 + description to s4 + ip address 10.0.1.1/24 +! +interface r1-eth2 + description to s5 + ip address 10.0.2.1/24 +! +ip forwarding +! +line vty +! diff --git a/tests/topotests/ldp-snmp/r2/isisd.conf b/tests/topotests/ldp-snmp/r2/isisd.conf new file mode 100644 index 0000000000..b29a2b93ee --- /dev/null +++ b/tests/topotests/ldp-snmp/r2/isisd.conf @@ -0,0 +1,28 @@ +hostname r2 +log file isisd.log +debug isis adj-packets +debug isis events +debug isis update-packets +debug isis ldp-sync +! +router isis 1 + lsp-gen-interval 2 + net 10.0000.0000.0000.0000.0000.0000.0000.0000.0002.00 + metric-style wide + redistribute ipv4 connected level-1 + redistribute ipv6 connected level-1 + mpls ldp-sync +! +interface r2-eth1 + ip router isis 1 + ipv6 router isis 1 + isis network point-to-point + isis circuit-type level-1 +! +interface r2-eth2 + ip router isis 1 + ipv6 router isis 1 + isis network point-to-point + isis circuit-type level-1 + no isis mpls ldp-sync +! diff --git a/tests/topotests/ldp-snmp/r2/ldpd.conf b/tests/topotests/ldp-snmp/r2/ldpd.conf new file mode 100644 index 0000000000..c93e1a6ac5 --- /dev/null +++ b/tests/topotests/ldp-snmp/r2/ldpd.conf @@ -0,0 +1,35 @@ +hostname r2 +log file ldpd.log +! +debug mpls ldp zebra +debug mpls ldp event +debug mpls ldp errors +debug mpls ldp sync +! +mpls ldp + router-id 2.2.2.2 + ! + address-family ipv4 + discovery transport-address 2.2.2.2 + label local allocate host-routes + ! + ttl-security disable + ! + interface r2-eth1 + ! + interface r2-eth2 + ! + ! +! +l2vpn CUST_A type vpls + member interface r2-eth0 + ! + member pseudowire r2-mpw0 + neighbor lsr-id 1.1.1.1 + pw-id 100 + ! +! +line vty +! +!agentx +! diff --git a/tests/topotests/ldp-snmp/r2/ospfd.conf b/tests/topotests/ldp-snmp/r2/ospfd.conf new file mode 100644 index 0000000000..f93f6aed56 --- /dev/null +++ b/tests/topotests/ldp-snmp/r2/ospfd.conf @@ -0,0 +1,19 @@ +hostname r2 +log file ospfd.log +debug ospf zebra interface +debug ospf ldp-sync +! +router ospf + router-id 2.2.2.2 + network 0.0.0.0/0 area 0 + mpls ldp-sync + mpls ldp-sync holddown 50 +! +interface r2-eth1 + ip ospf network point-to-point + ip ospf mpls ldp-sync holddown 300 +! +interface r2-eth2 + ip ospf network point-to-point + no ip ospf mpls ldp-sync +! diff --git a/tests/topotests/ldp-snmp/r2/show_ip_route.ref b/tests/topotests/ldp-snmp/r2/show_ip_route.ref new file mode 100644 index 0000000000..04f141aba4 --- /dev/null +++ b/tests/topotests/ldp-snmp/r2/show_ip_route.ref @@ -0,0 +1,134 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "distance":115, + "metric":10, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"r2-eth1", + "active":true + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"connected", + "selected":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"lo", + "active":true + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "distance":115, + "metric":10, + "nexthops":[ + { + "fib":true, + "ip":"10.0.3.3", + "afi":"ipv4", + "interfaceName":"r2-eth2", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "distance":115, + "metric":10, + "nexthops":[ + { + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"r2-eth1" + } + ] + }, + { + "prefix":"10.0.1.0\/24", + "protocol":"connected", + "selected":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"r2-eth1", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "selected":true, + "distance":115, + "metric":10, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"r2-eth1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.3", + "afi":"ipv4", + "interfaceName":"r2-eth2", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "distance":115, + "metric":10, + "nexthops":[ + { + "ip":"10.0.3.3", + "afi":"ipv4", + "interfaceName":"r2-eth2" + } + ] + }, + { + "prefix":"10.0.3.0\/24", + "protocol":"connected", + "selected":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"r2-eth2", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/ldp-snmp/r2/show_isis_interface_detail.ref b/tests/topotests/ldp-snmp/r2/show_isis_interface_detail.ref new file mode 100644 index 0000000000..844aa9402a --- /dev/null +++ b/tests/topotests/ldp-snmp/r2/show_isis_interface_detail.ref @@ -0,0 +1,16 @@ +{ + "1": { + "r2-eth1": [ + { + "level": "Level-1", + "metric": "10" + } + ], + "r2-eth2": [ + { + "level": "Level-1", + "metric": "10" + } + ] + } +} diff --git a/tests/topotests/ldp-snmp/r2/show_isis_interface_detail_r1_eth1_shutdown.ref b/tests/topotests/ldp-snmp/r2/show_isis_interface_detail_r1_eth1_shutdown.ref new file mode 100644 index 0000000000..821ec70ba5 --- /dev/null +++ b/tests/topotests/ldp-snmp/r2/show_isis_interface_detail_r1_eth1_shutdown.ref @@ -0,0 +1,16 @@ +{ + "1": { + "r2-eth1": [ + { + "level": "Level-1", + "metric": "16777214" + } + ], + "r2-eth2": [ + { + "level": "Level-1", + "metric": "10" + } + ] + } +} diff --git a/tests/topotests/ldp-snmp/r2/show_isis_interface_detail_r2_eth1_shutdown.ref b/tests/topotests/ldp-snmp/r2/show_isis_interface_detail_r2_eth1_shutdown.ref new file mode 100644 index 0000000000..821ec70ba5 --- /dev/null +++ b/tests/topotests/ldp-snmp/r2/show_isis_interface_detail_r2_eth1_shutdown.ref @@ -0,0 +1,16 @@ +{ + "1": { + "r2-eth1": [ + { + "level": "Level-1", + "metric": "16777214" + } + ], + "r2-eth2": [ + { + "level": "Level-1", + "metric": "10" + } + ] + } +} diff --git a/tests/topotests/ldp-snmp/r2/show_isis_ldp_sync.ref b/tests/topotests/ldp-snmp/r2/show_isis_ldp_sync.ref new file mode 100644 index 0000000000..433d89bd16 --- /dev/null +++ b/tests/topotests/ldp-snmp/r2/show_isis_ldp_sync.ref @@ -0,0 +1,13 @@ +{ + "r2-eth1":{ + "ldpIgpSyncEnabled":true, + "holdDownTimeInSec":0, + "ldpIgpSyncState":"Sync achieved" + }, + "r2-eth2":{ + "ldpIgpSyncEnabled":false, + "holdDownTimeInSec":0, + "ldpIgpSyncState":"Sync not required" + } + +} diff --git a/tests/topotests/ldp-snmp/r2/show_isis_ldp_sync_r1_eth1_shutdown.ref b/tests/topotests/ldp-snmp/r2/show_isis_ldp_sync_r1_eth1_shutdown.ref new file mode 100644 index 0000000000..2f3eae47c8 --- /dev/null +++ b/tests/topotests/ldp-snmp/r2/show_isis_ldp_sync_r1_eth1_shutdown.ref @@ -0,0 +1,13 @@ +{ + "r2-eth1":{ + "ldpIgpSyncEnabled":true, + "holdDownTimeInSec":0, + "ldpIgpSyncState":"Sync not achieved" + }, + "r2-eth2":{ + "ldpIgpSyncEnabled":false, + "holdDownTimeInSec":0, + "ldpIgpSyncState":"Sync not required" + } + +} diff --git a/tests/topotests/ldp-snmp/r2/show_isis_ldp_sync_r2_eth1_shutdown.ref b/tests/topotests/ldp-snmp/r2/show_isis_ldp_sync_r2_eth1_shutdown.ref new file mode 100644 index 0000000000..c3d97a3c73 --- /dev/null +++ b/tests/topotests/ldp-snmp/r2/show_isis_ldp_sync_r2_eth1_shutdown.ref @@ -0,0 +1,11 @@ +{ + "r2-eth1":{ + "Interface":true + }, + "r2-eth2":{ + "ldpIgpSyncEnabled":false, + "holdDownTimeInSec":0, + "ldpIgpSyncState":"Sync not required" + } + +} diff --git a/tests/topotests/ldp-snmp/r2/show_l2vpn_binding.ref b/tests/topotests/ldp-snmp/r2/show_l2vpn_binding.ref new file mode 100644 index 0000000000..42c5a1cbd9 --- /dev/null +++ b/tests/topotests/ldp-snmp/r2/show_l2vpn_binding.ref @@ -0,0 +1,16 @@ +{ + "1.1.1.1: 100":{ + "destination":"1.1.1.1", + "vcId":100, + "localLabel":16, + "localControlWord":1, + "localVcType":"Ethernet", + "localGroupID":0, + "localIfMtu":1500, + "remoteLabel":16, + "remoteControlWord":1, + "remoteVcType":"Ethernet", + "remoteGroupID":0, + "remoteIfMtu":1500 + } +} diff --git a/tests/topotests/ldp-snmp/r2/show_l2vpn_vc.ref b/tests/topotests/ldp-snmp/r2/show_l2vpn_vc.ref new file mode 100644 index 0000000000..942ed23a1e --- /dev/null +++ b/tests/topotests/ldp-snmp/r2/show_l2vpn_vc.ref @@ -0,0 +1,8 @@ +{ + "r2-mpw0":{ + "peerId":"1.1.1.1", + "vcId":100, + "VpnName":"CUST_A", + "status":"up" + } +} diff --git a/tests/topotests/ldp-snmp/r2/show_ldp_binding.ref b/tests/topotests/ldp-snmp/r2/show_ldp_binding.ref new file mode 100644 index 0000000000..c641fb47e6 --- /dev/null +++ b/tests/topotests/ldp-snmp/r2/show_ldp_binding.ref @@ -0,0 +1,44 @@ +{ + "bindings":[ + { + "addressFamily":"ipv4", + "prefix":"1.1.1.1/32", + "neighborId":"1.1.1.1", + "remoteLabel":"imp-null", + "inUse":1 + }, + { + "addressFamily":"ipv4", + "prefix":"1.1.1.1/32", + "neighborId":"3.3.3.3", + "inUse":0 + }, + { + "addressFamily":"ipv4", + "prefix":"2.2.2.2/32", + "neighborId":"1.1.1.1", + "localLabel":"imp-null", + "inUse":0 + }, + { + "addressFamily":"ipv4", + "prefix":"2.2.2.2/32", + "neighborId":"3.3.3.3", + "localLabel":"imp-null", + "inUse":0 + }, + { + "addressFamily":"ipv4", + "prefix":"3.3.3.3/32", + "neighborId":"1.1.1.1", + "inUse":0 + }, + { + "addressFamily":"ipv4", + "prefix":"3.3.3.3/32", + "neighborId":"3.3.3.3", + "remoteLabel":"imp-null", + "inUse":1 + } + ] +} diff --git a/tests/topotests/ldp-snmp/r2/show_ldp_discovery.ref b/tests/topotests/ldp-snmp/r2/show_ldp_discovery.ref new file mode 100644 index 0000000000..26801acade --- /dev/null +++ b/tests/topotests/ldp-snmp/r2/show_ldp_discovery.ref @@ -0,0 +1,25 @@ +{ + "adjacencies":[ + { + "addressFamily":"ipv4", + "neighborId":"1.1.1.1", + "type":"link", + "interface":"r2-eth1", + "helloHoldtime":15 + }, + { + "addressFamily":"ipv4", + "neighborId":"1.1.1.1", + "type":"targeted", + "peer":"1.1.1.1", + "helloHoldtime":45 + }, + { + "addressFamily":"ipv4", + "neighborId":"3.3.3.3", + "type":"link", + "interface":"r2-eth2", + "helloHoldtime":15 + } + ] +} diff --git a/tests/topotests/ldp-snmp/r2/show_ldp_igp_sync.ref b/tests/topotests/ldp-snmp/r2/show_ldp_igp_sync.ref new file mode 100644 index 0000000000..f2b24d7d62 --- /dev/null +++ b/tests/topotests/ldp-snmp/r2/show_ldp_igp_sync.ref @@ -0,0 +1,16 @@ +{ + "r2-eth1":{ + "state":"labelExchangeComplete", + "waitTime":10, + "waitTimeRemaining":0, + "timerRunning":false, + "peerLdpId":"1.1.1.1" + }, + "r2-eth2":{ + "state":"labelExchangeComplete", + "waitTime":10, + "waitTimeRemaining":0, + "timerRunning":false, + "peerLdpId":"3.3.3.3" + } +} diff --git a/tests/topotests/ldp-snmp/r2/show_ldp_igp_sync_r1_eth1_shutdown.ref b/tests/topotests/ldp-snmp/r2/show_ldp_igp_sync_r1_eth1_shutdown.ref new file mode 100644 index 0000000000..b5508dd35c --- /dev/null +++ b/tests/topotests/ldp-snmp/r2/show_ldp_igp_sync_r1_eth1_shutdown.ref @@ -0,0 +1,16 @@ +{ + "r2-eth1":{ + "state":"labelExchangeNotComplete", + "waitTime":10, + "waitTimeRemaining":0, + "timerRunning":false, + "peerLdpId":"" + }, + "r2-eth2":{ + "state":"labelExchangeComplete", + "waitTime":10, + "waitTimeRemaining":0, + "timerRunning":false, + "peerLdpId":"3.3.3.3" + } +} diff --git a/tests/topotests/ldp-snmp/r2/show_ldp_igp_sync_r2_eth1_shutdown.ref b/tests/topotests/ldp-snmp/r2/show_ldp_igp_sync_r2_eth1_shutdown.ref new file mode 100644 index 0000000000..f2b24d7d62 --- /dev/null +++ b/tests/topotests/ldp-snmp/r2/show_ldp_igp_sync_r2_eth1_shutdown.ref @@ -0,0 +1,16 @@ +{ + "r2-eth1":{ + "state":"labelExchangeComplete", + "waitTime":10, + "waitTimeRemaining":0, + "timerRunning":false, + "peerLdpId":"1.1.1.1" + }, + "r2-eth2":{ + "state":"labelExchangeComplete", + "waitTime":10, + "waitTimeRemaining":0, + "timerRunning":false, + "peerLdpId":"3.3.3.3" + } +} diff --git a/tests/topotests/ldp-snmp/r2/show_ldp_neighbor.ref b/tests/topotests/ldp-snmp/r2/show_ldp_neighbor.ref new file mode 100644 index 0000000000..eed35289ea --- /dev/null +++ b/tests/topotests/ldp-snmp/r2/show_ldp_neighbor.ref @@ -0,0 +1,16 @@ +{ + "neighbors":[ + { + "addressFamily":"ipv4", + "neighborId":"1.1.1.1", + "state":"OPERATIONAL", + "transportAddress":"1.1.1.1" + }, + { + "addressFamily":"ipv4", + "neighborId":"3.3.3.3", + "state":"OPERATIONAL", + "transportAddress":"3.3.3.3" + } + ] +} diff --git a/tests/topotests/ldp-snmp/r2/show_yang_interface_isis_adjacencies.ref b/tests/topotests/ldp-snmp/r2/show_yang_interface_isis_adjacencies.ref new file mode 100644 index 0000000000..4dd6ddd76b --- /dev/null +++ b/tests/topotests/ldp-snmp/r2/show_yang_interface_isis_adjacencies.ref @@ -0,0 +1,42 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "r2-eth1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0001", + "neighbor-extended-circuit-id": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "r2-eth2", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0003", + "neighbor-extended-circuit-id": 0, + "state": "up" + } + ] + } + } + } + } + ] + } +} diff --git a/tests/topotests/ldp-snmp/r2/snmpd.conf b/tests/topotests/ldp-snmp/r2/snmpd.conf new file mode 100644 index 0000000000..0f779b8b91 --- /dev/null +++ b/tests/topotests/ldp-snmp/r2/snmpd.conf @@ -0,0 +1,15 @@ +agentAddress udp:2.2.2.2:161 + +com2sec public 2.2.2.2 public + +group public_group v1 public +group public_group v2c public + +access public_group "" any noauth prefix all all none + +view all included .1 + +iquerySecName frr +rouser frr + +master agentx diff --git a/tests/topotests/ldp-snmp/r2/zebra.conf b/tests/topotests/ldp-snmp/r2/zebra.conf new file mode 100644 index 0000000000..c244442876 --- /dev/null +++ b/tests/topotests/ldp-snmp/r2/zebra.conf @@ -0,0 +1,28 @@ +log file zebra.log +! +hostname r2 +! +debug zebra rib detailed +debug zebra dplane detailed +debug zebra kernel +debug zebra nht +debug zebra pseudowires +! +interface lo + ip address 2.2.2.2/32 +! +interface r2-eth0 + description to s2 +! +interface r2-eth1 + description to s4 + ip address 10.0.1.2/24 +! +interface r2-eth2 + description to s6 + ip address 10.0.3.2/24 +! +ip forwarding +! +line vty +! diff --git a/tests/topotests/ldp-snmp/r3/isisd.conf b/tests/topotests/ldp-snmp/r3/isisd.conf new file mode 100644 index 0000000000..4c8499f23d --- /dev/null +++ b/tests/topotests/ldp-snmp/r3/isisd.conf @@ -0,0 +1,29 @@ +hostname r3 +log file isisd.log +debug isis adj-packets +debug isis events +debug isis update-packets +debug isis ldp-sync +! +router isis 1 + lsp-gen-interval 2 + net 10.0000.0000.0000.0000.0000.0000.0000.0000.0003.00 + metric-style wide + redistribute ipv4 connected level-1 + redistribute ipv6 connected level-1 + mpls ldp-sync + mpls ldp-sync holddown 50 +! +interface r3-eth1 + ip router isis 1 + ipv6 router isis 1 + isis network point-to-point + isis circuit-type level-1 + no isis mpls ldp-sync +! +interface r3-eth2 + ip router isis 1 + ipv6 router isis 1 + isis network point-to-point + isis circuit-type level-1 +! diff --git a/tests/topotests/ldp-snmp/r3/ldpd.conf b/tests/topotests/ldp-snmp/r3/ldpd.conf new file mode 100644 index 0000000000..b7eeb258f1 --- /dev/null +++ b/tests/topotests/ldp-snmp/r3/ldpd.conf @@ -0,0 +1,27 @@ +hostname r3 +log file ldpd.log +! +debug mpls ldp zebra +debug mpls ldp event +debug mpls ldp errors +debug mpls ldp sync +! +mpls ldp + router-id 3.3.3.3 + ! + address-family ipv4 + discovery transport-address 3.3.3.3 + label local allocate host-routes + ! + ttl-security disable + ! + interface r3-eth1 + ! + interface r3-eth2 + ! + ! +! +line vty +! +!agentx +! diff --git a/tests/topotests/ldp-snmp/r3/show_ip_route.ref b/tests/topotests/ldp-snmp/r3/show_ip_route.ref new file mode 100644 index 0000000000..22504046ed --- /dev/null +++ b/tests/topotests/ldp-snmp/r3/show_ip_route.ref @@ -0,0 +1,134 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "distance":115, + "metric":10, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.1", + "afi":"ipv4", + "interfaceName":"r3-eth1", + "active":true + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "distance":115, + "metric":10, + "nexthops":[ + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"r3-eth2", + "active":true + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"connected", + "selected":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"lo", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "selected":true, + "distance":115, + "metric":10, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.1", + "afi":"ipv4", + "interfaceName":"r3-eth1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"r3-eth2", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "distance":115, + "metric":10, + "nexthops":[ + { + "ip":"10.0.2.1", + "afi":"ipv4", + "interfaceName":"r3-eth1" + } + ] + }, + { + "prefix":"10.0.2.0\/24", + "protocol":"connected", + "selected":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"r3-eth1", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "distance":115, + "metric":10, + "nexthops":[ + { + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"r3-eth2" + } + ] + }, + { + "prefix":"10.0.3.0\/24", + "protocol":"connected", + "selected":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"r3-eth2", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/ldp-snmp/r3/show_isis_interface_detail.ref b/tests/topotests/ldp-snmp/r3/show_isis_interface_detail.ref new file mode 100644 index 0000000000..e323f61f25 --- /dev/null +++ b/tests/topotests/ldp-snmp/r3/show_isis_interface_detail.ref @@ -0,0 +1,16 @@ +{ + "1": { + "r3-eth1": [ + { + "level": "Level-1", + "metric": "10" + } + ], + "r3-eth2": [ + { + "level": "Level-1", + "metric": "10" + } + ] + } +} diff --git a/tests/topotests/ldp-snmp/r3/show_isis_interface_detail_r1_eth1_shutdown.ref b/tests/topotests/ldp-snmp/r3/show_isis_interface_detail_r1_eth1_shutdown.ref new file mode 100644 index 0000000000..e323f61f25 --- /dev/null +++ b/tests/topotests/ldp-snmp/r3/show_isis_interface_detail_r1_eth1_shutdown.ref @@ -0,0 +1,16 @@ +{ + "1": { + "r3-eth1": [ + { + "level": "Level-1", + "metric": "10" + } + ], + "r3-eth2": [ + { + "level": "Level-1", + "metric": "10" + } + ] + } +} diff --git a/tests/topotests/ldp-snmp/r3/show_isis_interface_detail_r2_eth1_shutdown.ref b/tests/topotests/ldp-snmp/r3/show_isis_interface_detail_r2_eth1_shutdown.ref new file mode 100644 index 0000000000..e323f61f25 --- /dev/null +++ b/tests/topotests/ldp-snmp/r3/show_isis_interface_detail_r2_eth1_shutdown.ref @@ -0,0 +1,16 @@ +{ + "1": { + "r3-eth1": [ + { + "level": "Level-1", + "metric": "10" + } + ], + "r3-eth2": [ + { + "level": "Level-1", + "metric": "10" + } + ] + } +} diff --git a/tests/topotests/ldp-snmp/r3/show_isis_ldp_sync.ref b/tests/topotests/ldp-snmp/r3/show_isis_ldp_sync.ref new file mode 100644 index 0000000000..9cb70a4758 --- /dev/null +++ b/tests/topotests/ldp-snmp/r3/show_isis_ldp_sync.ref @@ -0,0 +1,13 @@ +{ + "r3-eth1":{ + "ldpIgpSyncEnabled":false, + "holdDownTimeInSec":50, + "ldpIgpSyncState":"Sync not required" + }, + "r3-eth2":{ + "ldpIgpSyncEnabled":true, + "holdDownTimeInSec":50, + "ldpIgpSyncState":"Sync achieved" + } + +} diff --git a/tests/topotests/ldp-snmp/r3/show_isis_ldp_sync_r1_eth1_shutdown.ref b/tests/topotests/ldp-snmp/r3/show_isis_ldp_sync_r1_eth1_shutdown.ref new file mode 100644 index 0000000000..9cb70a4758 --- /dev/null +++ b/tests/topotests/ldp-snmp/r3/show_isis_ldp_sync_r1_eth1_shutdown.ref @@ -0,0 +1,13 @@ +{ + "r3-eth1":{ + "ldpIgpSyncEnabled":false, + "holdDownTimeInSec":50, + "ldpIgpSyncState":"Sync not required" + }, + "r3-eth2":{ + "ldpIgpSyncEnabled":true, + "holdDownTimeInSec":50, + "ldpIgpSyncState":"Sync achieved" + } + +} diff --git a/tests/topotests/ldp-snmp/r3/show_isis_ldp_sync_r2_eth1_shutdown.ref b/tests/topotests/ldp-snmp/r3/show_isis_ldp_sync_r2_eth1_shutdown.ref new file mode 100644 index 0000000000..9cb70a4758 --- /dev/null +++ b/tests/topotests/ldp-snmp/r3/show_isis_ldp_sync_r2_eth1_shutdown.ref @@ -0,0 +1,13 @@ +{ + "r3-eth1":{ + "ldpIgpSyncEnabled":false, + "holdDownTimeInSec":50, + "ldpIgpSyncState":"Sync not required" + }, + "r3-eth2":{ + "ldpIgpSyncEnabled":true, + "holdDownTimeInSec":50, + "ldpIgpSyncState":"Sync achieved" + } + +} diff --git a/tests/topotests/ldp-snmp/r3/show_l2vpn_binding.ref b/tests/topotests/ldp-snmp/r3/show_l2vpn_binding.ref new file mode 100644 index 0000000000..2c63c08510 --- /dev/null +++ b/tests/topotests/ldp-snmp/r3/show_l2vpn_binding.ref @@ -0,0 +1,2 @@ +{ +} diff --git a/tests/topotests/ldp-snmp/r3/show_l2vpn_vc.ref b/tests/topotests/ldp-snmp/r3/show_l2vpn_vc.ref new file mode 100644 index 0000000000..2c63c08510 --- /dev/null +++ b/tests/topotests/ldp-snmp/r3/show_l2vpn_vc.ref @@ -0,0 +1,2 @@ +{ +} diff --git a/tests/topotests/ldp-snmp/r3/show_ldp_binding.ref b/tests/topotests/ldp-snmp/r3/show_ldp_binding.ref new file mode 100644 index 0000000000..e54bd6e755 --- /dev/null +++ b/tests/topotests/ldp-snmp/r3/show_ldp_binding.ref @@ -0,0 +1,44 @@ +{ + "bindings":[ + { + "addressFamily":"ipv4", + "prefix":"1.1.1.1/32", + "neighborId":"1.1.1.1", + "remoteLabel":"imp-null", + "inUse":1 + }, + { + "addressFamily":"ipv4", + "prefix":"1.1.1.1/32", + "neighborId":"2.2.2.2", + "inUse":0 + }, + { + "addressFamily":"ipv4", + "prefix":"2.2.2.2/32", + "neighborId":"1.1.1.1", + "inUse":0 + }, + { + "addressFamily":"ipv4", + "prefix":"2.2.2.2/32", + "neighborId":"2.2.2.2", + "remoteLabel":"imp-null", + "inUse":1 + }, + { + "addressFamily":"ipv4", + "prefix":"3.3.3.3/32", + "neighborId":"1.1.1.1", + "localLabel":"imp-null", + "inUse":0 + }, + { + "addressFamily":"ipv4", + "prefix":"3.3.3.3/32", + "neighborId":"2.2.2.2", + "localLabel":"imp-null", + "inUse":0 + } + ] +} diff --git a/tests/topotests/ldp-snmp/r3/show_ldp_discovery.ref b/tests/topotests/ldp-snmp/r3/show_ldp_discovery.ref new file mode 100644 index 0000000000..42fa98d4da --- /dev/null +++ b/tests/topotests/ldp-snmp/r3/show_ldp_discovery.ref @@ -0,0 +1,18 @@ +{ + "adjacencies":[ + { + "addressFamily":"ipv4", + "neighborId":"1.1.1.1", + "type":"link", + "interface":"r3-eth1", + "helloHoldtime":15 + }, + { + "addressFamily":"ipv4", + "neighborId":"2.2.2.2", + "type":"link", + "interface":"r3-eth2", + "helloHoldtime":15 + } + ] +} diff --git a/tests/topotests/ldp-snmp/r3/show_ldp_igp_sync.ref b/tests/topotests/ldp-snmp/r3/show_ldp_igp_sync.ref new file mode 100644 index 0000000000..73261830c9 --- /dev/null +++ b/tests/topotests/ldp-snmp/r3/show_ldp_igp_sync.ref @@ -0,0 +1,16 @@ +{ + "r3-eth1":{ + "state":"labelExchangeComplete", + "waitTime":10, + "waitTimeRemaining":0, + "timerRunning":false, + "peerLdpId":"1.1.1.1" + }, + "r3-eth2":{ + "state":"labelExchangeComplete", + "waitTime":10, + "waitTimeRemaining":0, + "timerRunning":false, + "peerLdpId":"2.2.2.2" + } +} diff --git a/tests/topotests/ldp-snmp/r3/show_ldp_igp_sync_r1_eth1_shutdown.ref b/tests/topotests/ldp-snmp/r3/show_ldp_igp_sync_r1_eth1_shutdown.ref new file mode 100644 index 0000000000..73261830c9 --- /dev/null +++ b/tests/topotests/ldp-snmp/r3/show_ldp_igp_sync_r1_eth1_shutdown.ref @@ -0,0 +1,16 @@ +{ + "r3-eth1":{ + "state":"labelExchangeComplete", + "waitTime":10, + "waitTimeRemaining":0, + "timerRunning":false, + "peerLdpId":"1.1.1.1" + }, + "r3-eth2":{ + "state":"labelExchangeComplete", + "waitTime":10, + "waitTimeRemaining":0, + "timerRunning":false, + "peerLdpId":"2.2.2.2" + } +} diff --git a/tests/topotests/ldp-snmp/r3/show_ldp_neighbor.ref b/tests/topotests/ldp-snmp/r3/show_ldp_neighbor.ref new file mode 100644 index 0000000000..5c482da697 --- /dev/null +++ b/tests/topotests/ldp-snmp/r3/show_ldp_neighbor.ref @@ -0,0 +1,16 @@ +{ + "neighbors":[ + { + "addressFamily":"ipv4", + "neighborId":"1.1.1.1", + "state":"OPERATIONAL", + "transportAddress":"1.1.1.1" + }, + { + "addressFamily":"ipv4", + "neighborId":"2.2.2.2", + "state":"OPERATIONAL", + "transportAddress":"2.2.2.2" + } + ] +} diff --git a/tests/topotests/ldp-snmp/r3/show_yang_interface_isis_adjacencies.ref b/tests/topotests/ldp-snmp/r3/show_yang_interface_isis_adjacencies.ref new file mode 100644 index 0000000000..0922192361 --- /dev/null +++ b/tests/topotests/ldp-snmp/r3/show_yang_interface_isis_adjacencies.ref @@ -0,0 +1,42 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "r3-eth1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0001", + "neighbor-extended-circuit-id": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "r3-eth2", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0002", + "neighbor-extended-circuit-id": 0, + "state": "up" + } + ] + } + } + } + } + ] + } +} diff --git a/tests/topotests/ldp-snmp/r3/zebra.conf b/tests/topotests/ldp-snmp/r3/zebra.conf new file mode 100644 index 0000000000..b1919bd296 --- /dev/null +++ b/tests/topotests/ldp-snmp/r3/zebra.conf @@ -0,0 +1,32 @@ +log file zebra.log +! +hostname r3 +! +debug zebra rib detailed +debug zebra dplane detailed +debug zebra kernel +debug zebra nht +debug zebra pseudowires +! +interface lo + ip address 3.3.3.3/32 +! +interface r3-eth0 + description to s3 +! +interface r3-eth1 + description to s5 + ip address 10.0.2.3/24 +! +interface r3-eth2 + description to s6 + ip address 10.0.3.3/24 +! +!!interface r3-eth3 +!! description to s4 +!! ip address 10.0.1.3/24 +! +ip forwarding +! +line vty +! diff --git a/tests/topotests/ldp-snmp/test_ldp_snmp_topo1.py b/tests/topotests/ldp-snmp/test_ldp_snmp_topo1.py new file mode 100644 index 0000000000..4144f9b261 --- /dev/null +++ b/tests/topotests/ldp-snmp/test_ldp_snmp_topo1.py @@ -0,0 +1,421 @@ +#!/usr/bin/env python + +# +# test_ldp_isis_topo1.py +# Part of NetDEF Topology Tests +# +# Copyright (c) 2020 by Volta Networks +# +# 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_ldp_vpls_topo1.py: + + +---------+ +---------+ + | | | | + | CE1 | | CE2 | + | | | | + +---------+ +---------+ +ce1-eth0 (172.16.1.1/24)| |ce2-eth0 (172.16.1.2/24) + | | + | | + rt1-eth0| |rt2-eth0 + +---------+ 10.0.1.0/24 +---------+ + | |rt1-eth1 | | + | RT1 +----------------+ RT2 | + | 1.1.1.1 | rt2-eth1| 2.2.2.2 | + | | | | + +---------+ +---------+ + rt1-eth2| |rt2-eth2 + | | + | | + 10.0.2.0/24| +---------+ |10.0.3.0/24 + | | | | + | | RT3 | | + +--------+ 3.3.3.3 +-------+ + rt3-eth2| |rt3-eth1 + +---------+ + |rt3-eth0 + | + | + ce3-eth0 (172.16.1.3/24)| + +---------+ + | | + | CE3 | + | | + +---------+ +""" + +import os +import re +import sys +import pytest +import json +from time import sleep +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 +# Import topogen and topotest helpers +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger +from lib.snmptest import SnmpTester + +# Required to instantiate the topology builder class. +from mininet.topo import Topo + + +class TemplateTopo(Topo): + "Test topology builder" + + def build(self, *_args, **_opts): + "Build function" + tgen = get_topogen(self) + + # + # Define FRR Routers + # + for router in ["ce1", "ce2", "ce3", "r1", "r2", "r3"]: + tgen.add_router(router) + + # + # Define connections + # + switch = tgen.add_switch("s1") + switch.add_link(tgen.gears["ce1"]) + switch.add_link(tgen.gears["r1"]) + + switch = tgen.add_switch("s2") + switch.add_link(tgen.gears["ce2"]) + switch.add_link(tgen.gears["r2"]) + + switch = tgen.add_switch("s3") + switch.add_link(tgen.gears["ce3"]) + switch.add_link(tgen.gears["r3"]) + + switch = tgen.add_switch("s4") + switch.add_link(tgen.gears["r1"]) + switch.add_link(tgen.gears["r2"]) + + switch = tgen.add_switch("s5") + switch.add_link(tgen.gears["r1"]) + switch.add_link(tgen.gears["r3"]) + + switch = tgen.add_switch("s6") + switch.add_link(tgen.gears["r2"]) + switch.add_link(tgen.gears["r3"]) + + +def setup_module(mod): + "Sets up the pytest environment" + tgen = Topogen(TemplateTopo, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + # For all registered routers, load the zebra configuration file + for rname, router in router_list.items(): + router.load_config( + TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) + ) + # Don't start isisd and ldpd in the CE nodes + if router.name[0] == "r": + router.load_config( + TopoRouter.RD_ISIS, os.path.join(CWD, "{}/isisd.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_LDP, os.path.join(CWD, "{}/ldpd.conf".format(rname)), + "-M snmp" + ) + router.load_config( + TopoRouter.RD_SNMP, os.path.join(CWD, "{}/snmpd.conf".format(rname)), + "-Le -Ivacm_conf,usmConf,iquery -V -DAgentX,trap" + ) + + + tgen.start_router() + + +def teardown_module(mod): + "Teardown the pytest environment" + tgen = get_topogen() + + # This function tears down the whole topology. + tgen.stop_topology() + + +def router_compare_json_output(rname, command, reference): + "Compare router JSON output" + + logger.info('Comparing router "%s" "%s" output', rname, command) + + tgen = get_topogen() + filename = "{}/{}/{}".format(CWD, rname, reference) + expected = json.loads(open(filename).read()) + + # Run test function until we get an result. + test_func = partial(topotest.router_json_cmp, tgen.gears[rname], command, expected) + _, diff = topotest.run_and_expect(test_func, None, count=320, wait=0.5) + assertmsg = '"{}" JSON output mismatches the expected result'.format(rname) + assert diff is None, assertmsg + + +def test_isis_convergence(): + logger.info("Test: check ISIS adjacencies") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + for rname in ["r1", "r2", "r3"]: + router_compare_json_output( + rname, + "show yang operational-data /frr-interface:lib isisd", + "show_yang_interface_isis_adjacencies.ref", + ) + + +def test_rib(): + logger.info("Test: verify RIB") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + # TODO: disabling this check to avoid 'snmpd not running' errors + #if tgen.routers_have_failure(): + # pytest.skip(tgen.errors) + + for rname in ["r1", "r2", "r3"]: + router_compare_json_output(rname, "show ip route json", "show_ip_route.ref") + + +def test_ldp_adjacencies(): + logger.info("Test: verify LDP adjacencies") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + # TODO: disabling this check to avoid 'snmpd not running' errors + #if tgen.routers_have_failure(): + # pytest.skip(tgen.errors) + + for rname in ["r1", "r2", "r3"]: + router_compare_json_output( + rname, "show mpls ldp discovery json", "show_ldp_discovery.ref" + ) + + +def test_ldp_neighbors(): + logger.info("Test: verify LDP neighbors") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + #if tgen.routers_have_failure(): + # pytest.skip(tgen.errors) + + for rname in ["r1", "r2", "r3"]: + router_compare_json_output( + rname, "show mpls ldp neighbor json", "show_ldp_neighbor.ref" + ) + + +def test_r1_ldp_lsr_objects(): + "Test mplsLdpLsrObjects objects" + tgen = get_topogen() + + r1 = tgen.net.get("r1") + r1_snmp = SnmpTester(r1, "1.1.1.1", "public", "2c") + + assert r1_snmp.test_oid('mplsLdpLsrId', "01 01 01 01") + assert r1_snmp.test_oid('mplsLdpLsrLoopDetectionCapable', 'none(1)') + + +def test_r1_ldp_entity_table(): + "Test mplsLdpEntityTable" + tgen = get_topogen() + + r1 = tgen.net.get("r1") + r1_snmp = SnmpTester(r1, "1.1.1.1", "public", "2c") + + assert r1_snmp.test_oid_walk( + 'mplsLdpEntityLdpId', ['1.1.1.1:0']) + assert r1_snmp.test_oid_walk( + 'mplsLdpEntityIndex', ['1']) + assert r1_snmp.test_oid_walk( + 'mplsLdpEntityProtocolVersion', ['1']) + assert r1_snmp.test_oid_walk( + 'mplsLdpEntityAdminStatus', ['enable(1)']) + assert r1_snmp.test_oid_walk( + 'mplsLdpEntityOperStatus', ['enabled(2)']) + assert r1_snmp.test_oid_walk( + 'mplsLdpEntityTcpPort', ['646']) + assert r1_snmp.test_oid_walk( + 'mplsLdpEntityUdpDscPort', ['646']) + assert r1_snmp.test_oid_walk( + 'mplsLdpEntityMaxPduLength', ['4096 octets']) + assert r1_snmp.test_oid_walk( + 'mplsLdpEntityKeepAliveHoldTimer', ['180 seconds']) + assert r1_snmp.test_oid_walk( + 'mplsLdpEntityHelloHoldTimer', ['0 seconds']) + assert r1_snmp.test_oid_walk( + 'mplsLdpEntityInitSessionThreshold', ['0']) + assert r1_snmp.test_oid_walk( + 'mplsLdpEntityLabelDistMethod', ['downstreamUnsolicited(2)']) + assert r1_snmp.test_oid_walk( + 'mplsLdpEntityLabelRetentionMode', ['liberal(2)']) + assert r1_snmp.test_oid_walk( + 'mplsLdpEntityPathVectorLimit', ['0']) + assert r1_snmp.test_oid_walk( + 'mplsLdpEntityHopCountLimit', ['0']) + assert r1_snmp.test_oid_walk( + 'mplsLdpEntityTransportAddrKind', ['loopback(2)']) + assert r1_snmp.test_oid_walk( + 'mplsLdpEntityTargetPeer', ['true(1)']) + assert r1_snmp.test_oid_walk( + 'mplsLdpEntityTargetPeerAddrType', ['ipv4(1)']) + assert r1_snmp.test_oid_walk( + 'mplsLdpEntityTargetPeerAddr', ['01 01 01 01']) + assert r1_snmp.test_oid_walk( + 'mplsLdpEntityLabelType', ['generic(1)']) + assert r1_snmp.test_oid_walk( + 'mplsLdpEntityDiscontinuityTime', ['(0) 0:00:00.00']) + assert r1_snmp.test_oid_walk( + 'mplsLdpEntityStorageType', ['nonVolatile(3)']) + assert r1_snmp.test_oid_walk( + 'mplsLdpEntityRowStatus', ['createAndGo(4)']) + + +def test_r1_ldp_entity_stats_table(): + "Test mplsLdpEntityStatsTable" + tgen = get_topogen() + + r1 = tgen.net.get("r1") + r1_snmp = SnmpTester(r1, "1.1.1.1", "public", "2c") + + assert r1_snmp.test_oid_walk( + 'mplsLdpEntityStatsSessionAttempts', ['0']) + assert r1_snmp.test_oid_walk( + 'mplsLdpEntityStatsSessionRejectedNoHelloErrors', ['0']) + assert r1_snmp.test_oid_walk( + 'mplsLdpEntityStatsSessionRejectedAdErrors', ['0']) + assert r1_snmp.test_oid_walk( + 'mplsLdpEntityStatsSessionRejectedMaxPduErrors', ['0']) + assert r1_snmp.test_oid_walk( + 'mplsLdpEntityStatsSessionRejectedLRErrors', ['0']) + assert r1_snmp.test_oid_walk( + 'mplsLdpEntityStatsBadLdpIdentifierErrors', ['0']) + assert r1_snmp.test_oid_walk( + 'mplsLdpEntityStatsBadPduLengthErrors', ['0']) + assert r1_snmp.test_oid_walk( + 'mplsLdpEntityStatsBadMessageLengthErrors', ['0']) + assert r1_snmp.test_oid_walk( + 'mplsLdpEntityStatsBadTlvLengthErrors', ['0']) + assert r1_snmp.test_oid_walk( + 'mplsLdpEntityStatsMalformedTlvValueErrors', ['0']) + assert r1_snmp.test_oid_walk( + 'mplsLdpEntityStatsKeepAliveTimerExpErrors', ['0']) + assert r1_snmp.test_oid_walk( + 'mplsLdpEntityStatsShutdownReceivedNotifications', ['0']) + assert r1_snmp.test_oid_walk( + 'mplsLdpEntityStatsShutdownSentNotifications', ['0']) + + +def test_r1_ldp_peer_table(): + "Test mplsLdpPeerTable" + tgen = get_topogen() + + r1 = tgen.net.get("r1") + r1_snmp = SnmpTester(r1, "1.1.1.1", "public", "2c") + + assert r1_snmp.test_oid_walk( + 'mplsLdpPeerLdpId', ['2.2.2.2:0', '3.3.3.3:0']) + assert r1_snmp.test_oid_walk( + 'mplsLdpPeerLabelDistMethod', + ['downstreamUnsolicited(2)', 'downstreamUnsolicited(2)']) + assert r1_snmp.test_oid_walk( + 'mplsLdpPeerPathVectorLimit', ['0', '0']) + assert r1_snmp.test_oid_walk( + 'mplsLdpPeerTransportAddrType', ['ipv4(1)', 'ipv4(1)']) + assert r1_snmp.test_oid_walk( + 'mplsLdpPeerTransportAddr', ['02 02 02 02', '03 03 03 03']) + + +def test_r1_ldp_session_table(): + "Test mplsLdpSessionTable" + tgen = get_topogen() + + r1 = tgen.net.get("r1") + r1_snmp = SnmpTester(r1, "1.1.1.1", "public", "2c") + + assert r1_snmp.test_oid_walk('mplsLdpSessionState', + ['operational(5)', 'operational(5)']) + assert r1_snmp.test_oid_walk('mplsLdpSessionRole', + ['passive(3)', 'passive(3)']) + assert r1_snmp.test_oid_walk('mplsLdpSessionProtocolVersion', + ['1', '1']) + assert r1_snmp.test_oid_walk('mplsLdpSessionKeepAliveTime', + ['180 seconds', '180 seconds']) + assert r1_snmp.test_oid_walk('mplsLdpSessionMaxPduLength', + ['4096 octets', '4096 octets']) + assert r1_snmp.test_oid_walk('mplsLdpSessionDiscontinuityTime', + ['(0) 0:00:00.00', '(0) 0:00:00.00']) + + +def test_r1_ldp_session_stats_table(): + "Test mplsLdpSessionStatsTable" + tgen = get_topogen() + + r1 = tgen.net.get("r1") + r1_snmp = SnmpTester(r1, "1.1.1.1", "public", "2c") + + assert r1_snmp.test_oid_walk( + 'mplsLdpSessionStatsUnknownMesTypeErrors', ['0', '0']) + assert r1_snmp.test_oid_walk( + 'mplsLdpSessionStatsUnknownTlvErrors', ['0', '0']) + + +def test_r1_ldp_hello_adjacency_table(): + "Test mplsLdpHelloAdjacencyTable" + tgen = get_topogen() + + r1 = tgen.net.get("r1") + r1_snmp = SnmpTester(r1, "1.1.1.1", "public", "2c") + + assert r1_snmp.test_oid_walk('mplsLdpHelloAdjacencyIndex', + ['1', '2', '1']) + assert r1_snmp.test_oid_walk('mplsLdpHelloAdjacencyHoldTime', + ['15', '45', '15']) + assert r1_snmp.test_oid_walk('mplsLdpHelloAdjacencyType', + ['link(1)', 'targeted(2)', 'link(1)']) + + +# Memory leak test template +# disabling memory leak +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/ldp-sync-ospf-topo1/test_ldp_sync_ospf_topo1.py b/tests/topotests/ldp-sync-ospf-topo1/test_ldp_sync_ospf_topo1.py index 99c831c8cf..57b45e5fdf 100644 --- a/tests/topotests/ldp-sync-ospf-topo1/test_ldp_sync_ospf_topo1.py +++ b/tests/topotests/ldp-sync-ospf-topo1/test_ldp_sync_ospf_topo1.py @@ -81,6 +81,7 @@ from mininet.topo import Topo pytestmark = [pytest.mark.ldpd, pytest.mark.ospfd] + class TemplateTopo(Topo): "Test topology builder" diff --git a/tests/topotests/ldp-vpls-topo1/test_ldp_vpls_topo1.py b/tests/topotests/ldp-vpls-topo1/test_ldp_vpls_topo1.py index fe57f3707a..0ea7aca3eb 100644 --- a/tests/topotests/ldp-vpls-topo1/test_ldp_vpls_topo1.py +++ b/tests/topotests/ldp-vpls-topo1/test_ldp_vpls_topo1.py @@ -82,6 +82,7 @@ from mininet.topo import Topo pytestmark = [pytest.mark.ldpd, pytest.mark.ospfd] + class TemplateTopo(Topo): "Test topology builder" diff --git a/tests/topotests/lib/bgp.py b/tests/topotests/lib/bgp.py index 22602cb460..867831e114 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 @@ -2516,8 +2527,9 @@ def verify_best_path_as_per_admin_distance( @retry(attempts=5, wait=2, return_is_str=True, initial_wait=2) -def verify_bgp_rib(tgen, addr_type, dut, input_dict, next_hop=None, -aspath=None, multi_nh=None): +def verify_bgp_rib( + tgen, addr_type, dut, input_dict, next_hop=None, aspath=None, multi_nh=None +): """ This API is to verify whether bgp rib has any matching route for a nexthop. @@ -2620,7 +2632,7 @@ aspath=None, multi_nh=None): 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 @@ -2660,28 +2672,38 @@ aspath=None, multi_nh=None): 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 = [rib_r["ip"] for rib_r in - rib_routes_json["routes"][ - st_rt][0]["nexthops"]] + found_hops = [ + rib_r["ip"] + for rib_r in rib_routes_json["routes"][st_rt][0][ + "nexthops" + ] + ] list2 = found_hops - missing_list_of_nexthops = \ - set(list2).difference(list1) - additional_nexthops_in_required_nhs = \ - set(list1).difference(list2) + missing_list_of_nexthops = set(list2).difference(list1) + additional_nexthops_in_required_nhs = set( + list1 + ).difference(list2) if list2: if additional_nexthops_in_required_nhs: - logger.info("Missing nexthop %s for route"\ - " %s in RIB of router %s\n", \ - additional_nexthops_in_required_nhs, \ - st_rt, dut) - errormsg=("Nexthop {} is Missing for "\ - "route {} in RIB of router {}\n".format( + logger.info( + "Missing nexthop %s for route" + " %s in RIB of router %s\n", additional_nexthops_in_required_nhs, - st_rt, dut)) + st_rt, + dut, + ) + errormsg = ( + "Nexthop {} is Missing for " + "route {} in RIB of router {}\n".format( + additional_nexthops_in_required_nhs, + st_rt, + dut, + ) + ) return errormsg else: nh_found = True @@ -3869,6 +3891,7 @@ def verify_attributes_for_evpn_routes( return errormsg if rt == "auto": + vni_dict = {} logger.info( "[DUT: %s]: Verifying auto-rt value for " "evpn route %s:", dut, @@ -3876,8 +3899,6 @@ def verify_attributes_for_evpn_routes( ) if rt_peer: - vni_dict = {} - rnode = tgen.routers()[rt_peer] show_bgp_json = run_frr_cmd( rnode, "show bgp vrf all summary json", isjson=True @@ -4082,7 +4103,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 @@ -4160,7 +4181,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 @@ -4174,7 +4195,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 ce35bdc0fe..a4c98924b6 100644 --- a/tests/topotests/lib/common_config.py +++ b/tests/topotests/lib/common_config.py @@ -336,16 +336,15 @@ def start_router_daemons(tgen, router, daemons): router_list = tgen.routers() # Start daemons - result = router_list[router].startDaemons(daemons) - return result + res = router_list[router].startDaemons(daemons) except Exception as e: errormsg = traceback.format_exc() logger.error(errormsg) - return errormsg + res = errormsg logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name)) - return True + return res def kill_mininet_routers_process(tgen): @@ -1374,14 +1373,16 @@ 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) - if addr_type == "ipv6": + 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 [] next_ip = start_ip count = 0 @@ -1479,10 +1480,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 @@ -2390,14 +2387,7 @@ def create_bgp_community_lists(tgen, input_dict, build=False): logger.error(errormsg) return False - try: - community_type = int(community_type) - cmd = "{} {} {} {}".format(cmd, community_type, action, value) - except ValueError: - - cmd = "{} {} {} {} {}".format( - cmd, community_type, name, action, value - ) + cmd = "{} {} {} {} {}".format(cmd, community_type, name, action, value) if del_action: cmd = "no {}".format(cmd) @@ -2448,51 +2438,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 ): @@ -3760,6 +3705,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 5bc9f14fea..9f642411b5 100644 --- a/tests/topotests/lib/ospf.py +++ b/tests/topotests/lib/ospf.py @@ -94,7 +94,9 @@ def create_router_ospf(tgen, topo, input_dict=None, build=False, load_config=Tru return result -def __create_ospf_global(tgen, input_dict, router, build=False, load_config=True, ospf="ospf"): +def __create_ospf_global( + tgen, input_dict, router, build=False, load_config=True, ospf="ospf" +): """ Helper API to create ospf global configuration. @@ -342,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"] @@ -722,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/pim.py b/tests/topotests/lib/pim.py index 294f60bf68..d07b58a774 100644 --- a/tests/topotests/lib/pim.py +++ b/tests/topotests/lib/pim.py @@ -1564,26 +1564,30 @@ def verify_pim_interface(tgen, topo, dut, interface=None, interface_ip=None): logger.info("[DUT: %s]: Verifying PIM interface status:", dut) rnode = tgen.routers()[dut] - show_ip_pim_interface_json = rnode.\ - vtysh_cmd("show ip pim interface json", isjson=True) + show_ip_pim_interface_json = rnode.vtysh_cmd( + "show ip pim interface json", isjson=True + ) - logger.info("show_ip_pim_interface_json: \n %s", - show_ip_pim_interface_json) + logger.info("show_ip_pim_interface_json: \n %s", show_ip_pim_interface_json) if interface_ip: if interface in show_ip_pim_interface_json: pim_intf_json = show_ip_pim_interface_json[interface] if pim_intf_json["address"] != interface_ip: - errormsg = ("[DUT %s]: PIM interface " - "ip is not correct " - "[FAILED]!! Expected : %s, Found : %s" - %(dut, pim_intf_json["address"],interface_ip)) + errormsg = ( + "[DUT %s]: PIM interface " + "ip is not correct " + "[FAILED]!! Expected : %s, Found : %s" + % (dut, pim_intf_json["address"], interface_ip) + ) return errormsg else: - logger.info("[DUT %s]: PIM interface " - "ip is correct " - "[Passed]!! Expected : %s, Found : %s" - %(dut, pim_intf_json["address"],interface_ip)) + logger.info( + "[DUT %s]: PIM interface " + "ip is correct " + "[Passed]!! Expected : %s, Found : %s" + % (dut, pim_intf_json["address"], interface_ip) + ) return True else: for destLink, data in topo["routers"][dut]["links"].items(): @@ -1595,24 +1599,36 @@ def verify_pim_interface(tgen, topo, dut, interface=None, interface_ip=None): pim_intf_ip = data["ipv4"].split("/")[0] if pim_interface in show_ip_pim_interface_json: - pim_intf_json = show_ip_pim_interface_json\ - [pim_interface] + pim_intf_json = show_ip_pim_interface_json[pim_interface] # Verifying PIM interface - if pim_intf_json["address"] != pim_intf_ip and \ - pim_intf_json["state"] != "up": - errormsg = ("[DUT %s]: PIM interface: %s " - "PIM interface ip: %s, status check " - "[FAILED]!! Expected : %s, Found : %s" - %(dut, pim_interface, pim_intf_ip, - pim_interface, pim_intf_json["state"])) + if ( + pim_intf_json["address"] != pim_intf_ip + and pim_intf_json["state"] != "up" + ): + errormsg = ( + "[DUT %s]: PIM interface: %s " + "PIM interface ip: %s, status check " + "[FAILED]!! Expected : %s, Found : %s" + % ( + dut, + pim_interface, + pim_intf_ip, + pim_interface, + pim_intf_json["state"], + ) + ) return errormsg - logger.info("[DUT %s]: PIM interface: %s, " - "interface ip: %s, status: %s" - " [PASSED]!!", - dut, pim_interface, pim_intf_ip, - pim_intf_json["state"]) + logger.info( + "[DUT %s]: PIM interface: %s, " + "interface ip: %s, status: %s" + " [PASSED]!!", + dut, + pim_interface, + pim_intf_ip, + pim_intf_json["state"], + ) logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name)) return True @@ -3420,30 +3436,36 @@ def verify_igmp_interface(tgen, topo, dut, igmp_iface, interface_ip): if router != dut: continue - logger.info("[DUT: %s]: Verifying PIM interface status:", - dut) + logger.info("[DUT: %s]: Verifying PIM interface status:", dut) rnode = tgen.routers()[dut] - show_ip_igmp_interface_json = \ - run_frr_cmd(rnode, "show ip igmp interface json", isjson=True) + show_ip_igmp_interface_json = run_frr_cmd( + rnode, "show ip igmp interface json", isjson=True + ) - if igmp_iface in show_ip_igmp_interface_json: + if igmp_iface in show_ip_igmp_interface_json: igmp_intf_json = show_ip_igmp_interface_json[igmp_iface] # Verifying igmp interface - if igmp_intf_json["address"] != interface_ip: - errormsg = ("[DUT %s]: igmp interface ip is not correct " - "[FAILED]!! Expected : %s, Found : %s" - %(dut, igmp_intf_json["address"], interface_ip)) + if igmp_intf_json["address"] != interface_ip: + errormsg = ( + "[DUT %s]: igmp interface ip is not correct " + "[FAILED]!! Expected : %s, Found : %s" + % (dut, igmp_intf_json["address"], interface_ip) + ) return errormsg - logger.info("[DUT %s]: igmp interface: %s, " - "interface ip: %s" - " [PASSED]!!", - dut, igmp_iface, interface_ip) + logger.info( + "[DUT %s]: igmp interface: %s, " "interface ip: %s" " [PASSED]!!", + dut, + igmp_iface, + interface_ip, + ) else: - errormsg = ("[DUT %s]: igmp interface: %s " - "igmp interface ip: %s, is not present " - %(dut, igmp_iface, interface_ip)) + errormsg = ( + "[DUT %s]: igmp interface: %s " + "igmp interface ip: %s, is not present " + % (dut, igmp_iface, interface_ip) + ) return errormsg logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name)) diff --git a/tests/topotests/lib/snmptest.py b/tests/topotests/lib/snmptest.py index 5112500e0b..e6b140a0e2 100644 --- a/tests/topotests/lib/snmptest.py +++ b/tests/topotests/lib/snmptest.py @@ -86,12 +86,11 @@ class SnmpTester(object): def _get_snmp_oid(snmp_output): tokens = snmp_output.strip().split() -# if len(tokens) > 5: -# return None - + # if len(tokens) > 5: + # return None # third token is the value of the object - return tokens[0].split('.',1)[1] + return tokens[0].split(".", 1)[1] def _parse_multiline(self, snmp_output): results = snmp_output.strip().split("\r\n") @@ -142,7 +141,11 @@ class SnmpTester(object): print("FAIL: missing oid key {}".format(oid)) return False if results_dict[oid] != values[index]: - print("FAIL{} {} |{}| == |{}|".format(oid, index, results_dict[oid], values[index])) + print( + "FAIL{} {} |{}| == |{}|".format( + oid, index, results_dict[oid], values[index] + ) + ) return False index += 1 return True diff --git a/tests/topotests/lib/topogen.py b/tests/topotests/lib/topogen.py index f958cc11d3..553f2bc6cf 100644 --- a/tests/topotests/lib/topogen.py +++ b/tests/topotests/lib/topogen.py @@ -1006,7 +1006,7 @@ def diagnose_env_linux(): if not os.path.isdir("/tmp"): logger.warning("could not find /tmp for logs") else: - os.system("mkdir /tmp/topotests") + os.system("mkdir -p /tmp/topotests") # Log diagnostics to file so it can be examined later. fhandler = logging.FileHandler(filename="/tmp/topotests/diagnostics.txt") fhandler.setLevel(logging.DEBUG) diff --git a/tests/topotests/lib/topotest.py b/tests/topotests/lib/topotest.py index 1e6ef1b2b3..70b2cfd648 100644 --- a/tests/topotests/lib/topotest.py +++ b/tests/topotests/lib/topotest.py @@ -516,6 +516,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. @@ -1424,7 +1462,7 @@ class Router(Node): 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, self.logdir, self.name + zebra_path, zebra_option ) ) logger.debug("{}: {} zebra started".format(self, self.routertype)) @@ -1439,7 +1477,7 @@ class Router(Node): 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, self.logdir, self.name + staticd_path, staticd_option ) ) logger.debug("{}: {} staticd started".format(self, self.routertype)) @@ -1723,7 +1761,7 @@ class Router(Node): interface = "" ll_per_if_count = 0 for line in ifaces: - m = re.search("[0-9]+: ([^:@]+)[@if0-9:]+ <", line) + m = re.search("[0-9]+: ([^:@]+)[-@a-z0-9:]+ <", line) if m: interface = m.group(1) ll_per_if_count = 0 @@ -1831,8 +1869,8 @@ class LinuxRouter(Router): class FreeBSDRouter(Router): "A FreeBSD Router Node with IPv4/IPv6 forwarding enabled." - def __init__(eslf, name, **params): - Router.__init__(Self, name, **params) + def __init__(self, name, **params): + Router.__init__(self, name, **params) class LegacySwitch(OVSSwitch): diff --git a/tests/topotests/multicast-pim-bsm-topo1/test_mcast_pim_bsmp_01.py b/tests/topotests/multicast-pim-bsm-topo1/test_mcast_pim_bsmp_01.py index c670c82d21..6b7180978e 100644 --- a/tests/topotests/multicast-pim-bsm-topo1/test_mcast_pim_bsmp_01.py +++ b/tests/topotests/multicast-pim-bsm-topo1/test_mcast_pim_bsmp_01.py @@ -642,11 +642,13 @@ def test_BSR_CRP_with_blackhole_address_p1(request): next_hop_rp = topo["routers"]["f1"]["links"]["i1"]["ipv4"].split("/")[0] next_hop_lhr = topo["routers"]["i1"]["links"]["l1"]["ipv4"].split("/")[0] + next_hop_fhr = topo["routers"]["i1"]["links"]["f1"]["ipv4"].split("/")[0] + CRP = topo["routers"]["b1"]["bsm"]["bsr_packets"]["packet9"]["candidate_rp"] input_dict = { - "f1": {"static_routes": [{"network": BSR1_ADDR, "next_hop": NEXT_HOP1}]}, "i1": {"static_routes": [{"network": BSR1_ADDR, "next_hop": next_hop_rp}]}, "l1": {"static_routes": [{"network": BSR1_ADDR, "next_hop": next_hop_lhr}]}, + "f1": {"static_routes": [{"network": CRP, "next_hop": next_hop_fhr, "delete": True}]}, } result = create_static_routes(tgen, input_dict) @@ -655,7 +657,6 @@ def test_BSR_CRP_with_blackhole_address_p1(request): # Use scapy to send pre-defined packet from senser to receiver group = topo["routers"]["b1"]["bsm"]["bsr_packets"]["packet9"]["group"] - CRP = topo["routers"]["b1"]["bsm"]["bsr_packets"]["packet9"]["candidate_rp"] step("waiting for BSR to timeout before configuring blackhole route") clear_bsrp_data(tgen, topo) @@ -691,7 +692,10 @@ def test_BSR_CRP_with_blackhole_address_p1(request): step("Verify if b1 chosen as BSR in l1") result = verify_pim_bsr(tgen, topo, "l1", BSR_IP_1, expected=False) - assert result is not True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + assert result is not True, ("Testcase {} : Failed \n " + "b1 is not chosen as BSR in l1 \n Error: {}".format( + tc_name, result + )) state_after = verify_pim_interface_traffic(tgen, state_dict) assert isinstance( @@ -706,7 +710,8 @@ def test_BSR_CRP_with_blackhole_address_p1(request): input_dict = { "f1": { "static_routes": [ - {"network": [BSR1_ADDR, CRP], "next_hop": "blackhole", "delete": True} + {"network": [BSR1_ADDR, CRP], "next_hop": "blackhole", "delete": True}, + {"network": BSR1_ADDR, "next_hop": NEXT_HOP1}, ] } } @@ -836,7 +841,10 @@ def test_new_router_fwd_p0(request): # Verify bsr state in l1 step("Verify no BSR in l1 as i1 would not forward the no-forward bsm") result = verify_pim_bsr(tgen, topo, "l1", bsr_ip, expected=False) - assert result is not True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + assert result is not True, ("Testcase {} : Failed \n " + "BSR data is present after no-forward bsm also \n Error: {}".format( + tc_name, result + )) # unconfigure unicast bsm on f1-i1-eth2 step("unconfigure unicast bsm on f1-i1-eth2, will forward with only mcast") @@ -958,7 +966,10 @@ def test_int_bsm_config_p1(request): result = verify_ip_mroutes( tgen, "i1", src_addr, GROUP_ADDRESS, iif, oil, expected=False ) - assert result is not True, "Testcase {}:Failed \n Error: {}".format(tc_name, result) + assert result is not True, ("Testcase {} : Failed \n " + "Mroutes are still present \n Error: {}".format( + tc_name, result + )) # unconfigure bsm processing on f1 on f1-i1-eth2 step("unconfigure bsm processing on f1 in f1-i1-eth2, will drop bsm") @@ -978,14 +989,20 @@ def test_int_bsm_config_p1(request): # Verify bsr state in i1 step("Verify if b1 is not chosen as BSR in i1") result = verify_pim_bsr(tgen, topo, "i1", bsr_ip, expected=False) - assert result is not True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + assert result is not True, ("Testcase {} : Failed \n " + "b1 is chosen as BSR in i1 \n Error: {}".format( + tc_name, result + )) # check if mroute still not installed because of rp not available step("check if mroute still not installed because of rp not available") result = verify_ip_mroutes( tgen, "i1", src_addr, GROUP_ADDRESS, iif, oil, expected=False ) - assert result is not True, "Testcase {}:Failed \n Error: {}".format(tc_name, result) + assert result is not True, ("Testcase {} : Failed \n " + "mroute installed but rp not available \n Error: {}".format( + tc_name, result + )) # configure bsm processing on i1 on f1-i1-eth2 step("configure bsm processing on f1 in f1-i1-eth2, will accept bsm") @@ -1118,7 +1135,10 @@ def test_static_rp_override_p1(request): "l1": { "pim": { "rp": [ - {"rp_addr": "33.33.33.33", "group_addr_range": ["225.1.1.1/32"],} + { + "rp_addr": "33.33.33.33", + "group_addr_range": ["225.1.1.1/32"], + } ] } } @@ -1294,7 +1314,8 @@ def test_bsmp_stress_add_del_restart_p2(request): assert ( rp_add1 == rp2[group] ), "Testcase {} :Failed \n Error : rp expected {} rp received {}".format( - tc_name, rp_add1, + tc_name, + rp_add1, ) # Verify if that rp is installed @@ -1443,7 +1464,10 @@ def test_BSM_timeout_p0(request): tgen, topo, "f1", group, rp_source="BSR", expected=False ) - assert result is not True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + assert result is not True, ("Testcase {} : Failed \n " + "bsr has not aged out in f1 \n Error: {}".format( + tc_name, result + )) # Verify RP mapping removed after hold timer expires group = "225.1.1.1/32" @@ -1467,14 +1491,20 @@ def test_BSM_timeout_p0(request): result = verify_join_state_and_timer( tgen, dut, iif, src_addr, GROUP_ADDRESS, expected=False ) - assert result is not True, "Testcase {}:Failed \n Error: {}".format(tc_name, result) + assert result is not True, ("Testcase {} : Failed \n " + "join state is up and join timer is running in l1 \n Error: {}".format( + tc_name, result + )) # Verify ip mroute is not installed step("Verify mroute not installed in l1") result = verify_ip_mroutes( tgen, dut, src_addr, GROUP_ADDRESS, iif, oil, expected=False ) - assert result is not True, "Testcase {}:Failed \n Error: {}".format(tc_name, result) + assert result is not True, ("Testcase {} : Failed \n " + "mroute installed in l1 \n Error: {}".format( + tc_name, result + )) step("clear BSM database before moving to next case") clear_bsrp_data(tgen, topo) @@ -1627,12 +1657,22 @@ def test_iif_join_state_p0(request): result = verify_ip_mroutes( tgen, dut, src_addr, GROUP_ADDRESS, iif, oil, expected=False ) - assert result is not True, "Testcase {}:Failed \n Error: {}".format(tc_name, result) + assert result is not True, ("Testcase {} : Failed \n " + "mroute installed in l1 \n Error: {}".format( + tc_name, result + )) # Add back route for RP to make it reachable step("Add back route for RP to make it reachable") input_dict = { - "l1": {"static_routes": [{"network": rp_ip, "next_hop": next_hop_lhr,}]} + "l1": { + "static_routes": [ + { + "network": rp_ip, + "next_hop": next_hop_lhr, + } + ] + } } result = create_static_routes(tgen, input_dict) assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) diff --git a/tests/topotests/multicast-pim-bsm-topo2/test_mcast_pim_bsmp_02.py b/tests/topotests/multicast-pim-bsm-topo2/test_mcast_pim_bsmp_02.py index 459afb5a02..5fc5e52518 100644 --- a/tests/topotests/multicast-pim-bsm-topo2/test_mcast_pim_bsmp_02.py +++ b/tests/topotests/multicast-pim-bsm-topo2/test_mcast_pim_bsmp_02.py @@ -454,7 +454,10 @@ def test_starg_mroute_p0(request): result = verify_ip_mroutes( tgen, dut, src_addr, GROUP_ADDRESS, iif, oil, wait=20, expected=False ) - assert result is not True, "Testcase {}:Failed \n Error: {}".format(tc_name, result) + assert result is not True, ("Testcase {} : Failed \n " + "mroute installed in l1 \n Error: {}".format( + tc_name, result + )) # Send BSM again to configure rp step("Add back RP by sending BSM from b1") @@ -695,7 +698,8 @@ def test_RP_priority_p0(request): assert ( rp_add1 == rp2[group] ), "Testcase {} :Failed \n Error : rp expected {} rp received {}".format( - tc_name, rp_add1, + tc_name, + rp_add1, ) # Verify if that rp is installed @@ -803,7 +807,10 @@ def test_BSR_election_p0(request): # Verify bsr state in FHR step("Verify if b2 is not chosen as bsr in f1") result = verify_pim_bsr(tgen, topo, "f1", bsr_ip2, expected=False) - assert result is not True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + assert result is not True, ("Testcase {} : Failed \n " + "b2 is chosen as bsr in f1 \n Error: {}".format( + tc_name, result + )) # Verify if b1 is still chosen as bsr step("Verify if b1 is still chosen as bsr in f1") diff --git a/tests/topotests/multicast-pim-sm-topo1/test_multicast_pim_sm_topo1.py b/tests/topotests/multicast-pim-sm-topo1/test_multicast_pim_sm_topo1.py index ac675c5c2f..e55e30270d 100755 --- a/tests/topotests/multicast-pim-sm-topo1/test_multicast_pim_sm_topo1.py +++ b/tests/topotests/multicast-pim-sm-topo1/test_multicast_pim_sm_topo1.py @@ -102,7 +102,7 @@ from lib.pim import ( clear_ip_mroute, clear_ip_pim_interface_traffic, verify_igmp_config, - clear_ip_mroute_verify + clear_ip_mroute_verify, ) from lib.topolog import logger from lib.topojson import build_topo_from_json, build_config_from_json diff --git a/tests/topotests/multicast-pim-sm-topo2/test_multicast_pim_sm_topo2.py b/tests/topotests/multicast-pim-sm-topo2/test_multicast_pim_sm_topo2.py index a9d914da57..7e409c2a05 100755 --- a/tests/topotests/multicast-pim-sm-topo2/test_multicast_pim_sm_topo2.py +++ b/tests/topotests/multicast-pim-sm-topo2/test_multicast_pim_sm_topo2.py @@ -877,7 +877,7 @@ def test_verify_SPT_switchover_when_RPT_and_SPT_path_is_different_p0(request): data["src_address"], _IGMP_JOIN_RANGE, data["iif"], - data["oil"] + data["oil"], ) assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) @@ -1122,8 +1122,9 @@ def test_verify_mroute_after_shut_noshut_of_upstream_interface_p1(request): done_flag = False for retry in range(1, 11): - result = verify_upstream_iif(tgen, "l1", "Unknown", source, IGMP_JOIN_RANGE_2, - expected=False) + result = verify_upstream_iif( + tgen, "l1", "Unknown", source, IGMP_JOIN_RANGE_2, expected=False + ) if result is not True: done_flag = True else: @@ -1515,7 +1516,7 @@ def test_verify_mroute_when_FRR_is_FHR_and_LHR_p0(request): _IGMP_JOIN_RANGE, data["iif"], data["oil"], - expected=False + expected=False, ) if result is not True: done_flag = True @@ -1928,9 +1929,10 @@ def test_verify_oil_iif_for_mroute_after_shut_noshut_source_interface_p1(request "f1-i8-eth2", expected=False, ) - assert result is not True, ( - "Testcase {} : Failed \n mroutes are" - " still present \n Error: {}".format(tc_name, result) + assert ( + result is not True + ), "Testcase {} : Failed \n mroutes are" " still present \n Error: {}".format( + tc_name, result ) logger.info("Expected Behavior: {}".format(result)) diff --git a/tests/topotests/multicast-pim-sm-topo3/test_multicast_pim_sm_topo3.py b/tests/topotests/multicast-pim-sm-topo3/test_multicast_pim_sm_topo3.py index fdceb77fd1..1c22654541 100755 --- a/tests/topotests/multicast-pim-sm-topo3/test_multicast_pim_sm_topo3.py +++ b/tests/topotests/multicast-pim-sm-topo3/test_multicast_pim_sm_topo3.py @@ -597,9 +597,10 @@ def test_verify_oil_when_join_prune_sent_scenario_1_p1(request): input_traffic = {"l1": {"traffic_sent": [intf_l1_i1]}} result = verify_multicast_traffic(tgen, input_traffic, expected=False) - assert result is not True, ( - "Testcase {} : Failed \n " - " Traffic is not stopped yet \n Error: {}".format(tc_name, result) + assert ( + result is not True + ), "Testcase {} : Failed \n " " Traffic is not stopped yet \n Error: {}".format( + tc_name, result ) logger.info("Expected Behaviour: {}".format(result)) @@ -612,9 +613,10 @@ def test_verify_oil_when_join_prune_sent_scenario_1_p1(request): result = verify_igmp_groups( tgen, dut, intf_l1_i1, IGMP_JOIN_RANGE_1, expected=False ) - assert result is not True, ( - "Testcase {} : Failed \n " - "IGMP groups are not deleted \n Error: {}".format(tc_name, result) + assert ( + result is not True + ), "Testcase {} : Failed \n " "IGMP groups are not deleted \n Error: {}".format( + tc_name, result ) logger.info("Expected Behaviour: {}".format(result)) @@ -655,9 +657,10 @@ def test_verify_oil_when_join_prune_sent_scenario_1_p1(request): data["oil"], expected=False, ) - assert result is not True, ( - "Testcase {} : Failed \n " - "mroutes are still present \n Error: {}".format(tc_name, result) + assert ( + result is not True + ), "Testcase {} : Failed \n " "mroutes are still present \n Error: {}".format( + tc_name, result ) logger.info("Expected Behaviour: {}".format(result)) @@ -722,9 +725,10 @@ def test_verify_oil_when_join_prune_sent_scenario_1_p1(request): input_traffic = {"f1": {"traffic_sent": [intf_f1_i8]}} result = verify_multicast_traffic(tgen, input_traffic, expected=False) - assert result is not True, ( - "Testcase {} : Failed \n " - " Traffic is not stopped yet \n Error: {}".format(tc_name, result) + assert ( + result is not True + ), "Testcase {} : Failed \n " " Traffic is not stopped yet \n Error: {}".format( + tc_name, result ) logger.info("Expected Behaviour: {}".format(result)) @@ -737,9 +741,10 @@ def test_verify_oil_when_join_prune_sent_scenario_1_p1(request): result = verify_igmp_groups( tgen, dut, intf_f1_i8, IGMP_JOIN_RANGE_1, expected=False ) - assert result is not True, ( - "Testcase {} : Failed \n " - "IGMP groups are not deleted \n Error: {}".format(tc_name, result) + assert ( + result is not True + ), "Testcase {} : Failed \n " "IGMP groups are not deleted \n Error: {}".format( + tc_name, result ) logger.info("Expected Behaviour: {}".format(result)) @@ -775,9 +780,10 @@ def test_verify_oil_when_join_prune_sent_scenario_1_p1(request): data["oil"], expected=False, ) - assert result is not True, ( - "Testcase {} : Failed \n " - "mroutes are still present \n Error: {}".format(tc_name, result) + assert ( + result is not True + ), "Testcase {} : Failed \n " "mroutes are still present \n Error: {}".format( + tc_name, result ) logger.info("Expected Behaviour: {}".format(result)) @@ -959,9 +965,10 @@ def test_verify_oil_when_join_prune_sent_scenario_2_p1(request): data["oil"], expected=False, ) - assert result is not True, ( - "Testcase {} : Failed \n " - "mroutes are still present \n Error: {}".format(tc_name, result) + assert ( + result is not True + ), "Testcase {} : Failed \n " "mroutes are still present \n Error: {}".format( + tc_name, result ) logger.info("Expected Behaviour: {}".format(result)) @@ -1022,9 +1029,10 @@ def test_verify_oil_when_join_prune_sent_scenario_2_p1(request): data["oil"], expected=False, ) - assert result is not True, ( - "Testcase {} : Failed \n " - "mroutes are still present \n Error: {}".format(tc_name, result) + assert ( + result is not True + ), "Testcase {} : Failed \n " "mroutes are still present \n Error: {}".format( + tc_name, result ) logger.info("Expected Behaviour: {}".format(result)) @@ -1190,9 +1198,10 @@ def test_shut_noshut_source_interface_when_upstream_cleared_from_LHR_p1(request) result = verify_ip_mroutes( tgen, "f1", source_i2, IGMP_JOIN_RANGE_1, intf_f1_i2, intf_f1_r2, expected=False ) - assert result is not True, ( - "Testcase {} : Failed \n mroutes are" - " still present \n Error: {}".format(tc_name, result) + assert ( + result is not True + ), "Testcase {} : Failed \n mroutes are" " still present \n Error: {}".format( + tc_name, result ) logger.info("Expected Behavior: {}".format(result)) @@ -1630,7 +1639,14 @@ def test_verify_remove_add_igmp_config_to_receiver_interface_p0(request): input_dict_2 = { "l1": { "igmp": { - "interfaces": {intf_l1_i1: {"igmp": {"version": "2", "delete": True,}}} + "interfaces": { + intf_l1_i1: { + "igmp": { + "version": "2", + "delete": True, + } + } + } } } } @@ -1642,9 +1658,10 @@ def test_verify_remove_add_igmp_config_to_receiver_interface_p0(request): dut = "l1" interface = topo["routers"]["l1"]["links"]["i1"]["interface"] result = verify_igmp_groups(tgen, dut, interface, IGMP_JOIN_RANGE_1, expected=False) - assert result is not True, ( - "Testcase {} : Failed \n Groups are not" - " present \n Error: {}".format(tc_name, result) + assert ( + result is not True + ), "Testcase {} : Failed \n Groups are not" " present \n Error: {}".format( + tc_name, result ) logger.info("Expected Behaviour: {}".format(result)) @@ -1712,7 +1729,14 @@ def test_verify_remove_add_igmp_config_to_receiver_interface_p0(request): input_dict_2 = { "l1": { "igmp": { - "interfaces": {intf_l1_i1: {"igmp": {"version": "2", "delete": True,}}} + "interfaces": { + intf_l1_i1: { + "igmp": { + "version": "2", + "delete": True, + } + } + } } } } @@ -1725,9 +1749,10 @@ def test_verify_remove_add_igmp_config_to_receiver_interface_p0(request): dut = "l1" interface = topo["routers"]["l1"]["links"]["i1"]["interface"] result = verify_igmp_groups(tgen, dut, interface, IGMP_JOIN_RANGE_1, expected=False) - assert result is not True, ( - "Testcase {} : Failed \n Groups are not" - " present \n Error: {}".format(tc_name, result) + assert ( + result is not True + ), "Testcase {} : Failed \n Groups are not" " present \n Error: {}".format( + tc_name, result ) logger.info("Expected Behaviour: {}".format(result)) @@ -1811,7 +1836,14 @@ def test_verify_remove_add_igmp_config_to_receiver_interface_p0(request): input_dict_2 = { "l1": { "igmp": { - "interfaces": {intf_l1_i1: {"igmp": {"version": "2", "delete": True,}}} + "interfaces": { + intf_l1_i1: { + "igmp": { + "version": "2", + "delete": True, + } + } + } } } } @@ -1831,9 +1863,10 @@ def test_verify_remove_add_igmp_config_to_receiver_interface_p0(request): result = verify_ip_mroutes( tgen, dut, source, IGMP_JOIN_RANGE_1, iif, oil, expected=False ) - assert result is not True, ( - "Testcase {} : Failed \n routes are still" - " present \n Error: {}".format(tc_name, result) + assert ( + result is not True + ), "Testcase {} : Failed \n routes are still" " present \n Error: {}".format( + tc_name, result ) logger.info("Expected Behaviour: {}".format(result)) @@ -1995,7 +2028,14 @@ def test_verify_remove_add_igmp_commands_when_pim_configured_p0(request): input_dict_2 = { "l1": { "igmp": { - "interfaces": {intf_l1_i1: {"igmp": {"version": "2", "delete": True,}}} + "interfaces": { + intf_l1_i1: { + "igmp": { + "version": "2", + "delete": True, + } + } + } } } } @@ -2009,9 +2049,10 @@ def test_verify_remove_add_igmp_commands_when_pim_configured_p0(request): ) result = verify_igmp_config(tgen, input_dict_1, expected=False) - assert result is not True, ( - "Testcase {} : Failed \n " - "IGMP interface is not removed \n Error: {}".format(tc_name, result) + assert ( + result is not True + ), "Testcase {} : Failed \n " "IGMP interface is not removed \n Error: {}".format( + tc_name, result ) logger.info("Expected Behaviour: {}".format(result)) @@ -2914,9 +2955,10 @@ def test_mroute_after_removing_RP_sending_IGMP_prune_p2(request): data["oil"], expected=False, ) - assert result is not True, ( - "Testcase {} : Failed \n " - "mroute still present \n Error: {}".format(tc_name, result) + assert ( + result is not True + ), "Testcase {} : Failed \n " "mroute still present \n Error: {}".format( + tc_name, result ) logger.info("Expected Behaviour: {}".format(result)) @@ -3259,9 +3301,10 @@ def test_prune_sent_to_LHR_and_FHR_when_PIMnbr_down_p2(request): data["oil"], expected=False, ) - assert result is not True, ( - "Testcase {} : Failed \n " - "mroute still present \n Error: {}".format(tc_name, result) + assert ( + result is not True + ), "Testcase {} : Failed \n " "mroute still present \n Error: {}".format( + tc_name, result ) logger.info("Expected Behaviour: {}".format(result)) @@ -3287,9 +3330,10 @@ def test_prune_sent_to_LHR_and_FHR_when_PIMnbr_down_p2(request): IGMP_JOIN_RANGE_1, expected=False, ) - assert result is not True, ( - "Testcase {} : Failed \n " - "upstream still present \n Error: {}".format(tc_name, result) + assert ( + result is not True + ), "Testcase {} : Failed \n " "upstream still present \n Error: {}".format( + tc_name, result ) logger.info("Expected Behaviour: {}".format(result)) @@ -3311,9 +3355,10 @@ def test_prune_sent_to_LHR_and_FHR_when_PIMnbr_down_p2(request): result = verify_pim_rp_info( tgen, topo, dut, GROUP_RANGE_1, "Unknown", rp_address, SOURCE, expected=False ) - assert result is not True, ( - "Testcase {} : Failed \n " - "RP iif is not updated \n Error: {}".format(tc_name, result) + assert ( + result is not True + ), "Testcase {} : Failed \n " "RP iif is not updated \n Error: {}".format( + tc_name, result ) logger.info("Expected Behaviour: {}".format(result)) @@ -3442,9 +3487,11 @@ def test_prune_sent_to_LHR_and_FHR_when_PIMnbr_down_p2(request): IGMP_JOIN_RANGE_1, expected=False, ) - assert result is not True, "Testcase {} : Failed Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "upstream is still present after shut the link from " + "FHR to RP from RP node \n Error: {}".format( tc_name, result - ) + )) step(" No shut the link from FHR to RP from RP node") @@ -3459,9 +3506,10 @@ def test_prune_sent_to_LHR_and_FHR_when_PIMnbr_down_p2(request): result = verify_pim_rp_info( tgen, topo, dut, GROUP_RANGE_1, "Unknown", rp_address, SOURCE, expected=False ) - assert result is not True, ( - "Testcase {} : Failed \n " - "RP iif is not updated \n Error: {}".format(tc_name, result) + assert ( + result is not True + ), "Testcase {} : Failed \n " "RP iif is not updated \n Error: {}".format( + tc_name, result ) logger.info("Expected Behaviour: {}".format(result)) @@ -3590,9 +3638,11 @@ def test_prune_sent_to_LHR_and_FHR_when_PIMnbr_down_p2(request): IGMP_JOIN_RANGE_1, expected=False, ) - assert result is not True, "Testcase {} : Failed Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "upstream is still present after shut the link from " + "FHR to RP from FHR node \n Error: {}".format( tc_name, result - ) + )) step(" No shut the link from FHR to RP from FHR node") @@ -3606,9 +3656,10 @@ def test_prune_sent_to_LHR_and_FHR_when_PIMnbr_down_p2(request): result = verify_pim_rp_info( tgen, topo, dut, GROUP_RANGE_1, "Unknown", rp_address, SOURCE, expected=False ) - assert result is not True, ( - "Testcase {} : Failed \n " - "RP iif is not updated \n Error: {}".format(tc_name, result) + assert ( + result is not True + ), "Testcase {} : Failed \n " "RP iif is not updated \n Error: {}".format( + tc_name, result ) logger.info("Expected Behaviour: {}".format(result)) @@ -3873,7 +3924,12 @@ def test_verify_multicast_traffic_when_LHR_connected_to_RP_p1(request): "l1": { "igmp": { "interfaces": { - "l1-i1-eth1": {"igmp": {"version": "2", "delete": True,}} + "l1-i1-eth1": { + "igmp": { + "version": "2", + "delete": True, + } + } } } } @@ -4107,9 +4163,10 @@ def test_verify_multicast_traffic_when_LHR_connected_to_RP_p1(request): data["oil"], expected=False, ) - assert result is not True, ( - "Testcase {} : Failed \n" - "mroutes are cleared \n Error: {}".format(tc_name, result) + assert ( + result is not True + ), "Testcase {} : Failed \n" "mroutes are cleared \n Error: {}".format( + tc_name, result ) logger.info("Expected Behaviour: {}".format(result)) @@ -4181,9 +4238,10 @@ def test_verify_multicast_traffic_when_LHR_connected_to_RP_p1(request): data["oil"], expected=False, ) - assert result is not True, ( - "Testcase {} : Failed \n" - " mroutes are cleared \n Error: {}".format(tc_name, result) + assert ( + result is not True + ), "Testcase {} : Failed \n" " mroutes are cleared \n Error: {}".format( + tc_name, result ) logger.info("Expected Behaviour: {}".format(result)) @@ -4248,9 +4306,10 @@ def test_verify_multicast_traffic_when_LHR_connected_to_RP_p1(request): result = verify_ip_mroutes( tgen, dut, src_address, _IGMP_JOIN_RANGE, iif, oil, expected=False ) - assert result is not True, ( - "Testcase {} : Failed \n" - " mroutes are cleared \n Error: {}".format(tc_name, result) + assert ( + result is not True + ), "Testcase {} : Failed \n" " mroutes are cleared \n Error: {}".format( + tc_name, result ) logger.info("Expected Behaviour: {}".format(result)) @@ -4459,9 +4518,10 @@ def test_verify_multicast_traffic_when_FHR_connected_to_RP_p1(request): data["oil"], expected=False, ) - assert result is not True, ( - "Testcase {} : Failed \n" - " mroutes are cleared \n Error: {}".format(tc_name, result) + assert ( + result is not True + ), "Testcase {} : Failed \n" " mroutes are cleared \n Error: {}".format( + tc_name, result ) logger.info("Expected Behaviour: {}".format(result)) @@ -4524,9 +4584,10 @@ def test_verify_multicast_traffic_when_FHR_connected_to_RP_p1(request): data["oil"], expected=False, ) - assert result is not True, ( - "Testcase {} : Failed \n" - " mroutes are cleared \n Error: {}".format(tc_name, result) + assert ( + result is not True + ), "Testcase {} : Failed \n" " mroutes are cleared \n Error: {}".format( + tc_name, result ) logger.info("Expected Behaviour: {}".format(result)) @@ -4595,9 +4656,10 @@ def test_verify_multicast_traffic_when_FHR_connected_to_RP_p1(request): data["oil"], expected=False, ) - assert result is not True, ( - "Testcase {} : Failed \n" - " mroutes are cleared \n Error: {}".format(tc_name, result) + assert ( + result is not True + ), "Testcase {} : Failed \n" " mroutes are cleared \n Error: {}".format( + tc_name, result ) logger.info("Expected Behaviour: {}".format(result)) diff --git a/tests/topotests/multicast-pim-sm-topo3/test_multicast_pim_sm_topo4.py b/tests/topotests/multicast-pim-sm-topo3/test_multicast_pim_sm_topo4.py index e8579e2a1e..68b7849c2b 100755 --- a/tests/topotests/multicast-pim-sm-topo3/test_multicast_pim_sm_topo4.py +++ b/tests/topotests/multicast-pim-sm-topo3/test_multicast_pim_sm_topo4.py @@ -490,9 +490,10 @@ def test_mroute_when_RP_reachable_default_route_p2(request): data["oil"], expected=False, ) - assert result is not True, "Testcase {} : Failed Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "mroutes(S,G) are present after delete of static routes on c1 \n Error: {}".format( tc_name, result - ) + )) result = verify_upstream_iif( tgen, @@ -502,9 +503,10 @@ def test_mroute_when_RP_reachable_default_route_p2(request): IGMP_JOIN_RANGE_1, expected=False, ) - assert result is not True, "Testcase {} : Failed Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "upstream is present after delete of static routes on c1 \n Error: {}".format( tc_name, result - ) + )) for data in input_dict_starg: result = verify_ip_mroutes( @@ -516,9 +518,10 @@ def test_mroute_when_RP_reachable_default_route_p2(request): data["oil"], expected=False, ) - assert result is not True, "Testcase {} : Failed Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "mroutes(*,G) are present after delete of static routes on c1 \n Error: {}".format( tc_name, result - ) + )) result = verify_upstream_iif( tgen, @@ -528,9 +531,10 @@ def test_mroute_when_RP_reachable_default_route_p2(request): IGMP_JOIN_RANGE_1, expected=False, ) - assert result is not True, "Testcase {} : Failed Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "upstream is present after delete of static routes on c1 \n Error: {}".format( tc_name, result - ) + )) step("Configure default routes on c2") @@ -553,9 +557,10 @@ def test_mroute_when_RP_reachable_default_route_p2(request): result = verify_pim_rp_info( tgen, topo, dut, GROUP_RANGE_1, "Unknown", rp_address, SOURCE, expected=False ) - assert result is not True, "Testcase {} :Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "RP info is unknown after removing static route from c2 \n Error: {}".format( tc_name, result - ) + )) step("Verify (s,g) populated after adding default route ") @@ -782,9 +787,10 @@ def test_mroute_with_RP_default_route_all_nodes_p2(request): data["oil"], expected=False, ) - assert result is not True, "Testcase {} : Failed Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "mroutes are still present \n Error: {}".format( tc_name, result - ) + )) result = verify_upstream_iif( tgen, @@ -794,9 +800,10 @@ def test_mroute_with_RP_default_route_all_nodes_p2(request): IGMP_JOIN_RANGE_1, expected=False, ) - assert result is not True, "Testcase {} : Failed Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "upstream is still present \n Error: {}".format( tc_name, result - ) + )) step("Configure default routes on all the nodes") @@ -833,9 +840,10 @@ def test_mroute_with_RP_default_route_all_nodes_p2(request): result = verify_pim_rp_info( tgen, topo, dut, GROUP_RANGE_1, "Unknown", rp_address, SOURCE, expected=False ) - assert result is not True, "Testcase {} :Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "RP info is unknown after removing static route from c2 \n Error: {}".format( tc_name, result - ) + )) step("Verify (s,g) populated after adding default route ") @@ -1009,7 +1017,11 @@ def test_PIM_hello_tx_rx_p1(request): intf_c1_l1 = topo["routers"]["c1"]["links"]["l1"]["interface"] step("verify before stats on C1") - state_dict = {"c1": {intf_c1_l1: ["helloTx", "helloRx"],}} + state_dict = { + "c1": { + intf_c1_l1: ["helloTx", "helloRx"], + } + } c1_state_before = verify_pim_interface_traffic(tgen, state_dict) assert isinstance( @@ -1040,7 +1052,11 @@ def test_PIM_hello_tx_rx_p1(request): ), "Testcase{} : Failed Error: {}" "stats incremented".format(tc_name, result) step("verify before stats on l1") - l1_state_dict = {"l1": {intf_l1_c1: ["helloTx", "helloRx"],}} + l1_state_dict = { + "l1": { + intf_l1_c1: ["helloTx", "helloRx"], + } + } l1_state_before = verify_pim_interface_traffic(tgen, l1_state_dict) assert isinstance( @@ -1077,7 +1093,11 @@ def test_PIM_hello_tx_rx_p1(request): l1_state_after = {} step("verify before stats on C1") - state_dict = {"c1": {intf_c1_l1: ["helloTx", "helloRx"],}} + state_dict = { + "c1": { + intf_c1_l1: ["helloTx", "helloRx"], + } + } c1_state_before = verify_pim_interface_traffic(tgen, state_dict) assert isinstance( diff --git a/tests/topotests/multicast-pim-static-rp-topo1/test_multicast_pim_static_rp.py b/tests/topotests/multicast-pim-static-rp-topo1/test_multicast_pim_static_rp.py index 8dfdd50527..1317ec67b4 100755 --- a/tests/topotests/multicast-pim-static-rp-topo1/test_multicast_pim_static_rp.py +++ b/tests/topotests/multicast-pim-static-rp-topo1/test_multicast_pim_static_rp.py @@ -281,6 +281,7 @@ def teardown_module(): # ##################################################### + def config_to_send_igmp_join_and_traffic(tgen, tc_name): """ API to do pre-configuration to send IGMP join and multicast @@ -422,9 +423,10 @@ def test_add_delete_static_RP_p0(request): dut = "r1" interface = "r1-r0-eth0" result = verify_igmp_groups(tgen, dut, interface, GROUP_ADDRESS, expected=False) - assert result is not True, "Testcase {} :Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r1: igmp group present without any IGMP join \n Error: {}".format( tc_name, result - ) + )) step("r1: Verify show ip pim interface traffic without any IGMP join") state_dict = {"r1": {"r1-r2-eth1": ["pruneTx"]}} @@ -490,23 +492,26 @@ def test_add_delete_static_RP_p0(request): result = verify_pim_rp_info( tgen, topo, dut, GROUP_RANGE_ALL, iif, rp_address, SOURCE, expected=False ) - assert result is not True, "Testcase {} :Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r1: RP info present \n Error: {}".format( tc_name, result - ) + )) step("r1: Verify upstream IIF interface") result = verify_upstream_iif(tgen, dut, iif, STAR, GROUP_ADDRESS, expected=False) - assert result is not True, "Testcase {} :Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r1: upstream IIF interface present \n Error: {}".format( tc_name, result - ) + )) step("r1: Verify upstream join state and join timer") result = verify_join_state_and_timer( tgen, dut, iif, STAR, GROUP_ADDRESS, expected=False ) - assert result is not True, "Testcase {} :Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r1: upstream join state is up and join timer is running \n Error: {}".format( tc_name, result - ) + )) step("r1: Verify PIM state") result = verify_pim_state(tgen, dut, iif, oif, GROUP_ADDRESS, expected=False) @@ -516,9 +521,10 @@ def test_add_delete_static_RP_p0(request): step("r1: Verify ip mroutes") result = verify_ip_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif, expected=False) - assert result is not True, "Testcase {} :Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r1: mroutes are still present \n Error: {}".format( tc_name, result - ) + )) step("r1: Verify show ip pim interface traffic without any IGMP join") state_after = verify_pim_interface_traffic(tgen, state_dict) @@ -675,9 +681,10 @@ def test_SPT_RPT_path_same_p1(request): result = verify_join_state_and_timer( tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS, expected=False ) - assert result is not True, "Testcase {} :Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r3: (S, G) upstream join state is up and join timer is running\n Error: {}".format( tc_name, result - ) + )) step("r3: Verify (S, G) ip mroutes") oif = "r3-r2-eth1" @@ -804,15 +811,17 @@ def test_not_reachable_static_RP_p0(request): "using show ip pim state" ) result = verify_pim_state(tgen, dut, iif, oif, GROUP_ADDRESS, expected=False) - assert result is not True, "Testcase {} :Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "OIL is not same and IIF is not cleared on R1 \n Error: {}".format( tc_name, result - ) + )) step("r1: upstream IIF should be unknown , verify using show ip pim" "upstream") result = verify_upstream_iif(tgen, dut, iif, STAR, GROUP_ADDRESS, expected=False) - assert result is not True, "Testcase {} :Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r1: upstream IIF is not unknown \n Error: {}".format( tc_name, result - ) + )) step( "r1: join state should not be joined and join timer should stop," @@ -821,9 +830,10 @@ def test_not_reachable_static_RP_p0(request): result = verify_join_state_and_timer( tgen, dut, iif, STAR, GROUP_ADDRESS, expected=False ) - assert result is not True, "Testcase {} :Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r1: join state is joined and timer is not stopped \n Error: {}".format( tc_name, result - ) + )) step( "r1: (*,G) prune is sent towards the RP interface, verify using" @@ -840,9 +850,10 @@ def test_not_reachable_static_RP_p0(request): step("r1: (*, G) cleared from mroute table using show ip mroute") result = verify_ip_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif, expected=False) - assert result is not True, "Testcase {} :Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r1: (*, G) are not cleared from mroute table \n Error: {}".format( tc_name, result - ) + )) logger.info("Expected behavior: {}".format(result)) # Uncomment next line for debugging @@ -909,9 +920,10 @@ def test_add_RP_after_join_received_p1(request): result = verify_pim_rp_info( tgen, topo, dut, GROUP_RANGE_ALL, iif, rp_address, SOURCE, expected=False ) - assert result is not True, "Testcase {} :Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r1: rp-info is present \n Error: {}".format( tc_name, result - ) + )) step("joinTx value before join sent") state_dict = {"r1": {"r1-r2-eth1": ["joinTx"]}} @@ -932,36 +944,45 @@ def test_add_RP_after_join_received_p1(request): step("r1: Verify upstream IIF interface") result = verify_upstream_iif(tgen, dut, iif, STAR, GROUP_ADDRESS, expected=False) - assert result is not True, "Testcase {} :Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r1: upstream IFF interface is present \n Error: {}".format( tc_name, result - ) + )) step("r1: Verify upstream join state and join timer") result = verify_join_state_and_timer( tgen, dut, iif, STAR, GROUP_ADDRESS, expected=False ) - assert result is not True, "Testcase {} :Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r1: upstream join state is joined and timer is running \n Error: {}".format( tc_name, result - ) + )) step("r1: Verify PIM state") result = verify_pim_state(tgen, dut, iif, oif, GROUP_ADDRESS, expected=False) - assert result is not True, "Testcase {} :Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r1: PIM state is up\n Error: {}".format( tc_name, result - ) + )) step("r1: Verify ip mroutes") result = verify_ip_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif, expected=False) - assert result is not True, "Testcase {} :Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r1: mroutes are still present\n Error: {}".format( tc_name, result - ) + )) step("r1: Configure static RP") input_dict = { "r1": { "pim": { - "rp": [{"rp_addr": "1.0.2.17", "group_addr_range": GROUP_RANGE_ALL,}] + "rp": [ + { + "rp_addr": "1.0.2.17", + "group_addr_range": GROUP_RANGE_ALL, + } + ] } } } @@ -1074,29 +1095,33 @@ def test_reachable_static_RP_after_join_p0(request): step("r1 : Verify upstream IIF interface") iif = "r1-r2-eth1" result = verify_upstream_iif(tgen, dut, iif, STAR, GROUP_ADDRESS, expected=False) - assert result is not True, "Testcase {} :Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r1: upstream IIF interface is present\n Error: {}".format( tc_name, result - ) + )) step("r1 : Verify upstream join state and join timer") result = verify_join_state_and_timer( tgen, dut, iif, STAR, GROUP_ADDRESS, expected=False ) - assert result is not True, "Testcase {} :Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r1: upstream join state is joined and timer is running\n Error: {}".format( tc_name, result - ) + )) step("r1 : Verify PIM state") result = verify_pim_state(tgen, dut, iif, oif, GROUP_ADDRESS, expected=False) - assert result is not True, "Testcase {} :Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r1: PIM state is up\n Error: {}".format( tc_name, result - ) + )) step("r1 : Verify ip mroutes") result = verify_ip_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif, expected=False) - assert result is not True, "Testcase {} :Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r1: mroutes are still present\n Error: {}".format( tc_name, result - ) + )) step("r1: Make RP reachable") intf = "r1-r2-eth1" @@ -1147,32 +1172,32 @@ def test_reachable_static_RP_after_join_p0(request): def test_send_join_on_higher_preffered_rp_p1(request): """ - TC_11_P1 : Verify PIM join send towards the higher preferred RP - TC_12_P1 : Verify PIM prune send towards the lower preferred RP - TC_13_P1 : Verify RPF interface is updated in mroute (kernel) when higher - preferred overlapping RP configured - TC_14_P1 : Verify IIF and OIL in "show ip pim state" updated properly when - higher preferred overlapping RP configured - TC_15_P1 : Verify upstream interfaces(IIF) and join state are updated when - higher preferred overlapping RP is configured - TC_16_P1 : Verify join is send to lower preferred RP, when higher - preferred RP gets deleted - TC_17_P1 : Verify prune is send to higher preferred RP when higher - preferred RP gets deleted - TC_18_P1 : Verify RPF interface updated in mroute when higher preferred RP - gets deleted - TC_19_P1 : Verify IIF and OIL in "show ip pim state" updated when higher - preferred overlapping RP is deleted - TC_20_P1 : Verfiy PIM upstream IIF updated when higher preferred - overlapping RP deleted - - Topology used: - _______r2 - | - iperf | - r0-----r1 - | - |_______r4 + TC_11_P1 : Verify PIM join send towards the higher preferred RP + TC_12_P1 : Verify PIM prune send towards the lower preferred RP + TC_13_P1 : Verify RPF interface is updated in mroute (kernel) when higher + preferred overlapping RP configured + TC_14_P1 : Verify IIF and OIL in "show ip pim state" updated properly when + higher preferred overlapping RP configured + TC_15_P1 : Verify upstream interfaces(IIF) and join state are updated when + higher preferred overlapping RP is configured + TC_16_P1 : Verify join is send to lower preferred RP, when higher + preferred RP gets deleted + TC_17_P1 : Verify prune is send to higher preferred RP when higher + preferred RP gets deleted + TC_18_P1 : Verify RPF interface updated in mroute when higher preferred RP + gets deleted + TC_19_P1 : Verify IIF and OIL in "show ip pim state" updated when higher + preferred overlapping RP is deleted + TC_20_P1 : Verfiy PIM upstream IIF updated when higher preferred + overlapping RP deleted + + Topology used: + _______r2 + | + iperf | + r0-----r1 + | + |_______r4 """ tgen = get_topogen() @@ -1241,7 +1266,12 @@ def test_send_join_on_higher_preffered_rp_p1(request): input_dict = { "r4": { "pim": { - "rp": [{"rp_addr": "1.0.4.17", "group_addr_range": ["225.1.1.1/32"],}] + "rp": [ + { + "rp_addr": "1.0.4.17", + "group_addr_range": ["225.1.1.1/32"], + } + ] } } } @@ -1332,9 +1362,10 @@ def test_send_join_on_higher_preffered_rp_p1(request): result = verify_pim_rp_info( tgen, topo, dut, GROUP_RANGE, oif, rp_address_2, SOURCE, expected=False ) - assert result is not True, "Testcase {} :Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r1: rp-info is present for group 225.1.1.1 \n Error: {}".format( tc_name, result - ) + )) step( "r1 : Verify RPF interface updated in mroute when higher preferred" @@ -1483,22 +1514,42 @@ def test_RP_configured_as_LHR_1_p1(request): input_dict = { "r1": { "pim": { - "rp": [{"rp_addr": "1.0.1.17", "group_addr_range": GROUP_RANGE_ALL,}] + "rp": [ + { + "rp_addr": "1.0.1.17", + "group_addr_range": GROUP_RANGE_ALL, + } + ] } }, "r2": { "pim": { - "rp": [{"rp_addr": "1.0.1.17", "group_addr_range": GROUP_RANGE_ALL,}] + "rp": [ + { + "rp_addr": "1.0.1.17", + "group_addr_range": GROUP_RANGE_ALL, + } + ] } }, "r3": { "pim": { - "rp": [{"rp_addr": "1.0.1.17", "group_addr_range": GROUP_RANGE_ALL,}] + "rp": [ + { + "rp_addr": "1.0.1.17", + "group_addr_range": GROUP_RANGE_ALL, + } + ] } }, "r4": { "pim": { - "rp": [{"rp_addr": "1.0.1.17", "group_addr_range": GROUP_RANGE_ALL,}] + "rp": [ + { + "rp_addr": "1.0.1.17", + "group_addr_range": GROUP_RANGE_ALL, + } + ] } }, } @@ -1568,9 +1619,11 @@ def test_RP_configured_as_LHR_1_p1(request): result = verify_join_state_and_timer( tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS, expected=False ) - assert result is not True, "Testcase {} :Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r3: (S, G) upstream join state is joined and join" + " timer is running \n Error: {}".format( tc_name, result - ) + )) step("r3: Verify (S, G) ip mroutes") oif = "r3-r1-eth0" @@ -1677,22 +1730,42 @@ def test_RP_configured_as_LHR_2_p1(request): input_dict = { "r1": { "pim": { - "rp": [{"rp_addr": "1.0.1.17", "group_addr_range": GROUP_RANGE_ALL,}] + "rp": [ + { + "rp_addr": "1.0.1.17", + "group_addr_range": GROUP_RANGE_ALL, + } + ] } }, "r2": { "pim": { - "rp": [{"rp_addr": "1.0.1.17", "group_addr_range": GROUP_RANGE_ALL,}] + "rp": [ + { + "rp_addr": "1.0.1.17", + "group_addr_range": GROUP_RANGE_ALL, + } + ] } }, "r3": { "pim": { - "rp": [{"rp_addr": "1.0.1.17", "group_addr_range": GROUP_RANGE_ALL,}] + "rp": [ + { + "rp_addr": "1.0.1.17", + "group_addr_range": GROUP_RANGE_ALL, + } + ] } }, "r4": { "pim": { - "rp": [{"rp_addr": "1.0.1.17", "group_addr_range": GROUP_RANGE_ALL,}] + "rp": [ + { + "rp_addr": "1.0.1.17", + "group_addr_range": GROUP_RANGE_ALL, + } + ] } }, } @@ -1755,9 +1828,10 @@ def test_RP_configured_as_LHR_2_p1(request): result = verify_join_state_and_timer( tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS, expected=False ) - assert result is not True, "Testcase {} :Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r3: (S,G) upstream state is joined and join timer is running\n Error: {}".format( tc_name, result - ) + )) step("r3: Verify (S, G) ip mroutes") oif = "r3-r1-eth0" @@ -1863,22 +1937,42 @@ def test_RP_configured_as_FHR_1_p1(request): input_dict = { "r1": { "pim": { - "rp": [{"rp_addr": "1.0.3.17", "group_addr_range": GROUP_RANGE_ALL,}] + "rp": [ + { + "rp_addr": "1.0.3.17", + "group_addr_range": GROUP_RANGE_ALL, + } + ] } }, "r2": { "pim": { - "rp": [{"rp_addr": "1.0.3.17", "group_addr_range": GROUP_RANGE_ALL,}] + "rp": [ + { + "rp_addr": "1.0.3.17", + "group_addr_range": GROUP_RANGE_ALL, + } + ] } }, "r3": { "pim": { - "rp": [{"rp_addr": "1.0.3.17", "group_addr_range": GROUP_RANGE_ALL,}] + "rp": [ + { + "rp_addr": "1.0.3.17", + "group_addr_range": GROUP_RANGE_ALL, + } + ] } }, "r4": { "pim": { - "rp": [{"rp_addr": "1.0.3.17", "group_addr_range": GROUP_RANGE_ALL,}] + "rp": [ + { + "rp_addr": "1.0.3.17", + "group_addr_range": GROUP_RANGE_ALL, + } + ] } }, } @@ -1942,9 +2036,10 @@ def test_RP_configured_as_FHR_1_p1(request): result = verify_join_state_and_timer( tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS, expected=False ) - assert result is not True, "Testcase {} :Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r3: (S,G) upstream state is joined and join timer is running\n Error: {}".format( tc_name, result - ) + )) step("r3: Verify (S, G) ip mroutes") oif = "r3-r1-eth0" @@ -2050,22 +2145,42 @@ def test_RP_configured_as_FHR_2_p2(request): input_dict = { "r1": { "pim": { - "rp": [{"rp_addr": "1.0.3.17", "group_addr_range": GROUP_RANGE_ALL,}] + "rp": [ + { + "rp_addr": "1.0.3.17", + "group_addr_range": GROUP_RANGE_ALL, + } + ] } }, "r2": { "pim": { - "rp": [{"rp_addr": "1.0.3.17", "group_addr_range": GROUP_RANGE_ALL,}] + "rp": [ + { + "rp_addr": "1.0.3.17", + "group_addr_range": GROUP_RANGE_ALL, + } + ] } }, "r3": { "pim": { - "rp": [{"rp_addr": "1.0.3.17", "group_addr_range": GROUP_RANGE_ALL,}] + "rp": [ + { + "rp_addr": "1.0.3.17", + "group_addr_range": GROUP_RANGE_ALL, + } + ] } }, "r4": { "pim": { - "rp": [{"rp_addr": "1.0.3.17", "group_addr_range": GROUP_RANGE_ALL,}] + "rp": [ + { + "rp_addr": "1.0.3.17", + "group_addr_range": GROUP_RANGE_ALL, + } + ] } }, } @@ -2130,9 +2245,10 @@ def test_RP_configured_as_FHR_2_p2(request): result = verify_join_state_and_timer( tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS, expected=False ) - assert result is not True, "Testcase {} :Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r3: (S,G) upstream state is joined and join timer is running\n Error: {}".format( tc_name, result - ) + )) step("r3: Verify (S, G) ip mroutes") oif = "r3-r1-eth0" @@ -2256,9 +2372,10 @@ def test_SPT_RPT_path_different_p1(request): result = verify_join_state_and_timer( tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS, expected=False ) - assert result is not True, "Testcase {} :Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r3: (S,G) upstream state is joined and join timer is running\n Error: {}".format( tc_name, result - ) + )) step("r3: Verify (S, G) ip mroutes") oif = "r3-r1-eth0" @@ -2277,9 +2394,10 @@ def test_SPT_RPT_path_different_p1(request): result = verify_join_state_and_timer( tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS, expected=False ) - assert result is not True, "Testcase {} :Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r2: (S,G) upstream state is joined and join timer is running\n Error: {}".format( tc_name, result - ) + )) step("r2: Verify (S, G) ip mroutes") oif = "none" @@ -2505,9 +2623,10 @@ def test_restart_pimd_process_p2(request): result = verify_join_state_and_timer( tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS, expected=False ) - assert result is not True, "Testcase {} :Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r3: (S,G) upstream state is joined and join timer is running\n Error: {}".format( tc_name, result - ) + )) step("r3: Verify (S, G) ip mroutes") oif = "r3-r1-eth0" @@ -2672,9 +2791,10 @@ def test_multiple_groups_same_RP_address_p2(request): result = verify_join_state_and_timer( tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST, expected=False ) - assert result is not True, "Testcase {} :Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r3: (S,G) upstream state is joined and join timer is running\n Error: {}".format( tc_name, result - ) + )) step("r3: Verify (S, G) ip mroutes") oif = "r3-r1-eth0" @@ -2693,9 +2813,10 @@ def test_multiple_groups_same_RP_address_p2(request): result = verify_join_state_and_timer( tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST, expected=False ) - assert result is not True, "Testcase {} :Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r2: (S,G) upstream state is joined and join timer is running\n Error: {}".format( tc_name, result - ) + )) step("r2: Verify (S, G) ip mroutes") oif = "none" @@ -2733,7 +2854,12 @@ def test_multiple_groups_same_RP_address_p2(request): input_dict = { "r1": { "pim": { - "rp": [{"rp_addr": "1.0.2.17", "group_addr_range": GROUP_RANGE_ALL,}] + "rp": [ + { + "rp_addr": "1.0.2.17", + "group_addr_range": GROUP_RANGE_ALL, + } + ] } } } @@ -2806,9 +2932,10 @@ def test_multiple_groups_same_RP_address_p2(request): result = verify_join_state_and_timer( tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST, expected=False ) - assert result is not True, "Testcase {} :Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r2: (S,G) upstream state is joined and join timer is running\n Error: {}".format( tc_name, result - ) + )) step("r2: Verify (S, G) ip mroutes") oif = "none" @@ -2825,9 +2952,10 @@ def test_multiple_groups_same_RP_address_p2(request): result = verify_join_state_and_timer( tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST, expected=False ) - assert result is not True, "Testcase {} :Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r3: (S,G) upstream state is joined and join timer is running\n Error: {}".format( tc_name, result - ) + )) step("r3: Verify (S, G) ip mroutes") oif = "r3-r1-eth0" @@ -2893,12 +3021,22 @@ def test_multiple_groups_different_RP_address_p2(request): input_dict = { "r2": { "pim": { - "rp": [{"rp_addr": "1.0.2.17", "group_addr_range": GROUP_RANGE_LIST_1,}] + "rp": [ + { + "rp_addr": "1.0.2.17", + "group_addr_range": GROUP_RANGE_LIST_1, + } + ] } }, "r4": { "pim": { - "rp": [{"rp_addr": "1.0.4.17", "group_addr_range": GROUP_RANGE_LIST_2,}] + "rp": [ + { + "rp_addr": "1.0.4.17", + "group_addr_range": GROUP_RANGE_LIST_2, + } + ] } }, } @@ -2994,9 +3132,10 @@ def test_multiple_groups_different_RP_address_p2(request): result = verify_join_state_and_timer( tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_1, expected=False ) - assert result is not True, "Testcase {} :Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r2: (S,G) upstream state is joined and join timer is running\n Error: {}".format( tc_name, result - ) + )) step("r2: Verify (S, G) ip mroutes") oif = "none" @@ -3015,9 +3154,10 @@ def test_multiple_groups_different_RP_address_p2(request): result = verify_join_state_and_timer( tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_1, expected=False ) - assert result is not True, "Testcase {} :Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r3: (S,G) upstream state is joined and join timer is running\n Error: {}".format( tc_name, result - ) + )) step("r3: Verify (S, G) ip mroutes") oif = "r3-r1-eth0" @@ -3084,9 +3224,10 @@ def test_multiple_groups_different_RP_address_p2(request): result = verify_join_state_and_timer( tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_2, expected=False ) - assert result is not True, "Testcase {} :Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r4: (S,G) upstream state is joined and join timer is running\n Error: {}".format( tc_name, result - ) + )) step("r4: Verify (S, G) ip mroutes") oif = "none" @@ -3148,12 +3289,22 @@ def test_multiple_groups_different_RP_address_p2(request): input_dict = { "r2": { "pim": { - "rp": [{"rp_addr": "1.0.2.17", "group_addr_range": GROUP_RANGE_LIST_1,}] + "rp": [ + { + "rp_addr": "1.0.2.17", + "group_addr_range": GROUP_RANGE_LIST_1, + } + ] } }, "r4": { "pim": { - "rp": [{"rp_addr": "1.0.4.17", "group_addr_range": GROUP_RANGE_LIST_2,}] + "rp": [ + { + "rp_addr": "1.0.4.17", + "group_addr_range": GROUP_RANGE_LIST_2, + } + ] } }, } @@ -3248,9 +3399,10 @@ def test_multiple_groups_different_RP_address_p2(request): result = verify_join_state_and_timer( tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_1, expected=False ) - assert result is not True, "Testcase {} :Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r2: (S,G) upstream state is joined and join timer is running\n Error: {}".format( tc_name, result - ) + )) step("r2: Verify (S, G) ip mroutes") oif = "none" @@ -3269,9 +3421,10 @@ def test_multiple_groups_different_RP_address_p2(request): result = verify_join_state_and_timer( tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_1, expected=False ) - assert result is not True, "Testcase {} :Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r3: (S,G) upstream state is joined and join timer is running\n Error: {}".format( tc_name, result - ) + )) step("r3: Verify (S, G) ip mroutes") oif = "r3-r1-eth0" @@ -3338,9 +3491,10 @@ def test_multiple_groups_different_RP_address_p2(request): result = verify_join_state_and_timer( tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_2, expected=False ) - assert result is not True, "Testcase {} :Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r4: (S,G) upstream state is joined and join timer is running\n Error: {}".format( tc_name, result - ) + )) step("r4: Verify (S, G) ip mroutes") oif = "none" @@ -3359,9 +3513,10 @@ def test_multiple_groups_different_RP_address_p2(request): result = verify_join_state_and_timer( tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_2, expected=False ) - assert result is not True, "Testcase {} :Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r3: (S,G) upstream state is joined and join timer is running\n Error: {}".format( tc_name, result - ) + )) step("r3: Verify (S, G) ip mroutes") oif = "r3-r1-eth0" @@ -3488,27 +3643,30 @@ def test_shutdown_primary_path_p1(request): iif = "r1-r3-eth2" oif = "r1-r0-eth0" result = verify_ip_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif, expected=False) - assert result is not True, "Testcase {} :Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r1: (*,G) mroutes are not cleared after shut of R1 to R3 link\n Error: {}".format( tc_name, result - ) + )) step("r2: Verify (*, G) ip mroutes") dut = "r2" iif = "lo" oif = "r2-r3-eth1" result = verify_ip_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif, expected=False) - assert result is not True, "Testcase {} :Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r2: (*,G) mroutes are not cleared after shut of R1 to R3 link\n Error: {}".format( tc_name, result - ) + )) step("r3: Verify (*, G) ip mroutes") dut = "r3" iif = "r3-r2-eth1" oif = "r3-r1-eth0" result = verify_ip_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif, expected=False) - assert result is not True, "Testcase {} :Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r3: (*,G) mroutes are not cleared after shut of R1 to R3 link\n Error: {}".format( tc_name, result - ) + )) step("r3: No shutdown the link from R1 to R3 from R3 node") dut = "r3" @@ -3668,18 +3826,20 @@ def test_delete_RP_shut_noshut_upstream_interface_p1(request): iif = "r1-r2-eth1" oif = "r1-r0-eth0" result = verify_ip_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif, expected=False) - assert result is not True, "Testcase {} :Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r1: (*,G) mroutes are not cleared after shut of R1 to R0 link\n Error: {}".format( tc_name, result - ) + )) step("r2: Verify (*, G) ip mroutes cleared") dut = "r2" iif = "lo" oif = "r2-r1-eth0" result = verify_ip_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif, expected=False) - assert result is not True, "Testcase {} :Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r2: (*,G) mroutes are not cleared after shut of R1 to R0 link\n Error: {}".format( tc_name, result - ) + )) write_test_footer(tc_name) @@ -3789,18 +3949,20 @@ def test_delete_RP_shut_noshut_RP_interface_p1(request): iif = "r1-r2-eth1" oif = "r1-r0-eth0" result = verify_ip_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif, expected=False) - assert result is not True, "Testcase {} :Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r1: (*,G) mroutes are not cleared after shut of R1 to R2 and R3 link\n Error: {}".format( tc_name, result - ) + )) step("r2: Verify (*, G) ip mroutes cleared") dut = "r2" iif = "lo" oif = "r2-r1-eth0" result = verify_ip_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif, expected=False) - assert result is not True, "Testcase {} :Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r2: (*,G) mroutes are not cleared after shut of R1 to R2 and R3 link\n Error: {}".format( tc_name, result - ) + )) write_test_footer(tc_name) diff --git a/tests/topotests/ospf-sr-topo1/__init__.py b/tests/topotests/ospf-sr-topo1/__init__.py index e69de29bb2..e69de29bb2 100755..100644 --- a/tests/topotests/ospf-sr-topo1/__init__.py +++ b/tests/topotests/ospf-sr-topo1/__init__.py diff --git a/tests/topotests/ospf-sr-topo1/r1/ospf_srdb.json b/tests/topotests/ospf-sr-topo1/r1/ospf_srdb.json deleted file mode 100644 index 952a26ed10..0000000000 --- a/tests/topotests/ospf-sr-topo1/r1/ospf_srdb.json +++ /dev/null @@ -1,161 +0,0 @@ -{ - "srdbID":"10.0.255.1", - "srNodes":[ - { - "routerID":"10.0.255.2", - "srgbSize":8000, - "srgbLabel":16000, - "srlbSize":1000, - "srlbLabel":15000, - "algorithms":[ - { - "0":"SPF" - } - ], - "extendedPrefix":[ - { - "prefix":"10.0.255.2\/32", - "sid":200, - "inputLabel":20200, - "prefixRoute":[ - { - "outputLabel":3, - "interface":"r1-eth0", - "nexthop":"10.0.0.2" - }, - { - "outputLabel":3, - "interface":"r1-eth1", - "nexthop":"10.0.1.2" - } - ] - } - ] - }, - { - "routerID":"10.0.255.4", - "srgbSize":10000, - "srgbLabel":10000, - "srlbSize":1000, - "srlbLabel":5000, - "algorithms":[ - { - "0":"SPF" - } - ], - "nodeMsd":12, - "extendedPrefix":[ - { - "prefix":"10.0.255.4\/32", - "sid":400, - "inputLabel":20400, - "prefixRoute":[ - { - "outputLabel":16400, - "interface":"r1-eth0", - "nexthop":"10.0.0.2" - }, - { - "outputLabel":16400, - "interface":"r1-eth1", - "nexthop":"10.0.1.2" - } - ] - } - ] - }, - { - "routerID":"10.0.255.3", - "srgbSize":10000, - "srgbLabel":10000, - "srlbSize":1000, - "srlbLabel":5000, - "algorithms":[ - { - "0":"SPF" - } - ], - "nodeMsd":8, - "extendedPrefix":[ - { - "prefix":"10.0.255.3\/32", - "sid":300, - "inputLabel":20300, - "prefixRoute":[ - { - "outputLabel":16300, - "interface":"r1-eth0", - "nexthop":"10.0.0.2" - }, - { - "outputLabel":16300, - "interface":"r1-eth1", - "nexthop":"10.0.1.2" - } - ] - } - ] - }, - { - "routerID":"10.0.255.1", - "srgbSize":10000, - "srgbLabel":20000, - "srlbSize":1000, - "srlbLabel":15000, - "algorithms":[ - { - "0":"SPF" - } - ], - "nodeMsd":16, - "extendedPrefix":[ - { - "prefix":"10.0.255.1\/32", - "sid":100, - "inputLabel":0, - "prefixRoute":[ - { - "outputLabel":0, - "interface":"lo", - "nexthop":"10.0.255.1" - } - ] - } - ], - "extendedLink":[ - { - "prefix":"10.0.0.1\/32", - "sid":"*", - "inputLabel":"*", - "outputLabel":3, - "interface":"r1-eth0", - "nexthop":"10.0.0.2" - }, - { - "prefix":"10.0.0.1\/32", - "sid":"*", - "inputLabel":"*", - "outputLabel":3, - "interface":"r1-eth0", - "nexthop":"10.0.0.2" - }, - { - "prefix":"10.0.1.1\/32", - "sid":"*", - "inputLabel":"*", - "outputLabel":3, - "interface":"r1-eth1", - "nexthop":"10.0.1.2" - }, - { - "prefix":"10.0.1.1\/32", - "sid":"*", - "inputLabel":"*", - "outputLabel":3, - "interface":"r1-eth1", - "nexthop":"10.0.1.2" - } - ] - } - ] -} diff --git a/tests/topotests/ospf-sr-topo1/r1/ospfd.conf b/tests/topotests/ospf-sr-topo1/r1/ospfd.conf deleted file mode 100644 index 0773153a76..0000000000 --- a/tests/topotests/ospf-sr-topo1/r1/ospfd.conf +++ /dev/null @@ -1,27 +0,0 @@ -debug ospf sr -! -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 - router-info area 0.0.0.0 - segment-routing on - segment-routing node-msd 16 - segment-routing global-block 20000 29999 - segment-routing prefix 10.0.255.1/32 index 100 explicit-null -! - diff --git a/tests/topotests/ospf-sr-topo1/r1/zebra.conf b/tests/topotests/ospf-sr-topo1/r1/zebra.conf deleted file mode 100644 index faf71db25c..0000000000 --- a/tests/topotests/ospf-sr-topo1/r1/zebra.conf +++ /dev/null @@ -1,12 +0,0 @@ -! -interface lo - ip address 10.0.255.1/32 -! -interface r1-eth0 - ip address 10.0.0.1/24 -! -interface r1-eth1 - ip address 10.0.1.1/24 -! -ip forwarding -! diff --git a/tests/topotests/ospf-sr-topo1/r1/zebra_mpls.json b/tests/topotests/ospf-sr-topo1/r1/zebra_mpls.json deleted file mode 100644 index 6c87596acb..0000000000 --- a/tests/topotests/ospf-sr-topo1/r1/zebra_mpls.json +++ /dev/null @@ -1,115 +0,0 @@ -[ - { - "inLabel":20200, - "installed":true, - "nexthops":[ - { - "type":"SR (OSPF)", - "outLabel":3, - "outLabelStack":[ - 3 - ], - "distance":150, - "installed":true, - "nexthop":"10.0.1.2" - }, - { - "type":"SR (OSPF)", - "outLabel":3, - "distance":150, - "installed":true, - "nexthop":"10.0.0.2" - } - ] - }, - { - "inLabel":20300, - "installed":true, - "nexthops":[ - { - "type":"SR (OSPF)", - "outLabel":16300, - "outLabelStack":[ - 16300 - ], - "distance":150, - "installed":true, - "nexthop":"10.0.1.2" - } - ] - }, - { - "inLabel":20400, - "installed":true, - "nexthops":[ - { - "type":"SR (OSPF)", - "outLabel":16400, - "outLabelStack":[ - 16400 - ], - "distance":150, - "installed":true, - "nexthop":"10.0.1.2" - } - ] - }, - { - "inLabel":"*", - "installed":true, - "nexthops":[ - { - "type":"SR (OSPF)", - "outLabel":3, - "distance":150, - "installed":true, - "nexthop":"10.0.0.2" - } - ] - }, - { - "inLabel":"*", - "installed":true, - "nexthops":[ - { - "type":"SR (OSPF)", - "outLabel":3, - "distance":150, - "installed":true, - "nexthop":"10.0.0.2" - } - ] - }, - { - "inLabel":"*", - "installed":true, - "nexthops":[ - { - "type":"SR (OSPF)", - "outLabel":3, - "outLabelStack":[ - 3 - ], - "distance":150, - "installed":true, - "nexthop":"10.0.1.2" - } - ] - }, - { - "inLabel":"*", - "installed":true, - "nexthops":[ - { - "type":"SR (OSPF)", - "outLabel":3, - "outLabelStack":[ - 3 - ], - "distance":150, - "installed":true, - "nexthop":"10.0.1.2" - } - ] - } -] diff --git a/tests/topotests/ospf-sr-topo1/r2/ospf_srdb.json b/tests/topotests/ospf-sr-topo1/r2/ospf_srdb.json deleted file mode 100644 index 1de780d84e..0000000000 --- a/tests/topotests/ospf-sr-topo1/r2/ospf_srdb.json +++ /dev/null @@ -1,183 +0,0 @@ -{ - "srdbID":"10.0.255.2", - "srNodes":[ - { - "routerID":"10.0.255.2", - "srgbSize":8000, - "srgbLabel":16000, - "srlbSize":1000, - "srlbLabel":15000, - "algorithms":[ - { - "0":"SPF" - } - ], - "extendedPrefix":[ - { - "prefix":"10.0.255.2\/32", - "sid":200, - "inputLabel":0, - "prefixRoute":[ - { - "outputLabel":0, - "interface":"lo", - "nexthop":"10.0.255.2" - } - ] - } - ], - "extendedLink":[ - { - "prefix":"10.0.4.2\/32", - "sid":"*", - "inputLabel":"*", - "outputLabel":3, - "interface":"r2-eth3", - "nexthop":"10.0.4.1" - }, - { - "prefix":"10.0.4.2\/32", - "sid":"*", - "inputLabel":"*", - "outputLabel":3, - "interface":"r2-eth3", - "nexthop":"10.0.4.1" - }, - { - "prefix":"10.0.0.2\/32", - "sid":"*", - "inputLabel":"*", - "outputLabel":3, - "interface":"r2-eth0", - "nexthop":"10.0.0.1" - }, - { - "prefix":"10.0.0.2\/32", - "sid":"*", - "inputLabel":"*", - "outputLabel":3, - "interface":"r2-eth0", - "nexthop":"10.0.0.1" - }, - { - "prefix":"10.0.1.2\/32", - "sid":"*", - "inputLabel":"*", - "outputLabel":3, - "interface":"r2-eth1", - "nexthop":"10.0.1.1" - }, - { - "prefix":"10.0.1.2\/32", - "sid":"*", - "inputLabel":"*", - "outputLabel":3, - "interface":"r2-eth1", - "nexthop":"10.0.1.1" - }, - { - "prefix":"10.0.3.2\/32", - "sid":"*", - "inputLabel":"*", - "outputLabel":3, - "interface":"r2-eth2", - "nexthop":"10.0.3.1" - }, - { - "prefix":"10.0.3.2\/32", - "sid":"*", - "inputLabel":"*", - "outputLabel":3, - "interface":"r2-eth2", - "nexthop":"10.0.3.1" - } - ] - }, - { - "routerID":"10.0.255.4", - "srgbSize":10000, - "srgbLabel":10000, - "srlbSize":1000, - "srlbLabel":5000, - "algorithms":[ - { - "0":"SPF" - } - ], - "nodeMsd":12, - "extendedPrefix":[ - { - "prefix":"10.0.255.4\/32", - "sid":400, - "inputLabel":16400, - "prefixRoute":[ - { - "outputLabel":10400, - "interface":"r2-eth3", - "nexthop":"10.0.4.1" - } - ] - } - ] - }, - { - "routerID":"10.0.255.3", - "srgbSize":10000, - "srgbLabel":10000, - "srlbSize":1000, - "srlbLabel":5000, - "algorithms":[ - { - "0":"SPF" - } - ], - "nodeMsd":8, - "extendedPrefix":[ - { - "prefix":"10.0.255.3\/32", - "sid":300, - "inputLabel":16300, - "prefixRoute":[ - { - "outputLabel":3, - "interface":"r2-eth2", - "nexthop":"10.0.3.1" - } - ] - } - ] - }, - { - "routerID":"10.0.255.1", - "srgbSize":10000, - "srgbLabel":20000, - "srlbSize":1000, - "srlbLabel":15000, - "algorithms":[ - { - "0":"SPF" - } - ], - "nodeMsd":16, - "extendedPrefix":[ - { - "prefix":"10.0.255.1\/32", - "sid":100, - "inputLabel":16100, - "prefixRoute":[ - { - "outputLabel":0, - "interface":"r2-eth0", - "nexthop":"10.0.0.1" - }, - { - "outputLabel":0, - "interface":"r2-eth1", - "nexthop":"10.0.1.1" - } - ] - } - ] - } - ] -} diff --git a/tests/topotests/ospf-sr-topo1/r2/ospfd.conf b/tests/topotests/ospf-sr-topo1/r2/ospfd.conf deleted file mode 100644 index 92dc2f7cd1..0000000000 --- a/tests/topotests/ospf-sr-topo1/r2/ospfd.conf +++ /dev/null @@ -1,36 +0,0 @@ -! -debug ospf sr -! -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 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 - router-info area 0.0.0.0 - segment-routing on - segment-routing prefix 10.0.255.2/32 index 200 -! diff --git a/tests/topotests/ospf-sr-topo1/r2/zebra.conf b/tests/topotests/ospf-sr-topo1/r2/zebra.conf deleted file mode 100644 index ba1d833f50..0000000000 --- a/tests/topotests/ospf-sr-topo1/r2/zebra.conf +++ /dev/null @@ -1,18 +0,0 @@ -! -interface lo - ip address 10.0.255.2/32 -! -interface r2-eth0 - ip address 10.0.0.2/24 -! -interface r2-eth1 - ip address 10.0.1.2/24 -! -interface r2-eth2 - ip address 10.0.3.2/24 -! -interface r2-eth3 - ip address 10.0.4.2/24 -! -ip forwarding -! diff --git a/tests/topotests/ospf-sr-topo1/r2/zebra_mpls.json b/tests/topotests/ospf-sr-topo1/r2/zebra_mpls.json deleted file mode 100644 index a885e88fc5..0000000000 --- a/tests/topotests/ospf-sr-topo1/r2/zebra_mpls.json +++ /dev/null @@ -1,179 +0,0 @@ -[ - { - "inLabel":16100, - "installed":true, - "nexthops":[ - { - "type":"SR (OSPF)", - "outLabel":0, - "outLabelStack":[ - 0 - ], - "distance":150, - "installed":true, - "nexthop":"10.0.1.1" - }, - { - "type":"SR (OSPF)", - "outLabel":0, - "distance":150, - "installed":true, - "nexthop":"10.0.0.1" - } - ] - }, - { - "inLabel":16300, - "installed":true, - "nexthops":[ - { - "type":"SR (OSPF)", - "outLabel":3, - "outLabelStack":[ - 3 - ], - "distance":150, - "installed":true, - "nexthop":"10.0.3.1" - } - ] - }, - { - "inLabel":16400, - "installed":true, - "nexthops":[ - { - "type":"SR (OSPF)", - "outLabel":10400, - "outLabelStack":[ - 10400 - ], - "distance":150, - "installed":true, - "nexthop":"10.0.4.1" - } - ] - }, - { - "inLabel":"*", - "installed":true, - "nexthops":[ - { - "type":"SR (OSPF)", - "outLabel":3, - "outLabelStack":[ - 3 - ], - "distance":150, - "installed":true, - "nexthop":"10.0.4.1" - } - ] - }, - { - "inLabel":"*", - "installed":true, - "nexthops":[ - { - "type":"SR (OSPF)", - "outLabel":3, - "outLabelStack":[ - 3 - ], - "distance":150, - "installed":true, - "nexthop":"10.0.4.1" - } - ] - }, - { - "inLabel":"*", - "installed":true, - "nexthops":[ - { - "type":"SR (OSPF)", - "outLabel":3, - "outLabelStack":[ - 3 - ], - "distance":150, - "installed":true, - "nexthop":"10.0.0.1" - } - ] - }, - { - "inLabel":"*", - "installed":true, - "nexthops":[ - { - "type":"SR (OSPF)", - "outLabel":3, - "outLabelStack":[ - 3 - ], - "distance":150, - "installed":true, - "nexthop":"10.0.0.1" - } - ] - }, - { - "inLabel":"*", - "installed":true, - "nexthops":[ - { - "type":"SR (OSPF)", - "outLabel":3, - "outLabelStack":[ - 3 - ], - "distance":150, - "installed":true, - "nexthop":"10.0.1.1" - } - ] - }, - { - "inLabel":"*", - "installed":true, - "nexthops":[ - { - "type":"SR (OSPF)", - "outLabel":3, - "outLabelStack":[ - 3 - ], - "distance":150, - "installed":true, - "nexthop":"10.0.1.1" - } - ] - }, - { - "inLabel":"*", - "installed":true, - "nexthops":[ - { - "type":"SR (OSPF)", - "outLabel":3, - "distance":150, - "installed":true, - "nexthop":"10.0.3.1" - } - ] - }, - { - "inLabel":"*", - "installed":true, - "nexthops":[ - { - "type":"SR (OSPF)", - "outLabel":3, - "distance":150, - "installed":true, - "nexthop":"10.0.3.1" - } - ] - } -] diff --git a/tests/topotests/ospf-sr-topo1/r3/ospf_srdb.json b/tests/topotests/ospf-sr-topo1/r3/ospf_srdb.json deleted file mode 100644 index e7371ff593..0000000000 --- a/tests/topotests/ospf-sr-topo1/r3/ospf_srdb.json +++ /dev/null @@ -1,130 +0,0 @@ -{ - "srdbID":"10.0.255.3", - "srNodes":[ - { - "routerID":"10.0.255.2", - "srgbSize":8000, - "srgbLabel":16000, - "srlbSize":1000, - "srlbLabel":15000, - "algorithms":[ - { - "0":"SPF" - } - ], - "extendedPrefix":[ - { - "prefix":"10.0.255.2\/32", - "sid":200, - "inputLabel":10200, - "prefixRoute":[ - { - "outputLabel":3, - "interface":"r3-eth0", - "nexthop":"10.0.3.2" - } - ] - } - ] - }, - { - "routerID":"10.0.255.4", - "srgbSize":10000, - "srgbLabel":10000, - "srlbSize":1000, - "srlbLabel":5000, - "algorithms":[ - { - "0":"SPF" - } - ], - "nodeMsd":12, - "extendedPrefix":[ - { - "prefix":"10.0.255.4\/32", - "sid":400, - "inputLabel":10400, - "prefixRoute":[ - { - "outputLabel":16400, - "interface":"r3-eth0", - "nexthop":"10.0.3.2" - } - ] - } - ] - }, - { - "routerID":"10.0.255.3", - "srgbSize":10000, - "srgbLabel":10000, - "srlbSize":1000, - "srlbLabel":5000, - "algorithms":[ - { - "0":"SPF" - } - ], - "nodeMsd":8, - "extendedPrefix":[ - { - "prefix":"10.0.255.3\/32", - "sid":300, - "inputLabel":0, - "prefixRoute":[ - { - "outputLabel":0, - "interface":"lo", - "nexthop":"10.0.255.3" - } - ] - } - ], - "extendedLink":[ - { - "prefix":"10.0.3.1\/32", - "sid":"*", - "inputLabel":"*", - "outputLabel":3, - "interface":"r3-eth0", - "nexthop":"10.0.3.2" - }, - { - "prefix":"10.0.3.1\/32", - "sid":"*", - "inputLabel":"*", - "outputLabel":3, - "interface":"r3-eth0", - "nexthop":"10.0.3.2" - } - ] - }, - { - "routerID":"10.0.255.1", - "srgbSize":10000, - "srgbLabel":20000, - "srlbSize":1000, - "srlbLabel":15000, - "algorithms":[ - { - "0":"SPF" - } - ], - "nodeMsd":16, - "extendedPrefix":[ - { - "prefix":"10.0.255.1\/32", - "sid":100, - "inputLabel":10100, - "prefixRoute":[ - { - "outputLabel":16100, - "interface":"r3-eth0", - "nexthop":"10.0.3.2" - } - ] - } - ] - } - ] -} diff --git a/tests/topotests/ospf-sr-topo1/r3/ospfd.conf b/tests/topotests/ospf-sr-topo1/r3/ospfd.conf deleted file mode 100644 index e2766f202d..0000000000 --- a/tests/topotests/ospf-sr-topo1/r3/ospfd.conf +++ /dev/null @@ -1,22 +0,0 @@ -! -interface lo - ip ospf area 0.0.0.0 - ip ospf hello-interval 2 - ip ospf dead-interval 10 -! -interface r3-eth0 - 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 - router-info area 0.0.0.0 - segment-routing on - segment-routing local-block 5000 5999 - segment-routing global-block 10000 19999 - segment-routing node-msd 8 - segment-routing prefix 10.0.255.3/32 index 300 -! diff --git a/tests/topotests/ospf-sr-topo1/r3/zebra.conf b/tests/topotests/ospf-sr-topo1/r3/zebra.conf deleted file mode 100644 index ef16a8ca13..0000000000 --- a/tests/topotests/ospf-sr-topo1/r3/zebra.conf +++ /dev/null @@ -1,9 +0,0 @@ -! -interface lo - ip address 10.0.255.3/32 -! -interface r3-eth0 - ip address 10.0.3.1/24 -! -ip forwarding -! diff --git a/tests/topotests/ospf-sr-topo1/r4/ospf_srdb.json b/tests/topotests/ospf-sr-topo1/r4/ospf_srdb.json deleted file mode 100644 index a241b32607..0000000000 --- a/tests/topotests/ospf-sr-topo1/r4/ospf_srdb.json +++ /dev/null @@ -1,130 +0,0 @@ -{ - "srdbID":"10.0.255.4", - "srNodes":[ - { - "routerID":"10.0.255.2", - "srgbSize":8000, - "srgbLabel":16000, - "srlbSize":1000, - "srlbLabel":15000, - "algorithms":[ - { - "0":"SPF" - } - ], - "extendedPrefix":[ - { - "prefix":"10.0.255.2\/32", - "sid":200, - "inputLabel":10200, - "prefixRoute":[ - { - "outputLabel":3, - "interface":"r4-eth0", - "nexthop":"10.0.4.2" - } - ] - } - ] - }, - { - "routerID":"10.0.255.4", - "srgbSize":10000, - "srgbLabel":10000, - "srlbSize":1000, - "srlbLabel":5000, - "algorithms":[ - { - "0":"SPF" - } - ], - "nodeMsd":12, - "extendedPrefix":[ - { - "prefix":"10.0.255.4\/32", - "sid":400, - "inputLabel":10400, - "prefixRoute":[ - { - "outputLabel":3, - "interface":"lo", - "nexthop":"10.0.255.4" - } - ] - } - ], - "extendedLink":[ - { - "prefix":"10.0.4.1\/32", - "sid":"*", - "inputLabel":"*", - "outputLabel":3, - "interface":"r4-eth0", - "nexthop":"10.0.4.2" - }, - { - "prefix":"10.0.4.1\/32", - "sid":"*", - "inputLabel":"*", - "outputLabel":3, - "interface":"r4-eth0", - "nexthop":"10.0.4.2" - } - ] - }, - { - "routerID":"10.0.255.3", - "srgbSize":10000, - "srgbLabel":10000, - "srlbSize":1000, - "srlbLabel":5000, - "algorithms":[ - { - "0":"SPF" - } - ], - "nodeMsd":8, - "extendedPrefix":[ - { - "prefix":"10.0.255.3\/32", - "sid":300, - "inputLabel":10300, - "prefixRoute":[ - { - "outputLabel":16300, - "interface":"r4-eth0", - "nexthop":"10.0.4.2" - } - ] - } - ] - }, - { - "routerID":"10.0.255.1", - "srgbSize":10000, - "srgbLabel":20000, - "srlbSize":1000, - "srlbLabel":15000, - "algorithms":[ - { - "0":"SPF" - } - ], - "nodeMsd":16, - "extendedPrefix":[ - { - "prefix":"10.0.255.1\/32", - "sid":100, - "inputLabel":10100, - "prefixRoute":[ - { - "outputLabel":16100, - "interface":"r4-eth0", - "nexthop":"10.0.4.2" - } - ] - } - ] - } - ] -} diff --git a/tests/topotests/ospf-sr-topo1/r4/ospfd.conf b/tests/topotests/ospf-sr-topo1/r4/ospfd.conf deleted file mode 100644 index e80880af88..0000000000 --- a/tests/topotests/ospf-sr-topo1/r4/ospfd.conf +++ /dev/null @@ -1,23 +0,0 @@ -! -interface lo - ip ospf area 0.0.0.0 - ip ospf hello-interval 2 - ip ospf dead-interval 10 -! -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 - router-info area 0.0.0.0 - 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-sr-topo1/r4/zebra.conf b/tests/topotests/ospf-sr-topo1/r4/zebra.conf deleted file mode 100644 index 428f6f4156..0000000000 --- a/tests/topotests/ospf-sr-topo1/r4/zebra.conf +++ /dev/null @@ -1,9 +0,0 @@ -! -interface lo - ip address 10.0.255.4/32 -! -interface r4-eth0 - ip address 10.0.4.1/24 -! -ip forwarding -! diff --git a/tests/topotests/ospf-sr-topo1/r4/zebra_mpls.json b/tests/topotests/ospf-sr-topo1/r4/zebra_mpls.json deleted file mode 100644 index b5758f29a0..0000000000 --- a/tests/topotests/ospf-sr-topo1/r4/zebra_mpls.json +++ /dev/null @@ -1,97 +0,0 @@ -[ - { - "inLabel":10100, - "installed":true, - "nexthops":[ - { - "type":"SR (OSPF)", - "outLabel":16100, - "outLabelStack":[ - 16100 - ], - "distance":150, - "installed":true, - "nexthop":"10.0.4.2" - } - ] - }, - { - "inLabel":10200, - "installed":true, - "nexthops":[ - { - "type":"SR (OSPF)", - "outLabel":3, - "outLabelStack":[ - 3 - ], - "distance":150, - "installed":true, - "nexthop":"10.0.4.2" - } - ] - }, - { - "inLabel":10300, - "installed":true, - "nexthops":[ - { - "type":"SR (OSPF)", - "outLabel":16300, - "outLabelStack":[ - 16300 - ], - "distance":150, - "installed":true, - "nexthop":"10.0.4.2" - } - ] - }, - { - "inLabel":10400, - "installed":true, - "nexthops":[ - { - "type":"SR (OSPF)", - "outLabel":3, - "outLabelStack":[ - 3 - ], - "distance":150, - "installed":true - } - ] - }, - { - "inLabel":"*", - "installed":true, - "nexthops":[ - { - "type":"SR (OSPF)", - "outLabel":3, - "outLabelStack":[ - 3 - ], - "distance":150, - "installed":true, - "nexthop":"10.0.4.2" - } - ] - }, - { - "inLabel":"*", - "installed":true, - "nexthops":[ - { - "type":"SR (OSPF)", - "outLabel":3, - "outLabelStack":[ - 3 - ], - "distance":150, - "installed":true, - "nexthop":"10.0.4.2" - } - ] - } -] diff --git a/tests/topotests/ospf-sr-topo1/rt1/ospfd.conf b/tests/topotests/ospf-sr-topo1/rt1/ospfd.conf new file mode 100644 index 0000000000..94dba7c061 --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt1/ospfd.conf @@ -0,0 +1,29 @@ +password 1 +hostname rt1 +log file ospfd.log +! +debug ospf sr +debug ospf te +debug ospf event +debug ospf lsa +debug ospf zebra +! +interface lo +! +interface eth-sw1 + ip ospf network broadcast +! +router ospf + ospf router-id 1.1.1.1 + network 1.1.1.1/32 area 0.0.0.0 + network 10.0.0.0/16 area 0.0.0.0 + capability opaque + mpls-te on + mpls-te router-address 1.1.1.1 + router-info area 0.0.0.0 + passive-interface lo + segment-routing on + segment-routing global-block 16000 23999 + segment-routing node-msd 8 + segment-routing prefix 1.1.1.1/32 index 10 +! diff --git a/tests/topotests/ospf-sr-topo1/rt1/step1/show_ip_route.ref b/tests/topotests/ospf-sr-topo1/rt1/step1/show_ip_route.ref new file mode 100644 index 0000000000..374184e60a --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt1/step1/show_ip_route.ref @@ -0,0 +1,289 @@ +{ + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16020 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 17030 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 17050 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16060 + ] + }, + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 17060 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/ospf-sr-topo1/rt1/step1/show_mpls_table.ref b/tests/topotests/ospf-sr-topo1/rt1/step1/show_mpls_table.ref new file mode 100644 index 0000000000..de906c270d --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt1/step1/show_mpls_table.ref @@ -0,0 +1,68 @@ +{ + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.1.2" + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":17030, + "installed":true, + "nexthop":"10.0.1.3" + } + ] + }, + "16040":{ + "inLabel":16040, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16040, + "installed":true, + "nexthop":"10.0.1.2" + } + ] + }, + "16050":{ + "inLabel":16050, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":17050, + "installed":true, + "nexthop":"10.0.1.3" + } + ] + }, + "16060":{ + "inLabel":16060, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.1.2" + }, + { + "type":"SR (OSPF)", + "outLabel":17060, + "installed":true, + "nexthop":"10.0.1.3" + } + ] + } +} diff --git a/tests/topotests/ospf-sr-topo1/rt1/step10/show_ip_route.ref b/tests/topotests/ospf-sr-topo1/rt1/step10/show_ip_route.ref new file mode 100644 index 0000000000..37f73629fd --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt1/step10/show_ip_route.ref @@ -0,0 +1,282 @@ +{ + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16020 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 17030 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 17050 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16060 + ] + }, + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 17060 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/ospf-sr-topo1/rt1/step10/show_mpls_table.ref b/tests/topotests/ospf-sr-topo1/rt1/step10/show_mpls_table.ref new file mode 100644 index 0000000000..2006392564 --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt1/step10/show_mpls_table.ref @@ -0,0 +1,79 @@ +{ + "16010":{ + "inLabel":16010, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":3, + "installed":true + } + ] + }, + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.1.2" + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":17030, + "installed":true, + "nexthop":"10.0.1.3" + } + ] + }, + "16040":{ + "inLabel":16040, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16040, + "installed":true, + "nexthop":"10.0.1.2" + } + ] + }, + "16050":{ + "inLabel":16050, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":17050, + "installed":true, + "nexthop":"10.0.1.3" + } + ] + }, + "16060":{ + "inLabel":16060, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.1.2" + }, + { + "type":"SR (OSPF)", + "outLabel":17060, + "installed":true, + "nexthop":"10.0.1.3" + } + ] + } +} diff --git a/tests/topotests/ospf-sr-topo1/rt1/step2/show_ip_route.ref b/tests/topotests/ospf-sr-topo1/rt1/step2/show_ip_route.ref new file mode 100644 index 0000000000..37f73629fd --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt1/step2/show_ip_route.ref @@ -0,0 +1,282 @@ +{ + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16020 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 17030 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 17050 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16060 + ] + }, + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 17060 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/ospf-sr-topo1/rt1/step2/show_mpls_table.ref b/tests/topotests/ospf-sr-topo1/rt1/step2/show_mpls_table.ref new file mode 100644 index 0000000000..de906c270d --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt1/step2/show_mpls_table.ref @@ -0,0 +1,68 @@ +{ + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.1.2" + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":17030, + "installed":true, + "nexthop":"10.0.1.3" + } + ] + }, + "16040":{ + "inLabel":16040, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16040, + "installed":true, + "nexthop":"10.0.1.2" + } + ] + }, + "16050":{ + "inLabel":16050, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":17050, + "installed":true, + "nexthop":"10.0.1.3" + } + ] + }, + "16060":{ + "inLabel":16060, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.1.2" + }, + { + "type":"SR (OSPF)", + "outLabel":17060, + "installed":true, + "nexthop":"10.0.1.3" + } + ] + } +} diff --git a/tests/topotests/ospf-sr-topo1/rt1/step3/show_ip_route.ref b/tests/topotests/ospf-sr-topo1/rt1/step3/show_ip_route.ref new file mode 100644 index 0000000000..f6ead5cb91 --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt1/step3/show_ip_route.ref @@ -0,0 +1,249 @@ +{ + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16020 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 17030 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 17050 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/ospf-sr-topo1/rt1/step3/show_mpls_table.ref b/tests/topotests/ospf-sr-topo1/rt1/step3/show_mpls_table.ref new file mode 100644 index 0000000000..96e05913ed --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt1/step3/show_mpls_table.ref @@ -0,0 +1,50 @@ +{ + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.1.2" + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":17030, + "installed":true, + "nexthop":"10.0.1.3" + } + ] + }, + "16040":{ + "inLabel":16040, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16040, + "installed":true, + "nexthop":"10.0.1.2" + } + ] + }, + "16050":{ + "inLabel":16050, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":17050, + "installed":true, + "nexthop":"10.0.1.3" + } + ] + } +} diff --git a/tests/topotests/ospf-sr-topo1/rt1/step4/show_ip_route.ref b/tests/topotests/ospf-sr-topo1/rt1/step4/show_ip_route.ref new file mode 100644 index 0000000000..37f73629fd --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt1/step4/show_ip_route.ref @@ -0,0 +1,282 @@ +{ + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16020 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 17030 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 17050 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16060 + ] + }, + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 17060 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/ospf-sr-topo1/rt1/step4/show_mpls_table.ref b/tests/topotests/ospf-sr-topo1/rt1/step4/show_mpls_table.ref new file mode 100644 index 0000000000..de906c270d --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt1/step4/show_mpls_table.ref @@ -0,0 +1,68 @@ +{ + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.1.2" + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":17030, + "installed":true, + "nexthop":"10.0.1.3" + } + ] + }, + "16040":{ + "inLabel":16040, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16040, + "installed":true, + "nexthop":"10.0.1.2" + } + ] + }, + "16050":{ + "inLabel":16050, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":17050, + "installed":true, + "nexthop":"10.0.1.3" + } + ] + }, + "16060":{ + "inLabel":16060, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.1.2" + }, + { + "type":"SR (OSPF)", + "outLabel":17060, + "installed":true, + "nexthop":"10.0.1.3" + } + ] + } +} diff --git a/tests/topotests/ospf-sr-topo1/rt1/step5/show_ip_route.ref b/tests/topotests/ospf-sr-topo1/rt1/step5/show_ip_route.ref new file mode 100644 index 0000000000..f2b8924b85 --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt1/step5/show_ip_route.ref @@ -0,0 +1,276 @@ +{ + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16020 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 17030 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 17050 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/ospf-sr-topo1/rt1/step5/show_mpls_table.ref b/tests/topotests/ospf-sr-topo1/rt1/step5/show_mpls_table.ref new file mode 100644 index 0000000000..96e05913ed --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt1/step5/show_mpls_table.ref @@ -0,0 +1,50 @@ +{ + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.1.2" + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":17030, + "installed":true, + "nexthop":"10.0.1.3" + } + ] + }, + "16040":{ + "inLabel":16040, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16040, + "installed":true, + "nexthop":"10.0.1.2" + } + ] + }, + "16050":{ + "inLabel":16050, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":17050, + "installed":true, + "nexthop":"10.0.1.3" + } + ] + } +} diff --git a/tests/topotests/ospf-sr-topo1/rt1/step6/show_ip_route.ref b/tests/topotests/ospf-sr-topo1/rt1/step6/show_ip_route.ref new file mode 100644 index 0000000000..37f73629fd --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt1/step6/show_ip_route.ref @@ -0,0 +1,282 @@ +{ + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16020 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 17030 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 17050 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16060 + ] + }, + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 17060 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/ospf-sr-topo1/rt1/step6/show_mpls_table.ref b/tests/topotests/ospf-sr-topo1/rt1/step6/show_mpls_table.ref new file mode 100644 index 0000000000..de906c270d --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt1/step6/show_mpls_table.ref @@ -0,0 +1,68 @@ +{ + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.1.2" + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":17030, + "installed":true, + "nexthop":"10.0.1.3" + } + ] + }, + "16040":{ + "inLabel":16040, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16040, + "installed":true, + "nexthop":"10.0.1.2" + } + ] + }, + "16050":{ + "inLabel":16050, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":17050, + "installed":true, + "nexthop":"10.0.1.3" + } + ] + }, + "16060":{ + "inLabel":16060, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.1.2" + }, + { + "type":"SR (OSPF)", + "outLabel":17060, + "installed":true, + "nexthop":"10.0.1.3" + } + ] + } +} diff --git a/tests/topotests/ospf-sr-topo1/rt1/step7/show_ip_route.ref b/tests/topotests/ospf-sr-topo1/rt1/step7/show_ip_route.ref new file mode 100644 index 0000000000..37f73629fd --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt1/step7/show_ip_route.ref @@ -0,0 +1,282 @@ +{ + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16020 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 17030 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 17050 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16060 + ] + }, + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 17060 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/ospf-sr-topo1/rt1/step7/show_mpls_table.ref b/tests/topotests/ospf-sr-topo1/rt1/step7/show_mpls_table.ref new file mode 100644 index 0000000000..de906c270d --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt1/step7/show_mpls_table.ref @@ -0,0 +1,68 @@ +{ + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.1.2" + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":17030, + "installed":true, + "nexthop":"10.0.1.3" + } + ] + }, + "16040":{ + "inLabel":16040, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16040, + "installed":true, + "nexthop":"10.0.1.2" + } + ] + }, + "16050":{ + "inLabel":16050, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":17050, + "installed":true, + "nexthop":"10.0.1.3" + } + ] + }, + "16060":{ + "inLabel":16060, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.1.2" + }, + { + "type":"SR (OSPF)", + "outLabel":17060, + "installed":true, + "nexthop":"10.0.1.3" + } + ] + } +} diff --git a/tests/topotests/ospf-sr-topo1/rt1/step8/show_ip_route.ref b/tests/topotests/ospf-sr-topo1/rt1/step8/show_ip_route.ref new file mode 100644 index 0000000000..37f73629fd --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt1/step8/show_ip_route.ref @@ -0,0 +1,282 @@ +{ + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16020 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 17030 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 17050 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16060 + ] + }, + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 17060 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/ospf-sr-topo1/rt1/step8/show_mpls_table.ref b/tests/topotests/ospf-sr-topo1/rt1/step8/show_mpls_table.ref new file mode 100644 index 0000000000..de906c270d --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt1/step8/show_mpls_table.ref @@ -0,0 +1,68 @@ +{ + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.1.2" + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":17030, + "installed":true, + "nexthop":"10.0.1.3" + } + ] + }, + "16040":{ + "inLabel":16040, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16040, + "installed":true, + "nexthop":"10.0.1.2" + } + ] + }, + "16050":{ + "inLabel":16050, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":17050, + "installed":true, + "nexthop":"10.0.1.3" + } + ] + }, + "16060":{ + "inLabel":16060, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.1.2" + }, + { + "type":"SR (OSPF)", + "outLabel":17060, + "installed":true, + "nexthop":"10.0.1.3" + } + ] + } +} diff --git a/tests/topotests/ospf-sr-topo1/rt1/step9/show_ip_route.ref b/tests/topotests/ospf-sr-topo1/rt1/step9/show_ip_route.ref new file mode 100644 index 0000000000..37f73629fd --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt1/step9/show_ip_route.ref @@ -0,0 +1,282 @@ +{ + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16020 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 17030 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 17050 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16060 + ] + }, + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 17060 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/ospf-sr-topo1/rt1/step9/show_mpls_table.ref b/tests/topotests/ospf-sr-topo1/rt1/step9/show_mpls_table.ref new file mode 100644 index 0000000000..2006392564 --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt1/step9/show_mpls_table.ref @@ -0,0 +1,79 @@ +{ + "16010":{ + "inLabel":16010, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":3, + "installed":true + } + ] + }, + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.1.2" + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":17030, + "installed":true, + "nexthop":"10.0.1.3" + } + ] + }, + "16040":{ + "inLabel":16040, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16040, + "installed":true, + "nexthop":"10.0.1.2" + } + ] + }, + "16050":{ + "inLabel":16050, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":17050, + "installed":true, + "nexthop":"10.0.1.3" + } + ] + }, + "16060":{ + "inLabel":16060, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.1.2" + }, + { + "type":"SR (OSPF)", + "outLabel":17060, + "installed":true, + "nexthop":"10.0.1.3" + } + ] + } +} diff --git a/tests/topotests/ospf-sr-topo1/rt1/zebra.conf b/tests/topotests/ospf-sr-topo1/rt1/zebra.conf new file mode 100644 index 0000000000..7d3139a80e --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt1/zebra.conf @@ -0,0 +1,18 @@ +log file zebra.log +! +hostname rt1 +! +debug zebra kernel +debug zebra packet +debug zebra mpls +! +interface lo + ip address 1.1.1.1/32 +! +interface eth-sw1 + ip address 10.0.1.1/24 +! +ip forwarding +! +line vty +! diff --git a/tests/topotests/ospf-sr-topo1/rt2/ospfd.conf b/tests/topotests/ospf-sr-topo1/rt2/ospfd.conf new file mode 100644 index 0000000000..b47e788062 --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt2/ospfd.conf @@ -0,0 +1,35 @@ +password 1 +hostname rt2 +log file ospfd.log +! +debug ospf sr +debug ospf te +debug ospf event +debug ospf lsa +debug ospf zebra +! +interface lo +! +interface eth-sw1 + ip ospf network broadcast +! +interface eth-rt4-1 + ip ospf network point-to-point +! +interface eth-rt4-2 + ip ospf network point-to-point +! +router ospf + ospf router-id 2.2.2.2 + network 2.2.2.2/32 area 0.0.0.0 + network 10.0.0.0/16 area 0.0.0.0 + capability opaque + mpls-te on + mpls-te router-address 2.2.2.2 + router-info area 0.0.0.0 + passive-interface lo + segment-routing on + segment-routing global-block 16000 23999 + segment-routing node-msd 8 + segment-routing prefix 2.2.2.2/32 index 20 no-php-flag +! diff --git a/tests/topotests/ospf-sr-topo1/rt2/step1/show_ip_route.ref b/tests/topotests/ospf-sr-topo1/rt2/step1/show_ip_route.ref new file mode 100644 index 0000000000..3dde042b51 --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt2/step1/show_ip_route.ref @@ -0,0 +1,330 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 3 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 17030 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true, + "labels":[ + 16040 + ] + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 17050 + ] + }, + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true, + "labels":[ + 16050 + ] + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "labels":[ + 16050 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true, + "labels":[ + 16060 + ] + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "labels":[ + 16060 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt4-1", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/ospf-sr-topo1/rt2/step1/show_mpls_table.ref b/tests/topotests/ospf-sr-topo1/rt2/step1/show_mpls_table.ref new file mode 100644 index 0000000000..eba7c403d3 --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt2/step1/show_mpls_table.ref @@ -0,0 +1,97 @@ +{ + "16010":{ + "inLabel":16010, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.1.1" + } + ] + }, + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":3, + "installed":true + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":17030, + "installed":true, + "nexthop":"10.0.1.3" + } + ] + }, + "16040":{ + "inLabel":16040, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16040, + "installed":true, + "nexthop":"10.0.2.4" + }, + { + "type":"SR (OSPF)", + "outLabel":16040, + "installed":true, + "nexthop":"10.0.3.4" + } + ] + }, + "16050":{ + "inLabel":16050, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16050, + "installed":true, + "nexthop":"10.0.2.4" + }, + { + "type":"SR (OSPF)", + "outLabel":16050, + "installed":true, + "nexthop":"10.0.3.4" + }, + { + "type":"SR (OSPF)", + "outLabel":17050, + "installed":true, + "nexthop":"10.0.1.3" + } + ] + }, + "16060":{ + "inLabel":16060, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.2.4" + }, + { + "type":"SR (OSPF)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.3.4" + } + ] + } +} diff --git a/tests/topotests/ospf-sr-topo1/rt2/step10/show_ip_route.ref b/tests/topotests/ospf-sr-topo1/rt2/step10/show_ip_route.ref new file mode 100644 index 0000000000..9a06059df2 --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt2/step10/show_ip_route.ref @@ -0,0 +1,254 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16010 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 17030 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 17050 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "labels":[ + 16060 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/ospf-sr-topo1/rt2/step10/show_mpls_table.ref b/tests/topotests/ospf-sr-topo1/rt2/step10/show_mpls_table.ref new file mode 100644 index 0000000000..be44a7521d --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt2/step10/show_mpls_table.ref @@ -0,0 +1,73 @@ +{ + "16010":{ + "inLabel":16010, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.1.1" + } + ] + }, + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":3, + "installed":true + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":17030, + "installed":true, + "nexthop":"10.0.1.3" + } + ] + }, + "16040":{ + "inLabel":16040, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16040, + "installed":true, + "nexthop":"10.0.3.4" + } + ] + }, + "16050":{ + "inLabel":16050, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":17050, + "installed":true, + "nexthop":"10.0.1.3" + } + ] + }, + "16060":{ + "inLabel":16060, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.3.4" + } + ] + } +} diff --git a/tests/topotests/ospf-sr-topo1/rt2/step2/show_ip_route.ref b/tests/topotests/ospf-sr-topo1/rt2/step2/show_ip_route.ref new file mode 100644 index 0000000000..384aac032d --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt2/step2/show_ip_route.ref @@ -0,0 +1,303 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 3 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 17030 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true, + "labels":[ + 16040 + ] + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 17050 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true, + "labels":[ + 16060 + ] + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "labels":[ + 16060 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt4-1", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/ospf-sr-topo1/rt2/step2/show_mpls_table.ref b/tests/topotests/ospf-sr-topo1/rt2/step2/show_mpls_table.ref new file mode 100644 index 0000000000..5088aa2f7a --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt2/step2/show_mpls_table.ref @@ -0,0 +1,85 @@ +{ + "16010":{ + "inLabel":16010, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.1.1" + } + ] + }, + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":3, + "installed":true + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":17030, + "installed":true, + "nexthop":"10.0.1.3" + } + ] + }, + "16040":{ + "inLabel":16040, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16040, + "installed":true, + "nexthop":"10.0.2.4" + }, + { + "type":"SR (OSPF)", + "outLabel":16040, + "installed":true, + "nexthop":"10.0.3.4" + } + ] + }, + "16050":{ + "inLabel":16050, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":17050, + "installed":true, + "nexthop":"10.0.1.3" + } + ] + }, + "16060":{ + "inLabel":16060, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.2.4" + }, + { + "type":"SR (OSPF)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.3.4" + } + ] + } +} diff --git a/tests/topotests/ospf-sr-topo1/rt2/step3/show_ip_route.ref b/tests/topotests/ospf-sr-topo1/rt2/step3/show_ip_route.ref new file mode 100644 index 0000000000..879cd1e0c5 --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt2/step3/show_ip_route.ref @@ -0,0 +1,256 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 3 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 17030 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true, + "labels":[ + 16040 + ] + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 17050 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt4-1", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/ospf-sr-topo1/rt2/step3/show_mpls_table.ref b/tests/topotests/ospf-sr-topo1/rt2/step3/show_mpls_table.ref new file mode 100644 index 0000000000..6333e7f7f9 --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt2/step3/show_mpls_table.ref @@ -0,0 +1,67 @@ +{ + "16010":{ + "inLabel":16010, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.1.1" + } + ] + }, + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":3, + "installed":true + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":17030, + "installed":true, + "nexthop":"10.0.1.3" + } + ] + }, + "16040":{ + "inLabel":16040, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16040, + "installed":true, + "nexthop":"10.0.2.4" + }, + { + "type":"SR (OSPF)", + "outLabel":16040, + "installed":true, + "nexthop":"10.0.3.4" + } + ] + }, + "16050":{ + "inLabel":16050, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":17050, + "installed":true, + "nexthop":"10.0.1.3" + } + ] + } +} diff --git a/tests/topotests/ospf-sr-topo1/rt2/step4/show_ip_route.ref b/tests/topotests/ospf-sr-topo1/rt2/step4/show_ip_route.ref new file mode 100644 index 0000000000..384aac032d --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt2/step4/show_ip_route.ref @@ -0,0 +1,303 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 3 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 17030 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true, + "labels":[ + 16040 + ] + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 17050 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true, + "labels":[ + 16060 + ] + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "labels":[ + 16060 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt4-1", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/ospf-sr-topo1/rt2/step4/show_mpls_table.ref b/tests/topotests/ospf-sr-topo1/rt2/step4/show_mpls_table.ref new file mode 100644 index 0000000000..5088aa2f7a --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt2/step4/show_mpls_table.ref @@ -0,0 +1,85 @@ +{ + "16010":{ + "inLabel":16010, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.1.1" + } + ] + }, + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":3, + "installed":true + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":17030, + "installed":true, + "nexthop":"10.0.1.3" + } + ] + }, + "16040":{ + "inLabel":16040, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16040, + "installed":true, + "nexthop":"10.0.2.4" + }, + { + "type":"SR (OSPF)", + "outLabel":16040, + "installed":true, + "nexthop":"10.0.3.4" + } + ] + }, + "16050":{ + "inLabel":16050, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":17050, + "installed":true, + "nexthop":"10.0.1.3" + } + ] + }, + "16060":{ + "inLabel":16060, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.2.4" + }, + { + "type":"SR (OSPF)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.3.4" + } + ] + } +} diff --git a/tests/topotests/ospf-sr-topo1/rt2/step5/show_ip_route.ref b/tests/topotests/ospf-sr-topo1/rt2/step5/show_ip_route.ref new file mode 100644 index 0000000000..07edd42dc8 --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt2/step5/show_ip_route.ref @@ -0,0 +1,297 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 3 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 17030 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true, + "labels":[ + 16040 + ] + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 17050 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt4-1", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/ospf-sr-topo1/rt2/step5/show_mpls_table.ref b/tests/topotests/ospf-sr-topo1/rt2/step5/show_mpls_table.ref new file mode 100644 index 0000000000..6333e7f7f9 --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt2/step5/show_mpls_table.ref @@ -0,0 +1,67 @@ +{ + "16010":{ + "inLabel":16010, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.1.1" + } + ] + }, + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":3, + "installed":true + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":17030, + "installed":true, + "nexthop":"10.0.1.3" + } + ] + }, + "16040":{ + "inLabel":16040, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16040, + "installed":true, + "nexthop":"10.0.2.4" + }, + { + "type":"SR (OSPF)", + "outLabel":16040, + "installed":true, + "nexthop":"10.0.3.4" + } + ] + }, + "16050":{ + "inLabel":16050, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":17050, + "installed":true, + "nexthop":"10.0.1.3" + } + ] + } +} diff --git a/tests/topotests/ospf-sr-topo1/rt2/step6/show_ip_route.ref b/tests/topotests/ospf-sr-topo1/rt2/step6/show_ip_route.ref new file mode 100644 index 0000000000..384aac032d --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt2/step6/show_ip_route.ref @@ -0,0 +1,303 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 3 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 17030 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true, + "labels":[ + 16040 + ] + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 17050 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true, + "labels":[ + 16060 + ] + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "labels":[ + 16060 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt4-1", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/ospf-sr-topo1/rt2/step6/show_mpls_table.ref b/tests/topotests/ospf-sr-topo1/rt2/step6/show_mpls_table.ref new file mode 100644 index 0000000000..5088aa2f7a --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt2/step6/show_mpls_table.ref @@ -0,0 +1,85 @@ +{ + "16010":{ + "inLabel":16010, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.1.1" + } + ] + }, + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":3, + "installed":true + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":17030, + "installed":true, + "nexthop":"10.0.1.3" + } + ] + }, + "16040":{ + "inLabel":16040, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16040, + "installed":true, + "nexthop":"10.0.2.4" + }, + { + "type":"SR (OSPF)", + "outLabel":16040, + "installed":true, + "nexthop":"10.0.3.4" + } + ] + }, + "16050":{ + "inLabel":16050, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":17050, + "installed":true, + "nexthop":"10.0.1.3" + } + ] + }, + "16060":{ + "inLabel":16060, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.2.4" + }, + { + "type":"SR (OSPF)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.3.4" + } + ] + } +} diff --git a/tests/topotests/ospf-sr-topo1/rt2/step7/show_ip_route.ref b/tests/topotests/ospf-sr-topo1/rt2/step7/show_ip_route.ref new file mode 100644 index 0000000000..274931bef7 --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt2/step7/show_ip_route.ref @@ -0,0 +1,300 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 17030 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true, + "labels":[ + 16040 + ] + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 17050 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true, + "labels":[ + 16060 + ] + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "labels":[ + 16060 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt4-1", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/ospf-sr-topo1/rt2/step7/show_mpls_table.ref b/tests/topotests/ospf-sr-topo1/rt2/step7/show_mpls_table.ref new file mode 100644 index 0000000000..cd23725a80 --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt2/step7/show_mpls_table.ref @@ -0,0 +1,73 @@ +{ + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":3, + "installed":true + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":17030, + "installed":true, + "nexthop":"10.0.1.3" + } + ] + }, + "16040":{ + "inLabel":16040, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16040, + "installed":true, + "nexthop":"10.0.2.4" + }, + { + "type":"SR (OSPF)", + "outLabel":16040, + "installed":true, + "nexthop":"10.0.3.4" + } + ] + }, + "16050":{ + "inLabel":16050, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":17050, + "installed":true, + "nexthop":"10.0.1.3" + } + ] + }, + "16060":{ + "inLabel":16060, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.2.4" + }, + { + "type":"SR (OSPF)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.3.4" + } + ] + } +} diff --git a/tests/topotests/ospf-sr-topo1/rt2/step8/show_ip_route.ref b/tests/topotests/ospf-sr-topo1/rt2/step8/show_ip_route.ref new file mode 100644 index 0000000000..384aac032d --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt2/step8/show_ip_route.ref @@ -0,0 +1,303 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 3 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 17030 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true, + "labels":[ + 16040 + ] + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 17050 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true, + "labels":[ + 16060 + ] + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "labels":[ + 16060 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt4-1", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/ospf-sr-topo1/rt2/step8/show_mpls_table.ref b/tests/topotests/ospf-sr-topo1/rt2/step8/show_mpls_table.ref new file mode 100644 index 0000000000..5088aa2f7a --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt2/step8/show_mpls_table.ref @@ -0,0 +1,85 @@ +{ + "16010":{ + "inLabel":16010, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.1.1" + } + ] + }, + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":3, + "installed":true + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":17030, + "installed":true, + "nexthop":"10.0.1.3" + } + ] + }, + "16040":{ + "inLabel":16040, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16040, + "installed":true, + "nexthop":"10.0.2.4" + }, + { + "type":"SR (OSPF)", + "outLabel":16040, + "installed":true, + "nexthop":"10.0.3.4" + } + ] + }, + "16050":{ + "inLabel":16050, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":17050, + "installed":true, + "nexthop":"10.0.1.3" + } + ] + }, + "16060":{ + "inLabel":16060, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.2.4" + }, + { + "type":"SR (OSPF)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.3.4" + } + ] + } +} diff --git a/tests/topotests/ospf-sr-topo1/rt2/step9/show_ip_route.ref b/tests/topotests/ospf-sr-topo1/rt2/step9/show_ip_route.ref new file mode 100644 index 0000000000..c71515f3ff --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt2/step9/show_ip_route.ref @@ -0,0 +1,303 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16010 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 17030 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true, + "labels":[ + 16040 + ] + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 17050 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true, + "labels":[ + 16060 + ] + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "labels":[ + 16060 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt4-1", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/ospf-sr-topo1/rt2/step9/show_mpls_table.ref b/tests/topotests/ospf-sr-topo1/rt2/step9/show_mpls_table.ref new file mode 100644 index 0000000000..2f06641f7f --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt2/step9/show_mpls_table.ref @@ -0,0 +1,85 @@ +{ + "16010":{ + "inLabel":16010, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.1.1" + } + ] + }, + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":3, + "installed":true + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":17030, + "installed":true, + "nexthop":"10.0.1.3" + } + ] + }, + "16040":{ + "inLabel":16040, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16040, + "installed":true, + "nexthop":"10.0.2.4" + }, + { + "type":"SR (OSPF)", + "outLabel":16040, + "installed":true, + "nexthop":"10.0.3.4" + } + ] + }, + "16050":{ + "inLabel":16050, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":17050, + "installed":true, + "nexthop":"10.0.1.3" + } + ] + }, + "16060":{ + "inLabel":16060, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.2.4" + }, + { + "type":"SR (OSPF)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.3.4" + } + ] + } +} diff --git a/tests/topotests/ospf-sr-topo1/rt2/zebra.conf b/tests/topotests/ospf-sr-topo1/rt2/zebra.conf new file mode 100644 index 0000000000..c4ed4276d9 --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt2/zebra.conf @@ -0,0 +1,24 @@ +log file zebra.log +! +hostname rt2 +! +debug zebra kernel +debug zebra packet +debug zebra mpls +! +interface lo + ip address 2.2.2.2/32 +! +interface eth-sw1 + ip address 10.0.1.2/24 +! +interface eth-rt4-1 + ip address 10.0.2.2/24 +! +interface eth-rt4-2 + ip address 10.0.3.2/24 +! +ip forwarding +! +line vty +! diff --git a/tests/topotests/ospf-sr-topo1/rt3/ospfd.conf b/tests/topotests/ospf-sr-topo1/rt3/ospfd.conf new file mode 100644 index 0000000000..238d82ff97 --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt3/ospfd.conf @@ -0,0 +1,35 @@ +password 1 +hostname rt3 +log file ospfd.log +! +debug ospf sr +debug ospf te +debug ospf event +debug ospf lsa +debug ospf zebra +! +interface lo +! +interface eth-sw1 + ip ospf network broadcast +! +interface eth-rt5-1 + ip ospf network point-to-point +! +interface eth-rt5-2 + ip ospf network point-to-point +! +router ospf + ospf router-id 3.3.3.3 + network 3.3.3.3/32 area 0.0.0.0 + network 10.0.0.0/16 area 0.0.0.0 + capability opaque + mpls-te on + mpls-te router-address 3.3.3.3 + router-info area 0.0.0.0 + passive-interface lo + segment-routing on + segment-routing global-block 17000 24999 + segment-routing node-msd 8 + segment-routing prefix 3.3.3.3/32 index 30 no-php-flag +! diff --git a/tests/topotests/ospf-sr-topo1/rt3/step1/show_ip_route.ref b/tests/topotests/ospf-sr-topo1/rt3/step1/show_ip_route.ref new file mode 100644 index 0000000000..4b1500ef97 --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt3/step1/show_ip_route.ref @@ -0,0 +1,330 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 3 + ] + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16020 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16040 + ] + }, + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "labels":[ + 16040 + ] + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "labels":[ + 16050 + ] + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "labels":[ + 16050 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "labels":[ + 16060 + ] + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "labels":[ + 16060 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt5-1", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/ospf-sr-topo1/rt3/step1/show_mpls_table.ref b/tests/topotests/ospf-sr-topo1/rt3/step1/show_mpls_table.ref new file mode 100644 index 0000000000..39cc3e8ffd --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt3/step1/show_mpls_table.ref @@ -0,0 +1,97 @@ +{ + "17010":{ + "inLabel":17010, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.1.1" + } + ] + }, + "17020":{ + "inLabel":17020, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.1.2" + } + ] + }, + "17030":{ + "inLabel":17030, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":3, + "installed":true + } + ] + }, + "17040":{ + "inLabel":17040, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16040, + "installed":true, + "nexthop":"10.0.5.5" + }, + { + "type":"SR (OSPF)", + "outLabel":16040, + "installed":true, + "nexthop":"10.0.4.5" + }, + { + "type":"SR (OSPF)", + "outLabel":16040, + "installed":true, + "nexthop":"10.0.1.2" + } + ] + }, + "17050":{ + "inLabel":17050, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16050, + "installed":true, + "nexthop":"10.0.5.5" + }, + { + "type":"SR (OSPF)", + "outLabel":16050, + "installed":true, + "nexthop":"10.0.4.5" + } + ] + }, + "17060":{ + "inLabel":17060, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.5.5" + }, + { + "type":"SR (OSPF)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.4.5" + } + ] + } +} diff --git a/tests/topotests/ospf-sr-topo1/rt3/step10/show_ip_route.ref b/tests/topotests/ospf-sr-topo1/rt3/step10/show_ip_route.ref new file mode 100644 index 0000000000..14a2ac1e8a --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt3/step10/show_ip_route.ref @@ -0,0 +1,310 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16010 + ] + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16020 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "labels":[ + 16050 + ] + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "labels":[ + 16050 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "labels":[ + 16060 + ] + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "labels":[ + 16060 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt5-1", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/ospf-sr-topo1/rt3/step10/show_mpls_table.ref b/tests/topotests/ospf-sr-topo1/rt3/step10/show_mpls_table.ref new file mode 100644 index 0000000000..a0f7c790a0 --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt3/step10/show_mpls_table.ref @@ -0,0 +1,85 @@ +{ + "17010":{ + "inLabel":17010, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.1.1" + } + ] + }, + "17020":{ + "inLabel":17020, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.1.2" + } + ] + }, + "17030":{ + "inLabel":17030, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":3, + "installed":true + } + ] + }, + "17040":{ + "inLabel":17040, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16040, + "installed":true, + "nexthop":"10.0.1.2" + } + ] + }, + "17050":{ + "inLabel":17050, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16050, + "installed":true, + "nexthop":"10.0.5.5" + }, + { + "type":"SR (OSPF)", + "outLabel":16050, + "installed":true, + "nexthop":"10.0.4.5" + } + ] + }, + "17060":{ + "inLabel":17060, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.5.5" + }, + { + "type":"SR (OSPF)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.4.5" + } + ] + } +} diff --git a/tests/topotests/ospf-sr-topo1/rt3/step2/show_ip_route.ref b/tests/topotests/ospf-sr-topo1/rt3/step2/show_ip_route.ref new file mode 100644 index 0000000000..63c6a1845f --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt3/step2/show_ip_route.ref @@ -0,0 +1,310 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 3 + ] + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16020 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "labels":[ + 16050 + ] + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "labels":[ + 16050 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "labels":[ + 16060 + ] + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "labels":[ + 16060 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt5-1", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/ospf-sr-topo1/rt3/step2/show_mpls_table.ref b/tests/topotests/ospf-sr-topo1/rt3/step2/show_mpls_table.ref new file mode 100644 index 0000000000..1ab2242b7e --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt3/step2/show_mpls_table.ref @@ -0,0 +1,85 @@ +{ + "17010":{ + "inLabel":17010, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.1.1" + } + ] + }, + "17020":{ + "inLabel":17020, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.1.2" + } + ] + }, + "17030":{ + "inLabel":17030, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":3, + "installed":true + } + ] + }, + "17040":{ + "inLabel":17040, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16040, + "installed":true, + "nexthop":"10.0.1.2" + } + ] + }, + "17050":{ + "inLabel":17050, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16050, + "installed":true, + "nexthop":"10.0.5.5" + }, + { + "type":"SR (OSPF)", + "outLabel":16050, + "installed":true, + "nexthop":"10.0.4.5" + } + ] + }, + "17060":{ + "inLabel":17060, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.5.5" + }, + { + "type":"SR (OSPF)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.4.5" + } + ] + } +} diff --git a/tests/topotests/ospf-sr-topo1/rt3/step3/show_ip_route.ref b/tests/topotests/ospf-sr-topo1/rt3/step3/show_ip_route.ref new file mode 100644 index 0000000000..0894c51cf2 --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt3/step3/show_ip_route.ref @@ -0,0 +1,263 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 3 + ] + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16020 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "labels":[ + 16050 + ] + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "labels":[ + 16050 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt5-1", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/ospf-sr-topo1/rt3/step3/show_mpls_table.ref b/tests/topotests/ospf-sr-topo1/rt3/step3/show_mpls_table.ref new file mode 100644 index 0000000000..4dcaedeca1 --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt3/step3/show_mpls_table.ref @@ -0,0 +1,67 @@ +{ + "17010":{ + "inLabel":17010, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.1.1" + } + ] + }, + "17020":{ + "inLabel":17020, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.1.2" + } + ] + }, + "17030":{ + "inLabel":17030, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":3, + "installed":true + } + ] + }, + "17040":{ + "inLabel":17040, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16040, + "installed":true, + "nexthop":"10.0.1.2" + } + ] + }, + "17050":{ + "inLabel":17050, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16050, + "installed":true, + "nexthop":"10.0.5.5" + }, + { + "type":"SR (OSPF)", + "outLabel":16050, + "installed":true, + "nexthop":"10.0.4.5" + } + ] + } +} diff --git a/tests/topotests/ospf-sr-topo1/rt3/step4/show_ip_route.ref b/tests/topotests/ospf-sr-topo1/rt3/step4/show_ip_route.ref new file mode 100644 index 0000000000..63c6a1845f --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt3/step4/show_ip_route.ref @@ -0,0 +1,310 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 3 + ] + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16020 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "labels":[ + 16050 + ] + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "labels":[ + 16050 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "labels":[ + 16060 + ] + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "labels":[ + 16060 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt5-1", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/ospf-sr-topo1/rt3/step4/show_mpls_table.ref b/tests/topotests/ospf-sr-topo1/rt3/step4/show_mpls_table.ref new file mode 100644 index 0000000000..1ab2242b7e --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt3/step4/show_mpls_table.ref @@ -0,0 +1,85 @@ +{ + "17010":{ + "inLabel":17010, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.1.1" + } + ] + }, + "17020":{ + "inLabel":17020, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.1.2" + } + ] + }, + "17030":{ + "inLabel":17030, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":3, + "installed":true + } + ] + }, + "17040":{ + "inLabel":17040, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16040, + "installed":true, + "nexthop":"10.0.1.2" + } + ] + }, + "17050":{ + "inLabel":17050, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16050, + "installed":true, + "nexthop":"10.0.5.5" + }, + { + "type":"SR (OSPF)", + "outLabel":16050, + "installed":true, + "nexthop":"10.0.4.5" + } + ] + }, + "17060":{ + "inLabel":17060, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.5.5" + }, + { + "type":"SR (OSPF)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.4.5" + } + ] + } +} diff --git a/tests/topotests/ospf-sr-topo1/rt3/step5/show_ip_route.ref b/tests/topotests/ospf-sr-topo1/rt3/step5/show_ip_route.ref new file mode 100644 index 0000000000..3e74ff039c --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt3/step5/show_ip_route.ref @@ -0,0 +1,304 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 3 + ] + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16020 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "labels":[ + 16050 + ] + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "labels":[ + 16050 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt5-1", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/ospf-sr-topo1/rt3/step5/show_mpls_table.ref b/tests/topotests/ospf-sr-topo1/rt3/step5/show_mpls_table.ref new file mode 100644 index 0000000000..4dcaedeca1 --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt3/step5/show_mpls_table.ref @@ -0,0 +1,67 @@ +{ + "17010":{ + "inLabel":17010, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.1.1" + } + ] + }, + "17020":{ + "inLabel":17020, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.1.2" + } + ] + }, + "17030":{ + "inLabel":17030, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":3, + "installed":true + } + ] + }, + "17040":{ + "inLabel":17040, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16040, + "installed":true, + "nexthop":"10.0.1.2" + } + ] + }, + "17050":{ + "inLabel":17050, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16050, + "installed":true, + "nexthop":"10.0.5.5" + }, + { + "type":"SR (OSPF)", + "outLabel":16050, + "installed":true, + "nexthop":"10.0.4.5" + } + ] + } +} diff --git a/tests/topotests/ospf-sr-topo1/rt3/step6/show_ip_route.ref b/tests/topotests/ospf-sr-topo1/rt3/step6/show_ip_route.ref new file mode 100644 index 0000000000..63c6a1845f --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt3/step6/show_ip_route.ref @@ -0,0 +1,310 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 3 + ] + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16020 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "labels":[ + 16050 + ] + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "labels":[ + 16050 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "labels":[ + 16060 + ] + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "labels":[ + 16060 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt5-1", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/ospf-sr-topo1/rt3/step6/show_mpls_table.ref b/tests/topotests/ospf-sr-topo1/rt3/step6/show_mpls_table.ref new file mode 100644 index 0000000000..1ab2242b7e --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt3/step6/show_mpls_table.ref @@ -0,0 +1,85 @@ +{ + "17010":{ + "inLabel":17010, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.1.1" + } + ] + }, + "17020":{ + "inLabel":17020, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.1.2" + } + ] + }, + "17030":{ + "inLabel":17030, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":3, + "installed":true + } + ] + }, + "17040":{ + "inLabel":17040, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16040, + "installed":true, + "nexthop":"10.0.1.2" + } + ] + }, + "17050":{ + "inLabel":17050, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16050, + "installed":true, + "nexthop":"10.0.5.5" + }, + { + "type":"SR (OSPF)", + "outLabel":16050, + "installed":true, + "nexthop":"10.0.4.5" + } + ] + }, + "17060":{ + "inLabel":17060, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.5.5" + }, + { + "type":"SR (OSPF)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.4.5" + } + ] + } +} diff --git a/tests/topotests/ospf-sr-topo1/rt3/step7/show_ip_route.ref b/tests/topotests/ospf-sr-topo1/rt3/step7/show_ip_route.ref new file mode 100644 index 0000000000..41544d4296 --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt3/step7/show_ip_route.ref @@ -0,0 +1,307 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16020 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "labels":[ + 16050 + ] + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "labels":[ + 16050 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "labels":[ + 16060 + ] + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "labels":[ + 16060 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt5-1", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/ospf-sr-topo1/rt3/step7/show_mpls_table.ref b/tests/topotests/ospf-sr-topo1/rt3/step7/show_mpls_table.ref new file mode 100644 index 0000000000..bf055bad78 --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt3/step7/show_mpls_table.ref @@ -0,0 +1,73 @@ +{ + "17020":{ + "inLabel":17020, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.1.2" + } + ] + }, + "17030":{ + "inLabel":17030, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":3, + "installed":true + } + ] + }, + "17040":{ + "inLabel":17040, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16040, + "installed":true, + "nexthop":"10.0.1.2" + } + ] + }, + "17050":{ + "inLabel":17050, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16050, + "installed":true, + "nexthop":"10.0.5.5" + }, + { + "type":"SR (OSPF)", + "outLabel":16050, + "installed":true, + "nexthop":"10.0.4.5" + } + ] + }, + "17060":{ + "inLabel":17060, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.5.5" + }, + { + "type":"SR (OSPF)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.4.5" + } + ] + } +} diff --git a/tests/topotests/ospf-sr-topo1/rt3/step8/show_ip_route.ref b/tests/topotests/ospf-sr-topo1/rt3/step8/show_ip_route.ref new file mode 100644 index 0000000000..63c6a1845f --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt3/step8/show_ip_route.ref @@ -0,0 +1,310 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 3 + ] + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16020 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "labels":[ + 16050 + ] + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "labels":[ + 16050 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "labels":[ + 16060 + ] + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "labels":[ + 16060 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt5-1", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/ospf-sr-topo1/rt3/step8/show_mpls_table.ref b/tests/topotests/ospf-sr-topo1/rt3/step8/show_mpls_table.ref new file mode 100644 index 0000000000..1ab2242b7e --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt3/step8/show_mpls_table.ref @@ -0,0 +1,85 @@ +{ + "17010":{ + "inLabel":17010, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.1.1" + } + ] + }, + "17020":{ + "inLabel":17020, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.1.2" + } + ] + }, + "17030":{ + "inLabel":17030, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":3, + "installed":true + } + ] + }, + "17040":{ + "inLabel":17040, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16040, + "installed":true, + "nexthop":"10.0.1.2" + } + ] + }, + "17050":{ + "inLabel":17050, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16050, + "installed":true, + "nexthop":"10.0.5.5" + }, + { + "type":"SR (OSPF)", + "outLabel":16050, + "installed":true, + "nexthop":"10.0.4.5" + } + ] + }, + "17060":{ + "inLabel":17060, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.5.5" + }, + { + "type":"SR (OSPF)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.4.5" + } + ] + } +} diff --git a/tests/topotests/ospf-sr-topo1/rt3/step9/show_ip_route.ref b/tests/topotests/ospf-sr-topo1/rt3/step9/show_ip_route.ref new file mode 100644 index 0000000000..14a2ac1e8a --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt3/step9/show_ip_route.ref @@ -0,0 +1,310 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16010 + ] + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16020 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "labels":[ + 16050 + ] + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "labels":[ + 16050 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "labels":[ + 16060 + ] + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "labels":[ + 16060 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt5-1", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/ospf-sr-topo1/rt3/step9/show_mpls_table.ref b/tests/topotests/ospf-sr-topo1/rt3/step9/show_mpls_table.ref new file mode 100644 index 0000000000..a0f7c790a0 --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt3/step9/show_mpls_table.ref @@ -0,0 +1,85 @@ +{ + "17010":{ + "inLabel":17010, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.1.1" + } + ] + }, + "17020":{ + "inLabel":17020, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.1.2" + } + ] + }, + "17030":{ + "inLabel":17030, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":3, + "installed":true + } + ] + }, + "17040":{ + "inLabel":17040, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16040, + "installed":true, + "nexthop":"10.0.1.2" + } + ] + }, + "17050":{ + "inLabel":17050, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16050, + "installed":true, + "nexthop":"10.0.5.5" + }, + { + "type":"SR (OSPF)", + "outLabel":16050, + "installed":true, + "nexthop":"10.0.4.5" + } + ] + }, + "17060":{ + "inLabel":17060, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.5.5" + }, + { + "type":"SR (OSPF)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.4.5" + } + ] + } +} diff --git a/tests/topotests/ospf-sr-topo1/rt3/zebra.conf b/tests/topotests/ospf-sr-topo1/rt3/zebra.conf new file mode 100644 index 0000000000..89a781fe3c --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt3/zebra.conf @@ -0,0 +1,24 @@ +log file zebra.log +! +hostname rt3 +! +debug zebra kernel +debug zebra packet +debug zebra mpls +! +interface lo + ip address 3.3.3.3/32 +! +interface eth-sw1 + ip address 10.0.1.3/24 +! +interface eth-rt5-1 + ip address 10.0.4.3/24 +! +interface eth-rt5-2 + ip address 10.0.5.3/24 +! +ip forwarding +! +line vty +! diff --git a/tests/topotests/ospf-sr-topo1/rt4/ospfd.conf b/tests/topotests/ospf-sr-topo1/rt4/ospfd.conf new file mode 100644 index 0000000000..b12e0729ad --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt4/ospfd.conf @@ -0,0 +1,38 @@ +password 1 +hostname rt4 +log file ospfd.log +! +debug ospf sr +debug ospf te +debug ospf event +debug ospf lsa +debug ospf zebra +! +interface lo +! +interface eth-rt2-1 + ip ospf network point-to-point +! +interface eth-rt2-2 + ip ospf network point-to-point +! +interface eth-rt5 + ip ospf network point-to-point +! +interface eth-rt6 + ip ospf network point-to-point +! +router ospf + ospf router-id 4.4.4.4 + network 4.4.4.4/32 area 0.0.0.0 + network 10.0.0.0/16 area 0.0.0.0 + capability opaque + mpls-te on + mpls-te router-address 4.4.4.4 + router-info area 0.0.0.0 + passive-interface lo + segment-routing on + segment-routing global-block 16000 23999 + segment-routing node-msd 8 + segment-routing prefix 4.4.4.4/32 index 40 no-php-flag +! diff --git a/tests/topotests/ospf-sr-topo1/rt4/step1/show_ip_route.ref b/tests/topotests/ospf-sr-topo1/rt4/step1/show_ip_route.ref new file mode 100644 index 0000000000..4a2d3aa10f --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt4/step1/show_ip_route.ref @@ -0,0 +1,311 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true, + "labels":[ + 16010 + ] + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true, + "labels":[ + 16010 + ] + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true, + "labels":[ + 16020 + ] + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true, + "labels":[ + 16020 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true, + "labels":[ + 16030 + ] + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true, + "labels":[ + 16030 + ] + }, + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16030 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16050 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true, + "labels":[ + 0 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt2-1", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + }, + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/ospf-sr-topo1/rt4/step1/show_mpls_table.ref b/tests/topotests/ospf-sr-topo1/rt4/step1/show_mpls_table.ref new file mode 100644 index 0000000000..3246d22842 --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt4/step1/show_mpls_table.ref @@ -0,0 +1,97 @@ +{ + "16010":{ + "inLabel":16010, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.2.2" + }, + { + "type":"SR (OSPF)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.3.2" + } + ] + }, + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.2.2" + }, + { + "type":"SR (OSPF)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.3.2" + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16030, + "installed":true, + "nexthop":"10.0.2.2" + }, + { + "type":"SR (OSPF)", + "outLabel":16030, + "installed":true, + "nexthop":"10.0.3.2" + }, + { + "type":"SR (OSPF)", + "outLabel":16030, + "installed":true, + "nexthop":"10.0.6.5" + } + ] + }, + "16040":{ + "inLabel":16040, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":3, + "installed":true + } + ] + }, + "16050":{ + "inLabel":16050, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16050, + "installed":true, + "nexthop":"10.0.6.5" + } + ] + }, + "16060":{ + "inLabel":16060, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":0, + "installed":true, + "nexthop":"10.0.7.6" + } + ] + } +} diff --git a/tests/topotests/ospf-sr-topo1/rt4/step10/show_ip_route.ref b/tests/topotests/ospf-sr-topo1/rt4/step10/show_ip_route.ref new file mode 100644 index 0000000000..db4cf5b3f5 --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt4/step10/show_ip_route.ref @@ -0,0 +1,278 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true, + "labels":[ + 16010 + ] + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true, + "labels":[ + 16020 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true, + "labels":[ + 16030 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true, + "labels":[ + 18050 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true, + "labels":[ + 3 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + }, + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + }, + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"ospf", + "distance":110, + "metric":30, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/ospf-sr-topo1/r3/zebra_mpls.json b/tests/topotests/ospf-sr-topo1/rt4/step10/show_mpls_table.ref index 1b98ff4756..58cf526a83 100644 --- a/tests/topotests/ospf-sr-topo1/r3/zebra_mpls.json +++ b/tests/topotests/ospf-sr-topo1/rt4/step10/show_mpls_table.ref @@ -1,82 +1,73 @@ -[ - { - "inLabel":10100, +{ + "16010":{ + "inLabel":16010, "installed":true, "nexthops":[ { "type":"SR (OSPF)", - "outLabel":16100, - "outLabelStack":[ - 16100 - ], - "distance":150, + "outLabel":16010, "installed":true, "nexthop":"10.0.3.2" } ] }, - { - "inLabel":10200, + "16020":{ + "inLabel":16020, "installed":true, "nexthops":[ { "type":"SR (OSPF)", - "outLabel":3, - "outLabelStack":[ - 3 - ], - "distance":150, + "outLabel":16020, "installed":true, "nexthop":"10.0.3.2" } ] }, - { - "inLabel":10400, + "16030":{ + "inLabel":16030, "installed":true, "nexthops":[ { "type":"SR (OSPF)", - "outLabel":16400, - "outLabelStack":[ - 16400 - ], - "distance":150, + "outLabel":16030, "installed":true, "nexthop":"10.0.3.2" } ] }, - { - "inLabel":"*", + "16040":{ + "inLabel":16040, "installed":true, "nexthops":[ { "type":"SR (OSPF)", "outLabel":3, - "outLabelStack":[ - 3 - ], - "distance":150, + "installed":true + } + ] + }, + "16050":{ + "inLabel":16050, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":18050, "installed":true, - "nexthop":"10.0.3.2" + "nexthop":"10.0.7.6" } ] }, - { - "inLabel":"*", + "16060":{ + "inLabel":16060, "installed":true, "nexthops":[ { "type":"SR (OSPF)", "outLabel":3, - "outLabelStack":[ - 3 - ], - "distance":150, "installed":true, - "nexthop":"10.0.3.2" + "nexthop":"10.0.7.6" } ] } -] +} diff --git a/tests/topotests/ospf-sr-topo1/rt4/step2/show_ip_route.ref b/tests/topotests/ospf-sr-topo1/rt4/step2/show_ip_route.ref new file mode 100644 index 0000000000..c44b3eef30 --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt4/step2/show_ip_route.ref @@ -0,0 +1,324 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true, + "labels":[ + 16010 + ] + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true, + "labels":[ + 16010 + ] + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true, + "labels":[ + 16020 + ] + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true, + "labels":[ + 16020 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true, + "labels":[ + 16030 + ] + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true, + "labels":[ + 16030 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true, + "labels":[ + 16050 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true, + "labels":[ + 0 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt2-1", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + }, + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + }, + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"ospf", + "distance":110, + "metric":30, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/ospf-sr-topo1/rt4/step2/show_mpls_table.ref b/tests/topotests/ospf-sr-topo1/rt4/step2/show_mpls_table.ref new file mode 100644 index 0000000000..05f9f28cbd --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt4/step2/show_mpls_table.ref @@ -0,0 +1,91 @@ +{ + "16010":{ + "inLabel":16010, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.2.2" + }, + { + "type":"SR (OSPF)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.3.2" + } + ] + }, + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.2.2" + }, + { + "type":"SR (OSPF)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.3.2" + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16030, + "installed":true, + "nexthop":"10.0.2.2" + }, + { + "type":"SR (OSPF)", + "outLabel":16030, + "installed":true, + "nexthop":"10.0.3.2" + } + ] + }, + "16040":{ + "inLabel":16040, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":3, + "installed":true + } + ] + }, + "16050":{ + "inLabel":16050, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16050, + "installed":true, + "nexthop":"10.0.7.6" + } + ] + }, + "16060":{ + "inLabel":16060, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":0, + "installed":true, + "nexthop":"10.0.7.6" + } + ] + } +} diff --git a/tests/topotests/ospf-sr-topo1/rt4/step3/show_ip_route.ref b/tests/topotests/ospf-sr-topo1/rt4/step3/show_ip_route.ref new file mode 100644 index 0000000000..a078dd2daf --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt4/step3/show_ip_route.ref @@ -0,0 +1,296 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true, + "labels":[ + 16010 + ] + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true, + "labels":[ + 16010 + ] + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true, + "labels":[ + 16020 + ] + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true, + "labels":[ + 16020 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true, + "labels":[ + 16030 + ] + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true, + "labels":[ + 16030 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true, + "labels":[ + 16050 + ] + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true, + "labels":[ + 16050 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt2-1", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"ospf", + "distance":110, + "metric":40, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/ospf-sr-topo1/rt4/step3/show_mpls_table.ref b/tests/topotests/ospf-sr-topo1/rt4/step3/show_mpls_table.ref new file mode 100644 index 0000000000..f5515636d2 --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt4/step3/show_mpls_table.ref @@ -0,0 +1,85 @@ +{ + "16010":{ + "inLabel":16010, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.2.2" + }, + { + "type":"SR (OSPF)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.3.2" + } + ] + }, + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.2.2" + }, + { + "type":"SR (OSPF)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.3.2" + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16030, + "installed":true, + "nexthop":"10.0.2.2" + }, + { + "type":"SR (OSPF)", + "outLabel":16030, + "installed":true, + "nexthop":"10.0.3.2" + } + ] + }, + "16040":{ + "inLabel":16040, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":3, + "installed":true + } + ] + }, + "16050":{ + "inLabel":16050, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16050, + "installed":true, + "nexthop":"10.0.2.2" + }, + { + "type":"SR (OSPF)", + "outLabel":16050, + "installed":true, + "nexthop":"10.0.3.2" + } + ] + } +} diff --git a/tests/topotests/ospf-sr-topo1/rt4/step4/show_ip_route.ref b/tests/topotests/ospf-sr-topo1/rt4/step4/show_ip_route.ref new file mode 100644 index 0000000000..b63812ab1d --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt4/step4/show_ip_route.ref @@ -0,0 +1,324 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true, + "labels":[ + 16010 + ] + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true, + "labels":[ + 16010 + ] + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true, + "labels":[ + 16020 + ] + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true, + "labels":[ + 16020 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true, + "labels":[ + 16030 + ] + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true, + "labels":[ + 16030 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true, + "labels":[ + 18050 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true, + "labels":[ + 0 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt2-1", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + }, + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + }, + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"ospf", + "distance":110, + "metric":30, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/ospf-sr-topo1/rt4/step4/show_mpls_table.ref b/tests/topotests/ospf-sr-topo1/rt4/step4/show_mpls_table.ref new file mode 100644 index 0000000000..f2e56c2e19 --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt4/step4/show_mpls_table.ref @@ -0,0 +1,91 @@ +{ + "16010":{ + "inLabel":16010, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.2.2" + }, + { + "type":"SR (OSPF)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.3.2" + } + ] + }, + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.2.2" + }, + { + "type":"SR (OSPF)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.3.2" + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16030, + "installed":true, + "nexthop":"10.0.2.2" + }, + { + "type":"SR (OSPF)", + "outLabel":16030, + "installed":true, + "nexthop":"10.0.3.2" + } + ] + }, + "16040":{ + "inLabel":16040, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":3, + "installed":true + } + ] + }, + "16050":{ + "inLabel":16050, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":18050, + "installed":true, + "nexthop":"10.0.7.6" + } + ] + }, + "16060":{ + "inLabel":16060, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":0, + "installed":true, + "nexthop":"10.0.7.6" + } + ] + } +} diff --git a/tests/topotests/ospf-sr-topo1/rt4/step5/show_ip_route.ref b/tests/topotests/ospf-sr-topo1/rt4/step5/show_ip_route.ref new file mode 100644 index 0000000000..3157ae1ea1 --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt4/step5/show_ip_route.ref @@ -0,0 +1,318 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true, + "labels":[ + 16010 + ] + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true, + "labels":[ + 16010 + ] + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true, + "labels":[ + 16020 + ] + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true, + "labels":[ + 16020 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true, + "labels":[ + 16030 + ] + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true, + "labels":[ + 16030 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt2-1", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + }, + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + }, + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"ospf", + "distance":110, + "metric":30, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/ospf-sr-topo1/rt4/step5/show_mpls_table.ref b/tests/topotests/ospf-sr-topo1/rt4/step5/show_mpls_table.ref new file mode 100644 index 0000000000..8213840652 --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt4/step5/show_mpls_table.ref @@ -0,0 +1,67 @@ +{ + "16010":{ + "inLabel":16010, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.2.2" + }, + { + "type":"SR (OSPF)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.3.2" + } + ] + }, + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.2.2" + }, + { + "type":"SR (OSPF)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.3.2" + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16030, + "installed":true, + "nexthop":"10.0.2.2" + }, + { + "type":"SR (OSPF)", + "outLabel":16030, + "installed":true, + "nexthop":"10.0.3.2" + } + ] + }, + "16040":{ + "inLabel":16040, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":3, + "installed":true + } + ] + } +} diff --git a/tests/topotests/ospf-sr-topo1/rt4/step6/show_ip_route.ref b/tests/topotests/ospf-sr-topo1/rt4/step6/show_ip_route.ref new file mode 100644 index 0000000000..b63812ab1d --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt4/step6/show_ip_route.ref @@ -0,0 +1,324 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true, + "labels":[ + 16010 + ] + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true, + "labels":[ + 16010 + ] + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true, + "labels":[ + 16020 + ] + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true, + "labels":[ + 16020 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true, + "labels":[ + 16030 + ] + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true, + "labels":[ + 16030 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true, + "labels":[ + 18050 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true, + "labels":[ + 0 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt2-1", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + }, + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + }, + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"ospf", + "distance":110, + "metric":30, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/ospf-sr-topo1/rt4/step6/show_mpls_table.ref b/tests/topotests/ospf-sr-topo1/rt4/step6/show_mpls_table.ref new file mode 100644 index 0000000000..f2e56c2e19 --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt4/step6/show_mpls_table.ref @@ -0,0 +1,91 @@ +{ + "16010":{ + "inLabel":16010, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.2.2" + }, + { + "type":"SR (OSPF)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.3.2" + } + ] + }, + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.2.2" + }, + { + "type":"SR (OSPF)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.3.2" + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16030, + "installed":true, + "nexthop":"10.0.2.2" + }, + { + "type":"SR (OSPF)", + "outLabel":16030, + "installed":true, + "nexthop":"10.0.3.2" + } + ] + }, + "16040":{ + "inLabel":16040, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":3, + "installed":true + } + ] + }, + "16050":{ + "inLabel":16050, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":18050, + "installed":true, + "nexthop":"10.0.7.6" + } + ] + }, + "16060":{ + "inLabel":16060, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":0, + "installed":true, + "nexthop":"10.0.7.6" + } + ] + } +} diff --git a/tests/topotests/ospf-sr-topo1/rt4/step7/show_ip_route.ref b/tests/topotests/ospf-sr-topo1/rt4/step7/show_ip_route.ref new file mode 100644 index 0000000000..775d8c4034 --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt4/step7/show_ip_route.ref @@ -0,0 +1,318 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true, + "labels":[ + 16020 + ] + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true, + "labels":[ + 16020 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true, + "labels":[ + 16030 + ] + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true, + "labels":[ + 16030 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true, + "labels":[ + 18050 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true, + "labels":[ + 0 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt2-1", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + }, + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + }, + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"ospf", + "distance":110, + "metric":30, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/ospf-sr-topo1/rt4/step7/show_mpls_table.ref b/tests/topotests/ospf-sr-topo1/rt4/step7/show_mpls_table.ref new file mode 100644 index 0000000000..8a5fdef806 --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt4/step7/show_mpls_table.ref @@ -0,0 +1,73 @@ +{ + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.2.2" + }, + { + "type":"SR (OSPF)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.3.2" + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16030, + "installed":true, + "nexthop":"10.0.2.2" + }, + { + "type":"SR (OSPF)", + "outLabel":16030, + "installed":true, + "nexthop":"10.0.3.2" + } + ] + }, + "16040":{ + "inLabel":16040, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":3, + "installed":true + } + ] + }, + "16050":{ + "inLabel":16050, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":18050, + "installed":true, + "nexthop":"10.0.7.6" + } + ] + }, + "16060":{ + "inLabel":16060, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":0, + "installed":true, + "nexthop":"10.0.7.6" + } + ] + } +} diff --git a/tests/topotests/ospf-sr-topo1/rt4/step8/show_ip_route.ref b/tests/topotests/ospf-sr-topo1/rt4/step8/show_ip_route.ref new file mode 100644 index 0000000000..b63812ab1d --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt4/step8/show_ip_route.ref @@ -0,0 +1,324 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true, + "labels":[ + 16010 + ] + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true, + "labels":[ + 16010 + ] + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true, + "labels":[ + 16020 + ] + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true, + "labels":[ + 16020 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true, + "labels":[ + 16030 + ] + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true, + "labels":[ + 16030 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true, + "labels":[ + 18050 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true, + "labels":[ + 0 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt2-1", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + }, + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + }, + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"ospf", + "distance":110, + "metric":30, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/ospf-sr-topo1/rt4/step8/show_mpls_table.ref b/tests/topotests/ospf-sr-topo1/rt4/step8/show_mpls_table.ref new file mode 100644 index 0000000000..f2e56c2e19 --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt4/step8/show_mpls_table.ref @@ -0,0 +1,91 @@ +{ + "16010":{ + "inLabel":16010, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.2.2" + }, + { + "type":"SR (OSPF)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.3.2" + } + ] + }, + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.2.2" + }, + { + "type":"SR (OSPF)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.3.2" + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16030, + "installed":true, + "nexthop":"10.0.2.2" + }, + { + "type":"SR (OSPF)", + "outLabel":16030, + "installed":true, + "nexthop":"10.0.3.2" + } + ] + }, + "16040":{ + "inLabel":16040, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":3, + "installed":true + } + ] + }, + "16050":{ + "inLabel":16050, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":18050, + "installed":true, + "nexthop":"10.0.7.6" + } + ] + }, + "16060":{ + "inLabel":16060, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":0, + "installed":true, + "nexthop":"10.0.7.6" + } + ] + } +} diff --git a/tests/topotests/ospf-sr-topo1/rt4/step9/show_ip_route.ref b/tests/topotests/ospf-sr-topo1/rt4/step9/show_ip_route.ref new file mode 100644 index 0000000000..48e306d393 --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt4/step9/show_ip_route.ref @@ -0,0 +1,324 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true, + "labels":[ + 16010 + ] + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true, + "labels":[ + 16010 + ] + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true, + "labels":[ + 16020 + ] + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true, + "labels":[ + 16020 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true, + "labels":[ + 16030 + ] + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true, + "labels":[ + 16030 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true, + "labels":[ + 18050 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true, + "labels":[ + 3 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt2-1", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + }, + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + }, + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"ospf", + "distance":110, + "metric":30, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/ospf-sr-topo1/rt4/step9/show_mpls_table.ref b/tests/topotests/ospf-sr-topo1/rt4/step9/show_mpls_table.ref new file mode 100644 index 0000000000..275abab715 --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt4/step9/show_mpls_table.ref @@ -0,0 +1,91 @@ +{ + "16010":{ + "inLabel":16010, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.2.2" + }, + { + "type":"SR (OSPF)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.3.2" + } + ] + }, + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.2.2" + }, + { + "type":"SR (OSPF)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.3.2" + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16030, + "installed":true, + "nexthop":"10.0.2.2" + }, + { + "type":"SR (OSPF)", + "outLabel":16030, + "installed":true, + "nexthop":"10.0.3.2" + } + ] + }, + "16040":{ + "inLabel":16040, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":3, + "installed":true + } + ] + }, + "16050":{ + "inLabel":16050, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":18050, + "installed":true, + "nexthop":"10.0.7.6" + } + ] + }, + "16060":{ + "inLabel":16060, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.7.6" + } + ] + } +} diff --git a/tests/topotests/ospf-sr-topo1/rt4/zebra.conf b/tests/topotests/ospf-sr-topo1/rt4/zebra.conf new file mode 100644 index 0000000000..13c621eb31 --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt4/zebra.conf @@ -0,0 +1,27 @@ +log file zebra.log +! +hostname rt4 +! +debug zebra kernel +debug zebra packet +debug zebra mpls +! +interface lo + ip address 4.4.4.4/32 +! +interface eth-rt2-1 + ip address 10.0.2.4/24 +! +interface eth-rt2-2 + ip address 10.0.3.4/24 +! +interface eth-rt5 + ip address 10.0.6.4/24 +! +interface eth-rt6 + ip address 10.0.7.4/24 +! +ip forwarding +! +line vty +! diff --git a/tests/topotests/ospf-sr-topo1/rt5/ospfd.conf b/tests/topotests/ospf-sr-topo1/rt5/ospfd.conf new file mode 100644 index 0000000000..4e7b24c03a --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt5/ospfd.conf @@ -0,0 +1,38 @@ +password 1 +hostname rt5 +log file ospfd.log +! +debug ospf sr +debug ospf te +debug ospf event +debug ospf lsa +debug ospf zebra +! +interface lo +! +interface eth-rt3-1 + ip ospf network point-to-point +! +interface eth-rt3-2 + ip ospf network point-to-point +! +interface eth-rt4 + ip ospf network point-to-point +! +interface eth-rt6 + ip ospf network point-to-point +! +router ospf + ospf router-id 5.5.5.5 + network 5.5.5.5/32 area 0.0.0.0 + network 10.0.0.0/16 area 0.0.0.0 + capability opaque + mpls-te on + mpls-te router-address 5.5.5.5 + router-info area 0.0.0.0 + passive-interface lo + segment-routing on + segment-routing global-block 16000 23999 + segment-routing node-msd 8 + segment-routing prefix 5.5.5.5/32 index 50 no-php-flag +! diff --git a/tests/topotests/ospf-sr-topo1/rt5/step1/show_ip_route.ref b/tests/topotests/ospf-sr-topo1/rt5/step1/show_ip_route.ref new file mode 100644 index 0000000000..0a43788a18 --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt5/step1/show_ip_route.ref @@ -0,0 +1,311 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true, + "labels":[ + 17010 + ] + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true, + "labels":[ + 17010 + ] + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true, + "labels":[ + 17020 + ] + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true, + "labels":[ + 17020 + ] + }, + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16020 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true, + "labels":[ + 17030 + ] + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true, + "labels":[ + 17030 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true, + "labels":[ + 0 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt3-1", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/ospf-sr-topo1/rt5/step1/show_mpls_table.ref b/tests/topotests/ospf-sr-topo1/rt5/step1/show_mpls_table.ref new file mode 100644 index 0000000000..e8c46085be --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt5/step1/show_mpls_table.ref @@ -0,0 +1,97 @@ +{ + "16010":{ + "inLabel":16010, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":17010, + "installed":true, + "nexthop":"10.0.5.3" + }, + { + "type":"SR (OSPF)", + "outLabel":17010, + "installed":true, + "nexthop":"10.0.4.3" + } + ] + }, + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":17020, + "installed":true, + "nexthop":"10.0.5.3" + }, + { + "type":"SR (OSPF)", + "outLabel":17020, + "installed":true, + "nexthop":"10.0.4.3" + }, + { + "type":"SR (OSPF)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.6.4" + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":17030, + "installed":true, + "nexthop":"10.0.5.3" + }, + { + "type":"SR (OSPF)", + "outLabel":17030, + "installed":true, + "nexthop":"10.0.4.3" + } + ] + }, + "16040":{ + "inLabel":16040, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16040, + "installed":true, + "nexthop":"10.0.6.4" + } + ] + }, + "16050":{ + "inLabel":16050, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":3, + "installed":true + } + ] + }, + "16060":{ + "inLabel":16060, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":0, + "installed":true, + "nexthop":"10.0.8.6" + } + ] + } +} diff --git a/tests/topotests/ospf-sr-topo1/rt5/step10/show_ip_route.ref b/tests/topotests/ospf-sr-topo1/rt5/step10/show_ip_route.ref new file mode 100644 index 0000000000..2bad2eb7bf --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt5/step10/show_ip_route.ref @@ -0,0 +1,300 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true, + "labels":[ + 17010 + ] + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true, + "labels":[ + 17010 + ] + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true, + "labels":[ + 17020 + ] + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true, + "labels":[ + 17020 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true, + "labels":[ + 17030 + ] + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true, + "labels":[ + 17030 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true, + "labels":[ + 18040 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true, + "labels":[ + 3 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt3-1", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/ospf-sr-topo1/rt5/step10/show_mpls_table.ref b/tests/topotests/ospf-sr-topo1/rt5/step10/show_mpls_table.ref new file mode 100644 index 0000000000..c5ed18d76f --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt5/step10/show_mpls_table.ref @@ -0,0 +1,91 @@ +{ + "16010":{ + "inLabel":16010, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":17010, + "installed":true, + "nexthop":"10.0.5.3" + }, + { + "type":"SR (OSPF)", + "outLabel":17010, + "installed":true, + "nexthop":"10.0.4.3" + } + ] + }, + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":17020, + "installed":true, + "nexthop":"10.0.5.3" + }, + { + "type":"SR (OSPF)", + "outLabel":17020, + "installed":true, + "nexthop":"10.0.4.3" + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":17030, + "installed":true, + "nexthop":"10.0.5.3" + }, + { + "type":"SR (OSPF)", + "outLabel":17030, + "installed":true, + "nexthop":"10.0.4.3" + } + ] + }, + "16040":{ + "inLabel":16040, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":18040, + "installed":true, + "nexthop":"10.0.8.6" + } + ] + }, + "16050":{ + "inLabel":16050, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":3, + "installed":true + } + ] + }, + "16060":{ + "inLabel":16060, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.8.6" + } + ] + } +} diff --git a/tests/topotests/ospf-sr-topo1/rt5/step2/show_ip_route.ref b/tests/topotests/ospf-sr-topo1/rt5/step2/show_ip_route.ref new file mode 100644 index 0000000000..3572ec713f --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt5/step2/show_ip_route.ref @@ -0,0 +1,307 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true, + "labels":[ + 17010 + ] + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true, + "labels":[ + 17010 + ] + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true, + "labels":[ + 17020 + ] + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true, + "labels":[ + 17020 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true, + "labels":[ + 17030 + ] + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true, + "labels":[ + 17030 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true, + "labels":[ + 0 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt3-1", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/ospf-sr-topo1/rt5/step2/show_mpls_table.ref b/tests/topotests/ospf-sr-topo1/rt5/step2/show_mpls_table.ref new file mode 100644 index 0000000000..d9cadeb513 --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt5/step2/show_mpls_table.ref @@ -0,0 +1,91 @@ +{ + "16010":{ + "inLabel":16010, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":17010, + "installed":true, + "nexthop":"10.0.5.3" + }, + { + "type":"SR (OSPF)", + "outLabel":17010, + "installed":true, + "nexthop":"10.0.4.3" + } + ] + }, + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":17020, + "installed":true, + "nexthop":"10.0.5.3" + }, + { + "type":"SR (OSPF)", + "outLabel":17020, + "installed":true, + "nexthop":"10.0.4.3" + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":17030, + "installed":true, + "nexthop":"10.0.5.3" + }, + { + "type":"SR (OSPF)", + "outLabel":17030, + "installed":true, + "nexthop":"10.0.4.3" + } + ] + }, + "16040":{ + "inLabel":16040, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16040, + "installed":true, + "nexthop":"10.0.8.6" + } + ] + }, + "16050":{ + "inLabel":16050, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":3, + "installed":true + } + ] + }, + "16060":{ + "inLabel":16060, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":0, + "installed":true, + "nexthop":"10.0.8.6" + } + ] + } +} diff --git a/tests/topotests/ospf-sr-topo1/rt5/step3/show_ip_route.ref b/tests/topotests/ospf-sr-topo1/rt5/step3/show_ip_route.ref new file mode 100644 index 0000000000..2f7b0cc242 --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt5/step3/show_ip_route.ref @@ -0,0 +1,272 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true, + "labels":[ + 17010 + ] + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true, + "labels":[ + 17010 + ] + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true, + "labels":[ + 17020 + ] + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true, + "labels":[ + 17020 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true, + "labels":[ + 17030 + ] + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true, + "labels":[ + 17030 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true, + "labels":[ + 17040 + ] + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true, + "labels":[ + 17040 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt3-1", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/ospf-sr-topo1/rt5/step3/show_mpls_table.ref b/tests/topotests/ospf-sr-topo1/rt5/step3/show_mpls_table.ref new file mode 100644 index 0000000000..7c78d2ce53 --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt5/step3/show_mpls_table.ref @@ -0,0 +1,85 @@ +{ + "16010":{ + "inLabel":16010, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":17010, + "installed":true, + "nexthop":"10.0.5.3" + }, + { + "type":"SR (OSPF)", + "outLabel":17010, + "installed":true, + "nexthop":"10.0.4.3" + } + ] + }, + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":17020, + "installed":true, + "nexthop":"10.0.5.3" + }, + { + "type":"SR (OSPF)", + "outLabel":17020, + "installed":true, + "nexthop":"10.0.4.3" + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":17030, + "installed":true, + "nexthop":"10.0.5.3" + }, + { + "type":"SR (OSPF)", + "outLabel":17030, + "installed":true, + "nexthop":"10.0.4.3" + } + ] + }, + "16040":{ + "inLabel":16040, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":17040, + "installed":true, + "nexthop":"10.0.5.3" + }, + { + "type":"SR (OSPF)", + "outLabel":17040, + "installed":true, + "nexthop":"10.0.4.3" + } + ] + }, + "16050":{ + "inLabel":16050, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":3, + "installed":true + } + ] + } +} diff --git a/tests/topotests/ospf-sr-topo1/rt5/step4/show_ip_route.ref b/tests/topotests/ospf-sr-topo1/rt5/step4/show_ip_route.ref new file mode 100644 index 0000000000..1a12715086 --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt5/step4/show_ip_route.ref @@ -0,0 +1,307 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true, + "labels":[ + 17010 + ] + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true, + "labels":[ + 17010 + ] + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true, + "labels":[ + 17020 + ] + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true, + "labels":[ + 17020 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true, + "labels":[ + 17030 + ] + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true, + "labels":[ + 17030 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true, + "labels":[ + 18040 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true, + "labels":[ + 0 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt3-1", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/ospf-sr-topo1/rt5/step4/show_mpls_table.ref b/tests/topotests/ospf-sr-topo1/rt5/step4/show_mpls_table.ref new file mode 100644 index 0000000000..42e476e9d1 --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt5/step4/show_mpls_table.ref @@ -0,0 +1,91 @@ +{ + "16010":{ + "inLabel":16010, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":17010, + "installed":true, + "nexthop":"10.0.5.3" + }, + { + "type":"SR (OSPF)", + "outLabel":17010, + "installed":true, + "nexthop":"10.0.4.3" + } + ] + }, + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":17020, + "installed":true, + "nexthop":"10.0.5.3" + }, + { + "type":"SR (OSPF)", + "outLabel":17020, + "installed":true, + "nexthop":"10.0.4.3" + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":17030, + "installed":true, + "nexthop":"10.0.5.3" + }, + { + "type":"SR (OSPF)", + "outLabel":17030, + "installed":true, + "nexthop":"10.0.4.3" + } + ] + }, + "16040":{ + "inLabel":16040, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":18040, + "installed":true, + "nexthop":"10.0.8.6" + } + ] + }, + "16050":{ + "inLabel":16050, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":3, + "installed":true + } + ] + }, + "16060":{ + "inLabel":16060, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":0, + "installed":true, + "nexthop":"10.0.8.6" + } + ] + } +} diff --git a/tests/topotests/ospf-sr-topo1/rt5/step5/show_ip_route.ref b/tests/topotests/ospf-sr-topo1/rt5/step5/show_ip_route.ref new file mode 100644 index 0000000000..e50fa10ccb --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt5/step5/show_ip_route.ref @@ -0,0 +1,286 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true, + "labels":[ + 17010 + ] + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true, + "labels":[ + 17010 + ] + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true, + "labels":[ + 17020 + ] + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true, + "labels":[ + 17020 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true, + "labels":[ + 17030 + ] + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true, + "labels":[ + 17030 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt3-1", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/ospf-sr-topo1/rt5/step5/show_mpls_table.ref b/tests/topotests/ospf-sr-topo1/rt5/step5/show_mpls_table.ref new file mode 100644 index 0000000000..bb95379228 --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt5/step5/show_mpls_table.ref @@ -0,0 +1,67 @@ +{ + "16010":{ + "inLabel":16010, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":17010, + "installed":true, + "nexthop":"10.0.5.3" + }, + { + "type":"SR (OSPF)", + "outLabel":17010, + "installed":true, + "nexthop":"10.0.4.3" + } + ] + }, + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":17020, + "installed":true, + "nexthop":"10.0.5.3" + }, + { + "type":"SR (OSPF)", + "outLabel":17020, + "installed":true, + "nexthop":"10.0.4.3" + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":17030, + "installed":true, + "nexthop":"10.0.5.3" + }, + { + "type":"SR (OSPF)", + "outLabel":17030, + "installed":true, + "nexthop":"10.0.4.3" + } + ] + }, + "16050":{ + "inLabel":16050, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":3, + "installed":true + } + ] + } +} diff --git a/tests/topotests/ospf-sr-topo1/rt5/step6/show_ip_route.ref b/tests/topotests/ospf-sr-topo1/rt5/step6/show_ip_route.ref new file mode 100644 index 0000000000..1a12715086 --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt5/step6/show_ip_route.ref @@ -0,0 +1,307 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true, + "labels":[ + 17010 + ] + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true, + "labels":[ + 17010 + ] + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true, + "labels":[ + 17020 + ] + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true, + "labels":[ + 17020 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true, + "labels":[ + 17030 + ] + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true, + "labels":[ + 17030 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true, + "labels":[ + 18040 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true, + "labels":[ + 0 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt3-1", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/ospf-sr-topo1/rt5/step6/show_mpls_table.ref b/tests/topotests/ospf-sr-topo1/rt5/step6/show_mpls_table.ref new file mode 100644 index 0000000000..42e476e9d1 --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt5/step6/show_mpls_table.ref @@ -0,0 +1,91 @@ +{ + "16010":{ + "inLabel":16010, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":17010, + "installed":true, + "nexthop":"10.0.5.3" + }, + { + "type":"SR (OSPF)", + "outLabel":17010, + "installed":true, + "nexthop":"10.0.4.3" + } + ] + }, + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":17020, + "installed":true, + "nexthop":"10.0.5.3" + }, + { + "type":"SR (OSPF)", + "outLabel":17020, + "installed":true, + "nexthop":"10.0.4.3" + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":17030, + "installed":true, + "nexthop":"10.0.5.3" + }, + { + "type":"SR (OSPF)", + "outLabel":17030, + "installed":true, + "nexthop":"10.0.4.3" + } + ] + }, + "16040":{ + "inLabel":16040, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":18040, + "installed":true, + "nexthop":"10.0.8.6" + } + ] + }, + "16050":{ + "inLabel":16050, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":3, + "installed":true + } + ] + }, + "16060":{ + "inLabel":16060, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":0, + "installed":true, + "nexthop":"10.0.8.6" + } + ] + } +} diff --git a/tests/topotests/ospf-sr-topo1/rt5/step7/show_ip_route.ref b/tests/topotests/ospf-sr-topo1/rt5/step7/show_ip_route.ref new file mode 100644 index 0000000000..15a024d18b --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt5/step7/show_ip_route.ref @@ -0,0 +1,286 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true, + "labels":[ + 17020 + ] + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true, + "labels":[ + 17020 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true, + "labels":[ + 17030 + ] + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true, + "labels":[ + 17030 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true, + "labels":[ + 18040 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true, + "labels":[ + 0 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt3-1", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/ospf-sr-topo1/rt5/step7/show_mpls_table.ref b/tests/topotests/ospf-sr-topo1/rt5/step7/show_mpls_table.ref new file mode 100644 index 0000000000..cff0d25e25 --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt5/step7/show_mpls_table.ref @@ -0,0 +1,73 @@ +{ + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":17020, + "installed":true, + "nexthop":"10.0.5.3" + }, + { + "type":"SR (OSPF)", + "outLabel":17020, + "installed":true, + "nexthop":"10.0.4.3" + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":17030, + "installed":true, + "nexthop":"10.0.5.3" + }, + { + "type":"SR (OSPF)", + "outLabel":17030, + "installed":true, + "nexthop":"10.0.4.3" + } + ] + }, + "16040":{ + "inLabel":16040, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":18040, + "installed":true, + "nexthop":"10.0.8.6" + } + ] + }, + "16050":{ + "inLabel":16050, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":3, + "installed":true + } + ] + }, + "16060":{ + "inLabel":16060, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":0, + "installed":true, + "nexthop":"10.0.8.6" + } + ] + } +} diff --git a/tests/topotests/ospf-sr-topo1/rt5/step8/show_ip_route.ref b/tests/topotests/ospf-sr-topo1/rt5/step8/show_ip_route.ref new file mode 100644 index 0000000000..1a12715086 --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt5/step8/show_ip_route.ref @@ -0,0 +1,307 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true, + "labels":[ + 17010 + ] + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true, + "labels":[ + 17010 + ] + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true, + "labels":[ + 17020 + ] + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true, + "labels":[ + 17020 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true, + "labels":[ + 17030 + ] + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true, + "labels":[ + 17030 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true, + "labels":[ + 18040 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true, + "labels":[ + 0 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt3-1", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/ospf-sr-topo1/rt5/step8/show_mpls_table.ref b/tests/topotests/ospf-sr-topo1/rt5/step8/show_mpls_table.ref new file mode 100644 index 0000000000..42e476e9d1 --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt5/step8/show_mpls_table.ref @@ -0,0 +1,91 @@ +{ + "16010":{ + "inLabel":16010, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":17010, + "installed":true, + "nexthop":"10.0.5.3" + }, + { + "type":"SR (OSPF)", + "outLabel":17010, + "installed":true, + "nexthop":"10.0.4.3" + } + ] + }, + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":17020, + "installed":true, + "nexthop":"10.0.5.3" + }, + { + "type":"SR (OSPF)", + "outLabel":17020, + "installed":true, + "nexthop":"10.0.4.3" + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":17030, + "installed":true, + "nexthop":"10.0.5.3" + }, + { + "type":"SR (OSPF)", + "outLabel":17030, + "installed":true, + "nexthop":"10.0.4.3" + } + ] + }, + "16040":{ + "inLabel":16040, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":18040, + "installed":true, + "nexthop":"10.0.8.6" + } + ] + }, + "16050":{ + "inLabel":16050, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":3, + "installed":true + } + ] + }, + "16060":{ + "inLabel":16060, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":0, + "installed":true, + "nexthop":"10.0.8.6" + } + ] + } +} diff --git a/tests/topotests/ospf-sr-topo1/rt5/step9/show_ip_route.ref b/tests/topotests/ospf-sr-topo1/rt5/step9/show_ip_route.ref new file mode 100644 index 0000000000..d9ddad2462 --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt5/step9/show_ip_route.ref @@ -0,0 +1,292 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true, + "labels":[ + 17010 + ] + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true, + "labels":[ + 17010 + ] + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true, + "labels":[ + 17020 + ] + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true, + "labels":[ + 17020 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true, + "labels":[ + 17030 + ] + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true, + "labels":[ + 17030 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true, + "labels":[ + 18040 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true, + "labels":[ + 3 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt3-1", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/ospf-sr-topo1/rt5/step9/show_mpls_table.ref b/tests/topotests/ospf-sr-topo1/rt5/step9/show_mpls_table.ref new file mode 100644 index 0000000000..c5ed18d76f --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt5/step9/show_mpls_table.ref @@ -0,0 +1,91 @@ +{ + "16010":{ + "inLabel":16010, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":17010, + "installed":true, + "nexthop":"10.0.5.3" + }, + { + "type":"SR (OSPF)", + "outLabel":17010, + "installed":true, + "nexthop":"10.0.4.3" + } + ] + }, + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":17020, + "installed":true, + "nexthop":"10.0.5.3" + }, + { + "type":"SR (OSPF)", + "outLabel":17020, + "installed":true, + "nexthop":"10.0.4.3" + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":17030, + "installed":true, + "nexthop":"10.0.5.3" + }, + { + "type":"SR (OSPF)", + "outLabel":17030, + "installed":true, + "nexthop":"10.0.4.3" + } + ] + }, + "16040":{ + "inLabel":16040, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":18040, + "installed":true, + "nexthop":"10.0.8.6" + } + ] + }, + "16050":{ + "inLabel":16050, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":3, + "installed":true + } + ] + }, + "16060":{ + "inLabel":16060, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.8.6" + } + ] + } +} diff --git a/tests/topotests/ospf-sr-topo1/rt5/zebra.conf b/tests/topotests/ospf-sr-topo1/rt5/zebra.conf new file mode 100644 index 0000000000..ca2d6df665 --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt5/zebra.conf @@ -0,0 +1,27 @@ +log file zebra.log +! +hostname rt5 +! +debug zebra kernel +debug zebra packet +debug zebra mpls +! +interface lo + ip address 5.5.5.5/32 +! +interface eth-rt3-1 + ip address 10.0.4.5/24 +! +interface eth-rt3-2 + ip address 10.0.5.5/24 +! +interface eth-rt4 + ip address 10.0.6.5/24 +! +interface eth-rt6 + ip address 10.0.8.5/24 +! +ip forwarding +! +line vty +! diff --git a/tests/topotests/ospf-sr-topo1/rt6/ospfd.conf b/tests/topotests/ospf-sr-topo1/rt6/ospfd.conf new file mode 100644 index 0000000000..c6d07d169e --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt6/ospfd.conf @@ -0,0 +1,32 @@ +password 1 +hostname rt6 +log file ospfd.log +! +debug ospf sr +debug ospf te +debug ospf event +debug ospf lsa +debug ospf zebra +! +interface lo +! +interface eth-rt4 + ip ospf network point-to-point +! +interface eth-rt5 + ip ospf network point-to-point +! +router ospf + ospf router-id 6.6.6.6 + network 6.6.6.6/32 area 0.0.0.0 + network 10.0.0.0/16 area 0.0.0.0 + capability opaque + mpls-te on + mpls-te router-address 6.6.6.6 + router-info area 0.0.0.0 + passive-interface lo + segment-routing on + segment-routing global-block 16000 23999 + segment-routing node-msd 8 + segment-routing prefix 6.6.6.6/32 index 60 explicit-null +! diff --git a/tests/topotests/ospf-sr-topo1/rt6/step1/show_ip_route.ref b/tests/topotests/ospf-sr-topo1/rt6/step1/show_ip_route.ref new file mode 100644 index 0000000000..9f05ec7688 --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt6/step1/show_ip_route.ref @@ -0,0 +1,291 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16010 + ] + }, + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16010 + ] + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16020 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16030 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16050 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/ospf-sr-topo1/rt6/step1/show_mpls_table.ref b/tests/topotests/ospf-sr-topo1/rt6/step1/show_mpls_table.ref new file mode 100644 index 0000000000..baa2314454 --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt6/step1/show_mpls_table.ref @@ -0,0 +1,68 @@ +{ + "16010":{ + "inLabel":16010, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.7.4" + }, + { + "type":"SR (OSPF)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.8.5" + } + ] + }, + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.7.4" + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16030, + "installed":true, + "nexthop":"10.0.8.5" + } + ] + }, + "16040":{ + "inLabel":16040, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16040, + "installed":true, + "nexthop":"10.0.7.4" + } + ] + }, + "16050":{ + "inLabel":16050, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16050, + "installed":true, + "nexthop":"10.0.8.5" + } + ] + } +} diff --git a/tests/topotests/ospf-sr-topo1/rt6/step10/show_ip_route.ref b/tests/topotests/ospf-sr-topo1/rt6/step10/show_ip_route.ref new file mode 100644 index 0000000000..6abb3805a2 --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt6/step10/show_ip_route.ref @@ -0,0 +1,284 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16010 + ] + }, + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16010 + ] + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16020 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16030 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16050 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/ospf-sr-topo1/rt6/step10/show_mpls_table.ref b/tests/topotests/ospf-sr-topo1/rt6/step10/show_mpls_table.ref new file mode 100644 index 0000000000..09ecec29d9 --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt6/step10/show_mpls_table.ref @@ -0,0 +1,68 @@ +{ + "18010":{ + "inLabel":18010, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.8.5" + }, + { + "type":"SR (OSPF)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.7.4" + } + ] + }, + "18020":{ + "inLabel":18020, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.7.4" + } + ] + }, + "18030":{ + "inLabel":18030, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16030, + "installed":true, + "nexthop":"10.0.8.5" + } + ] + }, + "18040":{ + "inLabel":18040, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16040, + "installed":true, + "nexthop":"10.0.7.4" + } + ] + }, + "18050":{ + "inLabel":18050, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16050, + "installed":true, + "nexthop":"10.0.8.5" + } + ] + } +} diff --git a/tests/topotests/ospf-sr-topo1/rt6/step2/show_ip_route.ref b/tests/topotests/ospf-sr-topo1/rt6/step2/show_ip_route.ref new file mode 100644 index 0000000000..80b3c426d4 --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt6/step2/show_ip_route.ref @@ -0,0 +1,284 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16010 + ] + }, + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16010 + ] + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16020 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16030 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16050 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/ospf-sr-topo1/rt6/step2/show_mpls_table.ref b/tests/topotests/ospf-sr-topo1/rt6/step2/show_mpls_table.ref new file mode 100644 index 0000000000..baa2314454 --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt6/step2/show_mpls_table.ref @@ -0,0 +1,68 @@ +{ + "16010":{ + "inLabel":16010, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.7.4" + }, + { + "type":"SR (OSPF)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.8.5" + } + ] + }, + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.7.4" + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16030, + "installed":true, + "nexthop":"10.0.8.5" + } + ] + }, + "16040":{ + "inLabel":16040, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16040, + "installed":true, + "nexthop":"10.0.7.4" + } + ] + }, + "16050":{ + "inLabel":16050, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16050, + "installed":true, + "nexthop":"10.0.8.5" + } + ] + } +} diff --git a/tests/topotests/ospf-sr-topo1/rt6/step3/show_ip_route.ref b/tests/topotests/ospf-sr-topo1/rt6/step3/show_ip_route.ref new file mode 100644 index 0000000000..2c63c08510 --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt6/step3/show_ip_route.ref @@ -0,0 +1,2 @@ +{ +} diff --git a/tests/topotests/ospf-sr-topo1/rt6/step3/show_mpls_table.ref b/tests/topotests/ospf-sr-topo1/rt6/step3/show_mpls_table.ref new file mode 100644 index 0000000000..2c63c08510 --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt6/step3/show_mpls_table.ref @@ -0,0 +1,2 @@ +{ +} diff --git a/tests/topotests/ospf-sr-topo1/rt6/step4/show_ip_route.ref b/tests/topotests/ospf-sr-topo1/rt6/step4/show_ip_route.ref new file mode 100644 index 0000000000..80b3c426d4 --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt6/step4/show_ip_route.ref @@ -0,0 +1,284 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16010 + ] + }, + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16010 + ] + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16020 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16030 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16050 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/ospf-sr-topo1/rt6/step4/show_mpls_table.ref b/tests/topotests/ospf-sr-topo1/rt6/step4/show_mpls_table.ref new file mode 100644 index 0000000000..09ecec29d9 --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt6/step4/show_mpls_table.ref @@ -0,0 +1,68 @@ +{ + "18010":{ + "inLabel":18010, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.8.5" + }, + { + "type":"SR (OSPF)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.7.4" + } + ] + }, + "18020":{ + "inLabel":18020, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.7.4" + } + ] + }, + "18030":{ + "inLabel":18030, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16030, + "installed":true, + "nexthop":"10.0.8.5" + } + ] + }, + "18040":{ + "inLabel":18040, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16040, + "installed":true, + "nexthop":"10.0.7.4" + } + ] + }, + "18050":{ + "inLabel":18050, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16050, + "installed":true, + "nexthop":"10.0.8.5" + } + ] + } +} diff --git a/tests/topotests/ospf-sr-topo1/rt6/step5/show_ip_route.ref b/tests/topotests/ospf-sr-topo1/rt6/step5/show_ip_route.ref new file mode 100644 index 0000000000..0e4b3eba12 --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt6/step5/show_ip_route.ref @@ -0,0 +1,266 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/ospf-sr-topo1/rt6/step5/show_mpls_table.ref b/tests/topotests/ospf-sr-topo1/rt6/step5/show_mpls_table.ref new file mode 100644 index 0000000000..2c63c08510 --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt6/step5/show_mpls_table.ref @@ -0,0 +1,2 @@ +{ +} diff --git a/tests/topotests/ospf-sr-topo1/rt6/step6/show_ip_route.ref b/tests/topotests/ospf-sr-topo1/rt6/step6/show_ip_route.ref new file mode 100644 index 0000000000..80b3c426d4 --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt6/step6/show_ip_route.ref @@ -0,0 +1,284 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16010 + ] + }, + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16010 + ] + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16020 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16030 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16050 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/ospf-sr-topo1/rt6/step6/show_mpls_table.ref b/tests/topotests/ospf-sr-topo1/rt6/step6/show_mpls_table.ref new file mode 100644 index 0000000000..09ecec29d9 --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt6/step6/show_mpls_table.ref @@ -0,0 +1,68 @@ +{ + "18010":{ + "inLabel":18010, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.8.5" + }, + { + "type":"SR (OSPF)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.7.4" + } + ] + }, + "18020":{ + "inLabel":18020, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.7.4" + } + ] + }, + "18030":{ + "inLabel":18030, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16030, + "installed":true, + "nexthop":"10.0.8.5" + } + ] + }, + "18040":{ + "inLabel":18040, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16040, + "installed":true, + "nexthop":"10.0.7.4" + } + ] + }, + "18050":{ + "inLabel":18050, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16050, + "installed":true, + "nexthop":"10.0.8.5" + } + ] + } +} diff --git a/tests/topotests/ospf-sr-topo1/rt6/step7/show_ip_route.ref b/tests/topotests/ospf-sr-topo1/rt6/step7/show_ip_route.ref new file mode 100644 index 0000000000..aa2329a04a --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt6/step7/show_ip_route.ref @@ -0,0 +1,278 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16020 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16030 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16050 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/ospf-sr-topo1/rt6/step7/show_mpls_table.ref b/tests/topotests/ospf-sr-topo1/rt6/step7/show_mpls_table.ref new file mode 100644 index 0000000000..800b1ae2fd --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt6/step7/show_mpls_table.ref @@ -0,0 +1,50 @@ +{ + "18020":{ + "inLabel":18020, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.7.4" + } + ] + }, + "18030":{ + "inLabel":18030, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16030, + "installed":true, + "nexthop":"10.0.8.5" + } + ] + }, + "18040":{ + "inLabel":18040, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16040, + "installed":true, + "nexthop":"10.0.7.4" + } + ] + }, + "18050":{ + "inLabel":18050, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16050, + "installed":true, + "nexthop":"10.0.8.5" + } + ] + } +} diff --git a/tests/topotests/ospf-sr-topo1/rt6/step8/show_ip_route.ref b/tests/topotests/ospf-sr-topo1/rt6/step8/show_ip_route.ref new file mode 100644 index 0000000000..80b3c426d4 --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt6/step8/show_ip_route.ref @@ -0,0 +1,284 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16010 + ] + }, + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16010 + ] + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16020 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16030 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16050 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/ospf-sr-topo1/rt6/step8/show_mpls_table.ref b/tests/topotests/ospf-sr-topo1/rt6/step8/show_mpls_table.ref new file mode 100644 index 0000000000..09ecec29d9 --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt6/step8/show_mpls_table.ref @@ -0,0 +1,68 @@ +{ + "18010":{ + "inLabel":18010, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.8.5" + }, + { + "type":"SR (OSPF)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.7.4" + } + ] + }, + "18020":{ + "inLabel":18020, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.7.4" + } + ] + }, + "18030":{ + "inLabel":18030, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16030, + "installed":true, + "nexthop":"10.0.8.5" + } + ] + }, + "18040":{ + "inLabel":18040, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16040, + "installed":true, + "nexthop":"10.0.7.4" + } + ] + }, + "18050":{ + "inLabel":18050, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16050, + "installed":true, + "nexthop":"10.0.8.5" + } + ] + } +} diff --git a/tests/topotests/ospf-sr-topo1/rt6/step9/show_ip_route.ref b/tests/topotests/ospf-sr-topo1/rt6/step9/show_ip_route.ref new file mode 100644 index 0000000000..80b3c426d4 --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt6/step9/show_ip_route.ref @@ -0,0 +1,284 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16010 + ] + }, + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16010 + ] + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16020 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16030 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16050 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/ospf-sr-topo1/rt6/step9/show_mpls_table.ref b/tests/topotests/ospf-sr-topo1/rt6/step9/show_mpls_table.ref new file mode 100644 index 0000000000..09ecec29d9 --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt6/step9/show_mpls_table.ref @@ -0,0 +1,68 @@ +{ + "18010":{ + "inLabel":18010, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.8.5" + }, + { + "type":"SR (OSPF)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.7.4" + } + ] + }, + "18020":{ + "inLabel":18020, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.7.4" + } + ] + }, + "18030":{ + "inLabel":18030, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16030, + "installed":true, + "nexthop":"10.0.8.5" + } + ] + }, + "18040":{ + "inLabel":18040, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16040, + "installed":true, + "nexthop":"10.0.7.4" + } + ] + }, + "18050":{ + "inLabel":18050, + "installed":true, + "nexthops":[ + { + "type":"SR (OSPF)", + "outLabel":16050, + "installed":true, + "nexthop":"10.0.8.5" + } + ] + } +} diff --git a/tests/topotests/ospf-sr-topo1/rt6/zebra.conf b/tests/topotests/ospf-sr-topo1/rt6/zebra.conf new file mode 100644 index 0000000000..4b739d0bca --- /dev/null +++ b/tests/topotests/ospf-sr-topo1/rt6/zebra.conf @@ -0,0 +1,21 @@ +log file zebra.log +! +hostname rt6 +! +debug zebra kernel +debug zebra packet +debug zebra mpls +! +interface lo + ip address 6.6.6.6/32 +! +interface eth-rt4 + ip address 10.0.7.6/24 +! +interface eth-rt5 + ip address 10.0.8.6/24 +! +ip forwarding +! +line vty +! diff --git a/tests/topotests/ospf-sr-topo1/test_ospf_sr_topo1.dot b/tests/topotests/ospf-sr-topo1/test_ospf_sr_topo1.dot deleted file mode 100644 index d293669209..0000000000 --- a/tests/topotests/ospf-sr-topo1/test_ospf_sr_topo1.dot +++ /dev/null @@ -1,78 +0,0 @@ -## 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 SR topo1"; - - # Routers - r1 [ - label="r1\nrtr-id 10.0.255.1/32", - shape=doubleoctagon, - fillcolor="#f08080", - style=filled, - ]; - r2 [ - label="r2\nrtr-id 10.0.255.2/32", - shape=doubleoctagon, - fillcolor="#f08080", - style=filled, - ]; - r3 [ - label="r3\nrtr-id 10.0.255.3/32", - shape=doubleoctagon, - fillcolor="#f08080", - style=filled, - ]; - r4 [ - label="r4\nrtr-id 10.0.255.4/32", - shape=doubleoctagon, - fillcolor="#f08080", - style=filled, - ]; - - # Switches - s1 [ - label="s2\n10.0.1.0/24", - shape=oval, - fillcolor="#d0e0d0", - style=filled, - ]; - s2 [ - label="s1\n10.0.3.0/24", - shape=oval, - fillcolor="#d0e0d0", - style=filled, - ]; - s3 [ - label="s2\n10.0.4.0/24", - shape=oval, - fillcolor="#d0e0d0", - style=filled, - ]; - - # Connections - subgraph cluster0 { - label="area 0" - - r1 -- s1 [label="eth0\n.1"]; - - r2 -- s1 [label="eth0\n.2"]; - r2 -- s2 [label="eth1\n.2"]; - r2 -- s3 [label="eth2\n.2"]; - - r3 -- s2 [label="eth0\n.1"]; - - r4 -- s3 [label="eth0\n.1"]; - } -} diff --git a/tests/topotests/ospf-sr-topo1/test_ospf_sr_topo1.jpg b/tests/topotests/ospf-sr-topo1/test_ospf_sr_topo1.jpg Binary files differdeleted file mode 100644 index 636f9b320c..0000000000 --- a/tests/topotests/ospf-sr-topo1/test_ospf_sr_topo1.jpg +++ /dev/null diff --git a/tests/topotests/ospf-sr-topo1/test_ospf_sr_topo1.py b/tests/topotests/ospf-sr-topo1/test_ospf_sr_topo1.py index 5c901c067a..57b93c3fd5 100644 --- a/tests/topotests/ospf-sr-topo1/test_ospf_sr_topo1.py +++ b/tests/topotests/ospf-sr-topo1/test_ospf_sr_topo1.py @@ -4,7 +4,7 @@ # test_ospf_sr_topo1.py # Part of NetDEF Topology Tests # -# Copyright (c) 2017 by +# Copyright (c) 2020 by # Network Device Education Foundation, Inc. ("NetDEF") # # Permission to use, copy, modify, and/or distribute this software @@ -23,13 +23,52 @@ # """ -test_ospf_sr_topo1.py: Test the FRR OSPF routing daemon with Segment Routing. +test_ospf_sr_topo1.py: + + +---------+ + | | + | RT1 | + | 1.1.1.1 | + | | + +---------+ + |eth-sw1 + | + | + | + +---------+ | +---------+ + | | | | | + | RT2 |eth-sw1 | eth-sw1| RT3 | + | 2.2.2.2 +----------+----------+ 3.3.3.3 | + | | 10.0.1.0/24 | | + +---------+ +---------+ + eth-rt4-1| |eth-rt4-2 eth-rt5-1| |eth-rt5-2 + | | | | + 10.0.2.0/24| |10.0.3.0/24 10.0.4.0/24| |10.0.5.0/24 + | | | | + eth-rt2-1| |eth-rt2-2 eth-rt3-1| |eth-rt3-2 + +---------+ +---------+ + | | | | + | RT4 | 10.0.6.0/24 | RT5 | + | 4.4.4.4 +---------------------+ 5.5.5.5 | + | |eth-rt5 eth-rt4| | + +---------+ +---------+ + eth-rt6| |eth-rt6 + | | + 10.0.7.0/24| |10.0.8.0/24 + | +---------+ | + | | | | + | | RT6 | | + +----------+ 6.6.6.6 +-----------+ + eth-rt4| |eth-rt5 + +---------+ """ import os -import re import sys +import pytest import json +import re +from time import sleep from functools import partial # Save the Current Working Directory to find configuration files. @@ -37,63 +76,74 @@ 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 +# Required to instantiate the topology builder class. +from mininet.topo import Topo pytestmark = [pytest.mark.ospfd] -class OspfSrTopo(Topo): +class TemplateTopo(Topo): "Test topology builder" - def build(self): + def build(self, *_args, **_opts): "Build function" tgen = get_topogen(self) - # Check for mpls - if tgen.hasmpls is not True: - tgen.set_error("MPLS not available, tests will be skipped") + # + # Define FRR Routers + # + for router in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + tgen.add_router(router) - # Create 4 routers - for routern in range(1, 5): - tgen.add_router("r{}".format(routern)) - - # Interconect router 1 and 2 with 2 links + # + # Define connections + # switch = tgen.add_switch("s1") - switch.add_link(tgen.gears["r1"]) - switch.add_link(tgen.gears["r2"]) + switch.add_link(tgen.gears["rt1"], nodeif="eth-sw1") + switch.add_link(tgen.gears["rt2"], nodeif="eth-sw1") + switch.add_link(tgen.gears["rt3"], nodeif="eth-sw1") + switch = tgen.add_switch("s2") - switch.add_link(tgen.gears["r1"]) - switch.add_link(tgen.gears["r2"]) + switch.add_link(tgen.gears["rt2"], nodeif="eth-rt4-1") + switch.add_link(tgen.gears["rt4"], nodeif="eth-rt2-1") - # Interconect router 3 and 2 switch = tgen.add_switch("s3") - switch.add_link(tgen.gears["r3"]) - switch.add_link(tgen.gears["r2"]) + switch.add_link(tgen.gears["rt2"], nodeif="eth-rt4-2") + switch.add_link(tgen.gears["rt4"], nodeif="eth-rt2-2") - # Interconect router 4 and 2 switch = tgen.add_switch("s4") - switch.add_link(tgen.gears["r4"]) - switch.add_link(tgen.gears["r2"]) + switch.add_link(tgen.gears["rt3"], nodeif="eth-rt5-1") + switch.add_link(tgen.gears["rt5"], nodeif="eth-rt3-1") + switch = tgen.add_switch("s5") + switch.add_link(tgen.gears["rt3"], nodeif="eth-rt5-2") + switch.add_link(tgen.gears["rt5"], nodeif="eth-rt3-2") -def setup_module(mod): - "Sets up the pytest environment" + switch = tgen.add_switch("s6") + switch.add_link(tgen.gears["rt4"], nodeif="eth-rt5") + switch.add_link(tgen.gears["rt5"], nodeif="eth-rt4") + + switch = tgen.add_switch("s7") + switch.add_link(tgen.gears["rt4"], nodeif="eth-rt6") + switch.add_link(tgen.gears["rt6"], nodeif="eth-rt4") - logger.info("\n\n---- Starting OSPF Segment Routing tests ----\n") + switch = tgen.add_switch("s8") + switch.add_link(tgen.gears["rt5"], nodeif="eth-rt6") + switch.add_link(tgen.gears["rt6"], nodeif="eth-rt5") - tgen = Topogen(OspfSrTopo, mod.__name__) + +def setup_module(mod): + "Sets up the pytest environment" + tgen = Topogen(TemplateTopo, mod.__name__) tgen.start_topology() router_list = tgen.routers() + # For all registered routers, load the zebra configuration file for rname, router in router_list.items(): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) @@ -102,101 +152,536 @@ def setup_module(mod): TopoRouter.RD_OSPF, os.path.join(CWD, "{}/ospfd.conf".format(rname)) ) - # Initialize all routers. tgen.start_router() def teardown_module(mod): "Teardown the pytest environment" - tgen = get_topogen() + + # This function tears down the whole topology. tgen.stop_topology() - logger.info("\n\n---- OSPF Segment Routing tests End ----\n") + +def print_cmd_result(rname, command): + print(get_topogen().gears[rname].vtysh_cmd(command, isjson=False)) + + +def router_compare_json_output(rname, command, reference): + "Compare router JSON output" + + logger.info('Comparing router "%s" "%s" output', rname, command) + + tgen = get_topogen() + filename = "{}/{}/{}".format(CWD, rname, reference) + expected = json.loads(open(filename).read()) + + # 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=120, wait=0.5) + assertmsg = '"{}" JSON output mismatches the expected result'.format(rname) + assert diff is None, assertmsg + + +# +# Step 1 +# +# Test initial network convergence +# +def test_rib_step1(): + logger.info("Test (step 1): verify RIB") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, "show ip route ospf json", "step1/show_ip_route.ref" + ) + + +def test_mpls_lib_step1(): + logger.info("Test (step 1): verify MPLS LIB") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, "show mpls table json", "step1/show_mpls_table.ref" + ) + + +# +# Step 2 +# +# Action(s): +# -Disable OSPF on the eth-rt5 interface on rt4 +# +# Expected changes: +# -rt4 should uninstall the Adj-SIDs pointing to rt5 +# -rt5 should uninstall the Adj-SIDs pointing to rt4 +# -rt2 should reinstall rt5's Prefix-SIDs (2 nexthops deleted) +# -rt3 should reinstall rt4's Prefix-SIDs (2 nexthops deleted) +# -rt4 should reinstall rt3's Prefix-SIDs (1 nexthop deleted) +# -rt4 should reinstall rt5's Prefix-SIDs (1 nexthop changed) +# -rt5 should reinstall rt2's Prefix-SIDs (1 nexthop deleted) +# -rt5 should reinstall rt4's Prefix-SIDs (1 nexthop changed) +# +def test_rib_ipv4_step2(): + logger.info("Test (step 2): verify IPv4 RIB") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("Disabling OSPF on the eth-rt5 interface on rt4") + tgen.net["rt4"].cmd( + 'vtysh -c "conf t" -c "interface eth-rt5" -c "no ip ospf network point-to-point"' + ) + + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, "show ip route ospf json", "step2/show_ip_route.ref" + ) + + +def test_mpls_lib_step2(): + logger.info("Test (step 2): verify MPLS LIB") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, "show mpls table json", "step2/show_mpls_table.ref" + ) + + +# +# Step 3 +# +# Action(s): +# -Shut down the eth-rt4 interface on rt6 +# -Shut down the eth-rt5 interface on rt6 +# +# Expected changes: +# -All routers should uninstall rt6's Prefix-SIDs +# -rt4 and rt5 should uninstall the Adj-SIDs pointing to rt6 +# -rt4 should reconverge rt5's Prefix-SIDs through rt2 using ECMP +# -rt5 should reconverge rt4's Prefix-SIDs through rt3 using ECMP +# -rt6 should uninstall all its IS-IS routes, Prefix-SIDs and Adj-SIDs +# +def test_rib_ipv4_step3(): + logger.info("Test (step 3): verify IPv4 RIB") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("Shutting down the eth-rt4 interface on rt6") + tgen.net["rt6"].cmd('vtysh -c "conf t" -c "interface eth-rt4" -c "shutdown"') + logger.info("Shutting down the eth-rt5 interface on rt6") + tgen.net["rt6"].cmd('vtysh -c "conf t" -c "interface eth-rt5" -c "shutdown"') + + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, "show ip route ospf json", "step3/show_ip_route.ref" + ) + + +def test_mpls_lib_step3(): + logger.info("Test (step 3): verify MPLS LIB") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, "show mpls table json", "step3/show_mpls_table.ref" + ) + + +# +# Step 4 +# +# Action(s): +# -Bring up the eth-rt4 interface on rt6 +# -Bring up the eth-rt5 interface on rt6 +# -Change rt6's SRGB +# +# Expected changes: +# -All routers should install rt6's Prefix-SIDs +# -rt4 and rt5 should install Adj-SIDs for rt6 +# -rt4 should reconverge rt5's Prefix-SIDs through rt6 using the new SRGB +# -rt5 should reconverge rt4's Prefix-SIDs through rt6 using the new SRGB +# -rt6 should reinstall all IS-IS routes and Prefix-SIDs from the network, and Adj-SIDs for rt4 and rt5 +# +def test_rib_ipv4_step4(): + logger.info("Test (step 4): verify IPv4 RIB") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("Bringing up the eth-rt4 interface on rt6") + tgen.net["rt6"].cmd('vtysh -c "conf t" -c "interface eth-rt4" -c "no shutdown"') + logger.info("Bringing up the eth-rt5 interface on rt6") + tgen.net["rt6"].cmd('vtysh -c "conf t" -c "interface eth-rt5" -c "no shutdown"') + logger.info("Changing rt6's SRGB") + tgen.net["rt6"].cmd( + 'vtysh -c "conf t" -c "router ospf" -c "segment-routing global-block 18000 25999"' + ) + + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, "show ip route ospf json", "step4/show_ip_route.ref" + ) + + +def test_mpls_lib_step4(): + logger.info("Test (step 4): verify MPLS LIB") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, "show mpls table json", "step4/show_mpls_table.ref" + ) + + +# +# Step 5 +# +# Action(s): +# -Disable SR on rt6 +# +# Expected changes: +# -All routers should uninstall rt6's Prefix-SIDs +# -rt4 should uninstall rt5's Prefix-SIDs since the nexthop router hasn't SR enabled anymore +# -rt5 should uninstall rt4's Prefix-SIDs since the nexthop router hasn't SR enabled anymore +# -rt6 should uninstall all Prefix-SIDs from the network, and the Adj-SIDs for rt4 and rt5 +# +def test_rib_ipv4_step5(): + logger.info("Test (step 5): verify IPv4 RIB") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("Disabling SR on rt6") + tgen.net["rt6"].cmd( + 'vtysh -c "conf t" -c "router ospf" -c "no segment-routing on"' + ) + + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, "show ip route ospf json", "step5/show_ip_route.ref" + ) + + +def test_mpls_lib_step5(): + logger.info("Test (step 5): verify MPLS LIB") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, "show mpls table json", "step5/show_mpls_table.ref" + ) + + +# +# Step 6 +# +# Action(s): +# -Enable SR on rt6 +# +# Expected changes: +# -All routers should install rt6's Prefix-SIDs +# -rt4 should install rt5's Prefix-SIDs through rt6 +# -rt5 should install rt4's Prefix-SIDs through rt6 +# -rt6 should install all Prefix-SIDs from the network, and Adj-SIDs for rt4 and rt5 +# +def test_rib_ipv4_step6(): + logger.info("Test (step 6): verify IPv4 RIB") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("Enabling SR on rt6") + tgen.net["rt6"].cmd('vtysh -c "conf t" -c "router ospf" -c "segment-routing on"') + + # FIXME: This is currently necessary because the CLI is not yet yang based. + logger.info("Re-do rt6's SR config") + tgen.net["rt6"].cmd( + 'vtysh -c "conf t" -c "router ospf" -c "segment-routing global-block 18000 25999"' + ) + tgen.net["rt6"].cmd( + 'vtysh -c "conf t" -c "router ospf" -c "segment-routing node-msd 8"' + ) + tgen.net["rt6"].cmd( + 'vtysh -c "conf t" -c "router ospf" -c "segment-routing prefix 6.6.6.6/32 index 60 explicit-null"' + ) + + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, "show ip route ospf json", "step6/show_ip_route.ref" + ) + + +def test_mpls_lib_step6(): + logger.info("Test (step 6): verify MPLS LIB") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, "show mpls table json", "step6/show_mpls_table.ref" + ) + + +# +# Step 7 +# +# Action(s): +# -Delete rt1's Prefix-SIDs +# +# Expected changes: +# -All routers should uninstall rt1's Prefix-SIDs +# +def test_rib_ipv4_step7(): + logger.info("Test (step 7): verify IPv4 RIB") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("Deleting rt1's Prefix-SIDs") + tgen.net["rt1"].cmd( + 'vtysh -c "conf t" -c "router ospf" -c "no segment-routing prefix 1.1.1.1/32 index 10"' + ) + + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, "show ip route ospf json", "step7/show_ip_route.ref" + ) -def test_ospf_sr(): - "Test OSPF daemon Segment Routing" +def test_mpls_lib_step7(): + logger.info("Test (step 7): verify MPLS LIB") tgen = get_topogen() + + # Skip if previous fatal error condition is raised if tgen.routers_have_failure(): pytest.skip(tgen.errors) - logger.info("--- test OSPF Segment Routing Data Base ---") + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, "show mpls table json", "step7/show_mpls_table.ref" + ) - for rnum in range(1, 5): - router = "r{}".format(rnum) - logger.info('\tRouter "%s"', router) +# +# Step 8 +# +# Action(s): +# -Re-add rt1's Prefix-SIDs +# +# Expected changes: +# -All routers should install rt1's Prefix-SIDs +# +def test_rib_ipv4_step8(): + logger.info("Test (step 8): verify IPv4 RIB") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) - # Load expected results from the command - reffile = os.path.join(CWD, "{}/ospf_srdb.json".format(router)) - expected = json.loads(open(reffile).read()) + logger.info("Re-adding rt1's Prefix-SIDs") + tgen.net["rt1"].cmd( + 'vtysh -c "conf t" -c "router ospf" -c "segment-routing prefix 1.1.1.1/32 index 10"' + ) - # Run test function until we get an result. Wait at most 60 seconds. - rt = tgen.gears[router] - test_func = partial( - topotest.router_json_cmp, - rt, - "show ip ospf database segment-routing json", - expected, + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, "show ip route ospf json", "step8/show_ip_route.ref" ) - rv, diff = topotest.run_and_expect(test_func, None, count=25, wait=3) - assert rv, "OSPF did not start Segment Routing on {}:\n{}".format(router, diff) -def test_ospf_kernel_route(): - "Test OSPF Segment Routing MPLS route installation" +def test_mpls_lib_step8(): + logger.info("Test (step 8): verify MPLS LIB") tgen = get_topogen() + + # Skip if previous fatal error condition is raised if tgen.routers_have_failure(): pytest.skip(tgen.errors) - logger.info("--- test OSPF Segment Routing MPLS tables ---") + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, "show mpls table json", "step8/show_mpls_table.ref" + ) - def show_mpls_table_json_cmp(rt, expected): - """ - Reformat MPLS table output to use a list of labels instead of dict. - Original: - { - "X": { - inLabel: "X", - # ... - } - } +# +# Step 9 +# +# Action(s): +# -Change rt1's Prefix-SIDs to use the no-php option +# -Change rt6's Prefix-SIDs to stop using the explicit-null option +# +# Expected changes: +# -rt2 and rt3 should reinstall rt1's Prefix-SIDs accordingly +# -rt4 and rt5 should reinstall rt6's Prefix-SIDs accordingly +# +def test_rib_ipv4_step9(): + logger.info("Test (step 9): verify IPv4 RIB") + tgen = get_topogen() - List format: - [ - { - inLabel: "X", - } - ] - """ - out = rt.vtysh_cmd("show mpls table json", isjson=True) + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) - outlist = [] - for key in out.keys(): - outlist.append(out[key]) + logger.info("Changing rt1's Prefix-SIDs to use the no-php option") + tgen.net["rt1"].cmd( + 'vtysh -c "conf t" -c "router ospf" -c "segment-routing prefix 1.1.1.1/32 index 10 no-php-flag"' + ) - return topotest.json_cmp(outlist, expected) + logger.info("Change rt6's Prefix-SIDs to stop using the explicit-null option") + tgen.net["rt6"].cmd( + 'vtysh -c "conf t" -c "router ospf" -c "segment-routing prefix 6.6.6.6/32 index 60"' + ) + + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, "show ip route ospf json", "step9/show_ip_route.ref" + ) - for rnum in range(1, 5): - router = "r{}".format(rnum) - logger.info('\tRouter "%s"', router) +def test_mpls_lib_step9(): + logger.info("Test (step 9): verify MPLS LIB") + tgen = get_topogen() - # Load expected results from the command - reffile = os.path.join(CWD, "{}/zebra_mpls.json".format(router)) - expected = json.loads(open(reffile).read()) + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) - # Run test function until we get an result. Wait at most 60 seconds. - rt = tgen.gears[router] - test_func = partial(show_mpls_table_json_cmp, rt, expected) - rv, diff = topotest.run_and_expect(test_func, None, count=25, wait=3) - assert rv, "OSPF did not properly instal MPLS table on {}:\n{}".format( - router, diff + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, "show mpls table json", "step9/show_mpls_table.ref" ) +# +# Step 10 +# +# Action(s): +# -Remove the IPv4 address from rt4's eth-rt2-1 interface +# +# Expected changes: +# -rt2 should uninstall the IPv4 Adj-SIDs attached to the eth-rt4-1 interface +# -rt2 should reinstall all IPv4 Prefix-SIDs whose nexthop router is rt4 (ECMP shouldn't be used anymore) +# -rt4 should reinstall all IPv4 Prefix-SIDs whose nexthop router is rt2 (ECMP shouldn't be used anymore) +# +def test_rib_ipv4_step10(): + logger.info("Test (step 10): verify IPv4 RIB") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("Removing the IPv4 address from rt4's eth-rt2-1 interface") + tgen.net["rt4"].cmd( + 'vtysh -c "conf t" -c "interface eth-rt2-1" -c "no ip address 10.0.2.4/24"' + ) + + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, "show ip route ospf json", "step10/show_ip_route.ref" + ) + + +def test_mpls_lib_step10(): + logger.info("Test (step 10): verify MPLS LIB") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, "show mpls table json", "step10/show_mpls_table.ref" + ) + + +# FIXME: These tests don't work yet, this should be fixed with the +# switchover to a yang based CLI. +# +# Step 11 +# +# Action(s): +# -Enter invalid SR configuration +# +# Expected changes: +# -All commands should be rejected +# +#def test_ospf_invalid_config_step11(): +# logger.info("Test (step 11): check if invalid configuration is rejected") +# tgen = get_topogen() +# +# # Skip if previous fatal error condition is raised +# if tgen.routers_have_failure(): +# pytest.skip(tgen.errors) +# +# logger.info("Entering invalid Segment Routing configuration...") +# ret = tgen.net["rt1"].cmd( +# 'vtysh -c "conf t" -c "router ospf" -c "segment-routing prefix 1.1.1.1/32 index 10000"' +# ) +# assert ( +# re.search("Configuration failed", ret) is not None +# ), "Invalid SR configuration wasn't rejected" +# ret = tgen.net["rt1"].cmd( +# 'vtysh -c "conf t" -c "router ospf" -c "segment-routing global-block 16000 14999"' +# ) +# assert ( +# re.search("Configuration failed", ret) is not None +# ), "Invalid SR configuration wasn't rejected" +# ret = tgen.net["rt1"].cmd( +# 'vtysh -c "conf t" -c "router ospf" -c "segment-routing global-block 16000 16001"' +# ) +# assert ( +# re.search("Configuration failed", ret) is not None +# ), "Invalid SR configuration wasn't rejected" + + +# Memory leak test template def test_memory_leak(): "Run the memory leak test and report results." tgen = get_topogen() diff --git a/tests/topotests/ospf-tilfa-topo1/test_ospf_tilfa_topo1.py b/tests/topotests/ospf-tilfa-topo1/test_ospf_tilfa_topo1.py index eb3ad5d995..489690471c 100644 --- a/tests/topotests/ospf-tilfa-topo1/test_ospf_tilfa_topo1.py +++ b/tests/topotests/ospf-tilfa-topo1/test_ospf_tilfa_topo1.py @@ -166,6 +166,7 @@ def test_ospf_initial_convergence_step1(): "step1/show_ip_route_initial.ref", ) + def test_ospf_link_protection_step2(): logger.info("Test (step 2): check OSPF link protection") tgen = get_topogen() @@ -175,9 +176,7 @@ def test_ospf_link_protection_step2(): pytest.skip(tgen.errors) # enable TI-LFA link protection on all interfaces - tgen.net["rt1"].cmd( - 'vtysh -c "conf t" -c "router ospf" -c "fast-reroute ti-lfa"' - ) + tgen.net["rt1"].cmd('vtysh -c "conf t" -c "router ospf" -c "fast-reroute ti-lfa"') router_compare_json_output( "rt1", @@ -197,6 +196,7 @@ def test_ospf_link_protection_step2(): "step2/show_ip_route_initial.ref", ) + def test_ospf_node_protection_step3(): logger.info("Test (step 3): check OSPF node protection") tgen = get_topogen() @@ -228,6 +228,7 @@ def test_ospf_node_protection_step3(): "step3/show_ip_route_initial.ref", ) + # Memory leak test template def test_memory_leak(): "Run the memory leak test and report results." @@ -237,6 +238,7 @@ def test_memory_leak(): tgen.report_memory_leaks() + if __name__ == "__main__": args = ["-s"] + sys.argv[1:] sys.exit(pytest.main(args)) diff --git a/tests/topotests/ospf-topo1-vrf/test_ospf_topo1_vrf.py b/tests/topotests/ospf-topo1-vrf/test_ospf_topo1_vrf.py index 92dac0f39c..e2cb7bff03 100644 --- a/tests/topotests/ospf-topo1-vrf/test_ospf_topo1_vrf.py +++ b/tests/topotests/ospf-topo1-vrf/test_ospf_topo1_vrf.py @@ -47,6 +47,7 @@ from mininet.topo import Topo pytestmark = [pytest.mark.ospfd] + class OSPFTopo(Topo): "Test topology builder" diff --git a/tests/topotests/ospf-topo1/test_ospf_topo1.py b/tests/topotests/ospf-topo1/test_ospf_topo1.py index 7197c05812..5bb6c2c818 100644 --- a/tests/topotests/ospf-topo1/test_ospf_topo1.py +++ b/tests/topotests/ospf-topo1/test_ospf_topo1.py @@ -47,6 +47,7 @@ from mininet.topo import Topo pytestmark = [pytest.mark.ospfd] + class OSPFTopo(Topo): "Test topology builder" diff --git a/tests/topotests/ospf6-topo1/test_ospf6_topo1.py b/tests/topotests/ospf6-topo1/test_ospf6_topo1.py index c3efb6ff22..6ae886b76e 100644 --- a/tests/topotests/ospf6-topo1/test_ospf6_topo1.py +++ b/tests/topotests/ospf6-topo1/test_ospf6_topo1.py @@ -384,15 +384,14 @@ def test_linux_ipv6_kernel_routingTable(): % (i, diff) ) else: - logger.error( - "r{} failed - no nhid ref file: {}".format(i, refTableFile) - ) + logger.error("r{} failed - no nhid ref file: {}".format(i, refTableFile)) assert False, ( "Linux Kernel IPv6 Routing Table verification failed for router r%s\n" % (i) ) + def test_shutdown_check_stderr(): tgen = get_topogen() diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_chaos.py b/tests/topotests/ospf_basic_functionality/test_ospf_chaos.py index ca7cb736f9..cebe55b39c 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_chaos.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_chaos.py @@ -49,15 +49,14 @@ from lib.common_config import ( shutdown_bringup_interface, topo_daemons, verify_rib, - stop_router, start_router, + stop_router, + start_router, create_static_routes, start_router_daemons, - kill_router_daemons + kill_router_daemons, ) -from lib.ospf import ( - verify_ospf_neighbor, verify_ospf_rib, - create_router_ospf) +from lib.ospf import verify_ospf_neighbor, verify_ospf_rib, create_router_ospf from lib.topolog import logger from lib.topojson import build_topo_from_json, build_config_from_json @@ -69,8 +68,13 @@ pytestmark = [pytest.mark.ospfd, pytest.mark.staticd] topo = None NETWORK = { - "ipv4": ["11.0.20.1/32", "11.0.20.2/32", "11.0.20.3/32", "11.0.20.4/32", - "11.0.20.5/32"] + "ipv4": [ + "11.0.20.1/32", + "11.0.20.2/32", + "11.0.20.3/32", + "11.0.20.4/32", + "11.0.20.5/32", + ] } """ Topology: @@ -102,6 +106,7 @@ try: except IOError: assert False, "Could not read file {}".format(jsonFile) + class CreateTopo(Topo): """ Test topology builder. @@ -190,78 +195,71 @@ def test_ospf_chaos_tc31_p1(request): step( "Create static routes(10.0.20.1/32) in R1 and redistribute " - "to OSPF using route map.") + "to OSPF using route map." + ) # Create Static routes input_dict = { "r0": { "static_routes": [ { - "network": NETWORK['ipv4'][0], + "network": NETWORK["ipv4"][0], "no_of_ip": 5, - "next_hop": 'Null0', + "next_hop": "Null0", } ] } } result = create_static_routes(tgen, input_dict) - assert result is True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) - ospf_red_r0 = { - "r0": { - "ospf": { - "redistribute": [{ - "redist_type": "static" - }] - } - } - } + ospf_red_r0 = {"r0": {"ospf": {"redistribute": [{"redist_type": "static"}]}}} result = create_router_ospf(tgen, topo, ospf_red_r0) - assert result is True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) step("Verify OSPF neighbors after base config is done.") # Api call verify whether OSPF is converged ospf_covergence = verify_ospf_neighbor(tgen, topo) - assert ospf_covergence is True, ("setup_module :Failed \n Error:" - " {}".format(ospf_covergence)) + assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format( + ospf_covergence + ) step("Verify that route is advertised to R1.") - dut = 'r1' - protocol = 'ospf' - nh = topo['routers']['r0']['links']['r1']['ipv4'].split('/')[0] + dut = "r1" + protocol = "ospf" + nh = topo["routers"]["r0"]["links"]["r1"]["ipv4"].split("/")[0] result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh) - assert result is True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) - result = verify_rib( - tgen, "ipv4", dut, input_dict, protocol=protocol, next_hop=nh) - assert result is True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) + result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, next_hop=nh) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) step("Kill OSPFd daemon on R0.") kill_router_daemons(tgen, "r0", ["ospfd"]) step("Verify OSPF neighbors are down after killing ospfd in R0") - dut = 'r0' + dut = "r0" # Api call verify whether OSPF is converged - ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut, - expected=False) - assert ospf_covergence is not True, ("setup_module :Failed \n Error:" - " {}".format(ospf_covergence)) + ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut, expected=False) + assert ospf_covergence is not True, "setup_module :Failed \n Error:" " {}".format( + ospf_covergence + ) step("Verify that route advertised to R1 are deleted from RIB and FIB.") - dut = 'r1' - protocol = 'ospf' + dut = "r1" + protocol = "ospf" result = verify_ospf_rib(tgen, dut, input_dict, expected=False) - assert result is not True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) + assert result is not True, ("Testcase {} : Failed \n " + "r1: OSPF routes are present \n Error: {}".format( + tc_name, result + )) result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False) - assert result is not True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) + assert result is not True, ("Testcase {} : Failed \n " + "r1: routes are still present \n Error: {}".format( + tc_name, result + )) step("Bring up OSPFd daemon on R0.") start_router_daemons(tgen, "r0", ["ospfd"]) @@ -269,33 +267,32 @@ def test_ospf_chaos_tc31_p1(request): step("Verify OSPF neighbors are up after bringing back ospfd in R0") # Api call verify whether OSPF is converged ospf_covergence = verify_ospf_neighbor(tgen, topo) - assert ospf_covergence is True, ("setup_module :Failed \n Error:" - " {}".format(ospf_covergence)) + assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format( + ospf_covergence + ) step( "All the neighbours are up and routes are installed before the" - " restart. Verify OSPF route table and ip route table.") - dut = 'r1' - protocol = 'ospf' + " restart. Verify OSPF route table and ip route table." + ) + dut = "r1" + protocol = "ospf" result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh) - assert result is True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) - result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, - next_hop=nh) - assert result is True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) + result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, next_hop=nh) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) step("Kill OSPFd daemon on R1.") kill_router_daemons(tgen, "r1", ["ospfd"]) step("Verify OSPF neighbors are down after killing ospfd in R1") - dut = 'r1' + dut = "r1" # Api call verify whether OSPF is converged - ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut, - expected=False) - assert ospf_covergence is not True, ("setup_module :Failed \n Error:" - " {}".format(ospf_covergence)) + ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut, expected=False) + assert ospf_covergence is not True, "setup_module :Failed \n Error:" " {}".format( + ospf_covergence + ) step("Bring up OSPFd daemon on R1.") start_router_daemons(tgen, "r1", ["ospfd"]) @@ -303,23 +300,22 @@ def test_ospf_chaos_tc31_p1(request): step("Verify OSPF neighbors are up after bringing back ospfd in R1") # Api call verify whether OSPF is converged ospf_covergence = verify_ospf_neighbor(tgen, topo) - assert ospf_covergence is True, ("setup_module :Failed \n Error:" - " {}".format(ospf_covergence)) + assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format( + ospf_covergence + ) step( "All the neighbours are up and routes are installed before the" - " restart. Verify OSPF route table and ip route table.") + " restart. Verify OSPF route table and ip route table." + ) - dut = 'r1' - protocol = 'ospf' + dut = "r1" + protocol = "ospf" result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh) - assert result is True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) - result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, - next_hop=nh) - assert result is True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) + result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, next_hop=nh) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) write_test_footer(tc_name) @@ -335,104 +331,91 @@ def test_ospf_chaos_tc32_p1(request): step( "Create static routes(10.0.20.1/32) in R1 and redistribute " - "to OSPF using route map.") + "to OSPF using route map." + ) # Create Static routes input_dict = { "r0": { "static_routes": [ { - "network": NETWORK['ipv4'][0], + "network": NETWORK["ipv4"][0], "no_of_ip": 5, - "next_hop": 'Null0', + "next_hop": "Null0", } ] } } result = create_static_routes(tgen, input_dict) - assert result is True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) - ospf_red_r0 = { - "r0": { - "ospf": { - "redistribute": [{ - "redist_type": "static" - }] - } - } - } + ospf_red_r0 = {"r0": {"ospf": {"redistribute": [{"redist_type": "static"}]}}} result = create_router_ospf(tgen, topo, ospf_red_r0) - assert result is True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) step("Verify OSPF neighbors after base config is done.") # Api call verify whether OSPF is converged ospf_covergence = verify_ospf_neighbor(tgen, topo) - assert ospf_covergence is True, ("setup_module :Failed \n Error:" - " {}".format(ospf_covergence)) + assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format( + ospf_covergence + ) step("Verify that route is advertised to R1.") - dut = 'r1' - protocol = 'ospf' + dut = "r1" + protocol = "ospf" - nh = topo['routers']['r0']['links']['r1']['ipv4'].split('/')[0] + nh = topo["routers"]["r0"]["links"]["r1"]["ipv4"].split("/")[0] result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh) - assert result is True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) - result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, - next_hop=nh) - assert result is True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) + result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, next_hop=nh) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) step("Restart frr on R0") - stop_router(tgen, 'r0') - start_router(tgen, 'r0') + stop_router(tgen, "r0") + start_router(tgen, "r0") step("Verify OSPF neighbors are up after restarting R0") # Api call verify whether OSPF is converged ospf_covergence = verify_ospf_neighbor(tgen, topo) - assert ospf_covergence is True, ("setup_module :Failed \n Error:" - " {}".format(ospf_covergence)) + assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format( + ospf_covergence + ) step( "All the neighbours are up and routes are installed before the" - " restart. Verify OSPF route table and ip route table.") - dut = 'r1' - protocol = 'ospf' + " restart. Verify OSPF route table and ip route table." + ) + dut = "r1" + protocol = "ospf" result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh) - assert result is True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) - result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, - next_hop=nh) - assert result is True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) + result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, next_hop=nh) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) step("Restart frr on R1") - stop_router(tgen, 'r1') - start_router(tgen, 'r1') + stop_router(tgen, "r1") + start_router(tgen, "r1") step("Verify OSPF neighbors are up after restarting R1") # Api call verify whether OSPF is converged ospf_covergence = verify_ospf_neighbor(tgen, topo) - assert ospf_covergence is True, ("setup_module :Failed \n Error:" - " {}".format(ospf_covergence)) + assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format( + ospf_covergence + ) step( "All the neighbours are up and routes are installed before the" - " restart. Verify OSPF route table and ip route table.") - dut = 'r1' - protocol = 'ospf' + " restart. Verify OSPF route table and ip route table." + ) + dut = "r1" + protocol = "ospf" result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh) - assert result is True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) - result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, - next_hop=nh) - assert result is True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) + result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, next_hop=nh) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) write_test_footer(tc_name) @@ -453,70 +436,63 @@ def test_ospf_chaos_tc34_p1(request): step( "Create static routes(10.0.20.1/32) in R1 and redistribute " - "to OSPF using route map.") + "to OSPF using route map." + ) # Create Static routes input_dict = { "r0": { "static_routes": [ { - "network": NETWORK['ipv4'][0], + "network": NETWORK["ipv4"][0], "no_of_ip": 5, - "next_hop": 'Null0', + "next_hop": "Null0", } ] } } result = create_static_routes(tgen, input_dict) - assert result is True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) - ospf_red_r0 = { - "r0": { - "ospf": { - "redistribute": [{ - "redist_type": "static" - }] - } - } - } + ospf_red_r0 = {"r0": {"ospf": {"redistribute": [{"redist_type": "static"}]}}} result = create_router_ospf(tgen, topo, ospf_red_r0) - assert result is True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) step("Verify OSPF neighbors after base config is done.") # Api call verify whether OSPF is converged ospf_covergence = verify_ospf_neighbor(tgen, topo) - assert ospf_covergence is True, ("setup_module :Failed \n Error:" - " {}".format(ospf_covergence)) + assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format( + ospf_covergence + ) step("Verify that route is advertised to R1.") - dut = 'r1' - protocol = 'ospf' - nh = topo['routers']['r0']['links']['r1']['ipv4'].split('/')[0] + dut = "r1" + protocol = "ospf" + nh = topo["routers"]["r0"]["links"]["r1"]["ipv4"].split("/")[0] result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh) - assert result is True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) - result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, - next_hop=nh) - assert result is True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) + result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, next_hop=nh) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) step("Kill staticd daemon on R0.") kill_router_daemons(tgen, "r0", ["staticd"]) step("Verify that route advertised to R1 are deleted from RIB and FIB.") - dut = 'r1' - protocol = 'ospf' + dut = "r1" + protocol = "ospf" result = verify_ospf_rib(tgen, dut, input_dict, expected=False) - assert result is not True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) + assert result is not True, ("Testcase {} : Failed \n " + "r1: OSPF routes are present \n Error: {}".format( + tc_name, result + )) result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False) - assert result is not True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) + assert result is not True, ("Testcase {} : Failed \n " + "r1: routes are still present \n Error: {}".format( + tc_name, result + )) step("Bring up staticd daemon on R0.") start_router_daemons(tgen, "r0", ["staticd"]) @@ -524,22 +500,21 @@ def test_ospf_chaos_tc34_p1(request): step("Verify OSPF neighbors are up after bringing back ospfd in R0") # Api call verify whether OSPF is converged ospf_covergence = verify_ospf_neighbor(tgen, topo) - assert ospf_covergence is True, ("setup_module :Failed \n Error:" - " {}".format(ospf_covergence)) + assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format( + ospf_covergence + ) step( "All the neighbours are up and routes are installed before the" - " restart. Verify OSPF route table and ip route table.") - dut = 'r1' - protocol = 'ospf' + " restart. Verify OSPF route table and ip route table." + ) + dut = "r1" + protocol = "ospf" result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh) - assert result is True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) - result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, - next_hop=nh) - assert result is True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) + result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, next_hop=nh) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) step("Kill staticd daemon on R1.") kill_router_daemons(tgen, "r1", ["staticd"]) @@ -550,23 +525,22 @@ def test_ospf_chaos_tc34_p1(request): step("Verify OSPF neighbors are up after bringing back ospfd in R1") # Api call verify whether OSPF is converged ospf_covergence = verify_ospf_neighbor(tgen, topo) - assert ospf_covergence is True, ("setup_module :Failed \n Error:" - " {}".format(ospf_covergence)) + assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format( + ospf_covergence + ) step( "All the neighbours are up and routes are installed before the" - " restart. Verify OSPF route table and ip route table.") + " restart. Verify OSPF route table and ip route table." + ) - dut = 'r1' - protocol = 'ospf' + dut = "r1" + protocol = "ospf" result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh) - assert result is True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) - result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, - next_hop=nh) - assert result is True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) + result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, next_hop=nh) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) write_test_footer(tc_name) diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_ecmp.py b/tests/topotests/ospf_basic_functionality/test_ospf_ecmp.py index 441368e8fa..adf82a5e85 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_ecmp.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_ecmp.py @@ -259,17 +259,19 @@ def test_ospf_ecmp_tc16_p0(request): shutdown_bringup_interface(tgen, dut, intf, False) result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh, expected=False) - assert result is not True, "Testcase {} : Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r1: OSPF routes are present \n Error: {}".format( tc_name, result - ) + )) protocol = "ospf" result = verify_rib( tgen, "ipv4", dut, input_dict, protocol=protocol, next_hop=nh, expected=False ) - assert result is not True, "Testcase {} : Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r1: routes are still present \n Error: {}".format( tc_name, result - ) + )) for intfr in range(1, 7): intf = topo["routers"]["r1"]["links"]["r0-link{}".format(intfr)]["interface"] @@ -324,9 +326,10 @@ def test_ospf_ecmp_tc16_p0(request): result = verify_ospf_rib( tgen, dut, input_dict, next_hop=nh, attempts=5, expected=False ) - assert result is not True, "Testcase {} : Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r1: OSPF routes are present \n Error: {}".format( tc_name, result - ) + )) protocol = "ospf" result = verify_rib( @@ -339,9 +342,10 @@ def test_ospf_ecmp_tc16_p0(request): attempts=5, expected=False, ) - assert result is not True, "Testcase {} : Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r1: routes are still present \n Error: {}".format( tc_name, result - ) + )) step("Re configure the static route in R0.") dut = "r0" @@ -428,9 +432,10 @@ def test_ospf_ecmp_tc17_p0(request): result = verify_ospf_rib( tgen, dut, input_dict, next_hop=nh, attempts=5, expected=False ) - assert result is not True, "Testcase {} : Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r1: OSPF routes are present \n Error: {}".format( tc_name, result - ) + )) protocol = "ospf" result = verify_rib( @@ -443,9 +448,10 @@ def test_ospf_ecmp_tc17_p0(request): attempts=5, expected=False, ) - assert result is not True, "Testcase {} : Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r1: routes are still present \n Error: {}".format( tc_name, result - ) + )) step("Reconfigure the static route in R0.Change ECMP value to 2.") dut = "r0" diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_ecmp_lan.py b/tests/topotests/ospf_basic_functionality/test_ospf_ecmp_lan.py index 2da1dcd21a..c5230d6614 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_ecmp_lan.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_ecmp_lan.py @@ -307,9 +307,10 @@ def test_ospf_lan_ecmp_tc18_p0(request): result = verify_ospf_rib( tgen, dut, input_dict, next_hop=nh, attempts=5, expected=False ) - assert result is not True, "Testcase {} : Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r1: OSPF routes are present \n Error: {}".format( tc_name, result - ) + )) protocol = "ospf" result = verify_rib( @@ -322,9 +323,10 @@ def test_ospf_lan_ecmp_tc18_p0(request): attempts=5, expected=False, ) - assert result is not True, "Testcase {} : Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r1: routes are still present \n Error: {}".format( tc_name, result - ) + )) write_test_footer(tc_name) diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_lan.py b/tests/topotests/ospf_basic_functionality/test_ospf_lan.py index dac32090bc..2fbb27f4fc 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_lan.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_lan.py @@ -397,9 +397,10 @@ def test_ospf_lan_tc1_p0(request): shutdown_bringup_interface(tgen, dut, intf, False) result = verify_ospf_neighbor(tgen, topo, dut, lan=True, expected=False) - assert result is not True, "Testcase {} : Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r0: OSPF neighbors-hip is up \n Error: {}".format( tc_name, result - ) + )) step("No Shut interface on R0") dut = "r0" diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_p2mp.py b/tests/topotests/ospf_basic_functionality/test_ospf_p2mp.py index c90275ecb0..be18ba5a78 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_p2mp.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_p2mp.py @@ -146,7 +146,6 @@ def setup_module(mod): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - logger.info("Running setup_module() done") @@ -397,10 +396,7 @@ def test_ospf_p2mp_tc1_p0(request): "links": { "r3": { "interface": topo["routers"]["r0"]["links"]["r3"]["interface"], - "ospf": { - "area": "0.0.0.0", - "networkType":"POINTOMULTIPOINT" - }, + "ospf": {"area": "0.0.0.0", "networkType": "POINTOMULTIPOINT"}, } } } diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_routemaps.py b/tests/topotests/ospf_basic_functionality/test_ospf_routemaps.py index ceadb3975b..b99ce6cfb8 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_routemaps.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_routemaps.py @@ -332,16 +332,18 @@ def test_ospf_routemaps_functionality_tc19_p0(request): } } result = verify_ospf_rib(tgen, dut, input_dict, expected=False) - assert result is not True, "Testcase {} : Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r1: OSPF routes are present \n Error: {}".format( tc_name, result - ) + )) result = verify_rib( tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False ) - assert result is not True, "Testcase {} : Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r1: routes are present in fib \n Error: {}".format( tc_name, result - ) + )) step("Delete and reconfigure prefix list.") # Create ip prefix list @@ -381,16 +383,18 @@ def test_ospf_routemaps_functionality_tc19_p0(request): } } result = verify_ospf_rib(tgen, dut, input_dict, expected=False) - assert result is not True, "Testcase {} : Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r1: OSPF routes are present \n Error: {}".format( tc_name, result - ) + )) result = verify_rib( tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False ) - assert result is not True, "Testcase {} : Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r1: OSPF routes are present \n Error: {}".format( tc_name, result - ) + )) pfx_list = { "r0": { @@ -434,16 +438,18 @@ def test_ospf_routemaps_functionality_tc19_p0(request): } } result = verify_ospf_rib(tgen, dut, input_dict, expected=False) - assert result is not True, "Testcase {} : Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r1: OSPF routes are present \n Error: {}".format( tc_name, result - ) + )) result = verify_rib( tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False ) - assert result is not True, "Testcase {} : Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r1: routes are still present \n Error: {}".format( tc_name, result - ) + )) write_test_footer(tc_name) @@ -490,16 +496,18 @@ def test_ospf_routemaps_functionality_tc20_p0(request): dut = "r1" protocol = "ospf" result = verify_ospf_rib(tgen, dut, input_dict, attempts=2, expected=False) - assert result is not True, "Testcase {} : Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r1: OSPF routes are present \n Error: {}".format( tc_name, result - ) + )) result = verify_rib( tgen, "ipv4", dut, input_dict, protocol=protocol, attempts=2, expected=False ) - assert result is not True, "Testcase {} : Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r1: routes are still present \n Error: {}".format( tc_name, result - ) + )) step( "configure the route map with the same name that is used " @@ -515,16 +523,18 @@ def test_ospf_routemaps_functionality_tc20_p0(request): dut = "r1" protocol = "ospf" result = verify_ospf_rib(tgen, dut, input_dict, expected=False) - assert result is not True, "Testcase {} : Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r1: OSPF routes are present \n Error: {}".format( tc_name, result - ) + )) result = verify_rib( tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False ) - assert result is not True, "Testcase {} : Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r1: routes are still present \n Error: {}".format( tc_name, result - ) + )) # Create route map routemaps = {"r0": {"route_maps": {"rmap_ipv4": [{"action": "deny"}]}}} @@ -535,16 +545,18 @@ def test_ospf_routemaps_functionality_tc20_p0(request): dut = "r1" protocol = "ospf" result = verify_ospf_rib(tgen, dut, input_dict, expected=False) - assert result is not True, "Testcase {} : Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r1: OSPF routes are present \n Error: {}".format( tc_name, result - ) + )) result = verify_rib( tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False ) - assert result is not True, "Testcase {} : Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r1: routes are still present \n Error: {}".format( tc_name, result - ) + )) step("Delete the route map.") # Create route map @@ -561,16 +573,18 @@ def test_ospf_routemaps_functionality_tc20_p0(request): dut = "r1" protocol = "ospf" result = verify_ospf_rib(tgen, dut, input_dict, expected=False) - assert result is not True, "Testcase {} : Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r1: OSPF routes are present \n Error: {}".format( tc_name, result - ) + )) result = verify_rib( tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False ) - assert result is not True, "Testcase {} : Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r1: routes are still present \n Error: {}".format( tc_name, result - ) + )) write_test_footer(tc_name) diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_rte_calc.py b/tests/topotests/ospf_basic_functionality/test_ospf_rte_calc.py index 5aa2779aee..fb6b28ce5b 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_rte_calc.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_rte_calc.py @@ -247,9 +247,11 @@ def test_ospf_redistribution_tc5_p0(request): if result is not True: break - assert result is not True, "Testcase {} : Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r1: OSPF routes are present after deleting ip address of newly " + "configured interface of R0 \n Error: {}".format( tc_name, result - ) + )) protocol = "ospf" result = verify_rib( @@ -262,9 +264,11 @@ def test_ospf_redistribution_tc5_p0(request): attempts=5, expected=False, ) - assert result is not True, "Testcase {} : Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r1: OSPF routes are present in fib after deleting ip address of newly " + "configured interface of R0 \n Error: {}".format( tc_name, result - ) + )) step("Add back the deleted ip address on newly configured interface of R0") topo1 = { @@ -366,9 +370,11 @@ def test_ospf_redistribution_tc6_p0(request): result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh, expected=False) if result is not True: break - assert result is not True, "Testcase {} : Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r1: OSPF routes are present after deleting ip address of newly " + "configured loopback of R0 \n Error: {}".format( tc_name, result - ) + )) protocol = "ospf" result = verify_rib( @@ -380,9 +386,11 @@ def test_ospf_redistribution_tc6_p0(request): next_hop=nh, expected=False, ) - assert result is not True, "Testcase {} : Failed \n Error: {}".format( + assert result is not True, ("Testcase {} : Failed \n " + "r1: OSPF routes are present in fib after deleting ip address of newly " + "configured loopback of R0 \n Error: {}".format( tc_name, result - ) + )) step("Add back the deleted ip address on newly configured interface of R0") topo1 = { diff --git a/tests/topotests/pbr-topo1/test_pbr_topo1.py b/tests/topotests/pbr-topo1/test_pbr_topo1.py index 4b6de51c86..1a024063b8 100644 --- a/tests/topotests/pbr-topo1/test_pbr_topo1.py +++ b/tests/topotests/pbr-topo1/test_pbr_topo1.py @@ -82,6 +82,7 @@ class NetworkTopo(Topo): ## ##################################################### + def setup_module(module): "Setup topology" tgen = Topogen(NetworkTopo, module.__name__) diff --git a/tests/topotests/pim-basic/test_pim.py b/tests/topotests/pim-basic/test_pim.py index 918d3847ce..4debbeb851 100644 --- a/tests/topotests/pim-basic/test_pim.py +++ b/tests/topotests/pim-basic/test_pim.py @@ -45,6 +45,7 @@ from mininet.topo import Topo pytestmark = [pytest.mark.pimd] + class PIMTopo(Topo): def build(self, *_args, **_opts): "Build function" diff --git a/tests/topotests/pytest.ini b/tests/topotests/pytest.ini index 0c45a09445..562e754f21 100644 --- a/tests/topotests/pytest.ini +++ b/tests/topotests/pytest.ini @@ -24,6 +24,7 @@ markers = sharpd: Tests that run against SHARPD staticd: Tests that run against STATICD vrrpd: Tests that run against VRRPD + snmp: Tests that run against snmp changes [topogen] # Default configuration values diff --git a/tests/topotests/simple-snmp-test/test_simple_snmp.py b/tests/topotests/simple-snmp-test/test_simple_snmp.py index 88ff01bf0a..5647e2b663 100755 --- a/tests/topotests/simple-snmp-test/test_simple_snmp.py +++ b/tests/topotests/simple-snmp-test/test_simple_snmp.py @@ -46,6 +46,8 @@ from lib.snmptest import SnmpTester # Required to instantiate the topology builder class. from mininet.topo import Topo +pytestmark = [pytest.mark.bgpd, pytest.mark.isisd, pytest.mark.snmp] + class TemplateTopo(Topo): "Test topology builder" diff --git a/tests/topotests/static_routing_with_ebgp/test_static_routes_topo1_ebgp.py b/tests/topotests/static_routing_with_ebgp/test_static_routes_topo1_ebgp.py index 712a40c738..a4cc8e8e7a 100644 --- a/tests/topotests/static_routing_with_ebgp/test_static_routes_topo1_ebgp.py +++ b/tests/topotests/static_routing_with_ebgp/test_static_routes_topo1_ebgp.py @@ -35,6 +35,7 @@ import time import os import pytest import platform + # Save the Current Working Directory to find configuration files. CWD = os.path.dirname(os.path.realpath(__file__)) sys.path.append(os.path.join(CWD, "../")) @@ -44,6 +45,7 @@ sys.path.append(os.path.join(CWD, "../lib/")) from mininet.topo import Topo from lib.topogen import Topogen, get_topogen from lib.topotest import version_cmp + # Import topoJson from lib, to create topology and initial configuration from lib.common_config import ( start_topology, @@ -121,9 +123,11 @@ def setup_module(mod): # Creating configuration from JSON build_config_from_json(tgen, topo) - if version_cmp(platform.release(), '4.19') < 0: - error_msg = ('These tests will not run. (have kernel "{}", ' - 'requires kernel >= 4.19)'.format(platform.release())) + if version_cmp(platform.release(), "4.19") < 0: + error_msg = ( + 'These tests will not run. (have kernel "{}", ' + "requires kernel >= 4.19)".format(platform.release()) + ) pytest.skip(error_msg) # Checking BGP convergence diff --git a/tests/topotests/static_routing_with_ebgp/test_static_routes_topo2_ebgp.py b/tests/topotests/static_routing_with_ebgp/test_static_routes_topo2_ebgp.py index c009929a48..6649915dec 100644 --- a/tests/topotests/static_routing_with_ebgp/test_static_routes_topo2_ebgp.py +++ b/tests/topotests/static_routing_with_ebgp/test_static_routes_topo2_ebgp.py @@ -163,9 +163,11 @@ def setup_module(mod): # Creating configuration from JSON build_config_from_json(tgen, topo) - if version_cmp(platform.release(), '4.19') < 0: - error_msg = ('These tests will not run. (have kernel "{}", ' - 'requires kernel >= 4.19)'.format(platform.release())) + if version_cmp(platform.release(), "4.19") < 0: + error_msg = ( + 'These tests will not run. (have kernel "{}", ' + "requires kernel >= 4.19)".format(platform.release()) + ) pytest.skip(error_msg) # Checking BGP convergence @@ -854,12 +856,12 @@ def test_static_route_8nh_diff_AD_bgp_ecmp_p1_tc6_ebgp(request): for addr_type in ADDR_TYPES: input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}} result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol) - assert result is True, ( - "Testcase {} : Failed \n" - "Error: Routes are still present in RIB".format(tc_name) + assert ( + result is True + ), "Testcase {} : Failed \n" "Error: Routes are still present in RIB".format( + tc_name ) - write_test_footer(tc_name) @@ -1129,9 +1131,10 @@ def test_static_route_8nh_diff_AD_ebgp_ecmp_p1_tc8_ebgp(request): for addr_type in ADDR_TYPES: input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}} result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol) - assert result is True, ( - "Testcase {} : Failed \n" - "Error: Routes are still present in RIB".format(tc_name) + assert ( + result is True + ), "Testcase {} : Failed \n" "Error: Routes are still present in RIB".format( + tc_name ) write_test_footer(tc_name) @@ -1339,7 +1342,15 @@ def test_static_route_8nh_diff_AD_bgp_ecmp_p1_tc10_ebgp(request): " value and all the nexthop populated in RIB and FIB again" ) for addr_type in ADDR_TYPES: - input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type],}]}} + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + } + ] + } + } nh = NEXT_HOP_IP["nh1"][addr_type] result = verify_rib( tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True @@ -1468,9 +1479,10 @@ def test_static_route_8nh_diff_AD_bgp_ecmp_p1_tc10_ebgp(request): protocol=protocol, fib=True, ) - assert result is True, ( - "Testcase {} : Failed \nError: Route " - " is missing in RIB".format(tc_name) + assert ( + result is True + ), "Testcase {} : Failed \nError: Route " " is missing in RIB".format( + tc_name ) write_test_footer(tc_name) diff --git a/tests/topotests/static_routing_with_ebgp/test_static_routes_topo4_ebgp.py b/tests/topotests/static_routing_with_ebgp/test_static_routes_topo4_ebgp.py index 3d41d89443..dc4e29ebde 100644 --- a/tests/topotests/static_routing_with_ebgp/test_static_routes_topo4_ebgp.py +++ b/tests/topotests/static_routing_with_ebgp/test_static_routes_topo4_ebgp.py @@ -88,6 +88,7 @@ NEXT_HOP_IP = {} pytestmark = [pytest.mark.bgpd, pytest.mark.staticd] + class CreateTopo(Topo): """ Test CreateTopo - topology 1. @@ -126,9 +127,11 @@ def setup_module(mod): # Creating configuration from JSON build_config_from_json(tgen, topo) - if version_cmp(platform.release(), '4.19') < 0: - error_msg = ('These tests will not run. (have kernel "{}", ' - 'requires kernel >= 4.19)'.format(platform.release())) + if version_cmp(platform.release(), "4.19") < 0: + error_msg = ( + 'These tests will not run. (have kernel "{}", ' + "requires kernel >= 4.19)".format(platform.release()) + ) pytest.skip(error_msg) # Checking BGP convergence @@ -946,9 +949,10 @@ def static_routes_rmap_pfxlist_p0_tc7_ebgp(request): result4 = verify_rib( tgen, addr_type, dut, input_dict, protocol=protocol, expected=False ) - assert result4 is not True, "Testcase {} : Failed \n" "Error: {}".format( + assert result4 is not True, ("Testcase {} : Failed \n" + "routes are still present \n Error: {}".format( tc_name, result4 - ) + )) step("vm4 should be present in FRR1") dut = "r1" diff --git a/tests/topotests/static_routing_with_ibgp/test_static_routes_topo1_ibgp.py b/tests/topotests/static_routing_with_ibgp/test_static_routes_topo1_ibgp.py index ca67ff6645..8c2fdfca13 100644 --- a/tests/topotests/static_routing_with_ibgp/test_static_routes_topo1_ibgp.py +++ b/tests/topotests/static_routing_with_ibgp/test_static_routes_topo1_ibgp.py @@ -125,9 +125,11 @@ def setup_module(mod): # Creating configuration from JSON build_config_from_json(tgen, topo) - if version_cmp(platform.release(), '4.19') < 0: - error_msg = ('These tests will not run. (have kernel "{}", ' - 'requires kernel >= 4.19)'.format(platform.release())) + if version_cmp(platform.release(), "4.19") < 0: + error_msg = ( + 'These tests will not run. (have kernel "{}", ' + "requires kernel >= 4.19)".format(platform.release()) + ) pytest.skip(error_msg) # Checking BGP convergence diff --git a/tests/topotests/static_routing_with_ibgp/test_static_routes_topo2_ibgp.py b/tests/topotests/static_routing_with_ibgp/test_static_routes_topo2_ibgp.py index 2dc0a60d51..644ddc02d4 100644 --- a/tests/topotests/static_routing_with_ibgp/test_static_routes_topo2_ibgp.py +++ b/tests/topotests/static_routing_with_ibgp/test_static_routes_topo2_ibgp.py @@ -165,9 +165,11 @@ def setup_module(mod): # Creating configuration from JSON build_config_from_json(tgen, topo) - if version_cmp(platform.release(), '4.19') < 0: - error_msg = ('These tests will not run. (have kernel "{}", ' - 'requires kernel >= 4.19)'.format(platform.release())) + if version_cmp(platform.release(), "4.19") < 0: + error_msg = ( + 'These tests will not run. (have kernel "{}", ' + "requires kernel >= 4.19)".format(platform.release()) + ) pytest.skip(error_msg) # Checking BGP convergence @@ -884,9 +886,10 @@ def test_static_route_8nh_diff_AD_bgp_ecmp_p1_tc6_ibgp(request): for addr_type in ADDR_TYPES: input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}} result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol) - assert result is True, ( - "Testcase {} : Failed \n" - "Error: Routes are still present in RIB".format(tc_name) + assert ( + result is True + ), "Testcase {} : Failed \n" "Error: Routes are still present in RIB".format( + tc_name ) step("BGP neighbor remove and add") @@ -907,9 +910,10 @@ def test_static_route_8nh_diff_AD_bgp_ecmp_p1_tc6_ibgp(request): for addr_type in ADDR_TYPES: input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}} result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol) - assert result is True, ( - "Testcase {} : Failed \n" - "Error: Routes are still present in RIB".format(tc_name) + assert ( + result is True + ), "Testcase {} : Failed \n" "Error: Routes are still present in RIB".format( + tc_name ) dut = "r3" @@ -917,9 +921,10 @@ def test_static_route_8nh_diff_AD_bgp_ecmp_p1_tc6_ibgp(request): for addr_type in ADDR_TYPES: input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}} result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol) - assert result is True, ( - "Testcase {} : Failed \n" - "Error: Routes are still present in RIB".format(tc_name) + assert ( + result is True + ), "Testcase {} : Failed \n" "Error: Routes are still present in RIB".format( + tc_name ) step("Remove the redistribute static knob") @@ -1274,9 +1279,10 @@ def test_static_route_8nh_diff_AD_ibgp_ecmp_p1_tc7_ibgp(request): for addr_type in ADDR_TYPES: input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}} result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol) - assert result is True, ( - "Testcase {} : Failed \n" - "Error: Routes are still present in RIB".format(tc_name) + assert ( + result is True + ), "Testcase {} : Failed \n" "Error: Routes are still present in RIB".format( + tc_name ) step("BGP neighbor remove and add") @@ -1297,9 +1303,10 @@ def test_static_route_8nh_diff_AD_ibgp_ecmp_p1_tc7_ibgp(request): for addr_type in ADDR_TYPES: input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}} result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol) - assert result is True, ( - "Testcase {} : Failed \n" - "Error: Routes are still present in RIB".format(tc_name) + assert ( + result is True + ), "Testcase {} : Failed \n" "Error: Routes are still present in RIB".format( + tc_name ) dut = "r3" @@ -1307,9 +1314,10 @@ def test_static_route_8nh_diff_AD_ibgp_ecmp_p1_tc7_ibgp(request): for addr_type in ADDR_TYPES: input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}} result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol) - assert result is True, ( - "Testcase {} : Failed \n" - "Error: Routes are still present in RIB".format(tc_name) + assert ( + result is True + ), "Testcase {} : Failed \n" "Error: Routes are still present in RIB".format( + tc_name ) step("Remove the redistribute static knob") @@ -1557,7 +1565,15 @@ def test_static_route_8nh_diff_AD_bgp_ecmp_p1_tc10_ibgp(request): " value and all the nexthop populated in RIB and FIB again" ) for addr_type in ADDR_TYPES: - input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type],}]}} + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + } + ] + } + } nh = NEXT_HOP_IP["nh1"][addr_type] result = verify_rib( tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True @@ -1686,9 +1702,10 @@ def test_static_route_8nh_diff_AD_bgp_ecmp_p1_tc10_ibgp(request): protocol=protocol, fib=True, ) - assert result is True, ( - "Testcase {} : Failed \nError: Route " - " is missing in RIB".format(tc_name) + assert ( + result is True + ), "Testcase {} : Failed \nError: Route " " is missing in RIB".format( + tc_name ) step("Remove the redistribute static knob") diff --git a/tests/topotests/static_routing_with_ibgp/test_static_routes_topo3_ibgp.py b/tests/topotests/static_routing_with_ibgp/test_static_routes_topo3_ibgp.py index 3eb431d64f..8f9d88a442 100644 --- a/tests/topotests/static_routing_with_ibgp/test_static_routes_topo3_ibgp.py +++ b/tests/topotests/static_routing_with_ibgp/test_static_routes_topo3_ibgp.py @@ -149,9 +149,11 @@ def setup_module(mod): # Creating configuration from JSON build_config_from_json(tgen, topo) - if version_cmp(platform.release(), '4.19') < 0: - error_msg = ('These tests will not run. (have kernel "{}", ' - 'requires kernel >= 4.19)'.format(platform.release())) + if version_cmp(platform.release(), "4.19") < 0: + error_msg = ( + 'These tests will not run. (have kernel "{}", ' + "requires kernel >= 4.19)".format(platform.release()) + ) pytest.skip(error_msg) # Checking BGP convergence diff --git a/tests/topotests/static_routing_with_ibgp/test_static_routes_topo4_ibgp.py b/tests/topotests/static_routing_with_ibgp/test_static_routes_topo4_ibgp.py index 01fdff69e6..14db729195 100644 --- a/tests/topotests/static_routing_with_ibgp/test_static_routes_topo4_ibgp.py +++ b/tests/topotests/static_routing_with_ibgp/test_static_routes_topo4_ibgp.py @@ -69,6 +69,7 @@ from lib.bgp import ( ) from lib.topojson import build_topo_from_json, build_config_from_json from lib.topotest import version_cmp + # Reading the data from JSON File for topology creation jsonFile = "{}/static_routes_topo4_ibgp.json".format(CWD) try: @@ -85,6 +86,7 @@ NEXT_HOP_IP = {} pytestmark = [pytest.mark.bgpd, pytest.mark.staticd] + class CreateTopo(Topo): """ Test CreateTopo - topology 1. @@ -123,9 +125,11 @@ def setup_module(mod): # Creating configuration from JSON build_config_from_json(tgen, topo) - if version_cmp(platform.release(), '4.19') < 0: - error_msg = ('These tests will not run. (have kernel "{}", ' - 'requires kernel >= 4.19)'.format(platform.release())) + if version_cmp(platform.release(), "4.19") < 0: + error_msg = ( + 'These tests will not run. (have kernel "{}", ' + "requires kernel >= 4.19)".format(platform.release()) + ) pytest.skip(error_msg) # Checking BGP convergence @@ -943,9 +947,10 @@ def test_static_routes_rmap_pfxlist_p0_tc7_ibgp(request): result4 = verify_rib( tgen, addr_type, dut, input_dict, protocol=protocol, expected=False ) - assert result4 is not True, "Testcase {} : Failed \n" "Error: {}".format( + assert result4 is not True, ("Testcase {} : Failed \n" + "routes are still present \n Error: {}".format( tc_name, result4 - ) + )) step("vm4 should be present in FRR1") dut = "r1" diff --git a/tests/topotests/zebra_rib/test_zebra_rib.py b/tests/topotests/zebra_rib/test_zebra_rib.py index daf8f7be20..9fcf7b6820 100644 --- a/tests/topotests/zebra_rib/test_zebra_rib.py +++ b/tests/topotests/zebra_rib/test_zebra_rib.py @@ -76,9 +76,11 @@ def setup_module(mod): 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))) + TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) + ) router.load_config( - TopoRouter.RD_SHARP, os.path.join(CWD, "{}/sharpd.conf".format(rname))) + TopoRouter.RD_SHARP, os.path.join(CWD, "{}/sharpd.conf".format(rname)) + ) # Initialize all routers. tgen.start_router() @@ -159,6 +161,7 @@ def test_zebra_kernel_override(): _, result = topotest.run_and_expect(test_func, None, count=2, wait=0.5) assert result is None, '"r1" JSON output mismatches' + def test_route_map_usage(): "Test that FRR only reruns over routes associated with the routemap" logger.info("Test that FRR runs on selected re's on route-map changes") @@ -174,7 +177,9 @@ def test_route_map_usage(): r1.vtysh_cmd("conf\nroute-map static permit 10\nset src 192.168.215.1") r1.vtysh_cmd("conf\naccess-list 5 seq 5 permit 10.0.0.44/32") r1.vtysh_cmd("conf\naccess-list 10 seq 5 permit 10.0.1.0/24") - r1.vtysh_cmd("conf\nroute-map sharp permit 10\nmatch ip address 10\nset src 192.168.214.1") + r1.vtysh_cmd( + "conf\nroute-map sharp permit 10\nmatch ip address 10\nset src 192.168.214.1" + ) r1.vtysh_cmd("conf\nroute-map sharp permit 20\nset src 192.168.213.1") r1.vtysh_cmd("conf\nip protocol static route-map static") r1.vtysh_cmd("conf\nip protocol sharp route-map sharp") @@ -186,47 +191,57 @@ def test_route_map_usage(): static_rmapfile = "%s/r1/static_rmap.ref" % (thisDir) expected = open(static_rmapfile).read().rstrip() - expected = ('\n'.join(expected.splitlines()) + '\n').rstrip() + expected = ("\n".join(expected.splitlines()) + "\n").rstrip() actual = r1.vtysh_cmd("show route-map static") - actual = ('\n'.join(actual.splitlines()) + '\n').rstrip() - logger.info("Does the show route-map static command run the correct number of times") + actual = ("\n".join(actual.splitlines()) + "\n").rstrip() + logger.info( + "Does the show route-map static command run the correct number of times" + ) - diff = topotest.get_textdiff(actual, expected, - title1 = "Actual Route-map output", - title2 = "Expected Route-map output") + diff = topotest.get_textdiff( + actual, + expected, + title1="Actual Route-map output", + title2="Expected Route-map output", + ) if diff: logger.info("Actual:") logger.info(actual) logger.info("Expected:") logger.info(expected) srun = r1.vtysh_cmd("show run") - srun = ('\n'.join(srun.splitlines()) + '\n').rstrip() + srun = ("\n".join(srun.splitlines()) + "\n").rstrip() logger.info("Show run") logger.info(srun) assert 0, "r1 static route processing:\n" sharp_rmapfile = "%s/r1/sharp_rmap.ref" % (thisDir) expected = open(sharp_rmapfile).read().rstrip() - expected = ('\n'.join(expected.splitlines()) + '\n').rstrip() + expected = ("\n".join(expected.splitlines()) + "\n").rstrip() actual = r1.vtysh_cmd("show route-map sharp") - actual = ('\n'.join(actual.splitlines()) + '\n').rstrip() + actual = ("\n".join(actual.splitlines()) + "\n").rstrip() logger.info("Does the show route-map sharp command run the correct number of times") - diff = topotest.get_textdiff(actual, expected, - title1 = "Actual Route-map output", - title2 = "Expected Route-map output") + diff = topotest.get_textdiff( + actual, + expected, + title1="Actual Route-map output", + title2="Expected Route-map output", + ) if diff: logger.info("Actual:") logger.info(actual) logger.info("Expected:") logger.info(expected) srun = r1.vtysh_cmd("show run") - srun = ('\n'.join(srun.splitlines()) + '\n').rstrip() + srun = ("\n".join(srun.splitlines()) + "\n").rstrip() logger.info("Show run:") logger.info(srun) assert 0, "r1 sharp route-map processing:\n" - logger.info("Add a extension to the static route-map to see the static route go away") + logger.info( + "Add a extension to the static route-map to see the static route go away" + ) r1.vtysh_cmd("conf\nroute-map sharp deny 5\nmatch ip address 5") sleep(2) # we are only checking the kernel here as that this will give us the implied @@ -236,9 +251,9 @@ def test_route_map_usage(): logger.info("Test that the routes installed are correct") sharp_ipfile = "%s/r1/iproute.ref" % (thisDir) expected = open(sharp_ipfile).read().rstrip() - expected = ('\n'.join(expected.splitlines()) + '\n').rstrip() + expected = ("\n".join(expected.splitlines()) + "\n").rstrip() actual = r1.run("ip route show") - actual = ('\n'.join(actual.splitlines()) + '\n').rstrip() + actual = ("\n".join(actual.splitlines()) + "\n").rstrip() actual = re.sub(r" nhid [0-9][0-9]", "", actual) actual = re.sub(r" proto sharp", " proto XXXX", actual) actual = re.sub(r" proto static", " proto XXXX", actual) @@ -250,9 +265,9 @@ def test_route_map_usage(): actual = re.sub(r" proto XXXX ", " proto XXXX ", actual) actual = re.sub(r" metric", " metric", actual) actual = re.sub(r" link ", " link ", actual) - diff = topotest.get_textdiff(actual, expected, - title1 = "Actual ip route show", - title2 = "Expected ip route show") + diff = topotest.get_textdiff( + actual, expected, title1="Actual ip route show", title2="Expected ip route show" + ) if diff: logger.info("Actual:") @@ -260,11 +275,12 @@ def test_route_map_usage(): logger.info("Expected:") logger.info(expected) srun = r1.vtysh_cmd("show run") - srun = ('\n'.join(srun.splitlines()) + '\n').rstrip() + srun = ("\n".join(srun.splitlines()) + "\n").rstrip() logger.info("Show run:") logger.info(srun) assert 0, "r1 ip route show is not correct:" + def test_memory_leak(): "Run the memory leak test and report results." tgen = get_topogen() diff --git a/tools/etc/frr/support_bundle_commands.conf b/tools/etc/frr/support_bundle_commands.conf index 087c35981d..0bc6547994 100644 --- a/tools/etc/frr/support_bundle_commands.conf +++ b/tools/etc/frr/support_bundle_commands.conf @@ -42,12 +42,13 @@ show zebra client summary show zebra router table summary show ip nht vrf all show ipv6 nht vrf all +show ip route vrf all +show ipv6 route vrf all show nexthop-group rib show route-map show memory show interface vrf all show vrf -show zebra fpm stats show work-queues show debugging hashtable show running-config diff --git a/tools/frr-reload.py b/tools/frr-reload.py index b98c001e7d..1461e0f296 100755 --- a/tools/frr-reload.py +++ b/tools/frr-reload.py @@ -97,7 +97,7 @@ class Vtysh(object): args = ["-c", command] return self._call(args, stdin, stdout, stderr) - def __call__(self, command): + def __call__(self, command, stdouts=None): """ Call a CLI command (e.g. "show running-config") @@ -107,6 +107,8 @@ class Vtysh(object): proc = self._call_cmd(command, stdout=subprocess.PIPE) stdout, stderr = proc.communicate() if proc.wait() != 0: + if stdouts is not None: + stdouts.append(stdout.decode('UTF-8')) raise VtyshException( 'vtysh returned status %d for command "%s"' % (proc.returncode, command) ) @@ -2006,9 +2008,10 @@ if __name__ == "__main__": # frr(config-if)# no ip ospf authentication # frr(config-if)# + stdouts = [] while True: try: - vtysh(["configure"] + cmd) + vtysh(["configure"] + cmd, stdouts) except VtyshException: @@ -2024,6 +2027,10 @@ if __name__ == "__main__": '"%s" we failed to remove this command', " -- ".join(original_cmd), ) + # Log first error msg for original_cmd + if stdouts: + log.error(stdouts[0]) + reload_ok = False break new_last_arg = last_arg[0:-1] diff --git a/tools/nhrpd-event-handler.sh b/tools/nhrpd-event-handler.sh new file mode 100755 index 0000000000..5dce43fe84 --- /dev/null +++ b/tools/nhrpd-event-handler.sh @@ -0,0 +1,216 @@ +#!/bin/bash + +# Author: Joe Maimon +# Released to public domain +# +# 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 +# + +PROGNAME=`basename $0` +VERSION="0.0.6" +#api fields +EV_ID="eventid" +EV_TYPE="type" +EV_OTYPE="old_type" +EV_NUMNHS="num_nhs" +EV_INT="interface" +EV_LADDR="local_address" +EV_VCINIT="vc_initiated" +EV_LNBMA="local_nbma" +EV_LCERT="local_cert" +EV_RADDR="remote_addr" +EV_RNBMA="remote_nbma" +EV_RCERT="remote_cert" + +usage() +{ + echo "Usage: $PROGNAME [-s nhrp-sock] [-d] [-i interface-name] [-t table] [-e execute-cmd] [-u user] [-g group] [-r] [-l logfile]" + echo "" + echo "-s nhrp-sock file" + echo "-i interface-name to execute on, may be repeated multiple times" + echo "-t tableid to execute on for immdiate preceeding interface" + echo "-e execute command for immmediate preceeding interface" + echo " The command will be passed the following arguments $EV_ID $EV_TYPE $EV_INT $EV_LNMBA $EV_RADDR $EV_RNBMA int_table" + echo "-u user to own the sock" + echo "-g group to own the sock" + echo "-r send rejection (testing)" + echo "-l logfile to record conversation with nhrpd" + echo "-d daemonize" + + exit 1 +} + +declare -A EXECARR +declare -A TABLEARR +declare -Ag NHRPEVENT +SOCK="/var/run/frr/nhrp.sock" +USER="frr" +GROUP="frr" +DAEMON=0 +j=0 +RESULT="accept" + +while getopts rds:i:u:g:l:t:e: opt; do + case "$opt" in + d) + DAEMON=1 + ;; + s) + SOCK="$OPTARG" + ;; + i) + INTARR[((j++))]="$OPTARG" + ;; + e) + if [[ "$j" == "0" ]] || [[ "${INTARR[((j-1))]}" == "" ]]; then + echo "execute argument must follow interface argument" + usage + fi + EXECARR["${INTARR[((j-1))]}"]="$OPTARG" + ;; + t) + if [[ "$j" == "0" ]] || [[ "${INTARR[((j-1))]}" == "" ]]; then + echo "execute argument must follow interface argument" + usage + fi + TABLEARR["${INTARR[((j-1))]}"]="$OPTARG" + ;; + u) + USER="$OPTARG" + ;; + g) + GROUP="$OPTARG" + ;; + r) + RESULT="reject" + ;; + l) + EVLOGFILE="${OPTARG}" + ;; + esac; +done + +if [[ "$EVLOGFILE" != "" ]]; then + if [[ ! -w "${EVLOGFILE}" ]]; then + touch "$EVLOGFILE" || ( echo "Cannot write to logfile $EVLOGFILE" ; usage ) + fi + echo -e "PROG: $0 Startup\nPROG: Arguments $*" >> $EVLOGFILE +fi + + +function mainloop() +{ + +if [[ "$EVLOGFILE" != "" ]]; then + echo -e "PROG: `date -R`\nPROG: Starting mainloop" >> $EVLOGFILE +fi + +coproc socat - UNIX-LISTEN:$SOCK,unlink-early,setuid-early=$USER,unlink-close=0 || exit 1 +test -S $SOCK && chown $USER:$GROUP $SOCK + +OLDIFS="$IFS" + +TABLE="table " + +while read -r S; do + if [[ "$EVLOGFILE" != "" ]]; then + echo "IN: $S" >> $EVLOGFILE + fi + if [[ "$S" == "" ]]; then + if [[ "${NHRPEVENT[$EV_ID]}" != "" ]]; then + OUTMSG="eventid=${NHRPEVENT[$EV_ID]}\nresult=$RESULT\n" + echo -e "$OUTMSG" >&"${COPROC[1]}" + if [[ "$EVLOGFILE" != "" ]]; then + echo -e "OUT:\n${OUTMSG}" >> $EVLOGFILE; + fi + fi + + + for((i=0;i<${#INTARR[@]};i++)); do + if [[ "${NHRPEVENT[$EV_INT]}" == "" ]]; then break; fi + if [[ "${INTARR[$i]}" != "${NHRPEVENT[$EV_INT]}" ]]; then continue; fi + EVINT="${NHRPEVENT[$EV_INT]}" + if [[ "${NHRPEVENT[$EV_RADDR]}" == "" ]]; then break; fi + if [[ "${NHRPEVENT[$EV_RNBMA]}" == "" ]]; then break; fi + if [[ "${NHRPEVENT[$EV_TYPE]}" != "dynamic" ]]; then break; fi + + INTEXEC=${EXECARR["$EVINT"]} + INTABLE=${TABLEARR["$EVINT"]} + + unset CMD + unset CMDEND + CMDADD="ip neigh add " + CMDREPL="ip neigh replace" + CMDBEG="$CMDADD" + if [[ "$INTEXEC" != "" ]]; then + CMD="$INTEXEC ${NHRPEVENT[$EV_ID]:-nil}" + CMD="$CMD ${NHRPEVENT[$EV_TYPE]:-nil}" + CMD="$CMD ${NHRPEVENT[$EV_INT]:-nil}" + CMD="$CMD ${NHRPEVENT[$EV_LNBMA]:-nil}" + CMD="$CMD ${NHRPEVENT[$EV_RADDR]:-nil}" + CMD="$CMD ${NHRPEVENT[$EV_RNBMA]:-nil}" + CMD="$CMD ${INTABLE:-nil}" + unset CMDBEG + else + CMDTAB="${INTABLE:+${TABLE}${INTABLE}}" + CMDEND="$CMDEND ${NHRPEVENT[$EV_RADDR]} dev $EVINT lladdr ${NHRPEVENT[$EV_RNBMA]} nud noarp" + CMD="$CMDEND" + fi + unset CMDTAB + for ((k=0;k<2;k++)); do + for ((l=0;l<2;l++)); do + if [[ "$EVLOGFILE" != "" ]]; then + echo "PROG: Executing $CMD" >> $EVLOGFILE + CMDOUT=`$CMDBEG $CMD $CMDTAB 2>&1` + CMDRET="$?" + if [[ "$CMDOUT" != "" ]]; then + echo "PROG: Execution output: $CMDOUT" >> $EVLOGFILE + fi + else + $CMDBEG $CMD $CMDTAB + fi + if [[ "$CMDTAB" == "" ]] || [[ "$INTEXEC" != "" ]]; then break; fi + done + if [[ "$INTEXEC" != "" ]] || [[ "$CMDRET" == "0" ]]; then + break + fi + CMDBEG="$CMDREPL" + done + break + done + + unset NHRPEVENT + declare -Ag NHRPEVENT + continue + continue; + fi + IFS="${IFS}=" + SA=($S) + IFS="$OLDIFS" + eval NHRPEVENT[${SA[0]}]="\"${SA[1]}\"" + +done <&"${COPROC[0]}" + +if [[ "$COPROC_PID" != "" ]]; then kill "$COPROC_PID"; fi + +} + +while true; do + mainloop $* + if [[ "$DAEMON" == "0" ]]; then + break; + fi + sleep 10 +done 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 53067c43f4..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)) { @@ -107,7 +107,7 @@ sub scan_file { $protocol = "VTYSH_ALL"; } elsif ($file =~ /lib\/agentx\.c$/) { - $protocol = "VTYSH_RIPD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ZEBRA"; + $protocol = "VTYSH_ISISD|VTYSH_RIPD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ZEBRA"; } elsif ($file =~ /lib\/nexthop_group\.c$/) { $protocol = "VTYSH_NH_GROUP"; diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index e026a28628..06d224ec24 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; @@ -2693,7 +2693,7 @@ static int show_per_daemon(struct vty *vty, struct cmd_token **argv, int argc, char *line = do_prepend(vty, argv, argc); for (i = 0; i < array_size(vtysh_client); i++) - if (vtysh_client[i].fd >= 0) { + if (vtysh_client[i].fd >= 0 || vtysh_client[i].next) { vty_out(vty, headline, vtysh_client[i].name); ret = vtysh_client_execute(&vtysh_client[i], line); vty_out(vty, "\n"); @@ -2851,6 +2851,24 @@ DEFUN (vtysh_show_error_code, } /* Northbound. */ +DEFUN (show_config_running, + show_config_running_cmd, + "show configuration running\ + [<json|xml> [translate WORD]]\ + [with-defaults]" DAEMONS_LIST, + SHOW_STR + "Configuration information\n" + "Running configuration\n" + "Change output format to JSON\n" + "Change output format to XML\n" + "Translate output\n" + "YANG module translator\n" + "Show default values\n" + DAEMONS_STR) +{ + return show_one_daemon(vty, argv, argc - 1, argv[argc - 1]->text); +} + DEFUN (show_yang_operational_data, show_yang_operational_data_cmd, "show yang operational-data XPATH\ @@ -4564,6 +4582,7 @@ void vtysh_init_vty(void) install_element(CONFIG_NODE, &vtysh_debug_memstats_cmd); /* northbound */ + install_element(ENABLE_NODE, &show_config_running_cmd); install_element(ENABLE_NODE, &show_yang_operational_data_cmd); install_element(ENABLE_NODE, &debug_nb_cmd); install_element(CONFIG_NODE, &debug_nb_cmd); 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 441320b193..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; @@ -316,7 +316,7 @@ static pid_t run_background(char *shell_cmd) /* Use separate process group so child processes can be killed * easily. */ if (setpgid(0, 0) < 0) - zlog_warn("warning: setpgid(0,0) failed: %s", + zlog_warn("setpgid(0,0) failed: %s", safe_strerror(errno)); { char shell[] = "sh"; @@ -356,7 +356,7 @@ static int restart_kill(struct thread *t_kill) time_elapsed(&delay, &restart->time); zlog_warn( - "Warning: %s %s child process %d still running after %ld seconds, sending signal %d", + "%s %s child process %d still running after %ld seconds, sending signal %d", restart->what, restart->name, (int)restart->pid, (long)delay.tv_sec, (restart->kills ? SIGKILL : SIGTERM)); kill(-restart->pid, (restart->kills ? SIGKILL : SIGTERM)); @@ -423,7 +423,7 @@ static void sigchild(void) what = "background"; } if (WIFSTOPPED(status)) - zlog_warn("warning: %s %s process %d is stopped", what, name, + zlog_warn("%s %s process %d is stopped", what, name, (int)child); else if (WIFSIGNALED(status)) zlog_warn("%s %s process %d terminated due to signal %d", what, @@ -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-bfdd.yang b/yang/frr-bfdd.yang index 5b434162d0..d21ff5068a 100644 --- a/yang/frr-bfdd.yang +++ b/yang/frr-bfdd.yang @@ -185,7 +185,7 @@ module frr-bfdd { leaf administrative-down { type boolean; - default true; + default false; description "Disables or enables the session administratively"; } @@ -210,7 +210,14 @@ module frr-bfdd { type uint32; units microseconds; default 50000; - description "Minimum desired control packet transmission interval"; + description "Minimum desired echo packet transmission interval"; + } + + leaf required-echo-receive-interval { + type uint32; + units microseconds; + default 50000; + description "Minimum required echo packet receive interval"; } } diff --git a/yang/frr-filter.yang b/yang/frr-filter.yang index eb84dd7460..9a864213ee 100644 --- a/yang/frr-filter.yang +++ b/yang/frr-filter.yang @@ -292,8 +292,6 @@ module frr-filter { mandatory true; case ipv4-prefix { - when "../type = 'ipv4'"; - leaf ipv4-prefix { description "Configure IPv4 prefix to match"; type inet:ipv4-prefix; @@ -318,8 +316,6 @@ module frr-filter { } } case ipv6-prefix { - when "../type = 'ipv6'"; - leaf ipv6-prefix { description "Configure IPv6 prefix to match"; type inet:ipv6-prefix; diff --git a/yang/frr-isisd.yang b/yang/frr-isisd.yang index 8757ab6b8b..7c820c9611 100644 --- a/yang/frr-isisd.yang +++ b/yang/frr-isisd.yang @@ -60,6 +60,11 @@ module frr-isisd { (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."; + revision 2021-02-15 { + description + "Group SRGB and SRLB in a container so that they can be displayed + and configured together"; + } revision 2020-04-06 { description "Group LSP timers in a container so that they can be displayed and @@ -1491,38 +1496,42 @@ module frr-isisd { description "Enables segment-routing protocol extensions."; } - container srgb { - description - "Global blocks to be advertised."; - must "./upper-bound > ./lower-bound"; - leaf lower-bound { - type uint32; - default "16000"; - description - "Lower value in the label range."; - } - leaf upper-bound { - type uint32; - default "23999"; - description - "Upper value in the label range."; - } - } - container srlb { + container label-blocks { description - "Local blocks to be advertised."; - must "./upper-bound > ./lower-bound"; - leaf lower-bound { - type uint32; - default "15000"; - description - "Lower value in the label range."; + "Local and global label blocks."; + container srgb { + description + "Global blocks to be advertised."; + must "./upper-bound > ./lower-bound"; + leaf lower-bound { + type uint32; + default "16000"; + description + "Lower value in the label range."; + } + leaf upper-bound { + type uint32; + default "23999"; + description + "Upper value in the label range."; + } } - leaf upper-bound { - type uint32; - default "15999"; - description - "Upper value in the label range."; + container srlb { + description + "Local blocks to be advertised."; + must "./upper-bound > ./lower-bound"; + leaf lower-bound { + type uint32; + default "15000"; + description + "Lower value in the label range."; + } + leaf upper-bound { + type uint32; + default "15999"; + description + "Upper value in the label range."; + } } } container msd { diff --git a/zebra/connected.c b/zebra/connected.c index c885c533e6..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" @@ -321,11 +320,11 @@ void connected_add_ipv4(struct interface *ifp, int flags, struct in_addr *addr, if (IPV4_ADDR_SAME(addr, dest)) flog_warn( EC_ZEBRA_IFACE_SAME_LOCAL_AS_PEER, - "warning: interface %s has same local and peer address %pI4, routing protocols may malfunction", + "interface %s has same local and peer address %pI4, routing protocols may malfunction", ifp->name, addr); } else { zlog_debug( - "warning: %s called for interface %s with peer flag set, but no peer address supplied", + "%s called for interface %s with peer flag set, but no peer address supplied", __func__, ifp->name); UNSET_FLAG(ifc->flags, ZEBRA_IFA_PEER); } @@ -335,7 +334,7 @@ void connected_add_ipv4(struct interface *ifp, int flags, struct in_addr *addr, if (!dest && (prefixlen == IPV4_MAX_PREFIXLEN) && if_is_pointopoint(ifp)) zlog_debug( - "warning: PtP interface %s with addr %pI4/%d needs a peer address", + "PtP interface %s with addr %pI4/%d needs a peer address", ifp->name, addr, prefixlen); /* Label of this address. */ @@ -503,7 +502,7 @@ void connected_add_ipv6(struct interface *ifp, int flags, struct in6_addr *addr, } else { if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_PEER)) { zlog_debug( - "warning: %s called for interface %s with peer flag set, but no peer address supplied", + "%s called for interface %s with peer flag set, but no peer address supplied", __func__, ifp->name); UNSET_FLAG(ifc->flags, ZEBRA_IFA_PEER); } 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 3828f8800f..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" @@ -719,6 +718,21 @@ static void netlink_proc_dplane_if_protodown(struct zebra_if *zif, } } +static uint8_t netlink_parse_lacp_bypass(struct rtattr **linkinfo) +{ + uint8_t bypass = 0; + struct rtattr *mbrinfo[IFLA_BOND_SLAVE_MAX + 1]; + + memset(mbrinfo, 0, sizeof(mbrinfo)); + parse_rtattr_nested(mbrinfo, IFLA_BOND_SLAVE_MAX, + linkinfo[IFLA_INFO_SLAVE_DATA]); + if (mbrinfo[IFLA_BOND_SLAVE_AD_RX_BYPASS]) + bypass = *(uint8_t *)RTA_DATA( + mbrinfo[IFLA_BOND_SLAVE_AD_RX_BYPASS]); + + return bypass; +} + /* * Called from interface_lookup_netlink(). This function is only used * during bootstrap. @@ -743,6 +757,7 @@ static int netlink_interface(struct nlmsghdr *h, ns_id_t ns_id, int startup) ifindex_t bond_ifindex = IFINDEX_INTERNAL; struct zebra_if *zif; ns_id_t link_nsid = ns_id; + uint8_t bypass = 0; zns = zebra_ns_lookup(ns_id); ifi = NLMSG_DATA(h); @@ -816,6 +831,7 @@ static int netlink_interface(struct nlmsghdr *h, ns_id_t ns_id, int startup) } else if (slave_kind && (strcmp(slave_kind, "bond") == 0)) { zif_slave_type = ZEBRA_IF_SLAVE_BOND; bond_ifindex = *(ifindex_t *)RTA_DATA(tb[IFLA_MASTER]); + bypass = netlink_parse_lacp_bypass(linkinfo); } else zif_slave_type = ZEBRA_IF_SLAVE_OTHER; } @@ -882,7 +898,7 @@ static int netlink_interface(struct nlmsghdr *h, ns_id_t ns_id, int startup) if (IS_ZEBRA_IF_BRIDGE_SLAVE(ifp)) zebra_l2if_update_bridge_slave(ifp, bridge_ifindex, ns_id); else if (IS_ZEBRA_IF_BOND_SLAVE(ifp)) - zebra_l2if_update_bond_slave(ifp, bond_ifindex); + zebra_l2if_update_bond_slave(ifp, bond_ifindex, !!bypass); if (tb[IFLA_PROTO_DOWN]) { uint8_t protodown; @@ -1322,6 +1338,7 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) struct zebra_if *zif; ns_id_t link_nsid = ns_id; ifindex_t master_infindex = IFINDEX_INTERNAL; + uint8_t bypass = 0; zns = zebra_ns_lookup(ns_id); ifi = NLMSG_DATA(h); @@ -1423,6 +1440,7 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) zif_slave_type = ZEBRA_IF_SLAVE_BOND; master_infindex = bond_ifindex = *(ifindex_t *)RTA_DATA(tb[IFLA_MASTER]); + bypass = netlink_parse_lacp_bypass(linkinfo); } else zif_slave_type = ZEBRA_IF_SLAVE_OTHER; } @@ -1484,7 +1502,8 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) bridge_ifindex, ns_id); else if (IS_ZEBRA_IF_BOND_SLAVE(ifp)) - zebra_l2if_update_bond_slave(ifp, bond_ifindex); + zebra_l2if_update_bond_slave(ifp, bond_ifindex, + !!bypass); if (tb[IFLA_PROTO_DOWN]) { uint8_t protodown; @@ -1597,7 +1616,8 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) bridge_ifindex, ns_id); else if (IS_ZEBRA_IF_BOND_SLAVE(ifp) || was_bond_slave) - zebra_l2if_update_bond_slave(ifp, bond_ifindex); + zebra_l2if_update_bond_slave(ifp, bond_ifindex, + !!bypass); if (tb[IFLA_PROTO_DOWN]) { uint8_t protodown; @@ -1633,6 +1653,8 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) if (IS_ZEBRA_IF_BOND(ifp)) zebra_l2if_update_bond(ifp, false); + if (IS_ZEBRA_IF_BOND_SLAVE(ifp)) + zebra_l2if_update_bond_slave(ifp, bond_ifindex, false); /* Special handling for bridge or VxLAN interfaces. */ if (IS_ZEBRA_IF_BRIDGE(ifp)) zebra_l2_bridge_del(ifp); 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 f74030e4d8..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); @@ -241,6 +240,7 @@ static int if_zebra_delete_hook(struct interface *ifp) #endif /* HAVE_RTADV */ zebra_evpn_if_cleanup(zebra_if); + zebra_evpn_mac_ifp_del(ifp); if_nhg_dependents_release(ifp); zebra_if_nhg_dependents_free(zebra_if); @@ -826,6 +826,7 @@ void if_delete_update(struct interface *ifp) memset(&zif->brslave_info, 0, sizeof(struct zebra_l2info_brslave)); zebra_evpn_if_cleanup(zif); + zebra_evpn_mac_ifp_del(ifp); } if (!ifp->configured) { @@ -1604,6 +1605,9 @@ static void if_dump_vty(struct vty *vty, struct interface *ifp) } } + if (zebra_if->flags & ZIF_FLAG_LACP_BYPASS) + vty_out(vty, " LACP bypass: on\n"); + zebra_evpn_if_es_print(vty, zebra_if); vty_out(vty, " protodown: %s %s\n", (zebra_if->flags & ZIF_FLAG_PROTODOWN) ? "on" : "off", diff --git a/zebra/interface.h b/zebra/interface.h index 8dcb477f10..67eb1176b9 100644 --- a/zebra/interface.h +++ b/zebra/interface.h @@ -286,6 +286,9 @@ struct zebra_es_if_info { esi_t esi; uint16_t df_pref; + uint8_t flags; +#define ZIF_CFG_ES_FLAG_BYPASS (1 << 0) + struct zebra_evpn_es *es; /* local ES */ }; @@ -297,7 +300,13 @@ enum zebra_if_flags { ZIF_FLAG_EVPN_MH_UPLINK_OPER_UP = (1 << 1), /* Dataplane protodown-on */ - ZIF_FLAG_PROTODOWN = (1 << 2) + ZIF_FLAG_PROTODOWN = (1 << 2), + + /* LACP bypass state is set by the dataplane on a bond member + * and inherited by the bond (if one or more bond members are in + * a bypass state the bond is placed in a bypass state) + */ + ZIF_FLAG_LACP_BYPASS = (1 << 3) }; /* `zebra' daemon local interface structure. */ @@ -386,6 +395,9 @@ struct zebra_if { */ enum protodown_reasons protodown_rc; + /* list of zebra_mac entries using this interface as destination */ + struct list *mac_list; + /* Link fields - for sub-interfaces. */ ifindex_t link_ifindex; struct interface *link; @@ -405,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 c77a357e9f..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; @@ -1350,6 +1349,14 @@ static enum netlink_msg_status nl_put_msg(struct nl_batch *bth, case DPLANE_OP_BR_PORT_UPDATE: return FRR_NETLINK_SUCCESS; + case DPLANE_OP_IPTABLE_ADD: + case DPLANE_OP_IPTABLE_DELETE: + case DPLANE_OP_IPSET_ADD: + case DPLANE_OP_IPSET_DELETE: + case DPLANE_OP_IPSET_ENTRY_ADD: + case DPLANE_OP_IPSET_ENTRY_DELETE: + return FRR_NETLINK_ERROR; + case DPLANE_OP_NONE: return FRR_NETLINK_ERROR; } 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..09350f72c1 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" @@ -274,7 +273,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 b0f124ed55..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" @@ -542,7 +541,7 @@ void zebra_interface_address_add_update(struct interface *ifp, if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_REAL)) flog_warn( EC_ZEBRA_ADVERTISING_UNUSABLE_ADDR, - "WARNING: advertising address to clients that is not yet usable."); + "advertising address to clients that is not yet usable."); zebra_vxlan_add_del_gw_macip(ifp, ifc->address, 1); 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 46a751ce69..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" @@ -1767,6 +1766,33 @@ ssize_t netlink_route_multipath_msg_encode(int cmd, nl_attr_nest_end(&req->n, nest); } + /* + * Always install blackhole routes without using nexthops, because of + * the following kernel problems: + * 1. Kernel nexthops don't suport unreachable/prohibit route types. + * 2. Blackhole kernel nexthops are deleted when loopback is down. + */ + nexthop = dplane_ctx_get_ng(ctx)->nexthop; + if (nexthop) { + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) + nexthop = nexthop->resolved; + + if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE) { + switch (nexthop->bh_type) { + case BLACKHOLE_ADMINPROHIB: + req->r.rtm_type = RTN_PROHIBIT; + break; + case BLACKHOLE_REJECT: + req->r.rtm_type = RTN_UNREACHABLE; + break; + default: + req->r.rtm_type = RTN_BLACKHOLE; + break; + } + return NLMSG_ALIGN(req->n.nlmsg_len); + } + } + if ((!fpm && kernel_nexthops_supported() && (!proto_nexthops_only() || is_proto_nhg(dplane_ctx_get_nhe_id(ctx), 0))) @@ -1820,27 +1846,6 @@ ssize_t netlink_route_multipath_msg_encode(int cmd, if (nexthop_num == 1) { nexthop_num = 0; for (ALL_NEXTHOPS_PTR(dplane_ctx_get_ng(ctx), nexthop)) { - /* - * So we want to cover 2 types of blackhole - * routes here: - * 1) A normal blackhole route( ala from a static - * install. - * 2) A recursively resolved blackhole route - */ - if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE) { - switch (nexthop->bh_type) { - case BLACKHOLE_ADMINPROHIB: - req->r.rtm_type = RTN_PROHIBIT; - break; - case BLACKHOLE_REJECT: - req->r.rtm_type = RTN_UNREACHABLE; - break; - default: - req->r.rtm_type = RTN_BLACKHOLE; - break; - } - return NLMSG_ALIGN(req->n.nlmsg_len); - } if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) { @@ -2833,7 +2838,6 @@ static int netlink_macfdb_change(struct nlmsghdr *h, int len, ns_id_t ns_id) vlanid_t vid = 0; struct in_addr vtep_ip; int vid_present = 0, dst_present = 0; - char buf[ETHER_ADDR_STRLEN]; char vid_buf[20]; char dst_buf[30]; bool sticky; @@ -2912,11 +2916,10 @@ static int netlink_macfdb_change(struct nlmsghdr *h, int len, ns_id_t ns_id) } if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug("Rx %s AF_BRIDGE IF %u%s st 0x%x fl 0x%x MAC %s%s nhg %d", + zlog_debug("Rx %s AF_BRIDGE IF %u%s st 0x%x fl 0x%x MAC %pEA%s nhg %d", nl_msg_type_to_str(h->nlmsg_type), ndm->ndm_ifindex, vid_present ? vid_buf : "", - ndm->ndm_state, ndm->ndm_flags, - prefix_mac2str(&mac, buf, sizeof(buf)), + ndm->ndm_state, ndm->ndm_flags, &mac, dst_present ? dst_buf : "", nhg_id); /* The interface should exist. */ @@ -3117,7 +3120,6 @@ static int netlink_request_specific_mac_in_bridge(struct zebra_ns *zns, char buf[256]; } req; struct zebra_if *br_zif; - char buf[ETHER_ADDR_STRLEN]; memset(&req, 0, sizeof(req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)); @@ -3136,11 +3138,10 @@ static int netlink_request_specific_mac_in_bridge(struct zebra_ns *zns, if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug( - "%s: Tx family %s IF %s(%u) vrf %s(%u) MAC %s vid %u", + "%s: Tx family %s IF %s(%u) vrf %s(%u) MAC %pEA vid %u", __func__, nl_family_to_str(req.ndm.ndm_family), br_if->name, br_if->ifindex, - vrf_id_to_name(br_if->vrf_id), br_if->vrf_id, - prefix_mac2str(mac, buf, sizeof(buf)), vid); + vrf_id_to_name(br_if->vrf_id), br_if->vrf_id, mac, vid); return netlink_request(&zns->netlink_cmd, &req); } @@ -3225,8 +3226,6 @@ ssize_t netlink_macfdb_update_ctx(struct zebra_dplane_ctx *ctx, void *data, SET_IPADDR_V4(&vtep_ip); if (IS_ZEBRA_DEBUG_KERNEL) { - char ipbuf[PREFIX_STRLEN]; - char buf[ETHER_ADDR_STRLEN]; char vid_buf[20]; const struct ethaddr *mac = dplane_ctx_mac_get_addr(ctx); @@ -3237,12 +3236,11 @@ ssize_t netlink_macfdb_update_ctx(struct zebra_dplane_ctx *ctx, void *data, vid_buf[0] = '\0'; zlog_debug( - "Tx %s family %s IF %s(%u)%s %sMAC %s dst %s nhg %u%s%s%s%s%s", + "Tx %s family %s IF %s(%u)%s %sMAC %pEA dst %pIA nhg %u%s%s%s%s%s", nl_msg_type_to_str(cmd), nl_family_to_str(AF_BRIDGE), dplane_ctx_get_ifname(ctx), dplane_ctx_get_ifindex(ctx), vid_buf, dplane_ctx_mac_is_sticky(ctx) ? "sticky " : "", - prefix_mac2str(mac, buf, sizeof(buf)), - ipaddr2str(&vtep_ip, ipbuf, sizeof(ipbuf)), nhg_id, + mac, &vtep_ip, nhg_id, (update_flags & DPLANE_MAC_REMOTE) ? " rem" : "", (update_flags & DPLANE_MAC_WAS_STATIC) ? " clr_sync" : "", @@ -3303,7 +3301,6 @@ static int netlink_ipneigh_change(struct nlmsghdr *h, int len, ns_id_t ns_id) struct ipaddr ip; struct vrf *vrf; char buf[ETHER_ADDR_STRLEN]; - char buf2[INET6_ADDRSTRLEN]; int mac_present = 0; bool is_ext; bool is_router; @@ -3409,11 +3406,11 @@ static int netlink_ipneigh_change(struct nlmsghdr *h, int len, ns_id_t ns_id) if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug( - "Rx %s family %s IF %s(%u) vrf %s(%u) IP %s MAC %s state 0x%x flags 0x%x ext_flags 0x%x", + "Rx %s family %s IF %s(%u) vrf %s(%u) IP %pIA MAC %s state 0x%x flags 0x%x ext_flags 0x%x", nl_msg_type_to_str(h->nlmsg_type), nl_family_to_str(ndm->ndm_family), ifp->name, ndm->ndm_ifindex, VRF_LOGNAME(vrf), ifp->vrf_id, - ipaddr2str(&ip, buf2, sizeof(buf2)), + &ip, mac_present ? prefix_mac2str(&mac, buf, sizeof(buf)) : "", @@ -3445,11 +3442,11 @@ static int netlink_ipneigh_change(struct nlmsghdr *h, int len, ns_id_t ns_id) } if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug("Rx %s family %s IF %s(%u) vrf %s(%u) IP %s", + zlog_debug("Rx %s family %s IF %s(%u) vrf %s(%u) IP %pIA", nl_msg_type_to_str(h->nlmsg_type), nl_family_to_str(ndm->ndm_family), ifp->name, ndm->ndm_ifindex, VRF_LOGNAME(vrf), ifp->vrf_id, - ipaddr2str(&ip, buf2, sizeof(buf2))); + &ip); /* Process the delete - it may result in re-adding the neighbor if it is * a valid "remote" neighbor. @@ -3576,14 +3573,11 @@ static int netlink_request_specific_neigh_in_vlan(struct zebra_ns *zns, nl_attr_put(&req.n, sizeof(req), NDA_DST, &ip->ip.addr, ipa_len); - if (IS_ZEBRA_DEBUG_KERNEL) { - char buf[INET6_ADDRSTRLEN]; - - zlog_debug("%s: Tx %s family %s IF %u IP %s flags 0x%x", + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("%s: Tx %s family %s IF %u IP %pIA flags 0x%x", __func__, nl_msg_type_to_str(type), - nl_family_to_str(req.ndm.ndm_family), ifindex, - ipaddr2str(ip, buf, sizeof(buf)), req.n.nlmsg_flags); - } + nl_family_to_str(req.ndm.ndm_family), ifindex, ip, + req.n.nlmsg_flags); return netlink_request(&zns->netlink_cmd, &req); } @@ -3594,7 +3588,6 @@ int netlink_neigh_read_specific_ip(struct ipaddr *ip, int ret = 0; struct zebra_ns *zns; struct zebra_vrf *zvrf = zebra_vrf_lookup_by_id(vlan_if->vrf_id); - char buf[INET6_ADDRSTRLEN]; struct zebra_dplane_info dp_info; zns = zvrf->zns; @@ -3602,9 +3595,8 @@ int netlink_neigh_read_specific_ip(struct ipaddr *ip, zebra_dplane_info_from_zns(&dp_info, zns, true /*is_cmd*/); if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug("%s: neigh request IF %s(%u) IP %s vrf %s(%u)", - __func__, vlan_if->name, vlan_if->ifindex, - ipaddr2str(ip, buf, sizeof(buf)), + zlog_debug("%s: neigh request IF %s(%u) IP %pIA vrf %s(%u)", + __func__, vlan_if->name, vlan_if->ifindex, ip, vrf_id_to_name(vlan_if->vrf_id), vlan_if->vrf_id); ret = netlink_request_specific_neigh_in_vlan(zns, RTM_GETNEIGH, ip, @@ -3695,27 +3687,13 @@ static ssize_t netlink_neigh_update_ctx(const struct zebra_dplane_ctx *ctx, /* local neigh */ if (update_flags & DPLANE_NEIGH_SET_STATIC) ext_flags |= NTF_E_MH_PEER_SYNC; - - /* the ndm_state set for local entries can be REACHABLE or - * STALE. if the dataplane has already establish reachability - * (in the meantime) FRR must not over-write it with STALE. - * this accidental race/over-write is avoided by using the - * WEAK_OVERRIDE_STATE - */ - ext_flags |= NTF_E_WEAK_OVERRIDE_STATE; } - if (IS_ZEBRA_DEBUG_KERNEL) { - char buf[INET6_ADDRSTRLEN]; - char buf2[ETHER_ADDR_STRLEN]; - + if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug( - "Tx %s family %s IF %s(%u) Neigh %s MAC %s flags 0x%x state 0x%x %sext_flags 0x%x", + "Tx %s family %s IF %s(%u) Neigh %pIA MAC %pEA flags 0x%x state 0x%x %sext_flags 0x%x", nl_msg_type_to_str(cmd), nl_family_to_str(family), dplane_ctx_get_ifname(ctx), dplane_ctx_get_ifindex(ctx), - ipaddr2str(ip, buf, sizeof(buf)), - mac ? prefix_mac2str(mac, buf2, sizeof(buf2)) : "null", - flags, state, ext ? "ext " : "", ext_flags); - } + ip, mac, flags, state, ext ? "ext " : "", ext_flags); return netlink_neigh_update_msg_encode( ctx, cmd, mac, ip, true, family, RTN_UNICAST, flags, state, 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..b5c26d720f 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 \ @@ -158,7 +157,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 \ @@ -193,7 +191,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 diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index 46171df848..63ba6cd8d9 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 -------------------------------------------------------- */ @@ -866,18 +867,24 @@ void zsend_rule_notify_owner(const struct zebra_dplane_ctx *ctx, zserv_send_message(client, s); } -void zsend_ipset_notify_owner(struct zebra_pbr_ipset *ipset, - enum zapi_ipset_notify_owner note) +void zsend_iptable_notify_owner(const struct zebra_dplane_ctx *ctx, + uint16_t note) { struct listnode *node; struct zserv *client; struct stream *s; + struct zebra_pbr_iptable ipt; + uint16_t cmd = ZEBRA_IPTABLE_NOTIFY_OWNER; + + if (!dplane_ctx_get_pbr_iptable(ctx, &ipt)) + return; if (IS_ZEBRA_DEBUG_PACKET) - zlog_debug("%s: Notifying %u", __func__, ipset->unique); + zlog_debug("%s: Notifying %s id %u note %u", __func__, + zserv_command_string(cmd), ipt.unique, note); for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client)) { - if (ipset->sock == client->sock) + if (ipt.sock == client->sock) break; } @@ -886,27 +893,32 @@ void zsend_ipset_notify_owner(struct zebra_pbr_ipset *ipset, s = stream_new(ZEBRA_MAX_PACKET_SIZ); - zclient_create_header(s, ZEBRA_IPSET_NOTIFY_OWNER, VRF_DEFAULT); + zclient_create_header(s, cmd, VRF_DEFAULT); stream_put(s, ¬e, sizeof(note)); - stream_putl(s, ipset->unique); - stream_put(s, ipset->ipset_name, ZEBRA_IPSET_NAME_SIZE); + stream_putl(s, ipt.unique); + stream_put(s, ipt.ipset_name, ZEBRA_IPSET_NAME_SIZE); stream_putw_at(s, 0, stream_get_endp(s)); zserv_send_message(client, s); } -void zsend_ipset_entry_notify_owner(struct zebra_pbr_ipset_entry *ipset, - enum zapi_ipset_entry_notify_owner note) +void zsend_ipset_notify_owner(const struct zebra_dplane_ctx *ctx, uint16_t note) { struct listnode *node; struct zserv *client; struct stream *s; + struct zebra_pbr_ipset ipset; + uint16_t cmd = ZEBRA_IPSET_NOTIFY_OWNER; + + if (!dplane_ctx_get_pbr_ipset(ctx, &ipset)) + return; if (IS_ZEBRA_DEBUG_PACKET) - zlog_debug("%s: Notifying %u", __func__, ipset->unique); + zlog_debug("%s: Notifying %s id %u note %u", __func__, + zserv_command_string(cmd), ipset.unique, note); for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client)) { - if (ipset->sock == client->sock) + if (ipset.sock == client->sock) break; } @@ -915,27 +927,36 @@ void zsend_ipset_entry_notify_owner(struct zebra_pbr_ipset_entry *ipset, s = stream_new(ZEBRA_MAX_PACKET_SIZ); - zclient_create_header(s, ZEBRA_IPSET_ENTRY_NOTIFY_OWNER, VRF_DEFAULT); + zclient_create_header(s, cmd, VRF_DEFAULT); stream_put(s, ¬e, sizeof(note)); - stream_putl(s, ipset->unique); - stream_put(s, ipset->backpointer->ipset_name, ZEBRA_IPSET_NAME_SIZE); + stream_putl(s, ipset.unique); + stream_put(s, ipset.ipset_name, ZEBRA_IPSET_NAME_SIZE); stream_putw_at(s, 0, stream_get_endp(s)); zserv_send_message(client, s); } -void zsend_iptable_notify_owner(struct zebra_pbr_iptable *iptable, - enum zapi_iptable_notify_owner note) +void zsend_ipset_entry_notify_owner(const struct zebra_dplane_ctx *ctx, + uint16_t note) { struct listnode *node; struct zserv *client; struct stream *s; + struct zebra_pbr_ipset_entry ipent; + struct zebra_pbr_ipset ipset; + uint16_t cmd = ZEBRA_IPSET_ENTRY_NOTIFY_OWNER; + + if (!dplane_ctx_get_pbr_ipset_entry(ctx, &ipent)) + return; + if (!dplane_ctx_get_pbr_ipset(ctx, &ipset)) + return; if (IS_ZEBRA_DEBUG_PACKET) - zlog_debug("%s: Notifying %u", __func__, iptable->unique); + zlog_debug("%s: Notifying %s id %u note %u", __func__, + zserv_command_string(cmd), ipent.unique, note); for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client)) { - if (iptable->sock == client->sock) + if (ipent.sock == client->sock) break; } @@ -944,9 +965,10 @@ void zsend_iptable_notify_owner(struct zebra_pbr_iptable *iptable, s = stream_new(ZEBRA_MAX_PACKET_SIZ); - zclient_create_header(s, ZEBRA_IPTABLE_NOTIFY_OWNER, VRF_DEFAULT); + zclient_create_header(s, cmd, VRF_DEFAULT); stream_put(s, ¬e, sizeof(note)); - stream_putl(s, iptable->unique); + stream_putl(s, ipent.unique); + stream_put(s, ipset.ipset_name, ZEBRA_IPSET_NAME_SIZE); stream_putw_at(s, 0, stream_get_endp(s)); zserv_send_message(client, s); @@ -2055,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; diff --git a/zebra/zapi_msg.h b/zebra/zapi_msg.h index c03278669a..ca471f8d98 100644 --- a/zebra/zapi_msg.h +++ b/zebra/zapi_msg.h @@ -84,13 +84,13 @@ extern int zsend_route_notify_owner_ctx(const struct zebra_dplane_ctx *ctx, extern void zsend_rule_notify_owner(const struct zebra_dplane_ctx *ctx, enum zapi_rule_notify_owner note); -extern void zsend_ipset_notify_owner(struct zebra_pbr_ipset *ipset, - enum zapi_ipset_notify_owner note); -extern void -zsend_ipset_entry_notify_owner(struct zebra_pbr_ipset_entry *ipset, - enum zapi_ipset_entry_notify_owner note); -extern void zsend_iptable_notify_owner(struct zebra_pbr_iptable *iptable, - enum zapi_iptable_notify_owner note); + +extern void zsend_iptable_notify_owner(const struct zebra_dplane_ctx *ctx, + uint16_t note); +extern void zsend_ipset_notify_owner(const struct zebra_dplane_ctx *ctx, + uint16_t note); +extern void zsend_ipset_entry_notify_owner(const struct zebra_dplane_ctx *ctx, + uint16_t note); extern bool zserv_nexthop_num_warn(const char *caller, const struct prefix *p, const unsigned int nexthop_num); @@ -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 db2b9e002e..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,9 +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_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 @@ -307,6 +307,12 @@ struct zebra_dplane_ctx { struct dplane_mac_info macinfo; struct dplane_neigh_info neigh; struct dplane_rule_info rule; + struct zebra_pbr_iptable iptable; + struct zebra_pbr_ipset ipset; + union { + struct zebra_pbr_ipset_entry entry; + struct zebra_pbr_ipset_info info; + } ipset_entry; } u; /* Namespace info, used especially for netlink kernel communication */ @@ -438,6 +444,14 @@ static struct zebra_dplane_globals { _Atomic uint32_t dg_update_yields; + _Atomic uint32_t dg_iptable_in; + _Atomic uint32_t dg_iptable_errors; + + _Atomic uint32_t dg_ipset_in; + _Atomic uint32_t dg_ipset_errors; + _Atomic uint32_t dg_ipset_entry_in; + _Atomic uint32_t dg_ipset_entry_errors; + /* Dataplane pthread */ struct frr_pthread *dg_pthread; @@ -656,7 +670,29 @@ static void dplane_ctx_free_internal(struct zebra_dplane_ctx *ctx) case DPLANE_OP_NEIGH_DISCOVER: case DPLANE_OP_BR_PORT_UPDATE: case DPLANE_OP_NONE: + case DPLANE_OP_IPSET_ADD: + case DPLANE_OP_IPSET_DELETE: + break; + + case DPLANE_OP_IPSET_ENTRY_ADD: + case DPLANE_OP_IPSET_ENTRY_DELETE: break; + case DPLANE_OP_IPTABLE_ADD: + case DPLANE_OP_IPTABLE_DELETE: + if (ctx->u.iptable.interface_name_list) { + struct listnode *node, *nnode; + char *ifname; + + for (ALL_LIST_ELEMENTS( + ctx->u.iptable.interface_name_list, node, + nnode, ifname)) { + LISTNODE_DETACH( + ctx->u.iptable.interface_name_list, + node); + XFREE(MTYPE_DP_NETFILTER, ifname); + } + list_delete(&ctx->u.iptable.interface_name_list); + } } } @@ -895,6 +931,25 @@ const char *dplane_op2str(enum dplane_op_e op) case DPLANE_OP_NEIGH_DISCOVER: ret = "NEIGH_DISCOVER"; break; + + case DPLANE_OP_IPTABLE_ADD: + ret = "IPTABLE_ADD"; + break; + case DPLANE_OP_IPTABLE_DELETE: + ret = "IPTABLE_DELETE"; + break; + case DPLANE_OP_IPSET_ADD: + ret = "IPSET_ADD"; + break; + case DPLANE_OP_IPSET_DELETE: + ret = "IPSET_DELETE"; + break; + case DPLANE_OP_IPSET_ENTRY_ADD: + ret = "IPSET_ENTRY_ADD"; + break; + case DPLANE_OP_IPSET_ENTRY_DELETE: + ret = "IPSET_ENTRY_DELETE"; + break; } return ret; @@ -1843,6 +1898,46 @@ dplane_ctx_get_br_port_backup_nhg_id(const struct zebra_dplane_ctx *ctx) return ctx->u.br_port.backup_nhg_id; } +/* Accessors for PBR iptable information */ +bool +dplane_ctx_get_pbr_iptable(const struct zebra_dplane_ctx *ctx, + struct zebra_pbr_iptable *table) +{ + DPLANE_CTX_VALID(ctx); + + memcpy(table, &ctx->u.iptable, sizeof(struct zebra_pbr_iptable)); + return true; +} + +bool dplane_ctx_get_pbr_ipset(const struct zebra_dplane_ctx *ctx, + struct zebra_pbr_ipset *ipset) +{ + DPLANE_CTX_VALID(ctx); + + if (!ipset) + return false; + if (ctx->zd_op == DPLANE_OP_IPSET_ENTRY_ADD || + ctx->zd_op == DPLANE_OP_IPSET_ENTRY_DELETE) { + memset(ipset, 0, sizeof(struct zebra_pbr_ipset)); + ipset->type = ctx->u.ipset_entry.info.type; + memcpy(&ipset->ipset_name, &ctx->u.ipset_entry.info.ipset_name, + ZEBRA_IPSET_NAME_SIZE); + } else + memcpy(ipset, &ctx->u.ipset, sizeof(struct zebra_pbr_ipset)); + return true; +} + +bool dplane_ctx_get_pbr_ipset_entry(const struct zebra_dplane_ctx *ctx, + struct zebra_pbr_ipset_entry *entry) +{ + DPLANE_CTX_VALID(ctx); + + if (!entry) + return false; + memcpy(entry, &ctx->u.ipset_entry.entry, sizeof(struct zebra_pbr_ipset_entry)); + return true; +} + /* * End of dplane context accessors */ @@ -2398,6 +2493,126 @@ static int dplane_ctx_rule_init(struct zebra_dplane_ctx *ctx, return AOK; } +/** + * dplane_ctx_iptable_init() - Initialize a context block for a PBR iptable + * update. + * + * @ctx: Dataplane context to init + * @op: Operation being performed + * @new_rule: PBR iptable + * + * Return: Result status + */ +static int dplane_ctx_iptable_init(struct zebra_dplane_ctx *ctx, + enum dplane_op_e op, + struct zebra_pbr_iptable *iptable) +{ + char *ifname; + struct listnode *node; + + if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) { + zlog_debug( + "init dplane ctx %s: Unique %u Fwmark %u Family %s Action %s", + dplane_op2str(op), iptable->unique, iptable->fwmark, + family2str(iptable->family), + iptable->action == ZEBRA_IPTABLES_DROP ? "Drop" + : "Forward"); + } + + ctx->zd_op = op; + ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS; + + dplane_ctx_ns_init(ctx, zebra_ns_lookup(NS_DEFAULT), false); + ctx->zd_is_update = false; + + ctx->zd_vrf_id = iptable->vrf_id; + memcpy(&ctx->u.iptable, iptable, sizeof(struct zebra_pbr_iptable)); + ctx->u.iptable.interface_name_list = NULL; + if (iptable->nb_interface > 0) { + ctx->u.iptable.interface_name_list = list_new(); + for (ALL_LIST_ELEMENTS_RO(iptable->interface_name_list, node, + ifname)) { + listnode_add(ctx->u.iptable.interface_name_list, + XSTRDUP(MTYPE_DP_NETFILTER, ifname)); + } + } + return AOK; +} + +/** + * dplane_ctx_ipset_init() - Initialize a context block for a PBR ipset update. + * + * @ctx: Dataplane context to init + * @op: Operation being performed + * @new_rule: PBR ipset + * + * Return: Result status + */ +static int dplane_ctx_ipset_init(struct zebra_dplane_ctx *ctx, + enum dplane_op_e op, + struct zebra_pbr_ipset *ipset) +{ + if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) { + zlog_debug("init dplane ctx %s: %s Unique %u Family %s Type %s", + dplane_op2str(op), ipset->ipset_name, ipset->unique, + family2str(ipset->family), + zebra_pbr_ipset_type2str(ipset->type)); + } + + ctx->zd_op = op; + ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS; + + dplane_ctx_ns_init(ctx, zebra_ns_lookup(NS_DEFAULT), false); + ctx->zd_is_update = false; + + ctx->zd_vrf_id = ipset->vrf_id; + + memcpy(&ctx->u.ipset, ipset, sizeof(struct zebra_pbr_ipset)); + return AOK; +} + +/** + * dplane_ctx_ipset_entry_init() - Initialize a context block for a PBR ipset + * update. + * + * @ctx: Dataplane context to init + * @op: Operation being performed + * @new_rule: PBR ipset + * + * Return: Result status + */ +static int +dplane_ctx_ipset_entry_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op, + struct zebra_pbr_ipset_entry *ipset_entry) +{ + struct zebra_pbr_ipset *ipset; + + ipset = ipset_entry->backpointer; + if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) { + zlog_debug("init dplane ctx %s: %s Unique %u filter %u", + dplane_op2str(op), ipset->ipset_name, + ipset_entry->unique, ipset_entry->filter_bm); + } + + ctx->zd_op = op; + ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS; + + dplane_ctx_ns_init(ctx, zebra_ns_lookup(NS_DEFAULT), false); + ctx->zd_is_update = false; + + ctx->zd_vrf_id = ipset->vrf_id; + + memcpy(&ctx->u.ipset_entry.entry, ipset_entry, + sizeof(struct zebra_pbr_ipset_entry)); + ctx->u.ipset_entry.entry.backpointer = NULL; + ctx->u.ipset_entry.info.type = ipset->type; + memcpy(&ctx->u.ipset_entry.info.ipset_name, &ipset->ipset_name, + ZEBRA_IPSET_NAME_SIZE); + + return AOK; +} + + /* * Enqueue a new update, * and ensure an event is active for the dataplane pthread. @@ -3251,6 +3466,24 @@ enum zebra_dplane_result dplane_local_mac_add(const struct interface *ifp, } /* + * Enqueue local mac del + */ +enum zebra_dplane_result +dplane_local_mac_del(const struct interface *ifp, + const struct interface *bridge_ifp, vlanid_t vid, + const struct ethaddr *mac) +{ + enum zebra_dplane_result result; + struct in_addr vtep_ip; + + vtep_ip.s_addr = 0; + + /* Use common helper api */ + result = mac_update_common(DPLANE_OP_MAC_DELETE, ifp, bridge_ifp, vid, + mac, vtep_ip, false, 0, 0); + return result; +} +/* * Public api to init an empty context - either newly-allocated or * reset/cleared - for a MAC update. */ @@ -3305,15 +3538,9 @@ mac_update_common(enum dplane_op_e op, int ret; struct zebra_dplane_ctx *ctx = NULL; - if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) { - char buf1[ETHER_ADDR_STRLEN], buf2[PREFIX_STRLEN]; - - zlog_debug("init mac ctx %s: mac %s, ifp %s, vtep %s", - dplane_op2str(op), - prefix_mac2str(mac, buf1, sizeof(buf1)), - ifp->name, - inet_ntop(AF_INET, &vtep_ip, buf2, sizeof(buf2))); - } + if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) + zlog_debug("init mac ctx %s: mac %pEA, ifp %s, vtep %pI4", + dplane_op2str(op), mac, ifp->name, &vtep_ip); ctx = dplane_ctx_alloc(); ctx->zd_op = op; @@ -3491,14 +3718,9 @@ neigh_update_internal(enum dplane_op_e op, struct zebra_dplane_ctx *ctx = NULL; struct zebra_ns *zns; - if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) { - char buf1[ETHER_ADDR_STRLEN], buf2[PREFIX_STRLEN]; - - zlog_debug("init neigh ctx %s: ifp %s, mac %s, ip %s", - dplane_op2str(op), ifp->name, - prefix_mac2str(mac, buf1, sizeof(buf1)), - ipaddr2str(ip, buf2, sizeof(buf2))); - } + if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) + zlog_debug("init neigh ctx %s: ifp %s, mac %pEA, ip %pIA", + dplane_op2str(op), ifp->name, mac, ip); ctx = dplane_ctx_alloc(); @@ -3590,6 +3812,139 @@ enum zebra_dplane_result dplane_pbr_rule_update(struct zebra_pbr_rule *old_rule, { return rule_update_internal(DPLANE_OP_RULE_UPDATE, new_rule, old_rule); } +/* + * Common helper api for iptable updates + */ +static enum zebra_dplane_result +iptable_update_internal(enum dplane_op_e op, struct zebra_pbr_iptable *iptable) +{ + enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE; + struct zebra_dplane_ctx *ctx; + int ret; + + ctx = dplane_ctx_alloc(); + + ret = dplane_ctx_iptable_init(ctx, op, iptable); + if (ret != AOK) + goto done; + + ret = dplane_update_enqueue(ctx); + +done: + atomic_fetch_add_explicit(&zdplane_info.dg_iptable_in, 1, + memory_order_relaxed); + + if (ret == AOK) + result = ZEBRA_DPLANE_REQUEST_QUEUED; + else { + atomic_fetch_add_explicit(&zdplane_info.dg_iptable_errors, 1, + memory_order_relaxed); + dplane_ctx_free(&ctx); + } + + return result; +} + +enum zebra_dplane_result +dplane_pbr_iptable_add(struct zebra_pbr_iptable *iptable) +{ + return iptable_update_internal(DPLANE_OP_IPTABLE_ADD, iptable); +} + +enum zebra_dplane_result +dplane_pbr_iptable_delete(struct zebra_pbr_iptable *iptable) +{ + return iptable_update_internal(DPLANE_OP_IPTABLE_DELETE, iptable); +} + +/* + * Common helper api for ipset updates + */ +static enum zebra_dplane_result +ipset_update_internal(enum dplane_op_e op, struct zebra_pbr_ipset *ipset) +{ + enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE; + struct zebra_dplane_ctx *ctx; + int ret; + + ctx = dplane_ctx_alloc(); + + ret = dplane_ctx_ipset_init(ctx, op, ipset); + if (ret != AOK) + goto done; + + ret = dplane_update_enqueue(ctx); + +done: + atomic_fetch_add_explicit(&zdplane_info.dg_ipset_in, 1, + memory_order_relaxed); + + if (ret == AOK) + result = ZEBRA_DPLANE_REQUEST_QUEUED; + else { + atomic_fetch_add_explicit(&zdplane_info.dg_ipset_errors, 1, + memory_order_relaxed); + dplane_ctx_free(&ctx); + } + + return result; +} + +enum zebra_dplane_result dplane_pbr_ipset_add(struct zebra_pbr_ipset *ipset) +{ + return ipset_update_internal(DPLANE_OP_IPSET_ADD, ipset); +} + +enum zebra_dplane_result dplane_pbr_ipset_delete(struct zebra_pbr_ipset *ipset) +{ + return ipset_update_internal(DPLANE_OP_IPSET_DELETE, ipset); +} + +/* + * Common helper api for ipset updates + */ +static enum zebra_dplane_result +ipset_entry_update_internal(enum dplane_op_e op, + struct zebra_pbr_ipset_entry *ipset_entry) +{ + enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE; + struct zebra_dplane_ctx *ctx; + int ret; + + ctx = dplane_ctx_alloc(); + + ret = dplane_ctx_ipset_entry_init(ctx, op, ipset_entry); + if (ret != AOK) + goto done; + + ret = dplane_update_enqueue(ctx); + +done: + atomic_fetch_add_explicit(&zdplane_info.dg_ipset_entry_in, 1, + memory_order_relaxed); + + if (ret == AOK) + result = ZEBRA_DPLANE_REQUEST_QUEUED; + else { + atomic_fetch_add_explicit(&zdplane_info.dg_ipset_entry_errors, + 1, memory_order_relaxed); + dplane_ctx_free(&ctx); + } + + return result; +} + +enum zebra_dplane_result +dplane_pbr_ipset_entry_add(struct zebra_pbr_ipset_entry *ipset) +{ + return ipset_entry_update_internal(DPLANE_OP_IPSET_ENTRY_ADD, ipset); +} + +enum zebra_dplane_result +dplane_pbr_ipset_entry_delete(struct zebra_pbr_ipset_entry *ipset) +{ + return ipset_entry_update_internal(DPLANE_OP_IPSET_ENTRY_DELETE, ipset); +} /* * Handler for 'show dplane' @@ -3675,6 +4030,24 @@ int dplane_show_helper(struct vty *vty, bool detailed) vty_out(vty, "Bridge port updates: %" PRIu64 "\n", incoming); vty_out(vty, "Bridge port errors: %" PRIu64 "\n", errs); + incoming = atomic_load_explicit(&zdplane_info.dg_iptable_in, + memory_order_relaxed); + errs = atomic_load_explicit(&zdplane_info.dg_iptable_errors, + memory_order_relaxed); + vty_out(vty, "IPtable updates: %" PRIu64 "\n", incoming); + vty_out(vty, "IPtable errors: %" PRIu64 "\n", errs); + incoming = atomic_load_explicit(&zdplane_info.dg_ipset_in, + memory_order_relaxed); + errs = atomic_load_explicit(&zdplane_info.dg_ipset_errors, + memory_order_relaxed); + vty_out(vty, "IPset updates: %" PRIu64 "\n", incoming); + vty_out(vty, "IPset errors: %" PRIu64 "\n", errs); + incoming = atomic_load_explicit(&zdplane_info.dg_ipset_entry_in, + memory_order_relaxed); + errs = atomic_load_explicit(&zdplane_info.dg_ipset_entry_errors, + memory_order_relaxed); + vty_out(vty, "IPset entry updates: %" PRIu64 "\n", incoming); + vty_out(vty, "IPset entry errors: %" PRIu64 "\n", errs); return CMD_SUCCESS; } @@ -4085,6 +4458,33 @@ static void kernel_dplane_log_detail(struct zebra_dplane_ctx *ctx) case DPLANE_OP_NONE: break; + + case DPLANE_OP_IPTABLE_ADD: + case DPLANE_OP_IPTABLE_DELETE: { + struct zebra_pbr_iptable ipt; + + if (dplane_ctx_get_pbr_iptable(ctx, &ipt)) + zlog_debug("Dplane iptable update op %s, unique(%u), ctx %p", + dplane_op2str(dplane_ctx_get_op(ctx)), ipt.unique, ctx); + } break; + case DPLANE_OP_IPSET_ADD: + case DPLANE_OP_IPSET_DELETE: { + struct zebra_pbr_ipset ipset; + + if (dplane_ctx_get_pbr_ipset(ctx, &ipset)) + zlog_debug("Dplane ipset update op %s, unique(%u), ctx %p", + dplane_op2str(dplane_ctx_get_op(ctx)), + ipset.unique, ctx); + } break; + case DPLANE_OP_IPSET_ENTRY_ADD: + case DPLANE_OP_IPSET_ENTRY_DELETE: { + struct zebra_pbr_ipset_entry ipent; + + if (dplane_ctx_get_pbr_ipset_entry(ctx, &ipent)) + zlog_debug("Dplane ipset entry update op %s, unique(%u), ctx %p", + dplane_op2str(dplane_ctx_get_op(ctx)), + ipent.unique, ctx); + } break; } } @@ -4181,6 +4581,29 @@ static void kernel_dplane_handle_result(struct zebra_dplane_ctx *ctx) 1, memory_order_relaxed); break; + case DPLANE_OP_IPTABLE_ADD: + case DPLANE_OP_IPTABLE_DELETE: + if (res != ZEBRA_DPLANE_REQUEST_SUCCESS) + atomic_fetch_add_explicit( + &zdplane_info.dg_iptable_errors, 1, + memory_order_relaxed); + break; + + case DPLANE_OP_IPSET_ADD: + case DPLANE_OP_IPSET_DELETE: + if (res != ZEBRA_DPLANE_REQUEST_SUCCESS) + atomic_fetch_add_explicit(&zdplane_info.dg_ipset_errors, + 1, memory_order_relaxed); + break; + + case DPLANE_OP_IPSET_ENTRY_ADD: + case DPLANE_OP_IPSET_ENTRY_DELETE: + if (res != ZEBRA_DPLANE_REQUEST_SUCCESS) + atomic_fetch_add_explicit( + &zdplane_info.dg_ipset_entry_errors, 1, + memory_order_relaxed); + break; + /* Ignore 'notifications' - no-op */ case DPLANE_OP_SYS_ROUTE_ADD: case DPLANE_OP_SYS_ROUTE_DELETE: @@ -4197,6 +4620,28 @@ static void kernel_dplane_handle_result(struct zebra_dplane_ctx *ctx) } } +static void kernel_dplane_process_iptable(struct zebra_dplane_provider *prov, + struct zebra_dplane_ctx *ctx) +{ + zebra_pbr_process_iptable(ctx); + dplane_provider_enqueue_out_ctx(prov, ctx); +} + +static void kernel_dplane_process_ipset(struct zebra_dplane_provider *prov, + struct zebra_dplane_ctx *ctx) +{ + zebra_pbr_process_ipset(ctx); + dplane_provider_enqueue_out_ctx(prov, ctx); +} + +static void +kernel_dplane_process_ipset_entry(struct zebra_dplane_provider *prov, + struct zebra_dplane_ctx *ctx) +{ + zebra_pbr_process_ipset_entry(ctx); + dplane_provider_enqueue_out_ctx(prov, ctx); +} + /* * Kernel provider callback */ @@ -4218,11 +4663,21 @@ static int kernel_dplane_process_func(struct zebra_dplane_provider *prov) ctx = dplane_provider_dequeue_in_ctx(prov); if (ctx == NULL) break; - if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) kernel_dplane_log_detail(ctx); - TAILQ_INSERT_TAIL(&work_list, ctx, zd_q_entries); + if ((dplane_ctx_get_op(ctx) == DPLANE_OP_IPTABLE_ADD + || dplane_ctx_get_op(ctx) == DPLANE_OP_IPTABLE_DELETE)) + kernel_dplane_process_iptable(prov, ctx); + else if ((dplane_ctx_get_op(ctx) == DPLANE_OP_IPSET_ADD + || dplane_ctx_get_op(ctx) == DPLANE_OP_IPSET_DELETE)) + kernel_dplane_process_ipset(prov, ctx); + else if ((dplane_ctx_get_op(ctx) == DPLANE_OP_IPSET_ENTRY_ADD + || dplane_ctx_get_op(ctx) + == DPLANE_OP_IPSET_ENTRY_DELETE)) + kernel_dplane_process_ipset_entry(prov, ctx); + else + TAILQ_INSERT_TAIL(&work_list, ctx, zd_q_entries); } kernel_update_multi(&work_list); diff --git a/zebra/zebra_dplane.h b/zebra/zebra_dplane.h index 595d3fe562..4913ca251f 100644 --- a/zebra/zebra_dplane.h +++ b/zebra/zebra_dplane.h @@ -155,6 +155,16 @@ enum dplane_op_e { /* bridge port update */ DPLANE_OP_BR_PORT_UPDATE, + + /* Policy based routing iptable update */ + DPLANE_OP_IPTABLE_ADD, + DPLANE_OP_IPTABLE_DELETE, + + /* Policy based routing ipset update */ + DPLANE_OP_IPSET_ADD, + DPLANE_OP_IPSET_DELETE, + DPLANE_OP_IPSET_ENTRY_ADD, + DPLANE_OP_IPSET_ENTRY_DELETE, }; /* @@ -475,7 +485,19 @@ const struct prefix * dplane_ctx_rule_get_dst_ip(const struct zebra_dplane_ctx *ctx); const struct prefix * dplane_ctx_rule_get_old_dst_ip(const struct zebra_dplane_ctx *ctx); - +/* Accessors for policy based routing iptable information */ +struct zebra_pbr_iptable; +bool +dplane_ctx_get_pbr_iptable(const struct zebra_dplane_ctx *ctx, + struct zebra_pbr_iptable *table); +struct zebra_pbr_ipset; +bool +dplane_ctx_get_pbr_ipset(const struct zebra_dplane_ctx *ctx, + struct zebra_pbr_ipset *ipset); +struct zebra_pbr_ipset_entry; +bool +dplane_ctx_get_pbr_ipset_entry(const struct zebra_dplane_ctx *ctx, + struct zebra_pbr_ipset_entry *entry); /* Accessors for bridge port information */ uint32_t dplane_ctx_get_br_port_flags(const struct zebra_dplane_ctx *ctx); uint32_t @@ -582,6 +604,11 @@ enum zebra_dplane_result dplane_local_mac_add(const struct interface *ifp, uint32_t set_static, uint32_t set_inactive); +enum zebra_dplane_result +dplane_local_mac_del(const struct interface *ifp, + const struct interface *bridge_ifp, vlanid_t vid, + const struct ethaddr *mac); + enum zebra_dplane_result dplane_rem_mac_del(const struct interface *ifp, const struct interface *bridge_ifp, vlanid_t vid, @@ -643,6 +670,23 @@ enum zebra_dplane_result dplane_pbr_rule_delete(struct zebra_pbr_rule *rule); enum zebra_dplane_result dplane_pbr_rule_update(struct zebra_pbr_rule *old_rule, struct zebra_pbr_rule *new_rule); +/* iptable */ +enum zebra_dplane_result +dplane_pbr_iptable_add(struct zebra_pbr_iptable *iptable); +enum zebra_dplane_result +dplane_pbr_iptable_delete(struct zebra_pbr_iptable *iptable); + +/* ipset */ +struct zebra_pbr_ipset; +enum zebra_dplane_result dplane_pbr_ipset_add(struct zebra_pbr_ipset *ipset); +enum zebra_dplane_result dplane_pbr_ipset_delete(struct zebra_pbr_ipset *ipset); + +/* ipset entry */ +struct zebra_pbr_ipset_entry; +enum zebra_dplane_result +dplane_pbr_ipset_entry_add(struct zebra_pbr_ipset_entry *ipset); +enum zebra_dplane_result +dplane_pbr_ipset_entry_delete(struct zebra_pbr_ipset_entry *ipset); /* Encode route information into data plane context. */ int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op, diff --git a/zebra/zebra_evpn.c b/zebra/zebra_evpn.c index d7076ccce6..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" @@ -447,8 +446,6 @@ int zebra_evpn_gw_macip_add(struct interface *ifp, zebra_evpn_t *zevpn, int zebra_evpn_gw_macip_del(struct interface *ifp, zebra_evpn_t *zevpn, struct ipaddr *ip) { - char buf1[ETHER_ADDR_STRLEN]; - char buf2[INET6_ADDRSTRLEN]; zebra_neigh_t *n = NULL; zebra_mac_t *mac = NULL; @@ -461,11 +458,8 @@ int zebra_evpn_gw_macip_del(struct interface *ifp, zebra_evpn_t *zevpn, mac = zebra_evpn_mac_lookup(zevpn, &n->emac); if (!mac) { if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug("MAC %s doesn't exist for neigh %s on VNI %u", - prefix_mac2str(&n->emac, - buf1, sizeof(buf1)), - ipaddr2str(ip, buf2, sizeof(buf2)), - zevpn->vni); + zlog_debug("MAC %pEA doesn't exist for neigh %pIA on VNI %u", + &n->emac, ip, zevpn->vni); return -1; } @@ -476,10 +470,9 @@ int zebra_evpn_gw_macip_del(struct interface *ifp, zebra_evpn_t *zevpn, /* only need to delete the entry from bgp if we sent it before */ if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug( - "%u:SVI %s(%u) VNI %u, sending GW MAC %s IP %s del to BGP", + "%u:SVI %s(%u) VNI %u, sending GW MAC %pEA IP %pIA del to BGP", ifp->vrf_id, ifp->name, ifp->ifindex, zevpn->vni, - prefix_mac2str(&(n->emac), buf1, sizeof(buf1)), - ipaddr2str(ip, buf2, sizeof(buf2))); + &n->emac, ip); /* Remove neighbor from BGP. */ zebra_evpn_neigh_send_del_to_client(zevpn->vni, &n->ip, &n->emac, @@ -1321,7 +1314,6 @@ zebra_evpn_process_sync_macip_add(zebra_evpn_t *zevpn, struct ethaddr *macaddr, uint8_t flags, uint32_t seq, esi_t *esi) { struct sync_mac_ip_ctx ctx; - char macbuf[ETHER_ADDR_STRLEN]; char ipbuf[INET6_ADDRSTRLEN]; bool sticky; bool remote_gw; @@ -1334,9 +1326,9 @@ zebra_evpn_process_sync_macip_add(zebra_evpn_t *zevpn, struct ethaddr *macaddr, if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_NEIGH || IS_ZEBRA_DEBUG_EVPN_MH_MAC) zlog_debug( - "Ignore sync-macip vni %u mac %s%s%s%s%s", + "Ignore sync-macip vni %u mac %pEA%s%s%s%s", zevpn->vni, - prefix_mac2str(macaddr, macbuf, sizeof(macbuf)), + macaddr, ipa_len ? " IP " : "", ipa_len ? ipaddr2str(ipaddr, ipbuf, sizeof(ipbuf)) @@ -1455,7 +1447,6 @@ void process_remote_macip_del(vni_t vni, struct ethaddr *macaddr, struct zebra_ns *zns; struct zebra_l2info_vxlan *vxl; struct zebra_vrf *zvrf; - char buf[ETHER_ADDR_STRLEN]; char buf1[INET6_ADDRSTRLEN]; /* Locate EVPN hash entry - expected to exist. */ @@ -1485,9 +1476,8 @@ void process_remote_macip_del(vni_t vni, struct ethaddr *macaddr, if (n && !mac) { zlog_warn( - "Failed to locate MAC %s for neigh %s VNI %u upon remote MACIP DEL", - prefix_mac2str(macaddr, buf, sizeof(buf)), - ipaddr2str(ipaddr, buf1, sizeof(buf1)), vni); + "Failed to locate MAC %pEA for neigh %pIA VNI %u upon remote MACIP DEL", + macaddr, ipaddr, vni); return; } @@ -1503,8 +1493,8 @@ void process_remote_macip_del(vni_t vni, struct ethaddr *macaddr, if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL) && CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW)) { zlog_warn( - "Ignore remote MACIP DEL VNI %u MAC %s%s%s as MAC is already configured as gateway MAC", - vni, prefix_mac2str(macaddr, buf, sizeof(buf)), + "Ignore remote MACIP DEL VNI %u MAC %pEA%s%s as MAC is already configured as gateway MAC", + vni, macaddr, ipa_len ? " IP " : "", ipa_len ? ipaddr2str(ipaddr, buf1, sizeof(buf1)) : ""); return; @@ -1525,11 +1515,8 @@ void process_remote_macip_del(vni_t vni, struct ethaddr *macaddr, && CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) { if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug( - "%s: MAC %s (flags 0x%x) is remote and duplicate, read kernel for local entry", - __func__, - prefix_mac2str(macaddr, buf, - sizeof(buf)), - mac->flags); + "%s: MAC %pEA (flags 0x%x) is remote and duplicate, read kernel for local entry", + __func__, macaddr, mac->flags); macfdb_read_specific_mac(zns, zif->brslave_info.br_if, macaddr, vxl->access_vlan); } diff --git a/zebra/zebra_evpn_mac.c b/zebra/zebra_evpn_mac.c index 90227aa597..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" @@ -94,6 +93,97 @@ uint32_t num_dup_detected_macs(zebra_evpn_t *zevpn) return num_macs; } +/* Setup mac_list against the access port. This is done when a mac uses + * the ifp as destination for the first time + */ +static void zebra_evpn_mac_ifp_new(struct zebra_if *zif) +{ + if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) + zlog_debug("MAC list created for ifp %s (%u)", zif->ifp->name, + zif->ifp->ifindex); + + zif->mac_list = list_new(); + listset_app_node_mem(zif->mac_list); +} + +/* Free up the mac_list if any as a part of the interface del/cleanup */ +void zebra_evpn_mac_ifp_del(struct interface *ifp) +{ + struct zebra_if *zif = ifp->info; + + if (zif->mac_list) { + if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) + zlog_debug("MAC list deleted for ifp %s (%u)", + zif->ifp->name, zif->ifp->ifindex); + list_delete(&zif->mac_list); + } +} + +/* Unlink local mac from a destination access port */ +static void zebra_evpn_mac_ifp_unlink(zebra_mac_t *zmac) +{ + struct zebra_if *zif; + struct interface *ifp = zmac->ifp; + + if (!ifp) + return; + + if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) + zlog_debug("VNI %d MAC %pEA unlinked from ifp %s (%u)", + zmac->zevpn->vni, + &zmac->macaddr, + ifp->name, ifp->ifindex); + + zif = ifp->info; + list_delete_node(zif->mac_list, &zmac->ifp_listnode); + zmac->ifp = NULL; +} + +/* Link local mac to destination access port. This is done only if the + * local mac is associated with a zero ESI i.e. single attach or lacp-bypass + * bridge port member + */ +static void zebra_evpn_mac_ifp_link(zebra_mac_t *zmac, struct interface *ifp) +{ + struct zebra_if *zif; + + if (!CHECK_FLAG(zmac->flags, ZEBRA_MAC_LOCAL)) + return; + + /* already linked to the destination */ + if (zmac->ifp == ifp) + return; + + /* unlink the mac from any old destination */ + if (zmac->ifp) + zebra_evpn_mac_ifp_unlink(zmac); + + if (!ifp) + return; + + zif = ifp->info; + /* the interface mac_list is created on first mac link attempt */ + if (!zif->mac_list) + zebra_evpn_mac_ifp_new(zif); + + if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) + zlog_debug("VNI %d MAC %pEA linked to ifp %s (%u)", + zmac->zevpn->vni, + &zmac->macaddr, + ifp->name, ifp->ifindex); + + zmac->ifp = ifp; + listnode_init(&zmac->ifp_listnode, zmac); + listnode_add(zif->mac_list, &zmac->ifp_listnode); +} + +/* If the mac is a local mac clear links to destination access port */ +void zebra_evpn_mac_clear_fwd_info(zebra_mac_t *zmac) +{ + zebra_evpn_mac_ifp_unlink(zmac); + memset(&zmac->fwd_info, 0, sizeof(zmac->fwd_info)); +} + /* * Install remote MAC into the forwarding plane. */ @@ -293,7 +383,6 @@ static int zebra_evpn_dad_mac_auto_recovery_exp(struct thread *t) zebra_evpn_t *zevpn = NULL; struct listnode *node = NULL; zebra_neigh_t *nbr = NULL; - char buf[ETHER_ADDR_STRLEN]; mac = THREAD_ARG(t); @@ -314,9 +403,8 @@ static int zebra_evpn_dad_mac_auto_recovery_exp(struct thread *t) char mac_buf[MAC_BUF_SIZE]; zlog_debug( - "%s: duplicate addr mac %s flags %slearn count %u host count %u auto recovery expired", - __func__, - prefix_mac2str(&mac->macaddr, buf, sizeof(buf)), + "%s: duplicate addr mac %pEA flags %slearn count %u host count %u auto recovery expired", + __func__, &mac->macaddr, zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf)), mac->dad_count, listcount(mac->neigh_list)); @@ -375,8 +463,6 @@ static void zebra_evpn_dup_addr_detect_for_mac(struct zebra_vrf *zvrf, zebra_neigh_t *nbr; struct listnode *node = NULL; struct timeval elapsed = {0, 0}; - char buf[ETHER_ADDR_STRLEN]; - char buf1[INET6_ADDRSTRLEN]; bool reset_params = false; if (!(zebra_evpn_do_dup_addr_detect(zvrf) && do_dad)) @@ -391,9 +477,8 @@ static void zebra_evpn_dup_addr_detect_for_mac(struct zebra_vrf *zvrf, char mac_buf[MAC_BUF_SIZE]; zlog_debug( - "%s: duplicate addr MAC %s flags %sskip update to client, learn count %u recover time %u", - __func__, - prefix_mac2str(&mac->macaddr, buf, sizeof(buf)), + "%s: duplicate addr MAC %pEA flags %sskip update to client, learn count %u recover time %u", + __func__, &mac->macaddr, zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf)), mac->dad_count, zvrf->dad_freeze_time); @@ -429,9 +514,8 @@ static void zebra_evpn_dup_addr_detect_for_mac(struct zebra_vrf *zvrf, char mac_buf[MAC_BUF_SIZE]; zlog_debug( - "%s: duplicate addr MAC %s flags %sdetection time passed, reset learn count %u", - __func__, - prefix_mac2str(&mac->macaddr, buf, sizeof(buf)), + "%s: duplicate addr MAC %pEA flags %sdetection time passed, reset learn count %u", + __func__, &mac->macaddr, zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf)), mac->dad_count); @@ -461,9 +545,8 @@ static void zebra_evpn_dup_addr_detect_for_mac(struct zebra_vrf *zvrf, if (mac->dad_count >= zvrf->dad_max_moves) { flog_warn(EC_ZEBRA_DUP_MAC_DETECTED, - "VNI %u: MAC %s detected as duplicate during %s VTEP %pI4", - mac->zevpn->vni, - prefix_mac2str(&mac->macaddr, buf, sizeof(buf)), + "VNI %u: MAC %pEA detected as duplicate during %s VTEP %pI4", + mac->zevpn->vni, &mac->macaddr, is_local ? "local update, last" : "remote update, from", &vtep_ip); @@ -486,11 +569,8 @@ static void zebra_evpn_dup_addr_detect_for_mac(struct zebra_vrf *zvrf, nbr->dad_dup_detect_time = monotime(NULL); flog_warn(EC_ZEBRA_DUP_IP_INHERIT_DETECTED, - "VNI %u: MAC %s IP %s detected as duplicate during %s update, inherit duplicate from MAC", - mac->zevpn->vni, - prefix_mac2str(&mac->macaddr, - buf, sizeof(buf)), - ipaddr2str(&nbr->ip, buf1, sizeof(buf1)), + "VNI %u: MAC %pEA IP %pIA detected as duplicate during %s update, inherit duplicate from MAC", + mac->zevpn->vni, &mac->macaddr, &nbr->ip, is_local ? "local" : "remote"); } @@ -501,10 +581,8 @@ static void zebra_evpn_dup_addr_detect_for_mac(struct zebra_vrf *zvrf, char mac_buf[MAC_BUF_SIZE]; zlog_debug( - "%s: duplicate addr MAC %s flags %sauto recovery time %u start", - __func__, - prefix_mac2str(&mac->macaddr, buf, - sizeof(buf)), + "%s: duplicate addr MAC %pEA flags %sauto recovery time %u start", + __func__, &mac->macaddr, zebra_evpn_zebra_mac_flag_dump( mac, mac_buf, sizeof(mac_buf)), zvrf->dad_freeze_time); @@ -753,14 +831,10 @@ static char *zebra_evpn_print_mac_flags(zebra_mac_t *mac, char *flags_buf, size_t flags_buf_sz) { snprintf(flags_buf, flags_buf_sz, "%s%s%s%s", - mac->sync_neigh_cnt ? - "N" : "", - (mac->flags & ZEBRA_MAC_ES_PEER_ACTIVE) ? - "P" : "", - (mac->flags & ZEBRA_MAC_ES_PEER_PROXY) ? - "X" : "", - (mac->flags & ZEBRA_MAC_LOCAL_INACTIVE) ? - "I" : ""); + mac->sync_neigh_cnt ? "N" : "", + (mac->flags & ZEBRA_MAC_ES_PEER_ACTIVE) ? "P" : "", + (mac->flags & ZEBRA_MAC_ES_PEER_PROXY) ? "X" : "", + (mac->flags & ZEBRA_MAC_LOCAL_INACTIVE) ? "I" : ""); return flags_buf; } @@ -917,8 +991,6 @@ int zebra_evpn_macip_send_msg_to_client(vni_t vni, struct ethaddr *macaddr, uint32_t seq, int state, struct zebra_evpn_es *es, uint16_t cmd) { - char buf[ETHER_ADDR_STRLEN]; - char buf2[INET6_ADDRSTRLEN]; int ipa_len; struct zserv *client = NULL; struct stream *s = NULL; @@ -963,12 +1035,11 @@ int zebra_evpn_macip_send_msg_to_client(vni_t vni, struct ethaddr *macaddr, char flag_buf[MACIP_BUF_SIZE]; zlog_debug( - "Send MACIP %s f %s MAC %s IP %s seq %u L2-VNI %u ESI %s to %s", + "Send MACIP %s f %s MAC %pEA IP %pIA seq %u L2-VNI %u ESI %s to %s", (cmd == ZEBRA_MACIP_ADD) ? "Add" : "Del", zclient_evpn_dump_macip_flags(flags, flag_buf, sizeof(flag_buf)), - prefix_mac2str(macaddr, buf, sizeof(buf)), - ipaddr2str(ip, buf2, sizeof(buf2)), seq, vni, + macaddr, ip, seq, vni, es ? es->esi_str : "-", zebra_route_string(client->proto)); } @@ -1042,11 +1113,10 @@ zebra_mac_t *zebra_evpn_mac_add(zebra_evpn_t *zevpn, struct ethaddr *macaddr) mac->uptime = monotime(NULL); if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC) { - char buf[ETHER_ADDR_STRLEN]; char mac_buf[MAC_BUF_SIZE]; - zlog_debug("%s: MAC %s flags %s", __func__, - prefix_mac2str(&mac->macaddr, buf, sizeof(buf)), + zlog_debug("%s: MAC %pEA flags %s", __func__, + &mac->macaddr, zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf))); } @@ -1061,11 +1131,10 @@ int zebra_evpn_mac_del(zebra_evpn_t *zevpn, zebra_mac_t *mac) zebra_mac_t *tmp_mac; if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC) { - char buf[ETHER_ADDR_STRLEN]; char mac_buf[MAC_BUF_SIZE]; - zlog_debug("%s: MAC %s flags %s", __func__, - prefix_mac2str(&mac->macaddr, buf, sizeof(buf)), + zlog_debug("%s: MAC %pEA flags %s", __func__, + &mac->macaddr, zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf))); } @@ -1081,6 +1150,9 @@ int zebra_evpn_mac_del(zebra_evpn_t *zevpn, zebra_mac_t *mac) /* force de-ref any ES entry linked to the MAC */ zebra_evpn_es_mac_deref_entry(mac); + /* remove links to the destination access port */ + zebra_evpn_mac_clear_fwd_info(mac); + /* Cancel proxy hold timer */ zebra_evpn_mac_stop_hold_timer(mac); @@ -1111,12 +1183,11 @@ static bool zebra_evpn_check_mac_del_from_db(struct mac_walk_ctx *wctx, else if ((wctx->flags & DEL_LOCAL_MAC) && (mac->flags & ZEBRA_MAC_AUTO) && !listcount(mac->neigh_list)) { if (IS_ZEBRA_DEBUG_VXLAN) { - char buf[ETHER_ADDR_STRLEN]; char mac_buf[MAC_BUF_SIZE]; zlog_debug( - "%s: Del MAC %s flags %s", __func__, - prefix_mac2str(&mac->macaddr, buf, sizeof(buf)), + "%s: Del MAC %pEA flags %s", __func__, + &mac->macaddr, zebra_evpn_zebra_mac_flag_dump( mac, mac_buf, sizeof(mac_buf))); } @@ -1381,7 +1452,6 @@ static int zebra_evpn_mac_hold_exp_cb(struct thread *t) bool new_bgp_ready; bool old_static; bool new_static; - char macbuf[ETHER_ADDR_STRLEN]; mac = THREAD_ARG(t); /* the purpose of the hold timer is to age out the peer-active @@ -1400,9 +1470,8 @@ static int zebra_evpn_mac_hold_exp_cb(struct thread *t) char mac_buf[MAC_BUF_SIZE]; zlog_debug( - "sync-mac vni %u mac %s es %s %shold expired", - mac->zevpn->vni, - prefix_mac2str(&mac->macaddr, macbuf, sizeof(macbuf)), + "sync-mac vni %u mac %pEA es %s %shold expired", + mac->zevpn->vni, &mac->macaddr, mac->es ? mac->es->esi_str : "-", zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf))); @@ -1426,8 +1495,6 @@ static int zebra_evpn_mac_hold_exp_cb(struct thread *t) static inline void zebra_evpn_mac_start_hold_timer(zebra_mac_t *mac) { - char macbuf[ETHER_ADDR_STRLEN]; - if (mac->hold_timer) return; @@ -1435,9 +1502,8 @@ static inline void zebra_evpn_mac_start_hold_timer(zebra_mac_t *mac) char mac_buf[MAC_BUF_SIZE]; zlog_debug( - "sync-mac vni %u mac %s es %s %shold started", - mac->zevpn->vni, - prefix_mac2str(&mac->macaddr, macbuf, sizeof(macbuf)), + "sync-mac vni %u mac %pEA es %s %shold started", + mac->zevpn->vni, &mac->macaddr, mac->es ? mac->es->esi_str : "-", zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf))); @@ -1448,8 +1514,6 @@ static inline void zebra_evpn_mac_start_hold_timer(zebra_mac_t *mac) void zebra_evpn_mac_stop_hold_timer(zebra_mac_t *mac) { - char macbuf[ETHER_ADDR_STRLEN]; - if (!mac->hold_timer) return; @@ -1457,9 +1521,8 @@ void zebra_evpn_mac_stop_hold_timer(zebra_mac_t *mac) char mac_buf[MAC_BUF_SIZE]; zlog_debug( - "sync-mac vni %u mac %s es %s %shold stopped", - mac->zevpn->vni, - prefix_mac2str(&mac->macaddr, macbuf, sizeof(macbuf)), + "sync-mac vni %u mac %pEA es %s %shold stopped", + mac->zevpn->vni, &mac->macaddr, mac->es ? mac->es->esi_str : "-", zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf))); @@ -1470,7 +1533,6 @@ void zebra_evpn_mac_stop_hold_timer(zebra_mac_t *mac) void zebra_evpn_sync_mac_del(zebra_mac_t *mac) { - char macbuf[ETHER_ADDR_STRLEN]; bool old_static; bool new_static; @@ -1478,9 +1540,8 @@ void zebra_evpn_sync_mac_del(zebra_mac_t *mac) char mac_buf[MAC_BUF_SIZE]; zlog_debug( - "sync-mac del vni %u mac %s es %s seq %d f %s", - mac->zevpn->vni, - prefix_mac2str(&mac->macaddr, macbuf, sizeof(macbuf)), + "sync-mac del vni %u mac %pEA es %s seq %d f %s", + mac->zevpn->vni, &mac->macaddr, mac->es ? mac->es->esi_str : "-", mac->loc_seq, zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf))); @@ -1505,7 +1566,6 @@ static inline bool zebra_evpn_mac_is_bgp_seq_ok(zebra_evpn_t *zevpn, struct ipaddr *ipaddr, bool sync) { - char macbuf[ETHER_ADDR_STRLEN]; char ipbuf[INET6_ADDRSTRLEN]; uint32_t tmp_seq; const char *n_type; @@ -1530,11 +1590,10 @@ static inline bool zebra_evpn_mac_is_bgp_seq_ok(zebra_evpn_t *zevpn, char mac_buf[MAC_BUF_SIZE]; zlog_debug( - "%s-macip accept vni %u %s-mac %s%s%s lower seq %u f %s", + "%s-macip accept vni %u %s-mac %pEA%s%s lower seq %u f %s", sync ? "sync" : "rem", zevpn->vni, n_type, - prefix_mac2str(&mac->macaddr, macbuf, - sizeof(macbuf)), + &mac->macaddr, ipa_len ? " IP " : "", ipa_len ? ipaddr2str(ipaddr, ipbuf, sizeof(ipbuf)) @@ -1551,10 +1610,9 @@ static inline bool zebra_evpn_mac_is_bgp_seq_ok(zebra_evpn_t *zevpn, char mac_buf[MAC_BUF_SIZE]; zlog_debug( - "%s-macip ignore vni %u %s-mac %s%s%s as existing has higher seq %u f %s", + "%s-macip ignore vni %u %s-mac %pEA%s%s as existing has higher seq %u f %s", sync ? "sync" : "rem", zevpn->vni, n_type, - prefix_mac2str(&mac->macaddr, macbuf, - sizeof(macbuf)), + &mac->macaddr, ipa_len ? " IP " : "", ipa_len ? ipaddr2str(ipaddr, ipbuf, sizeof(ipbuf)) @@ -1581,7 +1639,6 @@ zebra_evpn_proc_sync_mac_update(zebra_evpn_t *zevpn, struct ethaddr *macaddr, bool seq_change = false; bool es_change = false; uint32_t tmp_seq; - char macbuf[ETHER_ADDR_STRLEN]; char ipbuf[INET6_ADDRSTRLEN]; bool old_local = false; bool old_bgp_ready; @@ -1629,10 +1686,8 @@ zebra_evpn_proc_sync_mac_update(zebra_evpn_t *zevpn, struct ethaddr *macaddr, if (sticky || remote_gw) { if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH) zlog_debug( - "Ignore sync-macip vni %u mac %s%s%s%s%s", - zevpn->vni, - prefix_mac2str(macaddr, macbuf, - sizeof(macbuf)), + "Ignore sync-macip vni %u mac %pEA%s%s%s%s", + zevpn->vni, macaddr, ipa_len ? " IP " : "", ipa_len ? ipaddr2str(ipaddr, ipbuf, sizeof(ipbuf)) @@ -1690,7 +1745,7 @@ zebra_evpn_proc_sync_mac_update(zebra_evpn_t *zevpn, struct ethaddr *macaddr, } } mac->rem_seq = 0; - memset(&mac->fwd_info, 0, sizeof(mac->fwd_info)); + zebra_evpn_mac_clear_fwd_info(mac); mac->flags = new_flags; if (IS_ZEBRA_DEBUG_EVPN_MH_MAC && (old_flags != new_flags)) { @@ -1699,9 +1754,8 @@ zebra_evpn_proc_sync_mac_update(zebra_evpn_t *zevpn, struct ethaddr *macaddr, omac.flags = old_flags; zlog_debug( - "sync-mac vni %u mac %s old_f %snew_f %s", - zevpn->vni, - prefix_mac2str(macaddr, macbuf, sizeof(macbuf)), + "sync-mac vni %u mac %pEA old_f %snew_f %s", + zevpn->vni, macaddr, zebra_evpn_zebra_mac_flag_dump( &omac, omac_buf, sizeof(omac_buf)), zebra_evpn_zebra_mac_flag_dump( @@ -1716,6 +1770,7 @@ zebra_evpn_proc_sync_mac_update(zebra_evpn_t *zevpn, struct ethaddr *macaddr, inform_dataplane = true; ctx->mac_inactive = true; } + /* if peer-flag is being set notify dataplane that the * entry must not be expired because of local inactivity */ @@ -1743,9 +1798,9 @@ zebra_evpn_proc_sync_mac_update(zebra_evpn_t *zevpn, struct ethaddr *macaddr, if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) { char mac_buf[MAC_BUF_SIZE]; - zlog_debug("sync-mac %s vni %u mac %s es %s seq %d f %s%s%s", - ctx->mac_created ? "created" : "updated", zevpn->vni, - prefix_mac2str(macaddr, macbuf, sizeof(macbuf)), + zlog_debug("sync-mac %s vni %u mac %pEA es %s seq %d f %s%s%s", + ctx->mac_created ? "created" : "updated", + zevpn->vni, macaddr, mac->es ? mac->es->esi_str : "-", mac->loc_seq, zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf)), @@ -1796,20 +1851,25 @@ static bool zebra_evpn_local_mac_update_fwd_info(zebra_mac_t *mac, bool es_change; ns_id_t local_ns_id = NS_DEFAULT; struct zebra_vrf *zvrf; + struct zebra_evpn_es *es; zvrf = zebra_vrf_lookup_by_id(ifp->vrf_id); if (zvrf && zvrf->zns) local_ns_id = zvrf->zns->ns_id; - memset(&mac->fwd_info, 0, sizeof(mac->fwd_info)); + zebra_evpn_mac_clear_fwd_info(mac); - es_change = zebra_evpn_es_mac_ref_entry(mac, zif->es_info.es); + es = zif->es_info.es; + if (es && (es->flags & ZEBRA_EVPNES_BYPASS)) + es = NULL; + es_change = zebra_evpn_es_mac_ref_entry(mac, es); if (!mac->es) { /* if es is set fwd_info is not-relevant/taped-out */ mac->fwd_info.local.ifindex = ifp->ifindex; mac->fwd_info.local.ns_id = local_ns_id; mac->fwd_info.local.vid = vid; + zebra_evpn_mac_ifp_link(mac, ifp); } return es_change; @@ -1904,7 +1964,6 @@ int process_mac_remote_macip_add(zebra_evpn_t *zevpn, struct zebra_vrf *zvrf, struct in_addr vtep_ip, uint8_t flags, uint32_t seq, esi_t *esi) { - char buf[ETHER_ADDR_STRLEN]; char buf1[INET6_ADDRSTRLEN]; bool sticky; bool remote_gw; @@ -1914,6 +1973,8 @@ int process_mac_remote_macip_add(zebra_evpn_t *zevpn, struct zebra_vrf *zvrf, esi_t *old_esi; bool old_static = false; zebra_mac_t *mac; + bool old_es_present; + bool new_es_present; sticky = !!CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY); remote_gw = !!CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW); @@ -1925,9 +1986,8 @@ int process_mac_remote_macip_add(zebra_evpn_t *zevpn, struct zebra_vrf *zvrf, && CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW)) { if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug( - "Ignore remote MACIP ADD VNI %u MAC %s%s%s as MAC is already configured as gateway MAC", - zevpn->vni, - prefix_mac2str(macaddr, buf, sizeof(buf)), + "Ignore remote MACIP ADD VNI %u MAC %pEA%s%s as MAC is already configured as gateway MAC", + zevpn->vni, macaddr, ipa_len ? " IP " : "", ipa_len ? ipaddr2str(ipaddr, buf1, sizeof(buf1)) : ""); @@ -1952,10 +2012,8 @@ int process_mac_remote_macip_add(zebra_evpn_t *zevpn, struct zebra_vrf *zvrf, mac = zebra_evpn_mac_add(zevpn, macaddr); if (!mac) { zlog_warn( - "Failed to add MAC %s VNI %u Remote VTEP %pI4", - prefix_mac2str(macaddr, buf, - sizeof(buf)), - zevpn->vni, &vtep_ip); + "Failed to add MAC %pEA VNI %u Remote VTEP %pI4", + macaddr, zevpn->vni, &vtep_ip); return -1; } @@ -1977,7 +2035,16 @@ int process_mac_remote_macip_add(zebra_evpn_t *zevpn, struct zebra_vrf *zvrf, zevpn, mac, seq, ipa_len, ipaddr, false)) return -1; + old_es_present = !!mac->es; zebra_evpn_es_mac_ref(mac, esi); + new_es_present = !!mac->es; + /* XXX - dataplane is curently not able to handle a MAC + * replace if the destination changes from L2-NHG to + * single VTEP and vice-versa. So delete the old entry + * and re-install + */ + if (old_es_present != new_es_present) + zebra_evpn_rem_mac_uninstall(zevpn, mac, false); } /* Check MAC's curent state is local (this is the case @@ -2005,10 +2072,8 @@ int process_mac_remote_macip_add(zebra_evpn_t *zevpn, struct zebra_vrf *zvrf, char mac_buf[MAC_BUF_SIZE]; zlog_debug( - "sync-mac->remote vni %u mac %s es %s seq %d f %s", - zevpn->vni, - prefix_mac2str(macaddr, buf, - sizeof(buf)), + "sync-mac->remote vni %u mac %pEA es %s seq %d f %s", + zevpn->vni, macaddr, mac->es ? mac->es->esi_str : "-", mac->loc_seq, zebra_evpn_zebra_mac_flag_dump( @@ -2022,8 +2087,8 @@ int process_mac_remote_macip_add(zebra_evpn_t *zevpn, struct zebra_vrf *zvrf, } /* Set "auto" and "remote" forwarding info. */ + zebra_evpn_mac_clear_fwd_info(mac); UNSET_FLAG(mac->flags, ZEBRA_MAC_ALL_LOCAL_FLAGS); - memset(&mac->fwd_info, 0, sizeof(mac->fwd_info)); SET_FLAG(mac->flags, ZEBRA_MAC_REMOTE); mac->fwd_info.r_vtep_ip = vtep_ip; @@ -2064,10 +2129,8 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, zebra_evpn_t *zevpn, struct interface *ifp, struct ethaddr *macaddr, vlanid_t vid, bool sticky, bool local_inactive, - bool dp_static) + bool dp_static, zebra_mac_t *mac) { - zebra_mac_t *mac; - char buf[ETHER_ADDR_STRLEN]; bool mac_sticky = false; bool inform_client = false; bool upd_neigh = false; @@ -2083,13 +2146,13 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, zebra_evpn_t *zevpn, assert(ifp); /* Check if we need to create or update or it is a NO-OP. */ - mac = zebra_evpn_mac_lookup(zevpn, macaddr); + if (!mac) + mac = zebra_evpn_mac_lookup(zevpn, macaddr); if (!mac) { if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC) zlog_debug( - "ADD %sMAC %s intf %s(%u) VID %u -> VNI %u%s", - sticky ? "sticky " : "", - prefix_mac2str(macaddr, buf, sizeof(buf)), + "ADD %sMAC %pEA intf %s(%u) VID %u -> VNI %u%s", + sticky ? "sticky " : "", macaddr, ifp->name, ifp->ifindex, vid, zevpn->vni, local_inactive ? " local-inactive" : ""); @@ -2097,9 +2160,9 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, zebra_evpn_t *zevpn, if (!mac) { flog_err( EC_ZEBRA_MAC_ADD_FAILED, - "Failed to add MAC %s intf %s(%u) VID %u VNI %u", - prefix_mac2str(macaddr, buf, sizeof(buf)), - ifp->name, ifp->ifindex, vid, zevpn->vni); + "Failed to add MAC %pEA intf %s(%u) VID %u VNI %u", + macaddr, ifp->name, ifp->ifindex, vid, + zevpn->vni); return -1; } SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL); @@ -2112,9 +2175,8 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, zebra_evpn_t *zevpn, char mac_buf[MAC_BUF_SIZE]; zlog_debug( - "UPD %sMAC %s intf %s(%u) VID %u -> VNI %u %scurFlags %s", - sticky ? "sticky " : "", - prefix_mac2str(macaddr, buf, sizeof(buf)), + "UPD %sMAC %pEA intf %s(%u) VID %u -> VNI %u %scurFlags %s", + sticky ? "sticky " : "", macaddr, ifp->name, ifp->ifindex, vid, zevpn->vni, local_inactive ? "local-inactive " : "", zebra_evpn_zebra_mac_flag_dump( @@ -2134,6 +2196,8 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, zebra_evpn_t *zevpn, old_static = zebra_evpn_mac_is_static(mac); if (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY)) mac_sticky = true; + es_change = zebra_evpn_local_mac_update_fwd_info( + mac, ifp, vid); /* * Update any changes and if changes are relevant to @@ -2142,16 +2206,14 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, zebra_evpn_t *zevpn, if (mac_sticky == sticky && old_ifp == ifp && old_vid == vid && old_local_inactive == local_inactive - && dp_static == old_static) { + && dp_static == old_static && !es_change) { if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug( - " Add/Update %sMAC %s intf %s(%u) VID %u -> VNI %u%s, " + " Add/Update %sMAC %pEA intf %s(%u) VID %u -> VNI %u%s, " "entry exists and has not changed ", - sticky ? "sticky " : "", - prefix_mac2str(macaddr, buf, - sizeof(buf)), - ifp->name, ifp->ifindex, vid, - zevpn->vni, + sticky ? "sticky " : "", + macaddr, ifp->name, + ifp->ifindex, vid, zevpn->vni, local_inactive ? " local_inactive" : ""); @@ -2166,15 +2228,17 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, zebra_evpn_t *zevpn, inform_client = true; } - es_change = zebra_evpn_local_mac_update_fwd_info( - mac, ifp, vid); /* If an es_change is detected we need to advertise * the route with a sequence that is one * greater. This is need to indicate a mac-move * to the ES peers */ if (es_change) { - mac->loc_seq = mac->loc_seq + 1; + /* update the sequence number only if the entry + * is locally active + */ + if (!local_inactive) + mac->loc_seq = mac->loc_seq + 1; /* force drop the peer/sync info as it is * simply no longer relevant */ @@ -2204,9 +2268,8 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, zebra_evpn_t *zevpn, if (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY)) { flog_warn( EC_ZEBRA_STICKY_MAC_ALREADY_LEARNT, - "MAC %s already learnt as remote sticky MAC behind VTEP %pI4 VNI %u", - prefix_mac2str(macaddr, buf, - sizeof(buf)), + "MAC %pEA already learnt as remote sticky MAC behind VTEP %pI4 VNI %u", + macaddr, &mac->fwd_info.r_vtep_ip, zevpn->vni); return 0; @@ -2271,9 +2334,8 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, zebra_evpn_t *zevpn, char mac_buf[MAC_BUF_SIZE]; zlog_debug( - "local mac vni %u mac %s es %s seq %d f %s%s", - zevpn->vni, - prefix_mac2str(macaddr, buf, sizeof(buf)), + "local mac vni %u mac %pEA es %s seq %d f %s%s", + zevpn->vni, macaddr, mac->es ? mac->es->esi_str : "", mac->loc_seq, zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf)), @@ -2308,32 +2370,30 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, zebra_evpn_t *zevpn, return 0; } -int zebra_evpn_del_local_mac(zebra_evpn_t *zevpn, zebra_mac_t *mac) +int zebra_evpn_del_local_mac(zebra_evpn_t *zevpn, zebra_mac_t *mac, + bool clear_static) { - char buf[ETHER_ADDR_STRLEN]; bool old_bgp_ready; bool new_bgp_ready; if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug("DEL MAC %s VNI %u seq %u flags 0x%x nbr count %u", - prefix_mac2str(&mac->macaddr, buf, sizeof(buf)), - zevpn->vni, mac->loc_seq, mac->flags, + zlog_debug("DEL MAC %pEA VNI %u seq %u flags 0x%x nbr count %u", + &mac->macaddr, zevpn->vni, mac->loc_seq, mac->flags, listcount(mac->neigh_list)); old_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags); - if (zebra_evpn_mac_is_static(mac)) { + if (!clear_static && zebra_evpn_mac_is_static(mac)) { /* this is a synced entry and can only be removed when the * es-peers stop advertising it. */ - memset(&mac->fwd_info, 0, sizeof(mac->fwd_info)); + zebra_evpn_mac_clear_fwd_info(mac); if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) { char mac_buf[MAC_BUF_SIZE]; zlog_debug( - "re-add sync-mac vni %u mac %s es %s seq %d f %s", - zevpn->vni, - prefix_mac2str(&mac->macaddr, buf, sizeof(buf)), + "re-add sync-mac vni %u mac %pEA es %s seq %d f %s", + zevpn->vni, &mac->macaddr, mac->es ? mac->es->esi_str : "-", mac->loc_seq, zebra_evpn_zebra_mac_flag_dump( mac, mac_buf, sizeof(mac_buf))); @@ -2356,6 +2416,9 @@ int zebra_evpn_del_local_mac(zebra_evpn_t *zevpn, zebra_mac_t *mac) return 0; } + /* flush the peer info */ + zebra_evpn_mac_clear_sync_info(mac); + /* Update all the neigh entries associated with this mac */ zebra_evpn_process_neigh_on_local_mac_del(zevpn, mac); @@ -2365,6 +2428,9 @@ int zebra_evpn_del_local_mac(zebra_evpn_t *zevpn, zebra_mac_t *mac) zebra_evpn_es_mac_deref_entry(mac); + /* remove links to the destination access port */ + zebra_evpn_mac_clear_fwd_info(mac); + /* * If there are no neigh associated with the mac delete the mac * else mark it as AUTO for forward reference @@ -2385,7 +2451,6 @@ int zebra_evpn_mac_gw_macip_add(struct interface *ifp, zebra_evpn_t *zevpn, struct ethaddr *macaddr, vlanid_t vlan_id, bool def_gw) { - char buf[ETHER_ADDR_STRLEN]; zebra_mac_t *mac; ns_id_t local_ns_id = NS_DEFAULT; struct zebra_vrf *zvrf; @@ -2399,19 +2464,18 @@ int zebra_evpn_mac_gw_macip_add(struct interface *ifp, zebra_evpn_t *zevpn, mac = zebra_evpn_mac_add(zevpn, macaddr); if (!mac) { flog_err(EC_ZEBRA_MAC_ADD_FAILED, - "Failed to add MAC %s intf %s(%u) VID %u", - prefix_mac2str(macaddr, buf, sizeof(buf)), - ifp->name, ifp->ifindex, vlan_id); + "Failed to add MAC %pEA intf %s(%u) VID %u", + macaddr, ifp->name, ifp->ifindex, vlan_id); return -1; } } /* Set "local" forwarding info. */ + zebra_evpn_mac_clear_fwd_info(mac); SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL); SET_FLAG(mac->flags, ZEBRA_MAC_AUTO); if (def_gw) SET_FLAG(mac->flags, ZEBRA_MAC_DEF_GW); - memset(&mac->fwd_info, 0, sizeof(mac->fwd_info)); mac->fwd_info.local.ifindex = ifp->ifindex; mac->fwd_info.local.ns_id = local_ns_id; mac->fwd_info.local.vid = vlan_id; diff --git a/zebra/zebra_evpn_mac.h b/zebra/zebra_evpn_mac.h index c021765843..fb162f1a93 100644 --- a/zebra/zebra_evpn_mac.h +++ b/zebra/zebra_evpn_mac.h @@ -90,7 +90,9 @@ struct zebra_mac_t_ { /* back pointer to zevpn */ zebra_evpn_t *zevpn; - /* Local or remote info. */ + /* Local or remote info. + * Note: fwd_info is only relevant if mac->es is NULL. + */ union { struct { ifindex_t ifindex; @@ -106,6 +108,16 @@ struct zebra_mac_t_ { /* memory used to link the mac to the es */ struct listnode es_listnode; + /* access-port/bridge member. only relevant for local macs that + * are associated with a zero-ESI, + * XXX - this belongs in fwd_info.local; however fwd_info is + * being cleared and memset to zero in different ways that can + * mess up the links. + */ + struct interface *ifp; + /* memory used to link the mac to the ifp */ + struct listnode ifp_listnode; + /* Mobility sequence numbers associated with this entry. */ uint32_t rem_seq; uint32_t loc_seq; @@ -260,14 +272,17 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, zebra_evpn_t *zevpn, struct interface *ifp, struct ethaddr *macaddr, vlanid_t vid, bool sticky, bool local_inactive, - bool dp_static); -int zebra_evpn_del_local_mac(zebra_evpn_t *zevpn, zebra_mac_t *mac); + bool dp_static, zebra_mac_t *mac); +int zebra_evpn_del_local_mac(zebra_evpn_t *zevpn, zebra_mac_t *mac, + bool clear_static); int zebra_evpn_mac_gw_macip_add(struct interface *ifp, zebra_evpn_t *zevpn, struct ipaddr *ip, zebra_mac_t **macp, struct ethaddr *macaddr, vlanid_t vlan_id, bool def_gw); void zebra_evpn_mac_svi_add(struct interface *ifp, zebra_evpn_t *zevpn); void zebra_evpn_mac_svi_del(struct interface *ifp, zebra_evpn_t *zevpn); +void zebra_evpn_mac_ifp_del(struct interface *ifp); +void zebra_evpn_mac_clear_fwd_info(zebra_mac_t *zmac); #ifdef __cplusplus } diff --git a/zebra/zebra_evpn_mh.c b/zebra/zebra_evpn_mh.c index 0bb1ebb564..1c258a04f7 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" @@ -1548,20 +1547,30 @@ static bool zebra_evpn_es_br_port_dplane_update(struct zebra_evpn_es *es, return false; if (IS_ZEBRA_DEBUG_EVPN_MH_ES) - zlog_debug("es %s br-port dplane update by %s", es->esi_str, caller); + zlog_debug("es %s br-port dplane update by %s", es->esi_str, + caller); backup_nhg_id = (es->flags & ZEBRA_EVPNES_NHG_ACTIVE) ? es->nhg_id : 0; memset(&sph_filters, 0, sizeof(sph_filters)); - if (listcount(es->es_vtep_list) > ES_VTEP_MAX_CNT) { - zlog_warn("es %s vtep count %d exceeds filter cnt %d", - es->esi_str, listcount(es->es_vtep_list), - ES_VTEP_MAX_CNT); + if (es->flags & ZEBRA_EVPNES_BYPASS) { + if (IS_ZEBRA_DEBUG_EVPN_MH_ES) + zlog_debug( + "es %s SPH filter disabled as it is in bypass", + es->esi_str); } else { - for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, es_vtep)) { - if (es_vtep->flags & ZEBRA_EVPNES_VTEP_DEL_IN_PROG) - continue; - sph_filters[sph_filter_cnt] = es_vtep->vtep_ip; - ++sph_filter_cnt; + if (listcount(es->es_vtep_list) > ES_VTEP_MAX_CNT) { + zlog_warn("es %s vtep count %d exceeds filter cnt %d", + es->esi_str, listcount(es->es_vtep_list), + ES_VTEP_MAX_CNT); + } else { + for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, + es_vtep)) { + if (es_vtep->flags + & ZEBRA_EVPNES_VTEP_DEL_IN_PROG) + continue; + sph_filters[sph_filter_cnt] = es_vtep->vtep_ip; + ++sph_filter_cnt; + } } } @@ -1609,6 +1618,7 @@ static bool zebra_evpn_es_run_df_election(struct zebra_evpn_es *es, * is no need to setup the BUM block filter */ if (!(es->flags & ZEBRA_EVPNES_LOCAL) + || (es->flags & ZEBRA_EVPNES_BYPASS) || !zmh_info->es_originator_ip.s_addr) return zebra_evpn_es_df_change(es, new_non_df, caller, "not-ready"); @@ -1834,6 +1844,7 @@ static int zebra_evpn_es_send_add_to_client(struct zebra_evpn_es *es) struct zserv *client; struct stream *s; uint8_t oper_up; + bool bypass; client = zserv_find_client(ZEBRA_ROUTE_BGP, 0); /* BGP may not be running. */ @@ -1848,15 +1859,18 @@ static int zebra_evpn_es_send_add_to_client(struct zebra_evpn_es *es) oper_up = !!(es->flags & ZEBRA_EVPNES_OPER_UP); stream_putc(s, oper_up); stream_putw(s, es->df_pref); + bypass = !!(es->flags & ZEBRA_EVPNES_BYPASS); + stream_putc(s, bypass); /* Write packet size. */ stream_putw_at(s, 0, stream_get_endp(s)); if (IS_ZEBRA_DEBUG_EVPN_MH_ES) - zlog_debug("send add local es %s %pI4 active %u df_pref %u to %s", - es->esi_str, &zmh_info->es_originator_ip, - oper_up, es->df_pref, - zebra_route_string(client->proto)); + zlog_debug( + "send add local es %s %pI4 active %u df_pref %u%s to %s", + es->esi_str, &zmh_info->es_originator_ip, oper_up, + es->df_pref, bypass ? " bypass" : "", + zebra_route_string(client->proto)); client->local_es_add_cnt++; return zserv_send_message(client, s); @@ -1980,18 +1994,50 @@ static void zebra_evpn_es_setup_evis(struct zebra_evpn_es *es) } } -static void zebra_evpn_es_local_mac_update(struct zebra_evpn_es *es, - bool force_clear_static) +static void zebra_evpn_flush_local_mac(zebra_mac_t *mac, struct interface *ifp) +{ + struct zebra_if *zif; + struct interface *br_ifp; + vlanid_t vid; + + zif = ifp->info; + br_ifp = zif->brslave_info.br_if; + if (!br_ifp) + return; + + if (mac->zevpn->vxlan_if) { + zif = mac->zevpn->vxlan_if->info; + vid = zif->l2info.vxl.access_vlan; + } else { + vid = 0; + } + + /* delete the local mac from the dataplane */ + dplane_local_mac_del(ifp, br_ifp, vid, &mac->macaddr); + /* delete the local mac in zebra */ + zebra_evpn_del_local_mac(mac->zevpn, mac, true); +} + +static void zebra_evpn_es_flush_local_macs(struct zebra_evpn_es *es, + struct interface *ifp, bool add) { zebra_mac_t *mac; struct listnode *node; + struct listnode *nnode; - for (ALL_LIST_ELEMENTS_RO(es->mac_list, node, mac)) { - if (CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_ACTIVE)) { - zebra_evpn_sync_mac_dp_install( - mac, false /* set_inactive */, - force_clear_static, __func__); - } + for (ALL_LIST_ELEMENTS(es->mac_list, node, nnode, mac)) { + if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) + continue; + + /* If ES is being attached/detached from the access port we + * need to clear local activity and peer activity and start + * over */ + if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) + zlog_debug("VNI %u mac %pEA update; local ES %s %s", + mac->zevpn->vni, + &mac->macaddr, + es->esi_str, add ? "add" : "del"); + zebra_evpn_flush_local_mac(mac, ifp); } } @@ -2134,6 +2180,10 @@ static void zebra_evpn_es_local_info_set(struct zebra_evpn_es *es, if (zif->brslave_info.bridge_ifindex != IFINDEX_INTERNAL) es->flags |= ZEBRA_EVPNES_BR_PORT; + /* inherit the bypass flag from the interface */ + if (zif->flags & ZIF_FLAG_LACP_BYPASS) + es->flags |= ZEBRA_EVPNES_BYPASS; + /* setup base-vni if one doesn't already exist; the ES will get sent * to BGP as a part of that process */ @@ -2165,11 +2215,9 @@ static void zebra_evpn_es_local_info_set(struct zebra_evpn_es *es, */ zebra_evpn_es_setup_evis(es); /* if there any local macs referring to the ES as dest we - * need to set the static reference on them if the MAC is - * synced from an ES peer + * need to clear the contents and start over */ - zebra_evpn_es_local_mac_update(es, - false /* force_clear_static */); + zebra_evpn_es_flush_local_macs(es, zif->ifp, true); /* inherit EVPN protodown flags on the access port */ zebra_evpn_mh_update_protodown_es(es, true /*resync_dplane*/); @@ -2184,33 +2232,34 @@ static void zebra_evpn_es_local_info_clear(struct zebra_evpn_es **esp) if (!(es->flags & ZEBRA_EVPNES_LOCAL)) return; + zif = es->zif; + + /* if there any local macs referring to the ES as dest we + * need to clear the contents and start over + */ + zebra_evpn_es_flush_local_macs(es, zif->ifp, false); + es->flags &= ~(ZEBRA_EVPNES_LOCAL | ZEBRA_EVPNES_READY_FOR_BGP); THREAD_OFF(es->df_delay_timer); - /* remove the DF filter */ - dplane_updated = zebra_evpn_es_run_df_election(es, __func__); - /* clear EVPN protodown flags on the access port */ zebra_evpn_mh_clear_protodown_es(es); - /* if there any local macs referring to the ES as dest we - * need to clear the static reference on them - */ - zebra_evpn_es_local_mac_update(es, - true /* force_clear_static */); + /* remove the DF filter */ + dplane_updated = zebra_evpn_es_run_df_election(es, __func__); /* flush the BUM filters and backup NHG */ if (!dplane_updated) zebra_evpn_es_br_port_dplane_clear(es); /* clear the es from the parent interface */ - zif = es->zif; zif->es_info.es = NULL; es->zif = NULL; /* clear all local flags associated with the ES */ - es->flags &= ~(ZEBRA_EVPNES_OPER_UP | ZEBRA_EVPNES_BR_PORT); + es->flags &= ~(ZEBRA_EVPNES_OPER_UP | ZEBRA_EVPNES_BR_PORT + | ZEBRA_EVPNES_BYPASS); /* remove from the ES list */ list_delete_node(zmh_info->local_es_list, &es->local_es_listnode); @@ -2623,6 +2672,102 @@ static void zebra_evpn_es_df_pref_update(struct zebra_if *zif, uint16_t df_pref) zebra_evpn_es_send_add_to_client(es); } +/* If bypass mode on an es changed we set all local macs to + * inactive and drop the sync info + */ +static void zebra_evpn_es_bypass_update_macs(struct zebra_evpn_es *es, + struct interface *ifp, bool bypass) +{ + zebra_mac_t *mac; + struct listnode *node; + struct listnode *nnode; + struct zebra_if *zif; + + /* Flush all MACs linked to the ES */ + for (ALL_LIST_ELEMENTS(es->mac_list, node, nnode, mac)) { + if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) + continue; + + if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) + zlog_debug("VNI %u mac %pEA %s update es %s", + mac->zevpn->vni, + &mac->macaddr, + bypass ? "bypass" : "non-bypass", + es->esi_str); + zebra_evpn_flush_local_mac(mac, ifp); + } + + /* While in bypass-mode locally learnt MACs are linked + * to the access port instead of the ES + */ + zif = ifp->info; + if (!zif->mac_list) + return; + + for (ALL_LIST_ELEMENTS(zif->mac_list, node, nnode, mac)) { + if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) + continue; + + if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) + zlog_debug("VNI %u mac %pEA %s update ifp %s", + mac->zevpn->vni, + &mac->macaddr, + bypass ? "bypass" : "non-bypass", ifp->name); + zebra_evpn_flush_local_mac(mac, ifp); + } +} + +void zebra_evpn_es_bypass_update(struct zebra_evpn_es *es, + struct interface *ifp, bool bypass) +{ + bool old_bypass; + bool dplane_updated; + + old_bypass = !!(es->flags & ZEBRA_EVPNES_BYPASS); + if (old_bypass == bypass) + return; + + if (bypass) + es->flags |= ZEBRA_EVPNES_BYPASS; + else + es->flags &= ~ZEBRA_EVPNES_BYPASS; + + if (IS_ZEBRA_DEBUG_EVPN_MH_ES) + zlog_debug("bond %s es %s lacp bypass changed to %s", ifp->name, + es->esi_str, bypass ? "on" : "off"); + + /* send bypass update to BGP */ + if (es->flags & ZEBRA_EVPNES_READY_FOR_BGP) + zebra_evpn_es_send_add_to_client(es); + + zebra_evpn_es_bypass_update_macs(es, ifp, bypass); + + /* re-run DF election */ + dplane_updated = zebra_evpn_es_run_df_election(es, __func__); + + /* disable SPH filter */ + if (!dplane_updated && (es->flags & ZEBRA_EVPNES_LOCAL) + && (listcount(es->es_vtep_list) > ES_VTEP_MAX_CNT)) + zebra_evpn_es_br_port_dplane_update(es, __func__); +} + +static void zebra_evpn_es_bypass_cfg_update(struct zebra_if *zif, bool bypass) +{ + bool old_bypass = !!(zif->es_info.flags & ZIF_CFG_ES_FLAG_BYPASS); + + if (old_bypass == bypass) + return; + + if (bypass) + zif->es_info.flags |= ZIF_CFG_ES_FLAG_BYPASS; + else + zif->es_info.flags &= ~ZIF_CFG_ES_FLAG_BYPASS; + + + if (zif->es_info.es) + zebra_evpn_es_bypass_update(zif->es_info.es, zif->ifp, bypass); +} + /* Only certain types of access ports can be setup as an Ethernet Segment */ bool zebra_evpn_is_if_es_capable(struct zebra_if *zif) @@ -2818,7 +2963,7 @@ static void zebra_evpn_es_json_vtep_fill(struct zebra_evpn_es *es, static void zebra_evpn_es_show_entry(struct vty *vty, struct zebra_evpn_es *es, json_object *json_array) { - char type_str[4]; + char type_str[5]; char vtep_str[ES_VTEP_LIST_STR_SZ]; if (json_array) { @@ -2839,6 +2984,8 @@ static void zebra_evpn_es_show_entry(struct vty *vty, struct zebra_evpn_es *es, json_array_string_add(json_flags, "remote"); if (es->flags & ZEBRA_EVPNES_NON_DF) json_array_string_add(json_flags, "nonDF"); + if (es->flags & ZEBRA_EVPNES_BYPASS) + json_array_string_add(json_flags, "bypass"); json_object_object_add(json, "flags", json_flags); } @@ -2860,6 +3007,8 @@ static void zebra_evpn_es_show_entry(struct vty *vty, struct zebra_evpn_es *es, strlcat(type_str, "R", sizeof(type_str)); if (es->flags & ZEBRA_EVPNES_NON_DF) strlcat(type_str, "N", sizeof(type_str)); + if (es->flags & ZEBRA_EVPNES_BYPASS) + strlcat(type_str, "B", sizeof(type_str)); zebra_evpn_es_vtep_str(vtep_str, es, sizeof(vtep_str)); @@ -2897,6 +3046,8 @@ static void zebra_evpn_es_show_entry_detail(struct vty *vty, json_array_string_add(json_flags, "remote"); if (es->flags & ZEBRA_EVPNES_NON_DF) json_array_string_add(json_flags, "nonDF"); + if (es->flags & ZEBRA_EVPNES_BYPASS) + json_array_string_add(json_flags, "bypass"); if (es->flags & ZEBRA_EVPNES_READY_FOR_BGP) json_array_string_add(json_flags, "readyForBgp"); @@ -2952,6 +3103,8 @@ static void zebra_evpn_es_show_entry_detail(struct vty *vty, vty_out(vty, " Ready for BGP: %s\n", (es->flags & ZEBRA_EVPNES_READY_FOR_BGP) ? "yes" : "no"); + if (es->flags & ZEBRA_EVPNES_BYPASS) + vty_out(vty, " LACP bypass: on\n"); vty_out(vty, " VNI Count: %d\n", listcount(es->es_evi_list)); vty_out(vty, " MAC Count: %d\n", listcount(es->mac_list)); if (es->flags & ZEBRA_EVPNES_LOCAL) @@ -2991,7 +3144,7 @@ void zebra_evpn_es_show(struct vty *vty, bool uj) if (uj) { json_array = json_object_new_array(); } else { - vty_out(vty, "Type: L local, R remote, N non-DF\n"); + vty_out(vty, "Type: B bypass, L local, R remote, N non-DF\n"); vty_out(vty, "%-30s %-4s %-21s %s\n", "ESI", "Type", "ES-IF", "VTEPs"); } @@ -3097,12 +3250,35 @@ int zebra_evpn_mh_if_write(struct vty *vty, struct interface *ifp) #ifndef VTYSH_EXTRACT_PL #include "zebra/zebra_evpn_mh_clippy.c" #endif +/* CLI for setting an ES in bypass mode */ +DEFPY_HIDDEN(zebra_evpn_es_bypass, zebra_evpn_es_bypass_cmd, + "[no] evpn mh bypass", + NO_STR "EVPN\n" EVPN_MH_VTY_STR "set bypass mode\n") +{ + VTY_DECLVAR_CONTEXT(interface, ifp); + struct zebra_if *zif; + + zif = ifp->info; + + if (no) { + zebra_evpn_es_bypass_cfg_update(zif, false); + } else { + if (!zebra_evpn_is_if_es_capable(zif)) { + vty_out(vty, + "%%DF bypass cannot be associated with this interface type\n"); + return CMD_WARNING; + } + zebra_evpn_es_bypass_cfg_update(zif, true); + } + return CMD_SUCCESS; +} + /* CLI for configuring DF preference part for an ES */ DEFPY(zebra_evpn_es_pref, zebra_evpn_es_pref_cmd, "[no$no] evpn mh es-df-pref [(1-65535)$df_pref]", NO_STR "EVPN\n" EVPN_MH_VTY_STR "preference value used for DF election\n" - "ID\n") + "pref\n") { VTY_DECLVAR_CONTEXT(interface, ifp); struct zebra_if *zif; @@ -3767,6 +3943,7 @@ void zebra_evpn_interface_init(void) install_element(INTERFACE_NODE, &zebra_evpn_es_id_cmd); install_element(INTERFACE_NODE, &zebra_evpn_es_sys_mac_cmd); install_element(INTERFACE_NODE, &zebra_evpn_es_pref_cmd); + install_element(INTERFACE_NODE, &zebra_evpn_es_bypass_cmd); install_element(INTERFACE_NODE, &zebra_evpn_mh_uplink_cmd); } diff --git a/zebra/zebra_evpn_mh.h b/zebra/zebra_evpn_mh.h index 94de84ff14..2361a70bff 100644 --- a/zebra/zebra_evpn_mh.h +++ b/zebra/zebra_evpn_mh.h @@ -60,6 +60,10 @@ struct zebra_evpn_es { * filter, SPH filter and backup NHG for fast-failover */ #define ZEBRA_EVPNES_BR_PORT (1 << 6) +/* ES is in bypass mode i.e. must not be advertised. ES-bypass is set + * when the associated host bond goes into LACP bypass + */ +#define ZEBRA_EVPNES_BYPASS (1 << 7) /* memory used for adding the es to zmh_info->es_rb_tree */ RB_ENTRY(zebra_evpn_es) rb_node; @@ -376,5 +380,7 @@ extern void zebra_evpn_l2_nh_show(struct vty *vty, bool uj); extern void zebra_evpn_acc_bd_svi_set(struct zebra_if *vlan_zif, struct zebra_if *br_zif, bool is_up); 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); #endif /* _ZEBRA_EVPN_MH_H */ diff --git a/zebra/zebra_evpn_neigh.c b/zebra/zebra_evpn_neigh.c index 834ad5381d..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" @@ -209,8 +208,6 @@ static void zebra_evpn_local_neigh_ref_mac(zebra_neigh_t *n, zebra_mac_t *mac, bool send_mac_update) { - char macbuf[ETHER_ADDR_STRLEN]; - char ipbuf[INET6_ADDRSTRLEN]; bool old_static; bool new_static; @@ -228,11 +225,8 @@ static void zebra_evpn_local_neigh_ref_mac(zebra_neigh_t *n, new_static = zebra_evpn_mac_is_static(mac); if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH) zlog_debug( - "sync-neigh ref mac vni %u ip %s mac %s ref %d", - n->zevpn->vni, - ipaddr2str(&n->ip, ipbuf, sizeof(ipbuf)), - prefix_mac2str(&n->emac, macbuf, - sizeof(macbuf)), + "sync-neigh ref mac vni %u ip %pIA mac %pEA ref %d", + n->zevpn->vni, &n->ip, &n->emac, mac->sync_neigh_cnt); if ((old_static != new_static) && send_mac_update) /* program the local mac in the kernel */ @@ -248,8 +242,6 @@ static void zebra_evpn_sync_neigh_dp_install(zebra_neigh_t *n, bool force_clear_static, const char *caller) { - char macbuf[ETHER_ADDR_STRLEN]; - char ipbuf[INET6_ADDRSTRLEN]; struct zebra_ns *zns; struct interface *ifp; bool set_static; @@ -260,11 +252,8 @@ static void zebra_evpn_sync_neigh_dp_install(zebra_neigh_t *n, if (!ifp) { if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH) zlog_debug( - "%s: dp-install sync-neigh vni %u ip %s mac %s if %d f 0x%x skipped", - caller, n->zevpn->vni, - ipaddr2str(&n->ip, ipbuf, sizeof(ipbuf)), - prefix_mac2str(&n->emac, macbuf, - sizeof(macbuf)), + "%s: dp-install sync-neigh vni %u ip %pIA mac %pEA if %d f 0x%x skipped", + caller, n->zevpn->vni, &n->ip, &n->emac, n->ifindex, n->flags); return; } @@ -282,10 +271,8 @@ static void zebra_evpn_sync_neigh_dp_install(zebra_neigh_t *n, if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH) zlog_debug( - "%s: dp-install sync-neigh vni %u ip %s mac %s if %s(%d) f 0x%x%s%s%s", - caller, n->zevpn->vni, - ipaddr2str(&n->ip, ipbuf, sizeof(ipbuf)), - prefix_mac2str(&n->emac, macbuf, sizeof(macbuf)), + "%s: dp-install sync-neigh vni %u ip %pIA mac %pEA if %s(%d) f 0x%x%s%s%s", + caller, n->zevpn->vni, &n->ip, &n->emac, ifp->name, n->ifindex, n->flags, set_router ? " router" : "", set_static ? " static" : "", @@ -327,9 +314,9 @@ int zebra_evpn_neigh_send_add_to_client(vni_t vni, struct ipaddr *ip, if (CHECK_FLAG(neigh_flags, ZEBRA_NEIGH_SVI_IP)) SET_FLAG(flags, ZEBRA_MACIP_TYPE_SVI_IP); - return zebra_evpn_macip_send_msg_to_client( - vni, macaddr, ip, flags, seq, ZEBRA_NEIGH_ACTIVE, - zmac ? zmac->es : NULL, ZEBRA_MACIP_ADD); + return zebra_evpn_macip_send_msg_to_client(vni, macaddr, ip, flags, seq, + ZEBRA_NEIGH_ACTIVE, zmac->es, + ZEBRA_MACIP_ADD); } /* @@ -375,8 +362,6 @@ void zebra_evpn_sync_neigh_static_chg(zebra_neigh_t *n, bool old_n_static, zebra_mac_t *mac = n->mac; bool old_mac_static; bool new_mac_static; - char macbuf[ETHER_ADDR_STRLEN]; - char ipbuf[INET6_ADDRSTRLEN]; if (old_n_static == new_n_static) return; @@ -411,10 +396,9 @@ void zebra_evpn_sync_neigh_static_chg(zebra_neigh_t *n, bool old_n_static, if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH) zlog_debug( - "sync-neigh ref-chg vni %u ip %s mac %s f 0x%x %d%s%s%s%s by %s", - n->zevpn->vni, ipaddr2str(&n->ip, ipbuf, sizeof(ipbuf)), - prefix_mac2str(&n->emac, macbuf, sizeof(macbuf)), - n->flags, mac->sync_neigh_cnt, + "sync-neigh ref-chg vni %u ip %pIA mac %pEA f 0x%x %d%s%s%s%s by %s", + n->zevpn->vni, &n->ip, &n->emac, n->flags, + mac->sync_neigh_cnt, old_n_static ? " old_n_static" : "", new_n_static ? " new_n_static" : "", old_mac_static ? " old_mac_static" : "", @@ -434,8 +418,6 @@ static int zebra_evpn_neigh_hold_exp_cb(struct thread *t) bool new_bgp_ready; bool old_n_static; bool new_n_static; - char macbuf[ETHER_ADDR_STRLEN]; - char ipbuf[INET6_ADDRSTRLEN]; n = THREAD_ARG(t); /* the purpose of the hold timer is to age out the peer-active @@ -451,11 +433,8 @@ static int zebra_evpn_neigh_hold_exp_cb(struct thread *t) new_n_static = zebra_evpn_neigh_is_static(n); if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH) - zlog_debug("sync-neigh vni %u ip %s mac %s 0x%x hold expired", - n->zevpn->vni, - ipaddr2str(&n->ip, ipbuf, sizeof(ipbuf)), - prefix_mac2str(&n->emac, macbuf, sizeof(macbuf)), - n->flags); + zlog_debug("sync-neigh vni %u ip %pIA mac %pEA 0x%x hold expired", + n->zevpn->vni, &n->ip, &n->emac, n->flags); /* re-program the local neigh in the dataplane if the neigh is no * longer static @@ -475,18 +454,12 @@ static int zebra_evpn_neigh_hold_exp_cb(struct thread *t) static inline void zebra_evpn_neigh_start_hold_timer(zebra_neigh_t *n) { - char macbuf[ETHER_ADDR_STRLEN]; - char ipbuf[INET6_ADDRSTRLEN]; - if (n->hold_timer) return; if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH) - zlog_debug("sync-neigh vni %u ip %s mac %s 0x%x hold start", - n->zevpn->vni, - ipaddr2str(&n->ip, ipbuf, sizeof(ipbuf)), - prefix_mac2str(&n->emac, macbuf, sizeof(macbuf)), - n->flags); + zlog_debug("sync-neigh vni %u ip %pIA mac %pEA 0x%x hold start", + n->zevpn->vni, &n->ip, &n->emac, n->flags); thread_add_timer(zrouter.master, zebra_evpn_neigh_hold_exp_cb, n, zmh_info->neigh_hold_time, &n->hold_timer); } @@ -496,8 +469,6 @@ static void zebra_evpn_local_neigh_deref_mac(zebra_neigh_t *n, { zebra_mac_t *mac = n->mac; zebra_evpn_t *zevpn = n->zevpn; - char macbuf[ETHER_ADDR_STRLEN]; - char ipbuf[INET6_ADDRSTRLEN]; bool old_static; bool new_static; @@ -511,11 +482,8 @@ static void zebra_evpn_local_neigh_deref_mac(zebra_neigh_t *n, new_static = zebra_evpn_mac_is_static(mac); if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH) zlog_debug( - "sync-neigh deref mac vni %u ip %s mac %s ref %d", - n->zevpn->vni, - ipaddr2str(&n->ip, ipbuf, sizeof(ipbuf)), - prefix_mac2str(&n->emac, macbuf, - sizeof(macbuf)), + "sync-neigh deref mac vni %u ip %pIA mac %pEA ref %d", + n->zevpn->vni, &n->ip, &n->emac, mac->sync_neigh_cnt); if ((old_static != new_static) && send_mac_update) /* program the local mac in the kernel */ @@ -532,8 +500,6 @@ bool zebra_evpn_neigh_is_bgp_seq_ok(zebra_evpn_t *zevpn, zebra_neigh_t *n, struct ethaddr *macaddr, uint32_t seq, bool sync) { - char macbuf[ETHER_ADDR_STRLEN]; - char ipbuf[INET6_ADDRSTRLEN]; uint32_t tmp_seq; const char *n_type; @@ -555,24 +521,18 @@ bool zebra_evpn_neigh_is_bgp_seq_ok(zebra_evpn_t *zevpn, zebra_neigh_t *n, if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH || IS_ZEBRA_DEBUG_VXLAN) zlog_debug( - "%s-macip accept vni %u %s mac %s IP %s lower seq %u f 0x%x", + "%s-macip accept vni %u %s mac %pEA IP %pIA lower seq %u f 0x%x", sync ? "sync" : "remote", zevpn->vni, - n_type, - prefix_mac2str(macaddr, macbuf, - sizeof(macbuf)), - ipaddr2str(&n->ip, ipbuf, - sizeof(ipbuf)), + n_type, macaddr, &n->ip, tmp_seq, n->flags); return true; } if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH || IS_ZEBRA_DEBUG_VXLAN) zlog_debug( - "%s-macip ignore vni %u %s mac %s IP %s as existing has higher seq %u f 0x%x", + "%s-macip ignore vni %u %s mac %pEA IP %pIA as existing has higher seq %u f 0x%x", sync ? "sync" : "remote", zevpn->vni, n_type, - prefix_mac2str(macaddr, macbuf, sizeof(macbuf)), - ipaddr2str(&n->ip, ipbuf, sizeof(ipbuf)), - tmp_seq, n->flags); + macaddr, &n->ip, tmp_seq, n->flags); return false; } @@ -636,15 +596,10 @@ void zebra_evpn_sync_neigh_del(zebra_neigh_t *n) { bool old_n_static; bool new_n_static; - char macbuf[ETHER_ADDR_STRLEN]; - char ipbuf[INET6_ADDRSTRLEN]; if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH) - zlog_debug("sync-neigh del vni %u ip %s mac %s f 0x%x", - n->zevpn->vni, - ipaddr2str(&n->ip, ipbuf, sizeof(ipbuf)), - prefix_mac2str(&n->emac, macbuf, sizeof(macbuf)), - n->flags); + zlog_debug("sync-neigh del vni %u ip %pIA mac %pEA f 0x%x", + n->zevpn->vni, &n->ip, &n->emac, n->flags); old_n_static = zebra_evpn_neigh_is_static(n); UNSET_FLAG(n->flags, ZEBRA_NEIGH_ES_PEER_PROXY); @@ -676,8 +631,6 @@ zebra_evpn_proc_sync_neigh_update(zebra_evpn_t *zevpn, zebra_neigh_t *n, bool old_mac_static; bool new_mac_static; bool set_dp_inactive = false; - char macbuf[ETHER_ADDR_STRLEN]; - char ipbuf[INET6_ADDRSTRLEN]; bool created; ifindex_t ifindex = 0; @@ -778,11 +731,8 @@ zebra_evpn_proc_sync_neigh_update(zebra_evpn_t *zevpn, zebra_neigh_t *n, if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH && (old_flags != n->flags)) zlog_debug( - "sync-neigh vni %u ip %s mac %s old_f 0x%x new_f 0x%x", - n->zevpn->vni, - ipaddr2str(&n->ip, ipbuf, sizeof(ipbuf)), - prefix_mac2str(&n->emac, macbuf, - sizeof(macbuf)), + "sync-neigh vni %u ip %pIA mac %pEA old_f 0x%x new_f 0x%x", + n->zevpn->vni, &n->ip, &n->emac, old_flags, n->flags); new_n_static = zebra_evpn_neigh_is_static(n); @@ -844,10 +794,9 @@ zebra_evpn_proc_sync_neigh_update(zebra_evpn_t *zevpn, zebra_neigh_t *n, if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH) zlog_debug( - "sync-neigh %s vni %u ip %s mac %s if %s(%d) seq %d f 0x%x%s%s", + "sync-neigh %s vni %u ip %pIA mac %pEA if %s(%d) seq %d f 0x%x%s%s", created ? "created" : "updated", n->zevpn->vni, - ipaddr2str(&n->ip, ipbuf, sizeof(ipbuf)), - prefix_mac2str(&n->emac, macbuf, sizeof(macbuf)), + &n->ip, &n->emac, ifp ? ifp->name : "", ifindex, n->loc_seq, n->flags, inform_bgp ? " inform_bgp" : "", inform_dataplane ? " inform_dp" : ""); @@ -970,14 +919,13 @@ void zebra_evpn_process_neigh_on_local_mac_change(zebra_evpn_t *zevpn, zebra_neigh_t *n = NULL; struct listnode *node = NULL; struct zebra_vrf *zvrf = NULL; - char buf[ETHER_ADDR_STRLEN]; zvrf = vrf_info_lookup(zevpn->vxlan_if->vrf_id); if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug("Processing neighbors on local MAC %s %s, VNI %u", - prefix_mac2str(&zmac->macaddr, buf, sizeof(buf)), - seq_change ? "CHANGE" : "ADD", zevpn->vni); + zlog_debug("Processing neighbors on local MAC %pEA %s, VNI %u", + &zmac->macaddr, seq_change ? "CHANGE" : "ADD", + zevpn->vni); /* Walk all neighbors and mark any inactive local neighbors as * active and/or update sequence number upon a move, and inform BGP. @@ -1012,12 +960,10 @@ void zebra_evpn_process_neigh_on_local_mac_del(zebra_evpn_t *zevpn, { zebra_neigh_t *n = NULL; struct listnode *node = NULL; - char buf[ETHER_ADDR_STRLEN]; if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug("Processing neighbors on local MAC %s DEL, VNI %u", - prefix_mac2str(&zmac->macaddr, buf, sizeof(buf)), - zevpn->vni); + zlog_debug("Processing neighbors on local MAC %pEA DEL, VNI %u", + &zmac->macaddr, zevpn->vni); /* Walk all local neighbors and mark as inactive and inform * BGP, if needed. @@ -1047,12 +993,10 @@ void zebra_evpn_process_neigh_on_remote_mac_add(zebra_evpn_t *zevpn, { zebra_neigh_t *n = NULL; struct listnode *node = NULL; - char buf[ETHER_ADDR_STRLEN]; if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug("Processing neighbors on remote MAC %s ADD, VNI %u", - prefix_mac2str(&zmac->macaddr, buf, sizeof(buf)), - zevpn->vni); + zlog_debug("Processing neighbors on remote MAC %pEA ADD, VNI %u", + &zmac->macaddr, zevpn->vni); /* Walk all local neighbors and mark as inactive and inform * BGP, if needed. @@ -1085,15 +1029,11 @@ static inline void zebra_evpn_local_neigh_update_log( bool old_bgp_ready, bool new_bgp_ready, bool inform_dataplane, bool inform_bgp, const char *sfx) { - char macbuf[ETHER_ADDR_STRLEN]; - char ipbuf[INET6_ADDRSTRLEN]; - if (!IS_ZEBRA_DEBUG_EVPN_MH_NEIGH) return; - zlog_debug("%s neigh vni %u ip %s mac %s f 0x%x%s%s%s%s%s%s %s", pfx, - n->zevpn->vni, ipaddr2str(&n->ip, ipbuf, sizeof(ipbuf)), - prefix_mac2str(&n->emac, macbuf, sizeof(macbuf)), n->flags, + zlog_debug("%s neigh vni %u ip %pIA mac %pEA f 0x%x%s%s%s%s%s%s %s", pfx, + n->zevpn->vni, &n->ip, &n->emac, n->flags, is_router ? " router" : "", local_inactive ? " local-inactive" : "", old_bgp_ready ? " old_bgp_ready" : "", @@ -1154,8 +1094,6 @@ static int zebra_evpn_dad_ip_auto_recovery_exp(struct thread *t) struct zebra_vrf *zvrf = NULL; zebra_neigh_t *nbr = NULL; zebra_evpn_t *zevpn = NULL; - char buf1[INET6_ADDRSTRLEN]; - char buf2[ETHER_ADDR_STRLEN]; nbr = THREAD_ARG(t); @@ -1174,10 +1112,8 @@ static int zebra_evpn_dad_ip_auto_recovery_exp(struct thread *t) if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug( - "%s: duplicate addr MAC %s IP %s flags 0x%x learn count %u vni %u auto recovery expired", - __func__, - prefix_mac2str(&nbr->emac, buf2, sizeof(buf2)), - ipaddr2str(&nbr->ip, buf1, sizeof(buf1)), nbr->flags, + "%s: duplicate addr MAC %pEA IP %pIA flags 0x%x learn count %u vni %u auto recovery expired", + __func__, &nbr->emac, &nbr->ip, nbr->flags, nbr->dad_count, zevpn->vni); UNSET_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE); @@ -1207,8 +1143,6 @@ zebra_evpn_dup_addr_detect_for_neigh(struct zebra_vrf *zvrf, zebra_neigh_t *nbr, { struct timeval elapsed = {0, 0}; - char buf[ETHER_ADDR_STRLEN]; - char buf1[INET6_ADDRSTRLEN]; bool reset_params = false; if (!zebra_evpn_do_dup_addr_detect(zvrf)) @@ -1221,10 +1155,8 @@ zebra_evpn_dup_addr_detect_for_neigh(struct zebra_vrf *zvrf, zebra_neigh_t *nbr, if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE)) { if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug( - "%s: duplicate addr MAC %s IP %s flags 0x%x skip installing, learn count %u recover time %u", - __func__, - prefix_mac2str(&nbr->emac, buf, sizeof(buf)), - ipaddr2str(&nbr->ip, buf1, sizeof(buf1)), + "%s: duplicate addr MAC %pEA IP %pIA flags 0x%x skip installing, learn count %u recover time %u", + __func__, &nbr->emac, &nbr->ip, nbr->flags, nbr->dad_count, zvrf->dad_freeze_time); @@ -1261,10 +1193,8 @@ zebra_evpn_dup_addr_detect_for_neigh(struct zebra_vrf *zvrf, zebra_neigh_t *nbr, if (reset_params) { if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug( - "%s: duplicate addr MAC %s IP %s flags 0x%x detection time passed, reset learn count %u", - __func__, - prefix_mac2str(&nbr->emac, buf, sizeof(buf)), - ipaddr2str(&nbr->ip, buf1, sizeof(buf1)), + "%s: duplicate addr MAC %pEA IP %pIA flags 0x%x detection time passed, reset learn count %u", + __func__, &nbr->emac, &nbr->ip, nbr->flags, nbr->dad_count); /* Reset learn count but do not start detection * during REMOTE learn event. @@ -1294,10 +1224,8 @@ zebra_evpn_dup_addr_detect_for_neigh(struct zebra_vrf *zvrf, zebra_neigh_t *nbr, if (nbr->dad_count >= zvrf->dad_max_moves) { flog_warn( EC_ZEBRA_DUP_IP_DETECTED, - "VNI %u: MAC %s IP %s detected as duplicate during %s VTEP %pI4", - nbr->zevpn->vni, - prefix_mac2str(&nbr->emac, buf, sizeof(buf)), - ipaddr2str(&nbr->ip, buf1, sizeof(buf1)), + "VNI %u: MAC %pEA IP %pIA detected as duplicate during %s VTEP %pI4", + nbr->zevpn->vni, &nbr->emac, &nbr->ip, is_local ? "local update, last" : "remote update, from", &vtep_ip); @@ -1311,12 +1239,8 @@ zebra_evpn_dup_addr_detect_for_neigh(struct zebra_vrf *zvrf, zebra_neigh_t *nbr, if (zvrf->dad_freeze && zvrf->dad_freeze_time) { if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug( - "%s: duplicate addr MAC %s IP %s flags 0x%x auto recovery time %u start", - __func__, - prefix_mac2str(&nbr->emac, buf, - sizeof(buf)), - ipaddr2str(&nbr->ip, buf1, - sizeof(buf1)), + "%s: duplicate addr MAC %pEA IP %pIA flags 0x%x auto recovery time %u start", + __func__, &nbr->emac, &nbr->ip, nbr->flags, zvrf->dad_freeze_time); thread_add_timer(zrouter.master, @@ -1334,8 +1258,6 @@ int zebra_evpn_local_neigh_update(zebra_evpn_t *zevpn, struct interface *ifp, bool is_router, bool local_inactive, bool dp_static) { - char buf[ETHER_ADDR_STRLEN]; - char buf2[INET6_ADDRSTRLEN]; struct zebra_vrf *zvrf; zebra_neigh_t *n = NULL; zebra_mac_t *zmac = NULL, *old_zmac = NULL; @@ -1357,20 +1279,17 @@ int zebra_evpn_local_neigh_update(zebra_evpn_t *zevpn, struct interface *ifp, if (!zmac) { /* create a dummy MAC if the MAC is not already present */ if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug("AUTO MAC %s created for neigh %s on VNI %u", - prefix_mac2str(macaddr, buf, sizeof(buf)), - ipaddr2str(ip, buf2, sizeof(buf2)), - zevpn->vni); + zlog_debug("AUTO MAC %pEA created for neigh %pIA on VNI %u", + macaddr, ip, zevpn->vni); zmac = zebra_evpn_mac_add(zevpn, macaddr); if (!zmac) { - zlog_debug("Failed to add MAC %s VNI %u", - prefix_mac2str(macaddr, buf, sizeof(buf)), + zlog_debug("Failed to add MAC %pEA VNI %u", macaddr, zevpn->vni); return -1; } - memset(&zmac->fwd_info, 0, sizeof(zmac->fwd_info)); + zebra_evpn_mac_clear_fwd_info(zmac); memset(&zmac->flags, 0, sizeof(uint32_t)); SET_FLAG(zmac->flags, ZEBRA_MAC_AUTO); } else { @@ -1402,10 +1321,9 @@ int zebra_evpn_local_neigh_update(zebra_evpn_t *zevpn, struct interface *ifp, if (!n) { flog_err( EC_ZEBRA_MAC_ADD_FAILED, - "Failed to add neighbor %s MAC %s intf %s(%u) -> VNI %u", - ipaddr2str(ip, buf2, sizeof(buf2)), - prefix_mac2str(macaddr, buf, sizeof(buf)), - ifp->name, ifp->ifindex, zevpn->vni); + "Failed to add neighbor %pIA MAC %pEA intf %s(%u) -> VNI %u", + ip, macaddr, ifp->name, ifp->ifindex, + zevpn->vni); return -1; } /* Set "local" forwarding info. */ @@ -1606,9 +1524,8 @@ int zebra_evpn_local_neigh_update(zebra_evpn_t *zevpn, struct interface *ifp, if (zebra_evpn_ip_inherit_dad_from_mac(zvrf, old_zmac, zmac, n)) { flog_warn( EC_ZEBRA_DUP_IP_INHERIT_DETECTED, - "VNI %u: MAC %s IP %s detected as duplicate during local update, inherit duplicate from MAC", - zevpn->vni, prefix_mac2str(macaddr, buf, sizeof(buf)), - ipaddr2str(&n->ip, buf2, sizeof(buf2))); + "VNI %u: MAC %pEA IP %pIA detected as duplicate during local update, inherit duplicate from MAC", + zevpn->vni, macaddr, &n->ip); } /* For IP Duplicate Address Detection (DAD) is trigger, @@ -1651,9 +1568,9 @@ int zebra_evpn_local_neigh_update(zebra_evpn_t *zevpn, struct interface *ifp, if (upd_mac_seq && zmac->loc_seq != mac_new_seq) { if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug( - "Seq changed for MAC %s VNI %u - old %u new %u", - prefix_mac2str(macaddr, buf, sizeof(buf)), - zevpn->vni, zmac->loc_seq, mac_new_seq); + "Seq changed for MAC %pEA VNI %u - old %u new %u", + macaddr, zevpn->vni, + zmac->loc_seq, mac_new_seq); zmac->loc_seq = mac_new_seq; if (zebra_evpn_mac_send_add_to_client(zevpn->vni, macaddr, zmac->flags, @@ -1682,8 +1599,6 @@ int zebra_evpn_remote_neigh_update(zebra_evpn_t *zevpn, struct interface *ifp, struct ipaddr *ip, struct ethaddr *macaddr, uint16_t state) { - char buf[ETHER_ADDR_STRLEN]; - char buf2[INET6_ADDRSTRLEN]; zebra_neigh_t *n = NULL; zebra_mac_t *zmac = NULL; @@ -1708,10 +1623,8 @@ int zebra_evpn_remote_neigh_update(zebra_evpn_t *zevpn, struct interface *ifp, zmac = zebra_evpn_mac_lookup(zevpn, macaddr); if (!zmac || !CHECK_FLAG(zmac->flags, ZEBRA_MAC_REMOTE)) { zlog_debug( - "Ignore remote neigh %s (MAC %s) on L2-VNI %u - MAC unknown or local", - ipaddr2str(&n->ip, buf2, sizeof(buf2)), - prefix_mac2str(macaddr, buf, sizeof(buf)), - zevpn->vni); + "Ignore remote neigh %pIA (MAC %pEA) on L2-VNI %u - MAC unknown or local", + &n->ip, macaddr, zevpn->vni); return -1; } @@ -2140,8 +2053,6 @@ void process_neigh_remote_macip_add(zebra_evpn_t *zevpn, struct zebra_vrf *zvrf, { zebra_neigh_t *n; int update_neigh = 0; - char buf[ETHER_ADDR_STRLEN]; - char buf1[INET6_ADDRSTRLEN]; zebra_mac_t *old_mac = NULL; bool old_static = false; bool do_dad = false; @@ -2167,11 +2078,9 @@ void process_neigh_remote_macip_add(zebra_evpn_t *zevpn, struct zebra_vrf *zvrf, mac, 0); if (!n) { zlog_warn( - "Failed to add Neigh %s MAC %s VNI %u Remote VTEP %pI4", - ipaddr2str(ipaddr, buf1, sizeof(buf1)), - prefix_mac2str(&mac->macaddr, buf, - sizeof(buf)), - zevpn->vni, &vtep_ip); + "Failed to add Neigh %pIA MAC %pEA VNI %u Remote VTEP %pI4", + ipaddr, &mac->macaddr, zevpn->vni, + &vtep_ip); return; } @@ -2192,12 +2101,8 @@ void process_neigh_remote_macip_add(zebra_evpn_t *zevpn, struct zebra_vrf *zvrf, old_static = zebra_evpn_neigh_is_static(n); if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH) zlog_debug( - "sync->remote neigh vni %u ip %s mac %s seq %d f0x%x", - n->zevpn->vni, - ipaddr2str(&n->ip, buf1, - sizeof(buf1)), - prefix_mac2str(&n->emac, buf, - sizeof(buf)), + "sync->remote neigh vni %u ip %pIA mac %pEA seq %d f0x%x", + n->zevpn->vni, &n->ip, &n->emac, seq, n->flags); zebra_evpn_neigh_clear_sync_info(n); if (IS_ZEBRA_NEIGH_ACTIVE(n)) @@ -2258,10 +2163,8 @@ void process_neigh_remote_macip_add(zebra_evpn_t *zevpn, struct zebra_vrf *zvrf, if (zebra_evpn_ip_inherit_dad_from_mac(zvrf, old_mac, mac, n)) { flog_warn( EC_ZEBRA_DUP_IP_INHERIT_DETECTED, - "VNI %u: MAC %s IP %s detected as duplicate during remote update, inherit duplicate from MAC", - zevpn->vni, - prefix_mac2str(&mac->macaddr, buf, sizeof(buf)), - ipaddr2str(&n->ip, buf1, sizeof(buf1))); + "VNI %u: MAC %pEA IP %pIA detected as duplicate during remote update, inherit duplicate from MAC", + zevpn->vni, &mac->macaddr, &n->ip); } /* Check duplicate address detection for IP */ @@ -2280,8 +2183,6 @@ int zebra_evpn_neigh_gw_macip_add(struct interface *ifp, zebra_evpn_t *zevpn, struct ipaddr *ip, zebra_mac_t *mac) { zebra_neigh_t *n; - char buf[ETHER_ADDR_STRLEN]; - char buf2[INET6_ADDRSTRLEN]; assert(mac); @@ -2291,9 +2192,8 @@ int zebra_evpn_neigh_gw_macip_add(struct interface *ifp, zebra_evpn_t *zevpn, if (!n) { flog_err( EC_ZEBRA_MAC_ADD_FAILED, - "Failed to add neighbor %s MAC %s intf %s(%u) -> VNI %u", - ipaddr2str(ip, buf2, sizeof(buf2)), - prefix_mac2str(&mac->macaddr, buf, sizeof(buf)), + "Failed to add neighbor %pIA MAC %pEA intf %s(%u) -> VNI %u", + ip, &mac->macaddr, ifp->name, ifp->ifindex, zevpn->vni); return -1; } @@ -2316,10 +2216,9 @@ int zebra_evpn_neigh_gw_macip_add(struct interface *ifp, zebra_evpn_t *zevpn, if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug( - "SVI %s(%u) L2-VNI %u, sending GW MAC %s IP %s add to BGP with flags 0x%x", + "SVI %s(%u) L2-VNI %u, sending GW MAC %pEA IP %pIA add to BGP with flags 0x%x", ifp->name, ifp->ifindex, zevpn->vni, - prefix_mac2str(&mac->macaddr, buf, sizeof(buf)), - ipaddr2str(ip, buf2, sizeof(buf2)), n->flags); + &mac->macaddr, ip, n->flags); zebra_evpn_neigh_send_add_to_client( zevpn->vni, ip, &n->emac, n->mac, n->flags, n->loc_seq); @@ -2328,10 +2227,9 @@ int zebra_evpn_neigh_gw_macip_add(struct interface *ifp, zebra_evpn_t *zevpn, SET_FLAG(n->flags, ZEBRA_NEIGH_SVI_IP); if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug( - "SVI %s(%u) L2-VNI %u, sending SVI MAC %s IP %s add to BGP with flags 0x%x", + "SVI %s(%u) L2-VNI %u, sending SVI MAC %pEA IP %pIA add to BGP with flags 0x%x", ifp->name, ifp->ifindex, zevpn->vni, - prefix_mac2str(&mac->macaddr, buf, sizeof(buf)), - ipaddr2str(ip, buf2, sizeof(buf2)), n->flags); + &mac->macaddr, ip, n->flags); zebra_evpn_neigh_send_add_to_client( zevpn->vni, ip, &n->emac, n->mac, n->flags, n->loc_seq); @@ -2344,8 +2242,6 @@ void zebra_evpn_neigh_remote_uninstall(zebra_evpn_t *zevpn, struct zebra_vrf *zvrf, zebra_neigh_t *n, zebra_mac_t *mac, struct ipaddr *ipaddr) { - char buf1[INET6_ADDRSTRLEN]; - if (zvrf->dad_freeze && CHECK_FLAG(n->flags, ZEBRA_NEIGH_DUPLICATE) && CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE) && (memcmp(n->emac.octet, mac->macaddr.octet, ETH_ALEN) == 0)) { @@ -2354,10 +2250,9 @@ void zebra_evpn_neigh_remote_uninstall(zebra_evpn_t *zevpn, vlan_if = zevpn_map_to_svi(zevpn); if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug( - "%s: IP %s (flags 0x%x intf %s) is remote and duplicate, read kernel for local entry", - __func__, - ipaddr2str(ipaddr, buf1, sizeof(buf1)), - n->flags, vlan_if ? vlan_if->name : "Unknown"); + "%s: IP %pIA (flags 0x%x intf %s) is remote and duplicate, read kernel for local entry", + __func__, ipaddr, n->flags, + vlan_if ? vlan_if->name : "Unknown"); if (vlan_if) neigh_read_specific_ip(ipaddr, vlan_if); } @@ -2384,8 +2279,6 @@ int zebra_evpn_neigh_del_ip(zebra_evpn_t *zevpn, struct ipaddr *ip) zebra_mac_t *zmac; bool old_bgp_ready; bool new_bgp_ready; - char buf[INET6_ADDRSTRLEN]; - char buf2[ETHER_ADDR_STRLEN]; struct zebra_vrf *zvrf; /* If entry doesn't exist, nothing to do. */ @@ -2397,9 +2290,8 @@ int zebra_evpn_neigh_del_ip(zebra_evpn_t *zevpn, struct ipaddr *ip) if (!zmac) { if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug( - "Trying to del a neigh %s without a mac %s on VNI %u", - ipaddr2str(ip, buf, sizeof(buf)), - prefix_mac2str(&n->emac, buf2, sizeof(buf2)), + "Trying to del a neigh %pIA without a mac %pEA on VNI %u", + ip, &n->emac, zevpn->vni); return 0; @@ -2419,10 +2311,8 @@ int zebra_evpn_neigh_del_ip(zebra_evpn_t *zevpn, struct ipaddr *ip) old_bgp_ready = zebra_evpn_neigh_is_ready_for_bgp(n); if (zebra_evpn_neigh_is_static(n)) { if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH) - zlog_debug("re-add sync neigh vni %u ip %s mac %s 0x%x", - n->zevpn->vni, - ipaddr2str(&n->ip, buf, sizeof(buf)), - prefix_mac2str(&n->emac, buf2, sizeof(buf2)), + zlog_debug("re-add sync neigh vni %u ip %pIA mac %pEA 0x%x", + n->zevpn->vni, &n->ip, &n->emac, n->flags); if (!CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL_INACTIVE)) diff --git a/zebra/zebra_evpn_neigh.h b/zebra/zebra_evpn_neigh.h index eac17a09b4..05156c1255 100644 --- a/zebra/zebra_evpn_neigh.h +++ b/zebra/zebra_evpn_neigh.h @@ -167,18 +167,12 @@ static inline bool zebra_evpn_neigh_is_ready_for_bgp(zebra_neigh_t *n) static inline void zebra_evpn_neigh_stop_hold_timer(zebra_neigh_t *n) { - char macbuf[ETHER_ADDR_STRLEN]; - char ipbuf[INET6_ADDRSTRLEN]; - if (!n->hold_timer) return; if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH) - zlog_debug("sync-neigh vni %u ip %s mac %s 0x%x hold stop", - n->zevpn->vni, - ipaddr2str(&n->ip, ipbuf, sizeof(ipbuf)), - prefix_mac2str(&n->emac, macbuf, sizeof(macbuf)), - n->flags); + zlog_debug("sync-neigh vni %u ip %pIA mac %pEA 0x%x hold stop", + n->zevpn->vni, &n->ip, &n->emac, n->flags); THREAD_OFF(n->hold_timer); } @@ -188,19 +182,13 @@ void zebra_evpn_sync_neigh_static_chg(zebra_neigh_t *n, bool old_n_static, static inline bool zebra_evpn_neigh_clear_sync_info(zebra_neigh_t *n) { - char macbuf[ETHER_ADDR_STRLEN]; - char ipbuf[INET6_ADDRSTRLEN]; bool old_n_static = false; bool new_n_static = false; if (n->flags & ZEBRA_NEIGH_ALL_PEER_FLAGS) { if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH) - zlog_debug("sync-neigh vni %u ip %s mac %s 0x%x clear", - n->zevpn->vni, - ipaddr2str(&n->ip, ipbuf, sizeof(ipbuf)), - prefix_mac2str(&n->emac, macbuf, - sizeof(macbuf)), - n->flags); + zlog_debug("sync-neigh vni %u ip %pIA mac %pEA 0x%x clear", + n->zevpn->vni, &n->ip, &n->emac, n->flags); old_n_static = zebra_evpn_neigh_is_static(n); UNSET_FLAG(n->flags, ZEBRA_NEIGH_ALL_PEER_FLAGS); diff --git a/zebra/zebra_fpm.c b/zebra/zebra_fpm.c index 73534c4332..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" @@ -1555,7 +1554,6 @@ static void zfpm_mac_info_del(struct fpm_mac_info_t *fpm_mac) static int zfpm_trigger_rmac_update(zebra_mac_t *rmac, zebra_l3vni_t *zl3vni, bool delete, const char *reason) { - char buf[ETHER_ADDR_STRLEN]; struct fpm_mac_info_t *fpm_mac, key; struct interface *vxlan_if, *svi_if; bool mac_found = false; @@ -1568,9 +1566,8 @@ static int zfpm_trigger_rmac_update(zebra_mac_t *rmac, zebra_l3vni_t *zl3vni, return 0; if (reason) { - zfpm_debug("triggering update to FPM - Reason: %s - %s", - reason, - prefix_mac2str(&rmac->macaddr, buf, sizeof(buf))); + zfpm_debug("triggering update to FPM - Reason: %s - %pEA", + reason, &rmac->macaddr); } vxlan_if = zl3vni_map_to_vxlan_if(zl3vni); @@ -2048,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_fpm_netlink.c b/zebra/zebra_fpm_netlink.c index f7c5da5dec..cebd576365 100644 --- a/zebra/zebra_fpm_netlink.c +++ b/zebra/zebra_fpm_netlink.c @@ -500,9 +500,8 @@ static void zfpm_log_route_info(struct netlink_route_info *ri, unsigned int i; char buf[PREFIX_STRLEN]; - zfpm_debug("%s : %s %s, Proto: %s, Metric: %u", label, - nl_msg_type_to_str(ri->nlmsg_type), - prefix2str(ri->prefix, buf, sizeof(buf)), + zfpm_debug("%s : %s %pFX, Proto: %s, Metric: %u", label, + nl_msg_type_to_str(ri->nlmsg_type), ri->prefix, nl_rtproto_to_str(ri->rtm_protocol), ri->metric ? *ri->metric : 0); @@ -557,7 +556,6 @@ int zfpm_netlink_encode_route(int cmd, rib_dest_t *dest, struct route_entry *re, int zfpm_netlink_encode_mac(struct fpm_mac_info_t *mac, char *in_buf, size_t in_buf_len) { - char buf1[ETHER_ADDR_STRLEN]; size_t buf_offset; struct macmsg { @@ -600,11 +598,10 @@ int zfpm_netlink_encode_mac(struct fpm_mac_info_t *mac, char *in_buf, assert(req->hdr.nlmsg_len < in_buf_len); - zfpm_debug("Tx %s family %s ifindex %u MAC %s DEST %pI4", + zfpm_debug("Tx %s family %s ifindex %u MAC %pEA DEST %pI4", nl_msg_type_to_str(req->hdr.nlmsg_type), nl_family_to_str(req->ndm.ndm_family), req->ndm.ndm_ifindex, - prefix_mac2str(&mac->macaddr, buf1, sizeof(buf1)), - &mac->r_vtep_ip); + &mac->macaddr, &mac->r_vtep_ip); return req->hdr.nlmsg_len; } diff --git a/zebra/zebra_l2.c b/zebra/zebra_l2.c index c1ad91c8ca..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" @@ -110,6 +109,44 @@ void zebra_l2_unmap_slave_from_bridge(struct zebra_l2info_brslave *br_slave) br_slave->br_if = NULL; } +/* If any of the bond members are in bypass state the bond is placed + * in bypass state + */ +static void zebra_l2_bond_lacp_bypass_eval(struct zebra_if *bond_zif) +{ + struct listnode *node; + struct zebra_if *bond_mbr; + bool old_bypass = !!(bond_zif->flags & ZIF_FLAG_LACP_BYPASS); + bool new_bypass = false; + + if (bond_zif->bond_info.mbr_zifs) { + for (ALL_LIST_ELEMENTS_RO(bond_zif->bond_info.mbr_zifs, node, + bond_mbr)) { + if (bond_mbr->flags & ZIF_FLAG_LACP_BYPASS) { + new_bypass = true; + break; + } + } + } + + if (old_bypass == new_bypass) + return; + + if (IS_ZEBRA_DEBUG_EVPN_MH_ES || IS_ZEBRA_DEBUG_EVENT) + zlog_debug("bond %s lacp bypass changed to %s", + bond_zif->ifp->name, new_bypass ? "on" : "off"); + + if (new_bypass) + bond_zif->flags |= ZIF_FLAG_LACP_BYPASS; + else + bond_zif->flags &= ~ZIF_FLAG_LACP_BYPASS; + + if (bond_zif->es_info.es) + zebra_evpn_es_bypass_update(bond_zif->es_info.es, bond_zif->ifp, + new_bypass); +} + +/* Returns true if member was newly linked to bond */ void zebra_l2_map_slave_to_bond(struct zebra_if *zif, vrf_id_t vrf_id) { struct interface *bond_if; @@ -138,6 +175,7 @@ void zebra_l2_map_slave_to_bond(struct zebra_if *zif, vrf_id_t vrf_id) if (zebra_evpn_is_es_bond(bond_if)) zebra_evpn_mh_update_protodown_bond_mbr( zif, false /*clear*/, __func__); + zebra_l2_bond_lacp_bypass_eval(bond_zif); } } else { if (IS_ZEBRA_DEBUG_EVPN_MH_ES || IS_ZEBRA_DEBUG_EVENT) @@ -170,6 +208,7 @@ void zebra_l2_unmap_slave_from_bond(struct zebra_if *zif) __func__); listnode_delete(bond_zif->bond_info.mbr_zifs, zif); bond_slave->bond_if = NULL; + zebra_l2_bond_lacp_bypass_eval(bond_zif); } void zebra_l2if_update_bond(struct interface *ifp, bool add) @@ -378,14 +417,36 @@ void zebra_l2if_update_bridge_slave(struct interface *ifp, } } -void zebra_l2if_update_bond_slave(struct interface *ifp, ifindex_t bond_ifindex) +void zebra_l2if_update_bond_slave(struct interface *ifp, ifindex_t bond_ifindex, + bool new_bypass) { struct zebra_if *zif; ifindex_t old_bond_ifindex; + bool old_bypass; + struct zebra_l2info_bondslave *bond_mbr; zif = ifp->info; assert(zif); + old_bypass = !!(zif->flags & ZIF_FLAG_LACP_BYPASS); + if (old_bypass != new_bypass) { + if (IS_ZEBRA_DEBUG_EVPN_MH_ES || IS_ZEBRA_DEBUG_EVENT) + zlog_debug("bond-mbr %s lacp bypass changed to %s", + zif->ifp->name, new_bypass ? "on" : "off"); + + if (new_bypass) + zif->flags |= ZIF_FLAG_LACP_BYPASS; + else + zif->flags &= ~ZIF_FLAG_LACP_BYPASS; + + bond_mbr = &zif->bondslave_info; + if (bond_mbr->bond_if) { + struct zebra_if *bond_zif = bond_mbr->bond_if->info; + + zebra_l2_bond_lacp_bypass_eval(bond_zif); + } + } + old_bond_ifindex = zif->bondslave_info.bond_ifindex; if (old_bond_ifindex == bond_ifindex) return; diff --git a/zebra/zebra_l2.h b/zebra/zebra_l2.h index 4b84eb071e..1834430287 100644 --- a/zebra/zebra_l2.h +++ b/zebra/zebra_l2.h @@ -107,7 +107,7 @@ extern void zebra_l2if_update_bridge_slave(struct interface *ifp, ns_id_t ns_id); extern void zebra_l2if_update_bond_slave(struct interface *ifp, - ifindex_t bond_ifindex); + ifindex_t bond_ifindex, bool bypass); extern void zebra_vlan_bitmap_compute(struct interface *ifp, uint32_t vid_start, uint16_t vid_end); extern void zebra_vlan_mbr_re_eval(struct interface *ifp, 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_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 2864b96c83..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" @@ -49,12 +48,23 @@ DEFINE_MTYPE_STATIC(ZEBRA, NHG, "Nexthop Group Entry"); DEFINE_MTYPE_STATIC(ZEBRA, NHG_CONNECTED, "Nexthop Group Connected"); DEFINE_MTYPE_STATIC(ZEBRA, NHG_CTX, "Nexthop Group Context"); +/* Map backup nexthop indices between two nhes */ +struct backup_nh_map_s { + int map_count; + + struct { + uint8_t orig_idx; + uint8_t new_idx; + } map[MULTIPATH_NUM]; +}; + /* id counter to keep in sync with kernel */ uint32_t id_counter; -/* */ +/* Controlled through ui */ static bool g_nexthops_enabled = true; static bool proto_nexthops_only; +static bool use_recursive_backups = true; static struct nhg_hash_entry *depends_find(const struct nexthop *nh, afi_t afi, int type, bool from_dplane); @@ -371,8 +381,8 @@ void zebra_nhe_init(struct nhg_hash_entry *nhe, afi_t afi, */ if (nh && (nh->next == NULL)) { switch (nh->type) { - case (NEXTHOP_TYPE_IFINDEX): - case (NEXTHOP_TYPE_BLACKHOLE): + case NEXTHOP_TYPE_IFINDEX: + case NEXTHOP_TYPE_BLACKHOLE: /* * This switch case handles setting the afi different * for ipv4/v6 routes. Ifindex/blackhole nexthop @@ -383,12 +393,12 @@ void zebra_nhe_init(struct nhg_hash_entry *nhe, afi_t afi, */ nhe->afi = afi; break; - case (NEXTHOP_TYPE_IPV4_IFINDEX): - case (NEXTHOP_TYPE_IPV4): + case NEXTHOP_TYPE_IPV4_IFINDEX: + case NEXTHOP_TYPE_IPV4: nhe->afi = AFI_IP; break; - case (NEXTHOP_TYPE_IPV6_IFINDEX): - case (NEXTHOP_TYPE_IPV6): + case NEXTHOP_TYPE_IPV6_IFINDEX: + case NEXTHOP_TYPE_IPV6: nhe->afi = AFI_IP6; break; } @@ -1626,9 +1636,10 @@ void zebra_nhg_increment_ref(struct nhg_hash_entry *nhe) nhg_connected_tree_increment_ref(&nhe->nhg_depends); } -static void nexthop_set_resolved(afi_t afi, const struct nexthop *newhop, - struct nexthop *nexthop, - struct zebra_sr_policy *policy) +static struct nexthop *nexthop_set_resolved(afi_t afi, + const struct nexthop *newhop, + struct nexthop *nexthop, + struct zebra_sr_policy *policy) { struct nexthop *resolved_hop; uint8_t num_labels = 0; @@ -1746,6 +1757,8 @@ static void nexthop_set_resolved(afi_t afi, const struct nexthop *newhop, resolved_hop->rparent = nexthop; _nexthop_add(&nexthop->resolved, resolved_hop); + + return resolved_hop; } /* Checks if nexthop we are trying to resolve to is valid */ @@ -1784,13 +1797,109 @@ static bool nexthop_valid_resolve(const struct nexthop *nexthop, } /* - * Given a nexthop we need to properly recursively resolve - * the route. As such, do a table lookup to find and match - * if at all possible. Set the nexthop->ifindex and resolved_id - * as appropriate + * When resolving a recursive nexthop, capture backup nexthop(s) also + * so they can be conveyed through the dataplane to the FIB. We'll look + * at the backups in the resolving nh 'nexthop' and its nhe, and copy them + * into the route's resolved nh 'resolved' and its nhe 'nhe'. + */ +static int resolve_backup_nexthops(const struct nexthop *nexthop, + const struct nhg_hash_entry *nhe, + struct nexthop *resolved, + struct nhg_hash_entry *resolve_nhe, + struct backup_nh_map_s *map) +{ + int i, j, idx; + const struct nexthop *bnh; + struct nexthop *nh, *newnh; + + assert(nexthop->backup_num <= NEXTHOP_MAX_BACKUPS); + + if (resolve_nhe->backup_info->nhe == NULL) + resolve_nhe->backup_info->nhe = zebra_nhg_alloc(); + + /* Locate backups from the original nexthop's backup index and nhe */ + for (i = 0; i < nexthop->backup_num; i++) { + idx = nexthop->backup_idx[i]; + + /* Do we already know about this particular backup? */ + for (j = 0; j < map->map_count; j++) { + if (map->map[j].orig_idx == idx) + break; + } + + if (j < map->map_count) { + resolved->backup_idx[resolved->backup_num] = + map->map[j].new_idx; + resolved->backup_num++; + + if (IS_ZEBRA_DEBUG_RIB_DETAILED) + zlog_debug("%s: found map idx orig %d, new %d", + __func__, map->map[j].orig_idx, + map->map[j].new_idx); + + continue; + } + + /* We can't handle any new map entries at this point. */ + if (map->map_count == MULTIPATH_NUM) + break; + + /* Need to create/copy a new backup */ + bnh = nhe->backup_info->nhe->nhg.nexthop; + for (j = 0; j < idx; j++) { + if (bnh == NULL) + break; + bnh = bnh->next; + } + + /* Whoops - bad index in the nexthop? */ + if (bnh == NULL) + continue; + + /* Update backup info in the resolving nexthop and its nhe */ + newnh = nexthop_dup_no_recurse(bnh, NULL); + + /* Need to compute the new backup index in the new + * backup list, and add to map struct. + */ + j = 0; + nh = resolve_nhe->backup_info->nhe->nhg.nexthop; + if (nh) { + while (nh->next) { + nh = nh->next; + j++; + } + + nh->next = newnh; + + } else /* First one */ + resolve_nhe->backup_info->nhe->nhg.nexthop = newnh; + + /* Capture index */ + resolved->backup_idx[resolved->backup_num] = j; + resolved->backup_num++; + + if (IS_ZEBRA_DEBUG_RIB_DETAILED) + zlog_debug("%s: added idx orig %d, new %d", + __func__, idx, j); + + /* Update map/cache */ + map->map[map->map_count].orig_idx = idx; + map->map[map->map_count].new_idx = j; + map->map_count++; + } + + return 0; +} + +/* + * Given a nexthop we need to properly recursively resolve, + * do a table lookup to find and match if at all possible. + * Set the nexthop->ifindex and resolution info as appropriate. */ -static int nexthop_active(afi_t afi, struct route_entry *re, - struct nexthop *nexthop, struct route_node *top) +static int nexthop_active(struct nexthop *nexthop, struct nhg_hash_entry *nhe, + const struct prefix *top, int type, uint32_t flags, + uint32_t *pmtu) { struct prefix p; struct route_table *table; @@ -1804,33 +1913,65 @@ static int nexthop_active(afi_t afi, struct route_entry *re, struct zebra_vrf *zvrf; struct in_addr local_ipv4; struct in_addr *ipv4; + afi_t afi = AFI_IP; + /* Reset some nexthop attributes that we'll recompute if necessary */ if ((nexthop->type == NEXTHOP_TYPE_IPV4) - || nexthop->type == NEXTHOP_TYPE_IPV6) + || (nexthop->type == NEXTHOP_TYPE_IPV6)) nexthop->ifindex = 0; - UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE); nexthops_free(nexthop->resolved); nexthop->resolved = NULL; - re->nexthop_mtu = 0; - - if (IS_ZEBRA_DEBUG_NHG_DETAIL) - zlog_debug("%s: re %p, nexthop %pNHv", - __func__, re, nexthop); /* - * If the kernel has sent us a NEW route, then - * by golly gee whiz it's a good route. - * - * If its an already INSTALLED route we have already handled, then the - * kernel route's nexthop might have became unreachable - * and we have to handle that. + * Set afi based on nexthop type. + * Some nexthop types get special handling, possibly skipping + * the normal processing. */ - if (!CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED) - && (re->type == ZEBRA_ROUTE_KERNEL - || re->type == ZEBRA_ROUTE_SYSTEM)) + switch (nexthop->type) { + case NEXTHOP_TYPE_IFINDEX: + + ifp = if_lookup_by_index(nexthop->ifindex, nexthop->vrf_id); + /* + * If the interface exists and its operative or its a kernel + * route and interface is up, its active. We trust kernel routes + * to be good. + */ + if (ifp + && (if_is_operative(ifp) + || (if_is_up(ifp) + && (type == ZEBRA_ROUTE_KERNEL + || type == ZEBRA_ROUTE_SYSTEM)))) + return 1; + else + return 0; + break; + + case NEXTHOP_TYPE_IPV6_IFINDEX: + afi = AFI_IP6; + + if (IN6_IS_ADDR_LINKLOCAL(&nexthop->gate.ipv6)) { + ifp = if_lookup_by_index(nexthop->ifindex, + nexthop->vrf_id); + if (ifp && if_is_operative(ifp)) + return 1; + else + return 0; + } + break; + + case NEXTHOP_TYPE_IPV4: + case NEXTHOP_TYPE_IPV4_IFINDEX: + afi = AFI_IP; + break; + case NEXTHOP_TYPE_IPV6: + afi = AFI_IP6; + break; + + case NEXTHOP_TYPE_BLACKHOLE: return 1; + } /* * If the nexthop has been marked as 'onlink' we just need to make @@ -1853,10 +1994,11 @@ static int nexthop_active(afi_t afi, struct route_entry *re, return 1; } - if ((top->p.family == AF_INET && top->p.prefixlen == 32 - && nexthop->gate.ipv4.s_addr == top->p.u.prefix4.s_addr) - || (top->p.family == AF_INET6 && top->p.prefixlen == 128 - && memcmp(&nexthop->gate.ipv6, &top->p.u.prefix6, 16) == 0)) { + if (top && + ((top->family == AF_INET && top->prefixlen == 32 + && nexthop->gate.ipv4.s_addr == top->u.prefix4.s_addr) + || (top->family == AF_INET6 && top->prefixlen == 128 + && memcmp(&nexthop->gate.ipv6, &top->u.prefix6, 16) == 0))) { if (IS_ZEBRA_DEBUG_RIB_DETAILED) zlog_debug( " :%s: Attempting to install a max prefixlength route through itself", @@ -1873,6 +2015,9 @@ static int nexthop_active(afi_t afi, struct route_entry *re, ipv4 = &nexthop->gate.ipv4; } + /* Processing for nexthops with SR 'color' attribute, using + * the corresponding SR policy object. + */ if (nexthop->srte_color) { struct ipaddr endpoint = {0}; struct zebra_sr_policy *policy; @@ -1950,7 +2095,7 @@ static int nexthop_active(afi_t afi, struct route_entry *re, * resolved by a route NH1. The exception is if the route is a * host route. */ - if (rn == top) + if (prefix_same(&rn->p, top)) if (((afi == AFI_IP) && (rn->p.prefixlen != 32)) || ((afi == AFI_IP6) && (rn->p.prefixlen != 128))) { if (IS_ZEBRA_DEBUG_RIB_DETAILED) @@ -2020,8 +2165,10 @@ static int nexthop_active(afi_t afi, struct route_entry *re, match->nhe->id, newhop); return 1; - } else if (CHECK_FLAG(re->flags, ZEBRA_FLAG_ALLOW_RECURSION)) { + } else if (CHECK_FLAG(flags, ZEBRA_FLAG_ALLOW_RECURSION)) { struct nexthop_group *nhg; + struct nexthop *resolver; + struct backup_nh_map_s map = {}; resolved = 0; @@ -2051,17 +2198,29 @@ static int nexthop_active(afi_t afi, struct route_entry *re, SET_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE); - nexthop_set_resolved(afi, newhop, nexthop, - NULL); + resolver = nexthop_set_resolved(afi, newhop, + nexthop, NULL); resolved = 1; + + /* If there are backup nexthops, capture + * that info with the resolving nexthop. + */ + if (resolver && newhop->backup_num > 0) { + resolve_backup_nexthops(newhop, + match->nhe, + resolver, nhe, + &map); + } } /* Examine installed backup nexthops, if any. There * are only installed backups *if* there is a - * dedicated fib list. + * dedicated fib list. The UI can also control use + * of backups for resolution. */ nhg = rib_get_fib_backup_nhg(match); - if (nhg == NULL || nhg->nexthop == NULL) + if (!use_recursive_backups || + nhg == NULL || nhg->nexthop == NULL) goto done_with_match; for (ALL_NEXTHOPS_PTR(nhg, newhop)) { @@ -2079,10 +2238,14 @@ static int nexthop_active(afi_t afi, struct route_entry *re, NULL); resolved = 1; } + done_with_match: - if (resolved) - re->nexthop_mtu = match->mtu; - else if (IS_ZEBRA_DEBUG_RIB_DETAILED) + /* Capture resolving mtu */ + if (resolved) { + if (pmtu) + *pmtu = match->mtu; + + } else if (IS_ZEBRA_DEBUG_RIB_DETAILED) zlog_debug( " %s: Recursion failed to find", __func__); @@ -2092,9 +2255,9 @@ done_with_match: if (IS_ZEBRA_DEBUG_RIB_DETAILED) { zlog_debug( " %s: Route Type %s has not turned on recursion", - __func__, zebra_route_string(re->type)); - if (re->type == ZEBRA_ROUTE_BGP - && !CHECK_FLAG(re->flags, ZEBRA_FLAG_IBGP)) + __func__, zebra_route_string(type)); + if (type == ZEBRA_ROUTE_BGP + && !CHECK_FLAG(flags, ZEBRA_FLAG_IBGP)) zlog_debug( " EBGP: see \"disable-ebgp-connected-route-check\" or \"disable-connected-check\""); } @@ -2110,23 +2273,23 @@ done_with_match: /* This function verifies reachability of one given nexthop, which can be * numbered or unnumbered, IPv4 or IPv6. The result is unconditionally stored * in nexthop->flags field. The nexthop->ifindex will be updated - * appropriately as well. An existing route map can turn an - * otherwise active nexthop into inactive, but not vice versa. + * appropriately as well. * - * If it finds a nexthop recursively, set the resolved_id - * to match that nexthop's nhg_hash_entry ID; + * An existing route map can turn an otherwise active nexthop into inactive, + * but not vice versa. * * The return value is the final value of 'ACTIVE' flag. */ static unsigned nexthop_active_check(struct route_node *rn, struct route_entry *re, - struct nexthop *nexthop) + struct nexthop *nexthop, + struct nhg_hash_entry *nhe) { - struct interface *ifp; route_map_result_t ret = RMAP_PERMITMATCH; afi_t family; const struct prefix *p, *src_p; struct zebra_vrf *zvrf; + uint32_t mtu = 0; srcdest_rnode_prefixes(rn, &p, &src_p); @@ -2137,19 +2300,28 @@ static unsigned nexthop_active_check(struct route_node *rn, else family = 0; + if (IS_ZEBRA_DEBUG_NHG_DETAIL) + zlog_debug("%s: re %p, nexthop %pNHv", __func__, re, nexthop); + + /* + * If the kernel has sent us a NEW route, then + * by golly gee whiz it's a good route. + * + * If its an already INSTALLED route we have already handled, then the + * kernel route's nexthop might have became unreachable + * and we have to handle that. + */ + if (!CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED) && + (re->type == ZEBRA_ROUTE_KERNEL || + re->type == ZEBRA_ROUTE_SYSTEM)) { + SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); + goto skip_check; + } + switch (nexthop->type) { case NEXTHOP_TYPE_IFINDEX: - ifp = if_lookup_by_index(nexthop->ifindex, nexthop->vrf_id); - /* - * If the interface exists and its operative or its a kernel - * route and interface is up, its active. We trust kernel routes - * to be good. - */ - if (ifp - && (if_is_operative(ifp) - || (if_is_up(ifp) - && (re->type == ZEBRA_ROUTE_KERNEL - || re->type == ZEBRA_ROUTE_SYSTEM)))) + if (nexthop_active(nexthop, nhe, &rn->p, re->type, + re->flags, &mtu)) SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); else UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); @@ -2157,14 +2329,16 @@ static unsigned nexthop_active_check(struct route_node *rn, case NEXTHOP_TYPE_IPV4: case NEXTHOP_TYPE_IPV4_IFINDEX: family = AFI_IP; - if (nexthop_active(AFI_IP, re, nexthop, rn)) + if (nexthop_active(nexthop, nhe, &rn->p, re->type, + re->flags, &mtu)) SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); else UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); break; case NEXTHOP_TYPE_IPV6: family = AFI_IP6; - if (nexthop_active(AFI_IP6, re, nexthop, rn)) + if (nexthop_active(nexthop, nhe, &rn->p, re->type, + re->flags, &mtu)) SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); else UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); @@ -2173,19 +2347,12 @@ static unsigned nexthop_active_check(struct route_node *rn, /* RFC 5549, v4 prefix with v6 NH */ if (rn->p.family != AF_INET) family = AFI_IP6; - if (IN6_IS_ADDR_LINKLOCAL(&nexthop->gate.ipv6)) { - ifp = if_lookup_by_index(nexthop->ifindex, - nexthop->vrf_id); - if (ifp && if_is_operative(ifp)) - SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); - else - UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); - } else { - if (nexthop_active(AFI_IP6, re, nexthop, rn)) - SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); - else - UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); - } + + if (nexthop_active(nexthop, nhe, &rn->p, re->type, + re->flags, &mtu)) + SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); + else + UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); break; case NEXTHOP_TYPE_BLACKHOLE: SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); @@ -2194,6 +2361,8 @@ static unsigned nexthop_active_check(struct route_node *rn, break; } +skip_check: + if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) { if (IS_ZEBRA_DEBUG_RIB_DETAILED) zlog_debug(" %s: Unable to find active nexthop", @@ -2201,6 +2370,18 @@ static unsigned nexthop_active_check(struct route_node *rn, return 0; } + /* Capture recursive nexthop mtu. + * TODO -- the code used to just reset the re's value to zero + * for each nexthop, and then jam any resolving route's mtu value in, + * whether or not that was zero, or lt/gt any existing value? The + * way this is used appears to be as a floor value, so let's try + * using it that way here. + */ + if (mtu > 0) { + if (re->nexthop_mtu == 0 || re->nexthop_mtu > mtu) + re->nexthop_mtu = mtu; + } + /* XXX: What exactly do those checks do? Do we support * e.g. IPv4 routes with IPv6 nexthops or vice versa? */ @@ -2214,7 +2395,7 @@ static unsigned nexthop_active_check(struct route_node *rn, * Possibly it may be better to use only the rib_table_info * in every case. */ - if (!family) { + if (family == 0) { struct rib_table_info *info; info = srcdest_rnode_table_info(rn); @@ -2277,21 +2458,26 @@ done: } /* - * Process a list of nexthops, given an nhg, determining + * Process a list of nexthops, given an nhe, determining * whether each one is ACTIVE/installable at this time. */ static uint32_t nexthop_list_active_update(struct route_node *rn, struct route_entry *re, - struct nexthop_group *nhg) + struct nhg_hash_entry *nhe, + bool is_backup) { union g_addr prev_src; unsigned int prev_active, new_active; ifindex_t prev_index; uint32_t counter = 0; struct nexthop *nexthop; + struct nexthop_group *nhg = &nhe->nhg; nexthop = nhg->nexthop; + /* Init recursive nh mtu */ + re->nexthop_mtu = 0; + /* Process nexthops one-by-one */ for ( ; nexthop; nexthop = nexthop->next) { @@ -2301,15 +2487,20 @@ static uint32_t nexthop_list_active_update(struct route_node *rn, prev_src = nexthop->rmap_src; prev_active = CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); prev_index = nexthop->ifindex; + + /* Include the containing nhe for primary nexthops: if there's + * recursive resolution, we capture the backup info also. + */ + new_active = + nexthop_active_check(rn, re, nexthop, + (is_backup ? NULL : nhe)); + /* * We need to respect the multipath_num here * as that what we should be able to install from * a multipath perspective should not be a data plane * decision point. */ - new_active = - nexthop_active_check(rn, re, nexthop); - if (new_active && counter >= zrouter.multipath_num) { struct nexthop *nh; @@ -2323,7 +2514,7 @@ static uint32_t nexthop_list_active_update(struct route_node *rn, if (new_active) counter++; - /* Don't allow src setting on IPv6 addr for now */ + /* Check for changes to the nexthop - set ROUTE_ENTRY_CHANGED */ if (prev_active != new_active || prev_index != nexthop->ifindex || ((nexthop->type >= NEXTHOP_TYPE_IFINDEX && nexthop->type < NEXTHOP_TYPE_IPV6) @@ -2392,7 +2583,7 @@ int nexthop_active_update(struct route_node *rn, struct route_entry *re) curr_nhe->id = 0; /* Process nexthops */ - curr_active = nexthop_list_active_update(rn, re, &curr_nhe->nhg); + curr_active = nexthop_list_active_update(rn, re, curr_nhe, false); if (IS_ZEBRA_DEBUG_NHG_DETAIL) zlog_debug("%s: re %p curr_active %u", __func__, re, @@ -2403,7 +2594,7 @@ int nexthop_active_update(struct route_node *rn, struct route_entry *re) goto backups_done; backup_active = nexthop_list_active_update( - rn, re, zebra_nhg_get_backup_nhg(curr_nhe)); + rn, re, curr_nhe->backup_info->nhe, true /*is_backup*/); if (IS_ZEBRA_DEBUG_NHG_DETAIL) zlog_debug("%s: re %p backup_active %u", __func__, re, @@ -2715,6 +2906,12 @@ void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx) case DPLANE_OP_NEIGH_DISCOVER: case DPLANE_OP_BR_PORT_UPDATE: case DPLANE_OP_NONE: + case DPLANE_OP_IPTABLE_ADD: + case DPLANE_OP_IPTABLE_DELETE: + case DPLANE_OP_IPSET_ADD: + case DPLANE_OP_IPSET_DELETE: + case DPLANE_OP_IPSET_ENTRY_ADD: + case DPLANE_OP_IPSET_ENTRY_DELETE: break; } @@ -2776,6 +2973,17 @@ bool zebra_nhg_kernel_nexthops_enabled(void) return g_nexthops_enabled; } +/* Global control for use of activated backups for recursive resolution. */ +void zebra_nhg_set_recursive_use_backups(bool set) +{ + use_recursive_backups = set; +} + +bool zebra_nhg_recursive_use_backups(void) +{ + return use_recursive_backups; +} + /* * Global control to only use kernel nexthops for protocol created NHGs. * There are some use cases where you may not want zebra to implicitly diff --git a/zebra/zebra_nhg.h b/zebra/zebra_nhg.h index db20f2beaf..38015bf557 100644 --- a/zebra/zebra_nhg.h +++ b/zebra/zebra_nhg.h @@ -180,8 +180,9 @@ struct nhg_ctx { vrf_id_t vrf_id; afi_t afi; + /* - * This should only every be ZEBRA_ROUTE_NHG unless we get a a kernel + * This should only ever be ZEBRA_ROUTE_NHG unless we get a a kernel * created nexthop not made by us. */ int type; @@ -211,6 +212,10 @@ bool zebra_nhg_kernel_nexthops_enabled(void); void zebra_nhg_set_proto_nexthops_only(bool set); bool zebra_nhg_proto_nexthops_only(void); +/* Global control for use of activated backups for recursive resolution. */ +void zebra_nhg_set_recursive_use_backups(bool set); +bool zebra_nhg_recursive_use_backups(void); + /** * NHE abstracted tree functions. * Use these where possible instead of direct access. 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 87ab900092..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)); @@ -542,6 +541,69 @@ void zebra_pbr_del_rule(struct zebra_pbr_rule *rule) __func__); } +void zebra_pbr_process_iptable(struct zebra_dplane_ctx *ctx) +{ + int mode, ret = 0; + struct zebra_pbr_iptable ipt; + + if (dplane_ctx_get_op(ctx) == DPLANE_OP_IPTABLE_ADD) + mode = 1; + else + mode = 0; + + if (dplane_ctx_get_pbr_iptable(ctx, &ipt)) { + ret = hook_call(zebra_pbr_iptable_update, mode, &ipt); + if (ret) + dplane_ctx_set_status(ctx, + ZEBRA_DPLANE_REQUEST_SUCCESS); + } + if (!ret) + dplane_ctx_set_status(ctx, ZEBRA_DPLANE_REQUEST_FAILURE); +} + +void zebra_pbr_process_ipset(struct zebra_dplane_ctx *ctx) +{ + int mode, ret = 0; + struct zebra_pbr_ipset ipset; + + if (dplane_ctx_get_op(ctx) == DPLANE_OP_IPSET_ADD) + mode = 1; + else + mode = 0; + if (dplane_ctx_get_pbr_ipset(ctx, &ipset)) { + ret = hook_call(zebra_pbr_ipset_update, mode, &ipset); + if (ret) + dplane_ctx_set_status(ctx, + ZEBRA_DPLANE_REQUEST_SUCCESS); + } + if (!ret) + dplane_ctx_set_status(ctx, ZEBRA_DPLANE_REQUEST_FAILURE); +} + +void zebra_pbr_process_ipset_entry(struct zebra_dplane_ctx *ctx) +{ + int mode, ret = 0; + struct zebra_pbr_ipset_entry ipset_entry; + struct zebra_pbr_ipset ipset; + + if (dplane_ctx_get_op(ctx) == DPLANE_OP_IPSET_ENTRY_ADD) + mode = 1; + else + mode = 0; + + if (!dplane_ctx_get_pbr_ipset_entry(ctx, &ipset_entry)) + return; + if (!dplane_ctx_get_pbr_ipset(ctx, &ipset)) + return; + ipset_entry.backpointer = &ipset; + + ret = hook_call(zebra_pbr_ipset_entry_update, mode, &ipset_entry); + if (ret) + dplane_ctx_set_status(ctx, ZEBRA_DPLANE_REQUEST_SUCCESS); + else + dplane_ctx_set_status(ctx, ZEBRA_DPLANE_REQUEST_FAILURE); +} + static void zebra_pbr_cleanup_rules(struct hash_bucket *b, void *data) { struct zebra_pbr_rule *rule = b->data; @@ -632,13 +694,8 @@ static void *pbr_ipset_alloc_intern(void *arg) void zebra_pbr_create_ipset(struct zebra_pbr_ipset *ipset) { - int ret; - (void)hash_get(zrouter.ipset_hash, ipset, pbr_ipset_alloc_intern); - ret = hook_call(zebra_pbr_ipset_update, 1, ipset); - kernel_pbr_ipset_add_del_status(ipset, - ret ? ZEBRA_DPLANE_INSTALL_SUCCESS - : ZEBRA_DPLANE_INSTALL_FAILURE); + (void)dplane_pbr_ipset_add(ipset); } void zebra_pbr_destroy_ipset(struct zebra_pbr_ipset *ipset) @@ -646,7 +703,7 @@ void zebra_pbr_destroy_ipset(struct zebra_pbr_ipset *ipset) struct zebra_pbr_ipset *lookup; lookup = hash_lookup(zrouter.ipset_hash, ipset); - hook_call(zebra_pbr_ipset_update, 0, ipset); + (void)dplane_pbr_ipset_delete(ipset); if (lookup) { hash_release(zrouter.ipset_hash, lookup); XFREE(MTYPE_TMP, lookup); @@ -711,14 +768,9 @@ static void *pbr_ipset_entry_alloc_intern(void *arg) void zebra_pbr_add_ipset_entry(struct zebra_pbr_ipset_entry *ipset) { - int ret; - (void)hash_get(zrouter.ipset_entry_hash, ipset, pbr_ipset_entry_alloc_intern); - ret = hook_call(zebra_pbr_ipset_entry_update, 1, ipset); - kernel_pbr_ipset_entry_add_del_status(ipset, - ret ? ZEBRA_DPLANE_INSTALL_SUCCESS - : ZEBRA_DPLANE_INSTALL_FAILURE); + (void)dplane_pbr_ipset_entry_add(ipset); } void zebra_pbr_del_ipset_entry(struct zebra_pbr_ipset_entry *ipset) @@ -726,7 +778,7 @@ void zebra_pbr_del_ipset_entry(struct zebra_pbr_ipset_entry *ipset) struct zebra_pbr_ipset_entry *lookup; lookup = hash_lookup(zrouter.ipset_entry_hash, ipset); - hook_call(zebra_pbr_ipset_entry_update, 0, ipset); + (void)dplane_pbr_ipset_entry_delete(ipset); if (lookup) { hash_release(zrouter.ipset_entry_hash, lookup); XFREE(MTYPE_TMP, lookup); @@ -761,13 +813,8 @@ static void *pbr_iptable_alloc_intern(void *arg) void zebra_pbr_add_iptable(struct zebra_pbr_iptable *iptable) { - int ret; - (void)hash_get(zrouter.iptable_hash, iptable, pbr_iptable_alloc_intern); - ret = hook_call(zebra_pbr_iptable_update, 1, iptable); - kernel_pbr_iptable_add_del_status(iptable, - ret ? ZEBRA_DPLANE_INSTALL_SUCCESS - : ZEBRA_DPLANE_INSTALL_FAILURE); + (void)dplane_pbr_iptable_add(iptable); } void zebra_pbr_del_iptable(struct zebra_pbr_iptable *iptable) @@ -775,7 +822,7 @@ void zebra_pbr_del_iptable(struct zebra_pbr_iptable *iptable) struct zebra_pbr_iptable *lookup; lookup = hash_lookup(zrouter.iptable_hash, iptable); - hook_call(zebra_pbr_iptable_update, 0, iptable); + (void)dplane_pbr_iptable_delete(iptable); if (lookup) { struct listnode *node, *nnode; char *name; @@ -812,6 +859,36 @@ void zebra_pbr_dplane_result(struct zebra_dplane_ctx *ctx) zsend_rule_notify_owner(ctx, res == ZEBRA_DPLANE_REQUEST_SUCCESS ? ZAPI_RULE_REMOVED : ZAPI_RULE_FAIL_REMOVE); + else if (op == DPLANE_OP_IPTABLE_ADD) + zsend_iptable_notify_owner(ctx, + res == ZEBRA_DPLANE_REQUEST_SUCCESS + ? ZAPI_IPTABLE_INSTALLED + : ZAPI_IPTABLE_FAIL_INSTALL); + else if (op == DPLANE_OP_IPTABLE_DELETE) + zsend_iptable_notify_owner(ctx, + res == ZEBRA_DPLANE_REQUEST_SUCCESS + ? ZAPI_IPTABLE_REMOVED + : ZAPI_IPTABLE_FAIL_REMOVE); + else if (op == DPLANE_OP_IPSET_ADD) + zsend_ipset_notify_owner(ctx, + res == ZEBRA_DPLANE_REQUEST_SUCCESS + ? ZAPI_IPSET_INSTALLED + : ZAPI_IPSET_FAIL_INSTALL); + else if (op == DPLANE_OP_IPSET_DELETE) + zsend_ipset_notify_owner(ctx, + res == ZEBRA_DPLANE_REQUEST_SUCCESS + ? ZAPI_IPSET_REMOVED + : ZAPI_IPSET_FAIL_REMOVE); + else if (op == DPLANE_OP_IPSET_ENTRY_ADD) + zsend_ipset_entry_notify_owner( + ctx, res == ZEBRA_DPLANE_REQUEST_SUCCESS + ? ZAPI_IPSET_ENTRY_INSTALLED + : ZAPI_IPSET_ENTRY_FAIL_INSTALL); + else if (op == DPLANE_OP_IPSET_ENTRY_DELETE) + zsend_ipset_entry_notify_owner( + ctx, res == ZEBRA_DPLANE_REQUEST_SUCCESS + ? ZAPI_IPSET_ENTRY_REMOVED + : ZAPI_IPSET_ENTRY_FAIL_REMOVE); else flog_err( EC_ZEBRA_PBR_RULE_UPDATE, @@ -823,85 +900,6 @@ void zebra_pbr_dplane_result(struct zebra_dplane_ctx *ctx) } /* - * Handle success or failure of ipset (un)install in the kernel. - */ -void kernel_pbr_ipset_add_del_status(struct zebra_pbr_ipset *ipset, - enum zebra_dplane_status res) -{ - switch (res) { - case ZEBRA_DPLANE_INSTALL_SUCCESS: - zsend_ipset_notify_owner(ipset, ZAPI_IPSET_INSTALLED); - break; - case ZEBRA_DPLANE_INSTALL_FAILURE: - zsend_ipset_notify_owner(ipset, ZAPI_IPSET_FAIL_INSTALL); - break; - case ZEBRA_DPLANE_DELETE_SUCCESS: - zsend_ipset_notify_owner(ipset, ZAPI_IPSET_REMOVED); - break; - case ZEBRA_DPLANE_DELETE_FAILURE: - zsend_ipset_notify_owner(ipset, ZAPI_IPSET_FAIL_REMOVE); - break; - case ZEBRA_DPLANE_STATUS_NONE: - break; - } -} - -/* - * Handle success or failure of ipset (un)install in the kernel. - */ -void kernel_pbr_ipset_entry_add_del_status( - struct zebra_pbr_ipset_entry *ipset, - enum zebra_dplane_status res) -{ - switch (res) { - case ZEBRA_DPLANE_INSTALL_SUCCESS: - zsend_ipset_entry_notify_owner(ipset, - ZAPI_IPSET_ENTRY_INSTALLED); - break; - case ZEBRA_DPLANE_INSTALL_FAILURE: - zsend_ipset_entry_notify_owner(ipset, - ZAPI_IPSET_ENTRY_FAIL_INSTALL); - break; - case ZEBRA_DPLANE_DELETE_SUCCESS: - zsend_ipset_entry_notify_owner(ipset, - ZAPI_IPSET_ENTRY_REMOVED); - break; - case ZEBRA_DPLANE_DELETE_FAILURE: - zsend_ipset_entry_notify_owner(ipset, - ZAPI_IPSET_ENTRY_FAIL_REMOVE); - break; - case ZEBRA_DPLANE_STATUS_NONE: - break; - } -} - -/* - * Handle success or failure of ipset (un)install in the kernel. - */ -void kernel_pbr_iptable_add_del_status(struct zebra_pbr_iptable *iptable, - enum zebra_dplane_status res) -{ - switch (res) { - case ZEBRA_DPLANE_INSTALL_SUCCESS: - zsend_iptable_notify_owner(iptable, ZAPI_IPTABLE_INSTALLED); - break; - case ZEBRA_DPLANE_INSTALL_FAILURE: - zsend_iptable_notify_owner(iptable, ZAPI_IPTABLE_FAIL_INSTALL); - break; - case ZEBRA_DPLANE_DELETE_SUCCESS: - zsend_iptable_notify_owner(iptable, - ZAPI_IPTABLE_REMOVED); - break; - case ZEBRA_DPLANE_DELETE_FAILURE: - zsend_iptable_notify_owner(iptable, - ZAPI_IPTABLE_FAIL_REMOVE); - break; - case ZEBRA_DPLANE_STATUS_NONE: - break; - } -} - -/* * Handle rule delete notification from kernel. */ int kernel_pbr_rule_del(struct zebra_pbr_rule *rule) diff --git a/zebra/zebra_pbr.h b/zebra/zebra_pbr.h index e7504a3547..2e9658e7e5 100644 --- a/zebra/zebra_pbr.h +++ b/zebra/zebra_pbr.h @@ -64,6 +64,15 @@ struct zebra_pbr_rule { * * This is a filter mapped on ipset entries */ +struct zebra_pbr_ipset_info { + /* type is encoded as uint32_t + * but value is an enum ipset_type + */ + uint32_t type; + + char ipset_name[ZEBRA_IPSET_NAME_SIZE]; +}; + struct zebra_pbr_ipset { /* * Originating zclient sock fd, so we can know who to send @@ -85,6 +94,7 @@ struct zebra_pbr_ipset { char ipset_name[ZEBRA_IPSET_NAME_SIZE]; }; + /* * An IPSet Entry Filter * @@ -177,6 +187,9 @@ void zebra_pbr_del_ipset_entry(struct zebra_pbr_ipset_entry *ipset); void zebra_pbr_add_iptable(struct zebra_pbr_iptable *iptable); void zebra_pbr_del_iptable(struct zebra_pbr_iptable *iptable); +void zebra_pbr_process_iptable(struct zebra_dplane_ctx *ctx); +void zebra_pbr_process_ipset(struct zebra_dplane_ctx *ctx); +void zebra_pbr_process_ipset_entry(struct zebra_dplane_ctx *ctx); /* * Get to know existing PBR rules in the kernel - typically called at startup. @@ -198,9 +211,6 @@ extern void kernel_pbr_ipset_entry_add_del_status( struct zebra_pbr_ipset_entry *ipset, enum zebra_dplane_status res); -extern void kernel_pbr_iptable_add_del_status(struct zebra_pbr_iptable *iptable, - enum zebra_dplane_status res); - /* * Handle rule delete notification from kernel. */ @@ -239,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 c5d977017e..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); } @@ -2830,8 +2850,10 @@ void _route_entry_dump(const char *func, union prefixconstptr pp, struct vrf *vrf = vrf_lookup_by_id(re->vrf_id); struct nexthop_group *nhg; + prefix2str(pp, straddr, sizeof(straddr)); + zlog_debug("%s: dumping RE entry %p for %s%s%s vrf %s(%u)", func, - (const void *)re, prefix2str(pp, straddr, sizeof(straddr)), + (const void *)re, straddr, is_srcdst ? " from " : "", is_srcdst ? prefix2str(src_pp, srcaddr, sizeof(srcaddr)) : "", @@ -3887,6 +3909,12 @@ static int rib_process_dplane_results(struct thread *thread) case DPLANE_OP_RULE_ADD: case DPLANE_OP_RULE_DELETE: case DPLANE_OP_RULE_UPDATE: + case DPLANE_OP_IPTABLE_ADD: + case DPLANE_OP_IPTABLE_DELETE: + case DPLANE_OP_IPSET_ADD: + case DPLANE_OP_IPSET_DELETE: + case DPLANE_OP_IPSET_ENTRY_ADD: + case DPLANE_OP_IPSET_ENTRY_DELETE: zebra_pbr_dplane_result(ctx); break; 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..c9660c7309 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" 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..b42923640f 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) @@ -413,23 +412,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..ed6376b01f 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, diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 6f075e3c8e..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" @@ -1636,6 +1635,18 @@ DEFPY_HIDDEN(proto_nexthop_group_only, proto_nexthop_group_only_cmd, return CMD_SUCCESS; } +DEFPY_HIDDEN(backup_nexthop_recursive_use_enable, + backup_nexthop_recursive_use_enable_cmd, + "[no] zebra nexthop resolve-via-backup", + NO_STR + ZEBRA_STR + "Nexthop configuration \n" + "Configure use of backup nexthops in recursive resolution\n") +{ + zebra_nhg_set_recursive_use_backups(!no); + return CMD_SUCCESS; +} + DEFUN (no_ip_nht_default_route, no_ip_nht_default_route_cmd, "no ip nht resolve-via-default", @@ -3642,6 +3653,9 @@ static int config_write_protocol(struct vty *vty) if (zebra_nhg_proto_nexthops_only()) vty_out(vty, "zebra nexthop proto only\n"); + if (!zebra_nhg_recursive_use_backups()) + vty_out(vty, "no zebra nexthop resolve-via-backup\n"); + #ifdef HAVE_NETLINK /* Include netlink info */ netlink_config_write_helper(vty); @@ -4077,6 +4091,7 @@ void zebra_vty_init(void) install_element(CONFIG_NODE, &no_zebra_packet_process_cmd); install_element(CONFIG_NODE, &nexthop_group_use_enable_cmd); install_element(CONFIG_NODE, &proto_nexthop_group_only_cmd); + install_element(CONFIG_NODE, &backup_nexthop_recursive_use_enable_cmd); install_element(VIEW_NODE, &show_nexthop_group_cmd); install_element(VIEW_NODE, &show_interface_nexthop_group_cmd); diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index a4365e551f..bc2eac7a0b 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, @@ -1226,7 +1225,6 @@ static int zl3vni_rmac_install(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac) */ static int zl3vni_rmac_uninstall(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac) { - char buf[ETHER_ADDR_STRLEN]; const struct zebra_if *zif = NULL, *br_zif; const struct zebra_l2info_vxlan *vxl = NULL; const struct interface *br_ifp; @@ -1240,10 +1238,8 @@ static int zl3vni_rmac_uninstall(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac) if (!zl3vni->vxlan_if) { if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug( - "RMAC %s on L3-VNI %u hash %p couldn't be uninstalled - no vxlan_if", - prefix_mac2str(&zrmac->macaddr, - buf, sizeof(buf)), - zl3vni->vni, zl3vni); + "RMAC %pEA on L3-VNI %u hash %p couldn't be uninstalled - no vxlan_if", + &zrmac->macaddr, zl3vni->vni, zl3vni); return -1; } @@ -1277,8 +1273,6 @@ static int zl3vni_remote_rmac_add(zebra_l3vni_t *zl3vni, const struct ipaddr *vtep_ip, const struct prefix *host_prefix) { - char buf[ETHER_ADDR_STRLEN]; - char buf1[INET6_ADDRSTRLEN]; zebra_mac_t *zrmac = NULL; zrmac = zl3vni_rmac_lookup(zl3vni, rmac); @@ -1288,11 +1282,8 @@ static int zl3vni_remote_rmac_add(zebra_l3vni_t *zl3vni, zrmac = zl3vni_rmac_add(zl3vni, rmac); if (!zrmac) { zlog_debug( - "Failed to add RMAC %s L3VNI %u Remote VTEP %s, prefix %pFX", - prefix_mac2str(rmac, buf, sizeof(buf)), - zl3vni->vni, - ipaddr2str(vtep_ip, buf1, sizeof(buf1)), - host_prefix); + "Failed to add RMAC %pEA L3VNI %u Remote VTEP %pIA, prefix %pFX", + rmac, zl3vni->vni, vtep_ip, host_prefix); return -1; } memset(&zrmac->fwd_info, 0, sizeof(zrmac->fwd_info)); @@ -1308,12 +1299,9 @@ static int zl3vni_remote_rmac_add(zebra_l3vni_t *zl3vni, &vtep_ip->ipaddr_v4)) { if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug( - "L3VNI %u Remote VTEP change(%pI4 -> %s) for RMAC %s, prefix %pFX", - zl3vni->vni, - &zrmac->fwd_info.r_vtep_ip, - ipaddr2str(vtep_ip, buf1, sizeof(buf1)), - prefix_mac2str(rmac, buf, sizeof(buf)), - host_prefix); + "L3VNI %u Remote VTEP change(%pI4 -> %pIA) for RMAC %pEA, prefix %pFX", + zl3vni->vni, &zrmac->fwd_info.r_vtep_ip, + vtep_ip, rmac, host_prefix); zrmac->fwd_info.r_vtep_ip = vtep_ip->ipaddr_v4; @@ -1470,9 +1458,6 @@ static int zl3vni_remote_nh_add(zebra_l3vni_t *zl3vni, const struct ethaddr *rmac, const struct prefix *host_prefix) { - char buf[ETHER_ADDR_STRLEN]; - char buf1[ETHER_ADDR_STRLEN]; - char buf2[INET6_ADDRSTRLEN]; zebra_neigh_t *nh = NULL; /* Create the next hop entry, or update its mac, if necessary. */ @@ -1481,10 +1466,8 @@ static int zl3vni_remote_nh_add(zebra_l3vni_t *zl3vni, nh = zl3vni_nh_add(zl3vni, vtep_ip, rmac); if (!nh) { zlog_debug( - "Failed to add NH %s as Neigh (RMAC %s L3-VNI %u prefix %pFX)", - ipaddr2str(vtep_ip, buf1, sizeof(buf2)), - prefix_mac2str(rmac, buf, sizeof(buf)), - zl3vni->vni, host_prefix); + "Failed to add NH %pIA as Neigh (RMAC %pEA L3-VNI %u prefix %pFX)", + vtep_ip, rmac, zl3vni->vni, host_prefix); return -1; } @@ -1493,11 +1476,8 @@ static int zl3vni_remote_nh_add(zebra_l3vni_t *zl3vni, } else if (memcmp(&nh->emac, rmac, ETH_ALEN) != 0) { if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug( - "L3VNI %u RMAC change(%s --> %s) for nexthop %s, prefix %pFX", - zl3vni->vni, - prefix_mac2str(&nh->emac, buf, sizeof(buf)), - prefix_mac2str(rmac, buf1, sizeof(buf1)), - ipaddr2str(vtep_ip, buf2, sizeof(buf2)), + "L3VNI %u RMAC change(%pEA --> %pEA) for nexthop %pIA, prefix %pFX", + zl3vni->vni, &nh->emac, rmac, vtep_ip, host_prefix); memcpy(&nh->emac, rmac, ETH_ALEN); @@ -1878,8 +1858,6 @@ static int zl3vni_send_add_to_client(zebra_l3vni_t *zl3vni) struct zserv *client = NULL; struct ethaddr svi_rmac, vrr_rmac = {.octet = {0} }; struct zebra_vrf *zvrf; - char buf[ETHER_ADDR_STRLEN]; - char buf1[ETHER_ADDR_STRLEN]; bool is_anycast_mac = true; client = zserv_find_client(ZEBRA_ROUTE_BGP, 0); @@ -1920,11 +1898,9 @@ static int zl3vni_send_add_to_client(zebra_l3vni_t *zl3vni) if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug( - "Send L3_VNI_ADD %u VRF %s RMAC %s VRR %s local-ip %pI4 filter %s to %s", + "Send L3_VNI_ADD %u VRF %s RMAC %pEA VRR %pEA local-ip %pI4 filter %s to %s", zl3vni->vni, vrf_id_to_name(zl3vni_vrf_id(zl3vni)), - prefix_mac2str(&svi_rmac, buf, sizeof(buf)), - prefix_mac2str(&vrr_rmac, buf1, sizeof(buf1)), - &zl3vni->local_vtep_ip, + &svi_rmac, &vrr_rmac, &zl3vni->local_vtep_ip, CHECK_FLAG(zl3vni->filter, PREFIX_ROUTES_ONLY) ? "prefix-routes-only" : "none", @@ -2138,7 +2114,6 @@ static void zl3vni_del_nh_hash_entry(struct hash_bucket *bucket, void *ctx) static int zebra_vxlan_readd_remote_rmac(zebra_l3vni_t *zl3vni, struct ethaddr *rmac) { - char buf[ETHER_ADDR_STRLEN]; zebra_mac_t *zrmac = NULL; zrmac = zl3vni_rmac_lookup(zl3vni, rmac); @@ -2146,8 +2121,8 @@ static int zebra_vxlan_readd_remote_rmac(zebra_l3vni_t *zl3vni, return 0; if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug("Del remote RMAC %s L3VNI %u - readd", - prefix_mac2str(rmac, buf, sizeof(buf)), zl3vni->vni); + zlog_debug("Del remote RMAC %pEA L3VNI %u - readd", + rmac, zl3vni->vni); zl3vni_rmac_install(zl3vni, zrmac); return 0; @@ -2852,11 +2827,10 @@ void zebra_vxlan_print_macs_vni(struct vty *vty, struct zebra_vrf *zvrf, vty_out(vty, "Number of MACs (local and remote) known for this VNI: %u\n", num_macs); - vty_out(vty, - "Flags: N=sync-neighs, I=local-inactive, P=peer-active, X=peer-proxy\n"); - vty_out(vty, "%-17s %-6s %-5s %-30s %-5s %s\n", "MAC", - "Type", "Flags", "Intf/Remote ES/VTEP", - "VLAN", "Seq #'s"); + vty_out(vty, + "Flags: N=sync-neighs, I=local-inactive, P=peer-active, X=peer-proxy\n"); + vty_out(vty, "%-17s %-6s %-5s %-30s %-5s %s\n", "MAC", "Type", + "Flags", "Intf/Remote ES/VTEP", "VLAN", "Seq #'s"); } else json_object_int_add(json, "numMacs", num_macs); @@ -3668,7 +3642,6 @@ int zebra_vxlan_handle_kernel_neigh_del(struct interface *ifp, struct interface *link_if, struct ipaddr *ip) { - char buf[INET6_ADDRSTRLEN]; zebra_evpn_t *zevpn = NULL; zebra_l3vni_t *zl3vni = NULL; @@ -3686,9 +3659,8 @@ int zebra_vxlan_handle_kernel_neigh_del(struct interface *ifp, if (!zevpn) { if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug( - "%s: Del neighbor %s EVPN is not present for interface %s", - __func__, ipaddr2str(ip, buf, sizeof(buf)), - ifp->name); + "%s: Del neighbor %pIA EVPN is not present for interface %s", + __func__, ip, ifp->name); return 0; } @@ -3700,9 +3672,8 @@ int zebra_vxlan_handle_kernel_neigh_del(struct interface *ifp, } if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug("Del neighbor %s intf %s(%u) -> L2-VNI %u", - ipaddr2str(ip, buf, sizeof(buf)), ifp->name, - ifp->ifindex, zevpn->vni); + zlog_debug("Del neighbor %pIA intf %s(%u) -> L2-VNI %u", + ip, ifp->name, ifp->ifindex, zevpn->vni); return zebra_evpn_neigh_del_ip(zevpn, ip); } @@ -3722,8 +3693,6 @@ int zebra_vxlan_handle_kernel_neigh_update(struct interface *ifp, bool is_router, bool local_inactive, bool dp_static) { - char buf[ETHER_ADDR_STRLEN]; - char buf2[INET6_ADDRSTRLEN]; zebra_evpn_t *zevpn = NULL; zebra_l3vni_t *zl3vni = NULL; @@ -3743,9 +3712,8 @@ int zebra_vxlan_handle_kernel_neigh_update(struct interface *ifp, if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_NEIGH) zlog_debug( - "Add/Update neighbor %s MAC %s intf %s(%u) state 0x%x %s%s%s%s-> L2-VNI %u", - ipaddr2str(ip, buf2, sizeof(buf2)), - prefix_mac2str(macaddr, buf, sizeof(buf)), ifp->name, + "Add/Update neighbor %pIA MAC %pEA intf %s(%u) state 0x%x %s%s%s%s-> L2-VNI %u", + ip, macaddr, ifp->name, ifp->ifindex, state, is_ext ? "ext-learned " : "", is_router ? "router " : "", local_inactive ? "local_inactive " : "", @@ -3823,7 +3791,6 @@ void zebra_vxlan_remote_macip_del(ZAPI_HANDLER_ARGS) struct ipaddr ip; struct in_addr vtep_ip; uint16_t l = 0, ipa_len; - char buf[ETHER_ADDR_STRLEN]; char buf1[INET6_ADDRSTRLEN]; memset(&macaddr, 0, sizeof(struct ethaddr)); @@ -3843,9 +3810,8 @@ void zebra_vxlan_remote_macip_del(ZAPI_HANDLER_ARGS) l += res_length; if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug( - "Recv MACIP DEL VNI %u MAC %s%s%s Remote VTEP %pI4 from %s", - vni, - prefix_mac2str(&macaddr, buf, sizeof(buf)), + "Recv MACIP DEL VNI %u MAC %pEA%s%s Remote VTEP %pI4 from %s", + vni, &macaddr, ipa_len ? " IP " : "", ipa_len ? ipaddr2str(&ip, buf1, sizeof(buf1)) : "", @@ -3873,7 +3839,6 @@ void zebra_vxlan_remote_macip_add(ZAPI_HANDLER_ARGS) uint16_t l = 0, ipa_len; uint8_t flags = 0; uint32_t seq; - char buf[ETHER_ADDR_STRLEN]; char buf1[INET6_ADDRSTRLEN]; esi_t esi; char esi_buf[ESI_STR_LEN]; @@ -3904,11 +3869,10 @@ void zebra_vxlan_remote_macip_add(ZAPI_HANDLER_ARGS) else strlcpy(esi_buf, "-", ESI_STR_LEN); zlog_debug( - "Recv %sMACIP ADD VNI %u MAC %s%s%s flags 0x%x seq %u VTEP %pI4 ESI %s from %s", + "Recv %sMACIP ADD VNI %u MAC %pEA%s%s flags 0x%x seq %u VTEP %pI4 ESI %s from %s", (flags & ZEBRA_MACIP_TYPE_SYNC_PATH) ? "sync-" : "", - vni, - prefix_mac2str(&macaddr, buf, sizeof(buf)), + vni, &macaddr, ipa_len ? " IP " : "", ipa_len ? ipaddr2str(&ip, buf1, sizeof(buf1)) : "", @@ -3985,7 +3949,6 @@ static int zebra_vxlan_check_del_local_mac(struct interface *ifp, vni_t vni; zebra_evpn_t *zevpn; zebra_mac_t *mac; - char buf[ETHER_ADDR_STRLEN]; zif = ifp->info; assert(zif); @@ -4012,9 +3975,8 @@ static int zebra_vxlan_check_del_local_mac(struct interface *ifp, if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug( - "Add/update remote MAC %s intf %s(%u) VNI %u flags 0x%x - del local", - prefix_mac2str(macaddr, buf, sizeof(buf)), ifp->name, - ifp->ifindex, vni, mac->flags); + "Add/update remote MAC %pEA intf %s(%u) VNI %u flags 0x%x - del local", + macaddr, ifp->name, ifp->ifindex, vni, mac->flags); /* Remove MAC from BGP. */ zebra_evpn_mac_send_del_to_client(zevpn->vni, macaddr, mac->flags, @@ -4027,6 +3989,7 @@ static int zebra_vxlan_check_del_local_mac(struct interface *ifp, if (!listcount(mac->neigh_list)) { zebra_evpn_mac_del(zevpn, mac); } else { + zebra_evpn_mac_clear_fwd_info(mac); UNSET_FLAG(mac->flags, ZEBRA_MAC_ALL_LOCAL_FLAGS); UNSET_FLAG(mac->flags, ZEBRA_MAC_STICKY); SET_FLAG(mac->flags, ZEBRA_MAC_AUTO); @@ -4123,7 +4086,8 @@ int zebra_vxlan_dp_network_mac_del(struct interface *ifp, if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC) zlog_debug("dpDel local-nw-MAC %pEA VNI %u", macaddr, vni); - return zebra_evpn_del_local_mac(zevpn, mac); + + zebra_evpn_del_local_mac(zevpn, mac, false); } return 0; @@ -4160,7 +4124,7 @@ int zebra_vxlan_local_mac_del(struct interface *ifp, struct interface *br_if, if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) return 0; - return zebra_evpn_del_local_mac(zevpn, mac); + return zebra_evpn_del_local_mac(zevpn, mac, false); } /* @@ -4174,7 +4138,6 @@ int zebra_vxlan_local_mac_add_update(struct interface *ifp, { zebra_evpn_t *zevpn; struct zebra_vrf *zvrf; - char buf[ETHER_ADDR_STRLEN]; assert(ifp); @@ -4185,9 +4148,8 @@ int zebra_vxlan_local_mac_add_update(struct interface *ifp, if (!zevpn) { if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug( - " Add/Update %sMAC %s intf %s(%u) VID %u, could not find EVPN", - sticky ? "sticky " : "", - prefix_mac2str(macaddr, buf, sizeof(buf)), + " Add/Update %sMAC %pEA intf %s(%u) VID %u, could not find EVPN", + sticky ? "sticky " : "", macaddr, ifp->name, ifp->ifindex, vid); return 0; } @@ -4209,7 +4171,7 @@ int zebra_vxlan_local_mac_add_update(struct interface *ifp, return zebra_evpn_add_update_local_mac(zvrf, zevpn, ifp, macaddr, vid, sticky, local_inactive, - dp_static); + dp_static, NULL); } /* 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 |
