diff options
52 files changed, 1682 insertions, 357 deletions
diff --git a/bfdd/bfd.c b/bfdd/bfd.c index a021b5cabc..7d6f4c1431 100644 --- a/bfdd/bfd.c +++ b/bfdd/bfd.c @@ -115,11 +115,13 @@ struct bfd_profile *bfd_profile_new(const char *name) void bfd_profile_free(struct bfd_profile *bp) { /* Detach from any session. */ - bfd_profile_detach(bp); + if (bglobal.bg_shutdown == false) + bfd_profile_detach(bp); /* Remove from global list. */ TAILQ_REMOVE(&bplist, bp, entry); - free(bp); + + XFREE(MTYPE_BFDD_PROFILE, bp); } /** @@ -765,6 +767,15 @@ static void _bfd_session_update(struct bfd_session *bs, */ bs->peer_profile.admin_shutdown = bpc->bpc_shutdown; bfd_set_shutdown(bs, bpc->bpc_shutdown); + + /* + * Apply profile last: it also calls `bfd_set_shutdown`. + * + * There is no problem calling `shutdown` twice if the value doesn't + * change or if it is overriden by peer specific configuration. + */ + if (bpc->bpc_has_profile) + bfd_profile_apply(bpc->bpc_profile, bs); } static int bfd_session_update(struct bfd_session *bs, struct bfd_peer_cfg *bpc) diff --git a/bfdd/bfd.h b/bfdd/bfd.h index 5984662a01..492334a670 100644 --- a/bfdd/bfd.h +++ b/bfdd/bfd.h @@ -429,6 +429,12 @@ struct bfd_global { struct zebra_privs_t bfdd_privs; + /** + * Daemon is exit()ing? Use this to avoid actions that expect a + * running system or to avoid unnecessary operations when quitting. + */ + bool bg_shutdown; + /* Debug options. */ /* Show all peer state changes events. */ bool debug_peer_event; diff --git a/bfdd/bfdctl.h b/bfdd/bfdctl.h index 4ce23a8f27..95cfcb1105 100644 --- a/bfdd/bfdctl.h +++ b/bfdd/bfdctl.h @@ -90,6 +90,9 @@ struct bfd_peer_cfg { bool bpc_cbit; + bool bpc_has_profile; + char bpc_profile[64]; + /* Status information */ enum bfd_peer_status bpc_bps; uint32_t bpc_id; diff --git a/bfdd/bfdd.c b/bfdd/bfdd.c index 258f074e8c..6b8f2c5d46 100644 --- a/bfdd/bfdd.c +++ b/bfdd/bfdd.c @@ -63,6 +63,8 @@ static void sigusr1_handler(void) static void sigterm_handler(void) { + bglobal.bg_shutdown = true; + /* Signalize shutdown. */ frr_early_fini(); diff --git a/bfdd/ptm_adapter.c b/bfdd/ptm_adapter.c index ed6db24115..1a23a690e0 100644 --- a/bfdd/ptm_adapter.c +++ b/bfdd/ptm_adapter.c @@ -85,6 +85,7 @@ static void debug_printbpc(const struct bfd_peer_cfg *bpc, const char *fmt, ...) { char timers[3][128] = {}; char addr[3][128] = {}; + char profile[128] = {}; char cbit_str[32]; char msgbuf[256]; va_list vl; @@ -119,13 +120,17 @@ static void debug_printbpc(const struct bfd_peer_cfg *bpc, const char *fmt, ...) snprintf(cbit_str, sizeof(cbit_str), " cbit:0x%02x", bpc->bpc_cbit); + if (bpc->bpc_has_profile) + snprintf(profile, sizeof(profile), " profile:%s", + bpc->bpc_profile); + va_start(vl, fmt); vsnprintf(msgbuf, sizeof(msgbuf), fmt, vl); va_end(vl); - zlog_debug("%s [mhop:%s %s%s%s%s%s%s%s]", msgbuf, + zlog_debug("%s [mhop:%s %s%s%s%s%s%s%s%s]", msgbuf, bpc->bpc_mhop ? "yes" : "no", addr[0], addr[1], addr[2], - timers[0], timers[1], timers[2], cbit_str); + timers[0], timers[1], timers[2], cbit_str, profile); } static void _ptm_bfd_session_del(struct bfd_session *bs, uint8_t diag) @@ -330,6 +335,8 @@ static int _ptm_msg_read(struct stream *msg, int command, vrf_id_t vrf_id, * - c: ifname length * - X bytes: interface name * - c: bfd_cbit + * - c: profile name length. + * - X bytes: profile name. * * q(64), l(32), w(16), c(8) */ @@ -410,6 +417,14 @@ static int _ptm_msg_read(struct stream *msg, int command, vrf_id_t vrf_id, STREAM_GETC(msg, bpc->bpc_cbit); + /* Handle profile names. */ + STREAM_GETC(msg, ifnamelen); + bpc->bpc_has_profile = ifnamelen > 0; + if (bpc->bpc_has_profile) { + STREAM_GET(bpc->bpc_profile, msg, ifnamelen); + bpc->bpc_profile[ifnamelen] = 0; + } + /* Sanity check: peer and local address must match IP types. */ if (bpc->bpc_local.sa_sin.sin_family != 0 && (bpc->bpc_local.sa_sin.sin_family @@ -450,10 +465,18 @@ static void bfdd_dest_register(struct stream *msg, vrf_id_t vrf_id) /* Protocol created peers are 'no shutdown' by default. */ bs->peer_profile.admin_shutdown = false; } else { - /* Don't try to change echo/shutdown state. */ - bpc.bpc_echo = CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO); - bpc.bpc_shutdown = - CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN); + /* + * BFD session was already created, we are just updating the + * current peer. + * + * `ptm-bfd` (or `HAVE_BFDD == 0`) is the only implementation + * that allow users to set peer specific timers via protocol. + * BFD daemon (this code) on the other hand only supports + * changing peer configuration manually (through `peer` node) + * or via profiles. + */ + if (bpc.bpc_has_profile) + bfd_profile_apply(bpc.bpc_profile, bs); } /* Create client peer notification register. */ diff --git a/bgpd/bgp_bfd.c b/bgpd/bgp_bfd.c index 1be7eff560..54970af67b 100644 --- a/bgpd/bgp_bfd.c +++ b/bgpd/bgp_bfd.c @@ -95,9 +95,24 @@ bool bgp_bfd_is_peer_multihop(struct peer *peer) */ static void bgp_bfd_peer_sendmsg(struct peer *peer, int command) { + struct bfd_session_arg arg = {}; struct bfd_info *bfd_info; - int multihop, cbit = 0; + 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) + return; bfd_info = (struct bfd_info *)peer->bfd_info; @@ -121,21 +136,49 @@ static void bgp_bfd_peer_sendmsg(struct peer *peer, int command) && !CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_CHECK_CONTROLPLANE)) SET_FLAG(bfd_info->flags, BFD_FLAG_BFD_CBIT_ON); - cbit = CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_CBIT_ON); - - if (peer->su.sa.sa_family == AF_INET) - bfd_peer_sendmsg( - zclient, bfd_info, AF_INET, &peer->su.sin.sin_addr, - (peer->su_local) ? &peer->su_local->sin.sin_addr : NULL, - (peer->nexthop.ifp) ? peer->nexthop.ifp->name : NULL, - peer->ttl, multihop, cbit, command, 1, vrf_id); - else if (peer->su.sa.sa_family == AF_INET6) - bfd_peer_sendmsg( - zclient, bfd_info, AF_INET6, &peer->su.sin6.sin6_addr, - (peer->su_local) ? &peer->su_local->sin6.sin6_addr - : NULL, - (peer->nexthop.ifp) ? peer->nexthop.ifp->name : NULL, - peer->ttl, multihop, cbit, command, 1, vrf_id); + /* 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->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); + } + + if (peer->nexthop.ifp) { + arg.ifnamelen = strlen(peer->nexthop.ifp->name); + strlcpy(arg.ifname, peer->nexthop.ifp->name, + sizeof(arg.ifname)); + } + + if (bfd_info->profile[0]) { + arg.profilelen = strlen(bfd_info->profile); + strlcpy(arg.profile, bfd_info->profile, sizeof(arg.profile)); + } + + 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); } /* @@ -438,6 +481,7 @@ 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; @@ -445,6 +489,10 @@ static int bgp_bfd_peer_param_set(struct peer *peer, uint32_t min_rx, bfd_set_param((struct bfd_info **)&(peer->bfd_info), min_rx, min_tx, detect_mult, 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)) { @@ -453,6 +501,13 @@ static int bgp_bfd_peer_param_set(struct peer *peer, uint32_t min_rx, min_rx, min_tx, detect_mult, 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); @@ -547,6 +602,61 @@ static int bgp_bfd_peer_param_type_set(struct peer *peer, return 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, 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, 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; +} + /* * bgp_bfd_peer_config_write - Write the peer BFD configuration. */ @@ -574,8 +684,12 @@ void bgp_bfd_peer_config_write(struct vty *vty, struct peer *peer, char *addr) : "singlehop"); if (!CHECK_FLAG(bfd_info->flags, BFD_FLAG_PARAM_CFG) - && (bfd_info->type == BFD_TYPE_NOT_CONFIGURED)) - vty_out(vty, " neighbor %s bfd\n", addr); + && (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); @@ -818,6 +932,58 @@ DEFUN_HIDDEN (no_neighbor_bfd_type, return CMD_SUCCESS; } +#if HAVE_BFDD > 0 +DEFUN(neighbor_bfd_profile, neighbor_bfd_profile_cmd, + "neighbor <A.B.C.D|X:X::X:X|WORD> bfd profile BFDPROF", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "BFD integration\n" + BFD_PROFILE_STR + BFD_PROFILE_NAME_STR) +{ + 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); + + return CMD_SUCCESS; +} + +DEFUN(no_neighbor_bfd_profile, no_neighbor_bfd_profile_cmd, + "no neighbor <A.B.C.D|X:X::X:X|WORD> bfd profile [BFDPROF]", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "BFD integration\n" + BFD_PROFILE_STR + BFD_PROFILE_NAME_STR) +{ + 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_set_profile(peer, NULL); + if (ret != 0) + return bgp_vty_return(vty, ret); + + return CMD_SUCCESS; +} +#endif /* HAVE_BFDD */ + void bgp_bfd_init(void) { bfd_gbl_init(); @@ -833,4 +999,9 @@ void bgp_bfd_init(void) 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); + install_element(BGP_NODE, &no_neighbor_bfd_profile_cmd); +#endif /* HAVE_BFDD */ } diff --git a/bgpd/bgp_bmp.c b/bgpd/bgp_bmp.c index c3fc230512..f1ad6a1e75 100644 --- a/bgpd/bgp_bmp.c +++ b/bgpd/bgp_bmp.c @@ -149,6 +149,16 @@ static int bmp_qhash_cmp(const struct bmp_queue_entry *a, const struct bmp_queue_entry *b) { int ret; + if (a->afi == AFI_L2VPN && a->safi == SAFI_EVPN && b->afi == AFI_L2VPN + && b->safi == SAFI_EVPN) { + ret = prefix_cmp(&a->rd, &b->rd); + if (ret) + return ret; + } else if (a->afi == AFI_L2VPN && a->safi == SAFI_EVPN) + return 1; + else if (b->afi == AFI_L2VPN && b->safi == SAFI_EVPN) + return -1; + ret = prefix_cmp(&a->p, &b->p); if (ret) return ret; @@ -164,9 +174,16 @@ static uint32_t bmp_qhash_hkey(const struct bmp_queue_entry *e) key = prefix_hash_key((void *)&e->p); key = jhash(&e->peerid, - offsetof(struct bmp_queue_entry, refcount) - - offsetof(struct bmp_queue_entry, peerid), - key); + offsetof(struct bmp_queue_entry, refcount) + - offsetof(struct bmp_queue_entry, peerid), + key); + if (e->afi == AFI_L2VPN && e->safi == SAFI_EVPN) + key = jhash(&e->rd, + offsetof(struct bmp_queue_entry, rd) + - offsetof(struct bmp_queue_entry, refcount) + + PSIZE(e->rd.prefixlen), + key); + return key; } @@ -765,8 +782,9 @@ static void bmp_eor(struct bmp *bmp, afi_t afi, safi_t safi, uint8_t flags) stream_free(s); } -static struct stream *bmp_update(const struct prefix *p, struct peer *peer, - struct attr *attr, afi_t afi, safi_t safi) +static struct stream *bmp_update(const struct prefix *p, struct prefix_rd *prd, + struct peer *peer, struct attr *attr, + afi_t afi, safi_t safi) { struct bpacket_attr_vec_arr vecarr; struct stream *s; @@ -801,8 +819,8 @@ static struct stream *bmp_update(const struct prefix *p, struct peer *peer, mpattrlen_pos = bgp_packet_mpattr_start(s, peer, afi, safi, &vecarr, attr); - bgp_packet_mpattr_prefix(s, afi, safi, p, NULL, NULL, 0, - 0, 0, attr); + bgp_packet_mpattr_prefix(s, afi, safi, p, prd, NULL, 0, 0, 0, + attr); bgp_packet_mpattr_end(s, mpattrlen_pos); total_attr_len += stream_get_endp(s) - p1; } @@ -813,7 +831,8 @@ static struct stream *bmp_update(const struct prefix *p, struct peer *peer, return s; } -static struct stream *bmp_withdraw(const struct prefix *p, afi_t afi, +static struct stream *bmp_withdraw(const struct prefix *p, + struct prefix_rd *prd, afi_t afi, safi_t safi) { struct stream *s; @@ -839,8 +858,8 @@ static struct stream *bmp_withdraw(const struct prefix *p, afi_t afi, mp_start = stream_get_endp(s); mplen_pos = bgp_packet_mpunreach_start(s, afi, safi); - bgp_packet_mpunreach_prefix(s, p, afi, safi, NULL, NULL, 0, - 0, 0, NULL); + bgp_packet_mpunreach_prefix(s, p, afi, safi, prd, NULL, 0, 0, 0, + NULL); /* Set the mp_unreach attr's length */ bgp_packet_mpunreach_end(s, mplen_pos); @@ -854,8 +873,9 @@ static struct stream *bmp_withdraw(const struct prefix *p, afi_t afi, } static void bmp_monitor(struct bmp *bmp, struct peer *peer, uint8_t flags, - const struct prefix *p, struct attr *attr, afi_t afi, - safi_t safi, time_t uptime) + const struct prefix *p, struct prefix_rd *prd, + struct attr *attr, afi_t afi, safi_t safi, + time_t uptime) { struct stream *hdr, *msg; struct timeval tv = { .tv_sec = uptime, .tv_usec = 0 }; @@ -863,9 +883,9 @@ static void bmp_monitor(struct bmp *bmp, struct peer *peer, uint8_t flags, monotime_to_realtime(&tv, &uptime_real); if (attr) - msg = bmp_update(p, peer, attr, afi, safi); + msg = bmp_update(p, prd, peer, attr, afi, safi); else - msg = bmp_withdraw(p, afi, safi); + msg = bmp_withdraw(p, prd, afi, safi); hdr = stream_new(BGP_MAX_PACKET_SIZE); bmp_common_hdr(hdr, BMP_VERSION_3, BMP_TYPE_ROUTE_MONITORING); @@ -898,6 +918,7 @@ static bool bmp_wrsync(struct bmp *bmp, struct pullwr *pullwr) bmp->syncpeerid = 0; memset(&bmp->syncpos, 0, sizeof(bmp->syncpos)); bmp->syncpos.family = afi2family(afi); + bmp->syncrdpos = NULL; zlog_info("bmp[%s] %s %s sending table", bmp->remote, afi2str(bmp->syncafi), @@ -926,11 +947,51 @@ afibreak: struct bgp_path_info *bpi = NULL, *bpiter; struct bgp_adj_in *adjin = NULL, *adjiter; + if (afi == AFI_L2VPN && safi == SAFI_EVPN) { + /* initialize syncrdpos to the first + * mid-layer table entry + */ + if (!bmp->syncrdpos) + bmp->syncrdpos = bgp_table_top(table); + + /* look for a valid mid-layer table */ + do { + table = bgp_dest_get_bgp_table_info(bmp->syncrdpos); + if (table) { + break; + } + bmp->syncrdpos = bgp_route_next(bmp->syncrdpos); + } while (bmp->syncrdpos); + + /* mid-layer table completed */ + if (!bmp->syncrdpos) + goto eor; + } + bn = bgp_node_lookup(table, &bmp->syncpos); do { if (!bn) { bn = bgp_table_get_next(table, &bmp->syncpos); if (!bn) { + if (afi == AFI_L2VPN && safi == SAFI_EVPN) { + /* reset bottom-layer pointer */ + memset(&bmp->syncpos, 0, + sizeof(bmp->syncpos)); + bmp->syncpos.family = afi2family(afi); + /* check whethere there is a valid + * next mid-layer table, otherwise + * declare table completed (eor) + */ + for (bmp->syncrdpos = bgp_route_next( + bmp->syncrdpos); + bmp->syncrdpos; + bmp->syncrdpos = bgp_route_next( + bmp->syncrdpos)) + if (bgp_dest_get_bgp_table_info( + bmp->syncrdpos)) + return true; + } + eor: zlog_info("bmp[%s] %s %s table completed (EoR)", bmp->remote, afi2str(afi), safi2str(safi)); @@ -947,7 +1008,8 @@ afibreak: } if (bmp->targets->afimon[afi][safi] & BMP_MON_POSTPOLICY) { - for (bpiter = bn->info; bpiter; bpiter = bpiter->next) { + for (bpiter = bgp_dest_get_bgp_path_info(bn); bpiter; + bpiter = bpiter->next) { if (!CHECK_FLAG(bpiter->flags, BGP_PATH_VALID)) continue; if (bpiter->peer->qobj_node.nid @@ -992,13 +1054,16 @@ afibreak: } const struct prefix *bn_p = bgp_dest_get_prefix(bn); + struct prefix_rd *prd = NULL; + if (afi == AFI_L2VPN && safi == SAFI_EVPN) + prd = (struct prefix_rd *)bgp_dest_get_prefix(bmp->syncrdpos); if (bpi) - bmp_monitor(bmp, bpi->peer, BMP_PEER_FLAG_L, bn_p, bpi->attr, - afi, safi, bpi->uptime); + bmp_monitor(bmp, bpi->peer, BMP_PEER_FLAG_L, bn_p, prd, + bpi->attr, afi, safi, bpi->uptime); if (adjin) - bmp_monitor(bmp, adjin->peer, 0, bn_p, adjin->attr, afi, safi, - adjin->uptime); + bmp_monitor(bmp, adjin->peer, 0, bn_p, prd, adjin->attr, afi, + safi, adjin->uptime); return true; } @@ -1061,18 +1126,22 @@ static bool bmp_wrqueue(struct bmp *bmp, struct pullwr *pullwr) goto out; bn = bgp_node_lookup(bmp->targets->bgp->rib[afi][safi], &bqe->p); + struct prefix_rd *prd = NULL; + if (bqe->afi == AFI_L2VPN && bqe->safi == SAFI_EVPN) + prd = &bqe->rd; if (bmp->targets->afimon[afi][safi] & BMP_MON_POSTPOLICY) { struct bgp_path_info *bpi; - for (bpi = bn ? bn->info : NULL; bpi; bpi = bpi->next) { + for (bpi = bn ? bgp_dest_get_bgp_path_info(bn) : NULL; bpi; + bpi = bpi->next) { if (!CHECK_FLAG(bpi->flags, BGP_PATH_VALID)) continue; if (bpi->peer == peer) break; } - bmp_monitor(bmp, peer, BMP_PEER_FLAG_L, &bqe->p, + bmp_monitor(bmp, peer, BMP_PEER_FLAG_L, &bqe->p, prd, bpi ? bpi->attr : NULL, afi, safi, bpi ? bpi->uptime : monotime(NULL)); written = true; @@ -1086,7 +1155,7 @@ static bool bmp_wrqueue(struct bmp *bmp, struct pullwr *pullwr) if (adjin->peer == peer) break; } - bmp_monitor(bmp, peer, BMP_PEER_FLAG_L, &bqe->p, + bmp_monitor(bmp, peer, BMP_PEER_FLAG_L, &bqe->p, prd, adjin ? adjin->attr : NULL, afi, safi, adjin ? adjin->uptime : monotime(NULL)); written = true; @@ -1146,6 +1215,10 @@ static void bmp_process_one(struct bmp_targets *bt, struct bgp *bgp, afi_t afi, bqeref.afi = afi; bqeref.safi = safi; + if (afi == AFI_L2VPN && safi == SAFI_EVPN && bn->pdest) + prefix_copy(&bqeref.rd, + (struct prefix_rd *)bgp_dest_get_prefix(bn->pdest)); + bqe = bmp_qhash_find(&bt->updhash, &bqeref); if (bqe) { if (bqe->refcount >= refcount) @@ -1960,13 +2033,12 @@ DEFPY(bmp_stats_cfg, DEFPY(bmp_monitor_cfg, bmp_monitor_cmd, - "[no] bmp monitor "BGP_AFI_CMD_STR" <unicast|multicast> <pre-policy|post-policy>$policy", + "[no] bmp monitor <ipv4|ipv6|l2vpn> <unicast|multicast|evpn> <pre-policy|post-policy>$policy", NO_STR BMP_STR "Send BMP route monitoring messages\n" - BGP_AFI_HELP_STR - "Address family modifier\n" - "Address family modifier\n" + "Address Family\nAddress Family\nAddress Family\n" + "Address Family\nAddress Family\nAddress Family\n" "Send state before policy and filter processing\n" "Send state with policy and filters applied\n") { diff --git a/bgpd/bgp_bmp.h b/bgpd/bgp_bmp.h index 94a17f70da..9032da55bf 100644 --- a/bgpd/bgp_bmp.h +++ b/bgpd/bgp_bmp.h @@ -79,6 +79,9 @@ struct bmp_queue_entry { safi_t safi; size_t refcount; + + /* initialized only for L2VPN/EVPN (S)AFIs */ + struct prefix_rd rd; }; /* This is for BMP Route Mirroring, which feeds fully raw BGP PDUs out to BMP @@ -153,6 +156,7 @@ struct bmp { * table entry, the sync* fields note down what we sent last */ struct prefix syncpos; + struct bgp_node *syncrdpos; uint64_t syncpeerid; afi_t syncafi; safi_t syncsafi; @@ -221,7 +225,11 @@ struct bmp_targets { #define BMP_STAT_DEFAULT_TIMER 60000 int stat_msec; - /* only IPv4 & IPv6 / unicast & multicast supported for now */ + /* only supporting: + * - IPv4 / unicast & multicast + * - IPv6 / unicast & multicast + * - L2VPN / EVPN + */ #define BMP_MON_PREPOLICY (1 << 0) #define BMP_MON_POSTPOLICY (1 << 1) uint8_t afimon[AFI_MAX][SAFI_MAX]; diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c index d13da74b04..7d5cac4d62 100644 --- a/bgpd/bgp_ecommunity.c +++ b/bgpd/bgp_ecommunity.c @@ -107,14 +107,14 @@ bool ecommunity_add_val(struct ecommunity *ecom, struct ecommunity_val *eval, p[1] == eval->val[1]) { if (overwrite) { memcpy(p, eval->val, ECOMMUNITY_SIZE); - return 1; + return true; } - return 0; + return false; } } int ret = memcmp(p, eval->val, ECOMMUNITY_SIZE); if (ret == 0) - return 0; + return false; if (ret > 0) { if (!unique) break; diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 76586c943a..ad437c6ba4 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -1941,7 +1941,7 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi, /* Codification of AS 0 Processing */ if (aspath_check_as_zero(attr->aspath)) - return 0; + return false; if (CHECK_FLAG(bgp->flags, BGP_FLAG_GRACEFUL_SHUTDOWN)) { if (peer->sort == BGP_PEER_IBGP @@ -3667,7 +3667,8 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, * subsequently processed for import with the new extended * community. */ - if (safi == SAFI_EVPN && !same_attr) { + if (((safi == SAFI_EVPN) || (safi == SAFI_MPLS_VPN)) + && !same_attr) { if ((pi->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES)) && (attr_new->flag @@ -3684,8 +3685,12 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, pi->attr->ecommunity), ecommunity_str( attr_new->ecommunity)); - bgp_evpn_unimport_route(bgp, afi, safi, - p, pi); + if (safi == SAFI_EVPN) + bgp_evpn_unimport_route( + bgp, afi, safi, p, pi); + else /* SAFI_MPLS_VPN */ + vpn_leak_to_vrf_withdraw(bgp, + pi); } } } diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index ebaa637525..449dab12b0 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -4529,23 +4529,31 @@ DEFUN (neighbor_capability_orf_prefix, "Capability to RECEIVE the ORF from this neighbor\n" "Capability to SEND the ORF to this neighbor\n") { - int idx_peer = 1; int idx_send_recv = 5; - uint16_t flag = 0; + char *peer_str = argv[1]->arg; + struct peer *peer; + afi_t afi = bgp_node_afi(vty); + safi_t safi = bgp_node_safi(vty); - if (strmatch(argv[idx_send_recv]->text, "send")) - flag = PEER_FLAG_ORF_PREFIX_SM; - else if (strmatch(argv[idx_send_recv]->text, "receive")) - flag = PEER_FLAG_ORF_PREFIX_RM; - else if (strmatch(argv[idx_send_recv]->text, "both")) - flag = PEER_FLAG_ORF_PREFIX_SM | PEER_FLAG_ORF_PREFIX_RM; - else { - vty_out(vty, "%% BGP invalid orf prefix-list option\n"); + peer = peer_and_group_lookup_vty(vty, peer_str); + if (!peer) return CMD_WARNING_CONFIG_FAILED; - } - return peer_af_flag_set_vty(vty, argv[idx_peer]->arg, bgp_node_afi(vty), - bgp_node_safi(vty), flag); + if (strmatch(argv[idx_send_recv]->text, "send")) + return peer_af_flag_set_vty(vty, peer_str, afi, safi, + PEER_FLAG_ORF_PREFIX_SM); + + if (strmatch(argv[idx_send_recv]->text, "receive")) + return peer_af_flag_set_vty(vty, peer_str, afi, safi, + PEER_FLAG_ORF_PREFIX_RM); + + if (strmatch(argv[idx_send_recv]->text, "both")) + return peer_af_flag_set_vty(vty, peer_str, afi, safi, + PEER_FLAG_ORF_PREFIX_SM) + | peer_af_flag_set_vty(vty, peer_str, afi, safi, + PEER_FLAG_ORF_PREFIX_RM); + + return CMD_WARNING_CONFIG_FAILED; } ALIAS_HIDDEN( @@ -4573,24 +4581,31 @@ DEFUN (no_neighbor_capability_orf_prefix, "Capability to RECEIVE the ORF from this neighbor\n" "Capability to SEND the ORF to this neighbor\n") { - int idx_peer = 2; int idx_send_recv = 6; - uint16_t flag = 0; + char *peer_str = argv[2]->arg; + struct peer *peer; + afi_t afi = bgp_node_afi(vty); + safi_t safi = bgp_node_safi(vty); - if (strmatch(argv[idx_send_recv]->text, "send")) - flag = PEER_FLAG_ORF_PREFIX_SM; - else if (strmatch(argv[idx_send_recv]->text, "receive")) - flag = PEER_FLAG_ORF_PREFIX_RM; - else if (strmatch(argv[idx_send_recv]->text, "both")) - flag = PEER_FLAG_ORF_PREFIX_SM | PEER_FLAG_ORF_PREFIX_RM; - else { - vty_out(vty, "%% BGP invalid orf prefix-list option\n"); + peer = peer_and_group_lookup_vty(vty, peer_str); + if (!peer) return CMD_WARNING_CONFIG_FAILED; - } - return peer_af_flag_unset_vty(vty, argv[idx_peer]->arg, - bgp_node_afi(vty), bgp_node_safi(vty), - flag); + if (strmatch(argv[idx_send_recv]->text, "send")) + return peer_af_flag_unset_vty(vty, peer_str, afi, safi, + PEER_FLAG_ORF_PREFIX_SM); + + if (strmatch(argv[idx_send_recv]->text, "receive")) + return peer_af_flag_unset_vty(vty, peer_str, afi, safi, + PEER_FLAG_ORF_PREFIX_RM); + + if (strmatch(argv[idx_send_recv]->text, "both")) + return peer_af_flag_unset_vty(vty, peer_str, afi, safi, + PEER_FLAG_ORF_PREFIX_SM) + | peer_af_flag_unset_vty(vty, peer_str, afi, safi, + PEER_FLAG_ORF_PREFIX_RM); + + return CMD_WARNING_CONFIG_FAILED; } ALIAS_HIDDEN( @@ -4965,27 +4980,40 @@ DEFUN (neighbor_send_community_type, "Send Standard Community attributes\n" "Send Large Community attributes\n") { - int idx_peer = 1; - uint32_t flag = 0; const char *type = argv[argc - 1]->text; + char *peer_str = argv[1]->arg; + struct peer *peer; + afi_t afi = bgp_node_afi(vty); + safi_t safi = bgp_node_safi(vty); - if (strmatch(type, "standard")) { - SET_FLAG(flag, PEER_FLAG_SEND_COMMUNITY); - } else if (strmatch(type, "extended")) { - SET_FLAG(flag, PEER_FLAG_SEND_EXT_COMMUNITY); - } else if (strmatch(type, "large")) { - SET_FLAG(flag, PEER_FLAG_SEND_LARGE_COMMUNITY); - } else if (strmatch(type, "both")) { - SET_FLAG(flag, PEER_FLAG_SEND_COMMUNITY); - SET_FLAG(flag, PEER_FLAG_SEND_EXT_COMMUNITY); - } else { /* if (strmatch(type, "all")) */ - SET_FLAG(flag, PEER_FLAG_SEND_COMMUNITY); - SET_FLAG(flag, PEER_FLAG_SEND_EXT_COMMUNITY); - SET_FLAG(flag, PEER_FLAG_SEND_LARGE_COMMUNITY); - } + peer = peer_and_group_lookup_vty(vty, peer_str); + if (!peer) + return CMD_WARNING_CONFIG_FAILED; - return peer_af_flag_set_vty(vty, argv[idx_peer]->arg, bgp_node_afi(vty), - bgp_node_safi(vty), flag); + if (strmatch(type, "standard")) + return peer_af_flag_set_vty(vty, peer_str, afi, safi, + PEER_FLAG_SEND_COMMUNITY); + + if (strmatch(type, "extended")) + return peer_af_flag_set_vty(vty, peer_str, afi, safi, + PEER_FLAG_SEND_EXT_COMMUNITY); + + if (strmatch(type, "large")) + return peer_af_flag_set_vty(vty, peer_str, afi, safi, + PEER_FLAG_SEND_LARGE_COMMUNITY); + + if (strmatch(type, "both")) { + return peer_af_flag_set_vty(vty, peer_str, afi, safi, + PEER_FLAG_SEND_COMMUNITY) + | peer_af_flag_set_vty(vty, peer_str, afi, safi, + PEER_FLAG_SEND_EXT_COMMUNITY); + } + return peer_af_flag_set_vty(vty, peer_str, afi, safi, + PEER_FLAG_SEND_COMMUNITY) + | peer_af_flag_set_vty(vty, peer_str, afi, safi, + PEER_FLAG_SEND_EXT_COMMUNITY) + | peer_af_flag_set_vty(vty, peer_str, afi, safi, + PEER_FLAG_SEND_LARGE_COMMUNITY); } ALIAS_HIDDEN( @@ -5012,28 +5040,42 @@ DEFUN (no_neighbor_send_community_type, "Send Standard Community attributes\n" "Send Large Community attributes\n") { - int idx_peer = 2; - uint32_t flag = 0; const char *type = argv[argc - 1]->text; + char *peer_str = argv[2]->arg; + struct peer *peer; + afi_t afi = bgp_node_afi(vty); + safi_t safi = bgp_node_safi(vty); - if (strmatch(type, "standard")) { - SET_FLAG(flag, PEER_FLAG_SEND_COMMUNITY); - } else if (strmatch(type, "extended")) { - SET_FLAG(flag, PEER_FLAG_SEND_EXT_COMMUNITY); - } else if (strmatch(type, "large")) { - SET_FLAG(flag, PEER_FLAG_SEND_LARGE_COMMUNITY); - } else if (strmatch(type, "both")) { - SET_FLAG(flag, PEER_FLAG_SEND_COMMUNITY); - SET_FLAG(flag, PEER_FLAG_SEND_EXT_COMMUNITY); - } else { /* if (strmatch(type, "all")) */ - SET_FLAG(flag, PEER_FLAG_SEND_COMMUNITY); - SET_FLAG(flag, PEER_FLAG_SEND_EXT_COMMUNITY); - SET_FLAG(flag, PEER_FLAG_SEND_LARGE_COMMUNITY); + peer = peer_and_group_lookup_vty(vty, peer_str); + if (!peer) + return CMD_WARNING_CONFIG_FAILED; + + if (strmatch(type, "standard")) + return peer_af_flag_unset_vty(vty, peer_str, afi, safi, + PEER_FLAG_SEND_COMMUNITY); + + if (strmatch(type, "extended")) + return peer_af_flag_unset_vty(vty, peer_str, afi, safi, + PEER_FLAG_SEND_EXT_COMMUNITY); + + if (strmatch(type, "large")) + return peer_af_flag_unset_vty(vty, peer_str, afi, safi, + PEER_FLAG_SEND_LARGE_COMMUNITY); + + if (strmatch(type, "both")) { + + return peer_af_flag_unset_vty(vty, peer_str, afi, safi, + PEER_FLAG_SEND_COMMUNITY) + | peer_af_flag_unset_vty(vty, peer_str, afi, safi, + PEER_FLAG_SEND_EXT_COMMUNITY); } - return peer_af_flag_unset_vty(vty, argv[idx_peer]->arg, - bgp_node_afi(vty), bgp_node_safi(vty), - flag); + return peer_af_flag_unset_vty(vty, peer_str, afi, safi, + PEER_FLAG_SEND_COMMUNITY) + | peer_af_flag_unset_vty(vty, peer_str, afi, safi, + PEER_FLAG_SEND_EXT_COMMUNITY) + | peer_af_flag_unset_vty(vty, peer_str, afi, safi, + PEER_FLAG_SEND_LARGE_COMMUNITY); } ALIAS_HIDDEN( @@ -5225,52 +5267,74 @@ DEFUN (neighbor_attr_unchanged, int idx = 0; char *peer_str = argv[1]->arg; struct peer *peer; - uint16_t flags = 0; + bool aspath = false; + bool nexthop = false; + bool med = false; afi_t afi = bgp_node_afi(vty); safi_t safi = bgp_node_safi(vty); + int ret = 0; peer = peer_and_group_lookup_vty(vty, peer_str); if (!peer) return CMD_WARNING_CONFIG_FAILED; if (argv_find(argv, argc, "as-path", &idx)) - SET_FLAG(flags, PEER_FLAG_AS_PATH_UNCHANGED); + aspath = true; + idx = 0; if (argv_find(argv, argc, "next-hop", &idx)) - SET_FLAG(flags, PEER_FLAG_NEXTHOP_UNCHANGED); + nexthop = true; + idx = 0; if (argv_find(argv, argc, "med", &idx)) - SET_FLAG(flags, PEER_FLAG_MED_UNCHANGED); + med = true; /* no flags means all of them! */ - if (!flags) { - SET_FLAG(flags, PEER_FLAG_AS_PATH_UNCHANGED); - SET_FLAG(flags, PEER_FLAG_NEXTHOP_UNCHANGED); - SET_FLAG(flags, PEER_FLAG_MED_UNCHANGED); + if (!aspath && !nexthop && !med) { + ret = peer_af_flag_set_vty(vty, peer_str, afi, safi, + PEER_FLAG_AS_PATH_UNCHANGED); + ret |= peer_af_flag_set_vty(vty, peer_str, afi, safi, + PEER_FLAG_NEXTHOP_UNCHANGED); + ret |= peer_af_flag_set_vty(vty, peer_str, afi, safi, + PEER_FLAG_MED_UNCHANGED); } else { - if (!CHECK_FLAG(flags, PEER_FLAG_AS_PATH_UNCHANGED) - && peer_af_flag_check(peer, afi, safi, - PEER_FLAG_AS_PATH_UNCHANGED)) { - peer_af_flag_unset_vty(vty, peer_str, afi, safi, - PEER_FLAG_AS_PATH_UNCHANGED); - } - - if (!CHECK_FLAG(flags, PEER_FLAG_NEXTHOP_UNCHANGED) - && peer_af_flag_check(peer, afi, safi, - PEER_FLAG_NEXTHOP_UNCHANGED)) { - peer_af_flag_unset_vty(vty, peer_str, afi, safi, - PEER_FLAG_NEXTHOP_UNCHANGED); - } + if (!aspath) { + if (peer_af_flag_check(peer, afi, safi, + PEER_FLAG_AS_PATH_UNCHANGED)) { + ret |= peer_af_flag_unset_vty( + vty, peer_str, afi, safi, + PEER_FLAG_AS_PATH_UNCHANGED); + } + } else + ret |= peer_af_flag_set_vty( + vty, peer_str, afi, safi, + PEER_FLAG_AS_PATH_UNCHANGED); + + if (!nexthop) { + if (peer_af_flag_check(peer, afi, safi, + PEER_FLAG_NEXTHOP_UNCHANGED)) { + ret |= peer_af_flag_unset_vty( + vty, peer_str, afi, safi, + PEER_FLAG_NEXTHOP_UNCHANGED); + } + } else + ret |= peer_af_flag_set_vty( + vty, peer_str, afi, safi, + PEER_FLAG_NEXTHOP_UNCHANGED); - if (!CHECK_FLAG(flags, PEER_FLAG_MED_UNCHANGED) - && peer_af_flag_check(peer, afi, safi, - PEER_FLAG_MED_UNCHANGED)) { - peer_af_flag_unset_vty(vty, peer_str, afi, safi, - PEER_FLAG_MED_UNCHANGED); - } + if (!med) { + if (peer_af_flag_check(peer, afi, safi, + PEER_FLAG_MED_UNCHANGED)) { + ret |= peer_af_flag_unset_vty( + vty, peer_str, afi, safi, + PEER_FLAG_MED_UNCHANGED); + } + } else + ret |= peer_af_flag_set_vty(vty, peer_str, afi, safi, + PEER_FLAG_MED_UNCHANGED); } - return peer_af_flag_set_vty(vty, peer_str, afi, safi, flags); + return ret; } ALIAS_HIDDEN( @@ -5294,27 +5358,51 @@ DEFUN (no_neighbor_attr_unchanged, "Med attribute\n") { int idx = 0; - char *peer = argv[2]->arg; - uint16_t flags = 0; + char *peer_str = argv[2]->arg; + struct peer *peer; + bool aspath = false; + bool nexthop = false; + bool med = false; + afi_t afi = bgp_node_afi(vty); + safi_t safi = bgp_node_safi(vty); + int ret = 0; + + peer = peer_and_group_lookup_vty(vty, peer_str); + if (!peer) + return CMD_WARNING_CONFIG_FAILED; if (argv_find(argv, argc, "as-path", &idx)) - SET_FLAG(flags, PEER_FLAG_AS_PATH_UNCHANGED); + aspath = true; + idx = 0; if (argv_find(argv, argc, "next-hop", &idx)) - SET_FLAG(flags, PEER_FLAG_NEXTHOP_UNCHANGED); + nexthop = true; + idx = 0; if (argv_find(argv, argc, "med", &idx)) - SET_FLAG(flags, PEER_FLAG_MED_UNCHANGED); + med = true; - if (!flags) // no flags means all of them! - { - SET_FLAG(flags, PEER_FLAG_AS_PATH_UNCHANGED); - SET_FLAG(flags, PEER_FLAG_NEXTHOP_UNCHANGED); - SET_FLAG(flags, PEER_FLAG_MED_UNCHANGED); - } + if (!aspath && !nexthop && !med) // no flags means all of them! + return peer_af_flag_unset_vty(vty, peer_str, afi, safi, + PEER_FLAG_AS_PATH_UNCHANGED) + | peer_af_flag_unset_vty(vty, peer_str, afi, safi, + PEER_FLAG_NEXTHOP_UNCHANGED) + | peer_af_flag_unset_vty(vty, peer_str, afi, safi, + PEER_FLAG_MED_UNCHANGED); + + if (aspath) + ret |= peer_af_flag_unset_vty(vty, peer_str, afi, safi, + PEER_FLAG_AS_PATH_UNCHANGED); - return peer_af_flag_unset_vty(vty, peer, bgp_node_afi(vty), - bgp_node_safi(vty), flags); + if (nexthop) + ret |= peer_af_flag_unset_vty(vty, peer_str, afi, safi, + PEER_FLAG_NEXTHOP_UNCHANGED); + + if (med) + ret |= peer_af_flag_unset_vty(vty, peer_str, afi, safi, + PEER_FLAG_MED_UNCHANGED); + + return ret; } ALIAS_HIDDEN( @@ -17244,8 +17332,7 @@ static int lcommunity_list_set_vty(struct vty *vty, int argc, char *cl_name; char *seq = NULL; - argv_find(argv, argc, "(1-4294967295)", &idx); - if (idx) + if (argv_find(argv, argc, "(1-4294967295)", &idx)) seq = argv[idx]->arg; idx = 0; @@ -17294,8 +17381,7 @@ static int lcommunity_list_unset_vty(struct vty *vty, int argc, int idx = 0; char *seq = NULL; - argv_find(argv, argc, "(1-4294967295)", &idx); - if (idx) + if (argv_find(argv, argc, "(1-4294967295)", &idx)) seq = argv[idx]->arg; idx = 0; diff --git a/doc/user/bfd.rst b/doc/user/bfd.rst index 40c2247b5b..b34bcba34d 100644 --- a/doc/user/bfd.rst +++ b/doc/user/bfd.rst @@ -232,6 +232,20 @@ The following commands are available inside the BGP configuration node. Disallow to write CBIT independence in BFD outgoing packets. Also disallow to ignore BFD down notification. This is the default behaviour. + +.. 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:: no 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-ospf-peer-config: OSPF BFD Configuration diff --git a/isisd/isis_adjacency.c b/isisd/isis_adjacency.c index 7be61fdf28..66de11e6f7 100644 --- a/isisd/isis_adjacency.c +++ b/isisd/isis_adjacency.c @@ -207,6 +207,22 @@ static const char *adj_state2string(int state) return NULL; /* not reached */ } +static const char *adj_level2string(int level) +{ + switch (level) { + case IS_LEVEL_1: + return "level-1"; + case IS_LEVEL_2: + return "level-2"; + case IS_LEVEL_1_AND_2: + return "level-1-2"; + default: + return "unknown"; + } + + return NULL; /* not reached */ +} + void isis_adj_process_threeway(struct isis_adjacency *adj, struct isis_threeway_adj *tw_adj, enum isis_adj_usage adj_usage) @@ -259,7 +275,25 @@ 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 *adj_name; + struct isis_dynhn *dyn; + dyn = dynhn_find_by_id(adj->sysid); + if (dyn) + adj_name = dyn->hostname; + else + adj_name = sysid_print(adj->sysid); + + zlog_info( + "%%ADJCHANGE: Adjacency to %s (%s) for %s changed from %s to %s, %s", + adj_name, adj->circuit->interface->name, + adj_level2string(adj->level), adj_state2string(old_state), + adj_state2string(new_state), reason ? reason : "unspecified"); +} void isis_adj_state_change(struct isis_adjacency **padj, enum isis_adj_state new_state, const char *reason) { @@ -280,23 +314,8 @@ void isis_adj_state_change(struct isis_adjacency **padj, reason ? reason : "unspecified"); } - if (circuit->area->log_adj_changes) { - const char *adj_name; - struct isis_dynhn *dyn; - - dyn = dynhn_find_by_id(adj->sysid); - if (dyn) - adj_name = dyn->hostname; - else - adj_name = sysid_print(adj->sysid); - - zlog_info( - "%%ADJCHANGE: Adjacency to %s (%s) changed from %s to %s, %s", - adj_name, adj->circuit->interface->name, - adj_state2string(old_state), - adj_state2string(new_state), - reason ? reason : "unspecified"); - } + if (circuit->area->log_adj_changes) + isis_log_adj_change(adj, old_state, new_state, reason); circuit->adj_state_changes++; #ifndef FABRICD diff --git a/isisd/isis_adjacency.h b/isisd/isis_adjacency.h index ec17446ade..d61fbbd751 100644 --- a/isisd/isis_adjacency.h +++ b/isisd/isis_adjacency.h @@ -126,6 +126,9 @@ DECLARE_HOOK(isis_adj_ip_enabled_hook, (struct isis_adjacency *adj, int family), (adj, family)) DECLARE_HOOK(isis_adj_ip_disabled_hook, (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); void isis_adj_state_change(struct isis_adjacency **adj, enum isis_adj_state state, const char *reason); void isis_adj_print(struct isis_adjacency *adj); diff --git a/isisd/isis_bfd.c b/isisd/isis_bfd.c index 8168af2fff..9f8424fcd6 100644 --- a/isisd/isis_bfd.c +++ b/isisd/isis_bfd.c @@ -263,9 +263,10 @@ static void bfd_handle_adj_down(struct isis_adjacency *adj) ZEBRA_BFD_DEST_DEREGISTER); bfd_peer_sendmsg(zclient, NULL, adj->bfd_session->family, - &adj->bfd_session->dst_ip, - &adj->bfd_session->src_ip, - adj->circuit->interface->name, + &adj->bfd_session->dst_ip, &adj->bfd_session->src_ip, + (adj->circuit->interface) + ? adj->circuit->interface->name + : NULL, 0, /* ttl */ 0, /* multihop */ 1, /* control plane independent bit is on */ @@ -324,7 +325,9 @@ static void bfd_handle_adj_up(struct isis_adjacency *adj, int command) bfd_peer_sendmsg(zclient, circuit->bfd_info, adj->bfd_session->family, &adj->bfd_session->dst_ip, &adj->bfd_session->src_ip, - circuit->interface->name, + (adj->circuit->interface) + ? adj->circuit->interface->name + : NULL, 0, /* ttl */ 0, /* multihop */ 1, /* control plane independent bit is on */ diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c index 9804841d6d..03d7b3d07b 100644 --- a/isisd/isis_circuit.c +++ b/isisd/isis_circuit.c @@ -720,6 +720,43 @@ void isis_circuit_down(struct isis_circuit *circuit) isis_notif_if_state_change(circuit, true); #endif /* ifndef FABRICD */ + /* log adjacency changes if configured to do so */ + if (circuit->area && circuit->area->log_adj_changes) { + struct isis_adjacency *adj = NULL; + if (circuit->circ_type == CIRCUIT_T_P2P) { + adj = circuit->u.p2p.neighbor; + if (adj) + isis_log_adj_change( + adj, adj->adj_state, ISIS_ADJ_DOWN, + "circuit is being brought down"); + } else if (circuit->circ_type == CIRCUIT_T_BROADCAST) { + struct list *adj_list; + struct listnode *node; + if (circuit->u.bc.adjdb[0]) { + adj_list = list_new(); + isis_adj_build_up_list(circuit->u.bc.adjdb[0], + adj_list); + for (ALL_LIST_ELEMENTS_RO(adj_list, node, adj)) + isis_log_adj_change( + adj, adj->adj_state, + ISIS_ADJ_DOWN, + "circuit is being brought down"); + list_delete(&adj_list); + } + if (circuit->u.bc.adjdb[1]) { + adj_list = list_new(); + isis_adj_build_up_list(circuit->u.bc.adjdb[1], + adj_list); + for (ALL_LIST_ELEMENTS_RO(adj_list, node, adj)) + isis_log_adj_change( + adj, adj->adj_state, + ISIS_ADJ_DOWN, + "circuit is being brought down"); + list_delete(&adj_list); + } + } + } + /* Clear the flags for all the lsps of the circuit. */ isis_circuit_update_all_srmflags(circuit, 0); @@ -127,9 +127,8 @@ void bfd_peer_sendmsg(struct zclient *zclient, struct bfd_info *bfd_info, int ttl, int multihop, int cbit, int command, int set_flag, vrf_id_t vrf_id) { - struct stream *s; - int ret; - int len; + struct bfd_session_arg args = {}; + size_t addrlen; /* Individual reg/dereg messages are suppressed during shutdown. */ if (CHECK_FLAG(bfd_gbl.flags, BFD_GBL_FLAG_IN_SHUTDOWN)) { @@ -150,86 +149,32 @@ void bfd_peer_sendmsg(struct zclient *zclient, struct bfd_info *bfd_info, return; } - s = zclient->obuf; - stream_reset(s); - zclient_create_header(s, command, vrf_id); - - stream_putl(s, getpid()); - - stream_putw(s, family); - switch (family) { - case AF_INET: - stream_put_in_addr(s, (struct in_addr *)dst_ip); - break; - case AF_INET6: - stream_put(s, dst_ip, 16); - break; - default: - break; - } - - if (command != ZEBRA_BFD_DEST_DEREGISTER) { - stream_putl(s, bfd_info->required_min_rx); - stream_putl(s, bfd_info->desired_min_tx); - stream_putc(s, bfd_info->detect_mult); - } - - if (multihop) { - stream_putc(s, 1); - /* Multi-hop destination send the source IP address to BFD */ - if (src_ip) { - stream_putw(s, family); - switch (family) { - case AF_INET: - stream_put_in_addr(s, (struct in_addr *)src_ip); - break; - case AF_INET6: - stream_put(s, src_ip, 16); - break; - default: - break; - } - } - stream_putc(s, ttl); - } else { - stream_putc(s, 0); - if ((family == AF_INET6) && (src_ip)) { - stream_putw(s, family); - stream_put(s, src_ip, 16); - } - if (if_name) { - len = strlen(if_name); - stream_putc(s, len); - stream_put(s, if_name, len); - } else { - stream_putc(s, 0); - } + /* Fill in all arguments. */ + args.ttl = ttl; + args.cbit = cbit; + args.family = family; + args.mhop = multihop; + args.vrf_id = vrf_id; + args.command = command; + args.set_flag = set_flag; + args.bfd_info = bfd_info; + if (args.bfd_info) { + args.min_rx = bfd_info->required_min_rx; + args.min_tx = bfd_info->desired_min_tx; + args.detection_multiplier = bfd_info->detect_mult; } - /* cbit */ - if (cbit) - stream_putc(s, 1); - else - stream_putc(s, 0); - stream_putw_at(s, 0, stream_get_endp(s)); + addrlen = family == AF_INET ? sizeof(struct in_addr) + : sizeof(struct in6_addr); + memcpy(&args.dst, dst_ip, addrlen); + if (src_ip) + memcpy(&args.src, src_ip, addrlen); - ret = zclient_send_message(zclient); + if (if_name) + args.ifnamelen = + strlcpy(args.ifname, if_name, sizeof(args.ifname)); - if (ret < 0) { - if (bfd_debug) - zlog_debug( - "bfd_peer_sendmsg: zclient_send_message() failed"); - return; - } - - if (set_flag) { - if (command == ZEBRA_BFD_DEST_REGISTER) - SET_FLAG(bfd_info->flags, BFD_FLAG_BFD_REG); - else if (command == ZEBRA_BFD_DEST_DEREGISTER) - UNSET_FLAG(bfd_info->flags, BFD_FLAG_BFD_REG); - } - - return; + zclient_bfd_command(zclient, &args); } /* @@ -478,3 +423,93 @@ void bfd_client_sendmsg(struct zclient *zclient, int command, return; } + +int zclient_bfd_command(struct zclient *zc, struct bfd_session_arg *args) +{ + struct stream *s; + size_t addrlen; + + /* Check socket. */ + if (!zc || zc->sock < 0) { + if (bfd_debug) + zlog_debug("%s: zclient unavailable", __func__); + return -1; + } + + s = zc->obuf; + stream_reset(s); + + /* Create new message. */ + zclient_create_header(s, args->command, args->vrf_id); + stream_putl(s, getpid()); + + /* Encode destination address. */ + stream_putw(s, args->family); + addrlen = (args->family == AF_INET) ? sizeof(struct in_addr) + : sizeof(struct in6_addr); + stream_put(s, &args->dst, addrlen); + + /* Encode timers if this is a registration message. */ + if (args->command != ZEBRA_BFD_DEST_DEREGISTER) { + stream_putl(s, args->min_rx); + stream_putl(s, args->min_tx); + stream_putc(s, args->detection_multiplier); + } + + if (args->mhop) { + /* Multi hop indicator. */ + stream_putc(s, 1); + + /* Multi hop always sends the source address. */ + stream_putw(s, args->family); + stream_put(s, &args->src, addrlen); + + /* Send the expected TTL. */ + stream_putc(s, args->ttl); + } else { + /* Multi hop indicator. */ + stream_putc(s, 0); + + /* Single hop only sends the source address when IPv6. */ + if (args->family == AF_INET6) { + stream_putw(s, args->family); + stream_put(s, &args->src, addrlen); + } + + /* Send interface name if any. */ + stream_putc(s, args->ifnamelen); + if (args->ifnamelen) + stream_put(s, args->ifname, args->ifnamelen); + } + + /* Send the C bit indicator. */ + stream_putc(s, args->cbit); + + /* `ptm-bfd` doesn't support profiles yet. */ +#if HAVE_BFDD > 0 + /* Send profile name if any. */ + stream_putc(s, args->profilelen); + if (args->profilelen) + stream_put(s, args->profile, args->profilelen); +#endif /* HAVE_BFDD */ + + /* Finish the message by writing the size. */ + stream_putw_at(s, 0, stream_get_endp(s)); + + /* Send message to zebra. */ + if (zclient_send_message(zc) == -1) { + if (bfd_debug) + zlog_debug("%s: zclient_send_message failed", __func__); + return -1; + } + + /* Write registration indicator into data structure. */ + if (args->bfd_info && args->set_flag) { + if (args->command == ZEBRA_BFD_DEST_REGISTER) + SET_FLAG(args->bfd_info->flags, BFD_FLAG_BFD_REG); + else if (args->command == ZEBRA_BFD_DEST_DEREGISTER) + UNSET_FLAG(args->bfd_info->flags, BFD_FLAG_BFD_REG); + } + + return 0; +} @@ -56,6 +56,8 @@ struct bfd_gbl { #define BFD_STATUS_UP (1 << 2) /* BFD session status is up */ #define BFD_STATUS_ADMIN_DOWN (1 << 3) /* BFD session is admin down */ +#define BFD_PROFILE_NAME_LEN 64 + #define BFD_SET_CLIENT_STATUS(current_status, new_status) \ do { \ (current_status) = \ @@ -77,6 +79,7 @@ struct bfd_info { time_t last_update; uint8_t status; enum bfd_sess_type type; + char profile[BFD_PROFILE_NAME_LEN]; }; extern struct bfd_info *bfd_info_create(void); @@ -120,6 +123,88 @@ extern void bfd_gbl_init(void); extern void bfd_gbl_exit(void); + +/* + * BFD new API. + */ + +/** + * BFD session registration arguments. + */ +struct bfd_session_arg { + /** + * BFD command. + * + * Valid commands: + * - `ZEBRA_BFD_DEST_REGISTER` + * - `ZEBRA_BFD_DEST_DEREGISTER` + */ + int32_t command; + + /** + * BFD family type. + * + * Supported types: + * - `AF_INET` + * - `AF_INET6`. + */ + uint32_t family; + /** Source address. */ + struct in6_addr src; + /** Source address. */ + struct in6_addr dst; + + /** Multi hop indicator. */ + uint8_t mhop; + /** Expected TTL. */ + uint8_t ttl; + /** C bit (Control Plane Independent bit) indicator. */ + uint8_t cbit; + + /** Interface name size. */ + uint8_t ifnamelen; + /** Interface name. */ + char ifname[64]; + + /** Daemon or session VRF. */ + vrf_id_t vrf_id; + + /** Profile name length. */ + uint8_t profilelen; + /** Profile name. */ + char profile[BFD_PROFILE_NAME_LEN]; + + /* + * Deprecation fields: these fields should be removed once `ptm-bfd` + * no longer uses this interface. + */ + + /** Minimum required receive interval (in microseconds). */ + uint32_t min_rx; + /** Minimum desired transmission interval (in microseconds). */ + uint32_t min_tx; + /** Detection multiplier. */ + uint32_t detection_multiplier; + + /** BFD client information output. */ + struct bfd_info *bfd_info; + + /** Write registration indicator. */ + uint8_t set_flag; +}; + +/** + * Send a message to BFD daemon through the zebra client. + * + * \param zc the zebra client context. + * \param arg the BFD session command arguments. + * + * \returns `-1` on failure otherwise `0`. + * + * \see bfd_session_arg. + */ +extern int zclient_bfd_command(struct zclient *zc, struct bfd_session_arg *arg); + #ifdef __cplusplus } #endif diff --git a/tests/topotests/bfd-profiles-topo1/__init__.py b/tests/topotests/bfd-profiles-topo1/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/topotests/bfd-profiles-topo1/__init__.py diff --git a/tests/topotests/bfd-profiles-topo1/r1/bfd-peers-initial.json b/tests/topotests/bfd-profiles-topo1/r1/bfd-peers-initial.json new file mode 100644 index 0000000000..bab24c4fa0 --- /dev/null +++ b/tests/topotests/bfd-profiles-topo1/r1/bfd-peers-initial.json @@ -0,0 +1,38 @@ +[ + { + "detect-multiplier": 3, + "diagnostic": "ok", + "id": "*", + "interface": "r1-eth1", + "multihop": false, + "peer": "172.16.100.2", + "receive-interval": 300, + "remote-detect-multiplier": 3, + "remote-diagnostic": "ok", + "remote-id": "*", + "remote-receive-interval": 300, + "remote-transmit-interval": 300, + "status": "up", + "transmit-interval": 300, + "uptime": "*", + "vrf": "default" + }, + { + "detect-multiplier": 3, + "diagnostic": "ok", + "id": "*", + "interface": "r1-eth0", + "multihop": false, + "peer": "172.16.0.1", + "receive-interval": 800, + "remote-detect-multiplier": 3, + "remote-diagnostic": "ok", + "remote-id": "*", + "remote-receive-interval": 800, + "remote-transmit-interval": 800, + "status": "up", + "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 new file mode 100644 index 0000000000..4d636ab052 --- /dev/null +++ b/tests/topotests/bfd-profiles-topo1/r1/bfdd.conf @@ -0,0 +1,14 @@ +debug bfd peer +debug bfd network +debug bfd zebra +! +bfd + profile slowtx + receive-interval 800 + transmit-interval 800 + ! + peer 172.16.0.1 interface r1-eth0 + profile slowtx + no shutdown + ! +! diff --git a/tests/topotests/bfd-profiles-topo1/r1/ospfd.conf b/tests/topotests/bfd-profiles-topo1/r1/ospfd.conf new file mode 100644 index 0000000000..c0896353ae --- /dev/null +++ b/tests/topotests/bfd-profiles-topo1/r1/ospfd.conf @@ -0,0 +1,8 @@ +interface r1-eth1 + ip ospf area 0 + ip ospf bfd +! +router ospf + ospf router-id 10.254.254.1 + redistribute connected +! diff --git a/tests/topotests/bfd-profiles-topo1/r1/zebra.conf b/tests/topotests/bfd-profiles-topo1/r1/zebra.conf new file mode 100644 index 0000000000..4b7982b235 --- /dev/null +++ b/tests/topotests/bfd-profiles-topo1/r1/zebra.conf @@ -0,0 +1,9 @@ +interface lo + ip address 10.254.254.1/32 +! +interface r1-eth0 + ip address 172.16.0.2/24 +! +interface r1-eth1 + ip address 172.16.100.1/24 +! diff --git a/tests/topotests/bfd-profiles-topo1/r2/bfd-peers-initial.json b/tests/topotests/bfd-profiles-topo1/r2/bfd-peers-initial.json new file mode 100644 index 0000000000..3df9ec9c9d --- /dev/null +++ b/tests/topotests/bfd-profiles-topo1/r2/bfd-peers-initial.json @@ -0,0 +1,39 @@ +[ + { + "detect-multiplier": 3, + "diagnostic": "ok", + "id": "*", + "interface": "r2-eth0", + "multihop": false, + "peer": "172.16.0.2", + "receive-interval": 800, + "remote-detect-multiplier": 3, + "remote-diagnostic": "ok", + "remote-id": "*", + "remote-receive-interval": 800, + "remote-transmit-interval": 800, + "status": "up", + "transmit-interval": 800, + "uptime": "*", + "vrf": "default" + }, + { + "detect-multiplier": 3, + "diagnostic": "ok", + "id": "*", + "interface": "r2-eth1", + "multihop": false, + "peer": "172.16.1.1", + "receive-interval": 250, + "remote-detect-multiplier": 3, + "remote-diagnostic": "ok", + "remote-echo-interval": 50, + "remote-id": "*", + "remote-receive-interval": 300, + "remote-transmit-interval": 300, + "status": "up", + "transmit-interval": 250, + "uptime": "*", + "vrf": "default" + } +] diff --git a/tests/topotests/bfd-profiles-topo1/r2/bfdd.conf b/tests/topotests/bfd-profiles-topo1/r2/bfdd.conf new file mode 100644 index 0000000000..23a39a6ee0 --- /dev/null +++ b/tests/topotests/bfd-profiles-topo1/r2/bfdd.conf @@ -0,0 +1,18 @@ +debug bfd peer +debug bfd network +debug bfd zebra +! +bfd + profile slowtx + receive-interval 800 + transmit-interval 800 + ! + profile fasttx + receive-interval 250 + transmit-interval 250 + ! + peer 172.16.0.2 interface r2-eth0 + profile slowtx + no shutdown + ! +! diff --git a/tests/topotests/bfd-profiles-topo1/r2/bgpd.conf b/tests/topotests/bfd-profiles-topo1/r2/bgpd.conf new file mode 100644 index 0000000000..824d01983f --- /dev/null +++ b/tests/topotests/bfd-profiles-topo1/r2/bgpd.conf @@ -0,0 +1,19 @@ +debug bgp neighbor-events +! +router bgp 100 + bgp router-id 10.254.254.2 + no bgp ebgp-requires-policy + neighbor 172.16.1.1 remote-as 100 + neighbor 172.16.1.1 bfd profile fasttx + neighbor 2001:db8:2::2 remote-as 200 + neighbor 2001:db8:2::2 ebgp-multihop 2 + neighbor 2001:db8:2::2 bfd profile slowtx + address-family ipv4 unicast + redistribute connected + exit-address-family + address-family ipv6 unicast + redistribute connected + neighbor 172.16.1.1 activate + neighbor 2001:db8:2::2 activate + exit-address-family +! diff --git a/tests/topotests/bfd-profiles-topo1/r2/zebra.conf b/tests/topotests/bfd-profiles-topo1/r2/zebra.conf new file mode 100644 index 0000000000..6acef139b9 --- /dev/null +++ b/tests/topotests/bfd-profiles-topo1/r2/zebra.conf @@ -0,0 +1,10 @@ +interface lo + ip address 10.254.254.2/32 +! +interface r2-eth0 + ip address 172.16.0.1/24 +! +interface r2-eth1 + ip address 172.16.1.2/24 + ipv6 address 2001:db8:1::2/64 +! diff --git a/tests/topotests/bfd-profiles-topo1/r3/bfd-peers-initial.json b/tests/topotests/bfd-profiles-topo1/r3/bfd-peers-initial.json new file mode 100644 index 0000000000..abca1ed131 --- /dev/null +++ b/tests/topotests/bfd-profiles-topo1/r3/bfd-peers-initial.json @@ -0,0 +1,39 @@ +[ + { + "detect-multiplier": 3, + "diagnostic": "ok", + "id": "*", + "interface": "r3-eth0", + "multihop": false, + "peer": "172.16.1.2", + "receive-interval": 300, + "remote-detect-multiplier": 3, + "remote-diagnostic": "ok", + "remote-id": "*", + "remote-receive-interval": 250, + "remote-transmit-interval": 250, + "status": "up", + "transmit-interval": 300, + "uptime": "*", + "vrf": "default" + }, + { + "detect-multiplier": 3, + "diagnostic": "ok", + "id": "*", + "interface": "r3-eth1", + "local": "*", + "multihop": false, + "peer": "*", + "receive-interval": 300, + "remote-detect-multiplier": 3, + "remote-diagnostic": "ok", + "remote-id": "*", + "remote-receive-interval": 300, + "remote-transmit-interval": 300, + "status": "up", + "transmit-interval": 300, + "uptime": "*", + "vrf": "default" + } +] diff --git a/tests/topotests/bfd-profiles-topo1/r3/bfdd.conf b/tests/topotests/bfd-profiles-topo1/r3/bfdd.conf new file mode 100644 index 0000000000..74dae5a60d --- /dev/null +++ b/tests/topotests/bfd-profiles-topo1/r3/bfdd.conf @@ -0,0 +1,11 @@ +debug bfd peer +debug bfd network +debug bfd zebra +! +bfd + ! profile is commented out on purpose. + !profile fasttx + ! receive-interval 250 + ! transmit-interval 250 + !! +! diff --git a/tests/topotests/bfd-profiles-topo1/r3/bgpd.conf b/tests/topotests/bfd-profiles-topo1/r3/bgpd.conf new file mode 100644 index 0000000000..9c56a349ed --- /dev/null +++ b/tests/topotests/bfd-profiles-topo1/r3/bgpd.conf @@ -0,0 +1,13 @@ +router bgp 100 + bgp router-id 10.254.254.3 + neighbor 172.16.1.2 remote-as 100 + neighbor 172.16.1.2 bfd profile fasttx + address-family ipv4 unicast + redistribute connected + exit-address-family + address-family ipv6 unicast + redistribute connected + neighbor 172.16.1.2 activate + exit-address-family + ! +! diff --git a/tests/topotests/bfd-profiles-topo1/r3/isisd.conf b/tests/topotests/bfd-profiles-topo1/r3/isisd.conf new file mode 100644 index 0000000000..5d774a356b --- /dev/null +++ b/tests/topotests/bfd-profiles-topo1/r3/isisd.conf @@ -0,0 +1,15 @@ +hostname r3 +! +debug isis adj-packets +debug isis events +debug isis update-packets +! +interface r3-eth1 + ipv6 router isis lan + isis circuit-type level-1 + isis bfd +! +router isis lan + net 10.0000.0000.0000.0000.0000.0000.0000.0000.0001.00 + redistribute ipv6 connected level-1 +! diff --git a/tests/topotests/bfd-profiles-topo1/r3/zebra.conf b/tests/topotests/bfd-profiles-topo1/r3/zebra.conf new file mode 100644 index 0000000000..2297bfafe9 --- /dev/null +++ b/tests/topotests/bfd-profiles-topo1/r3/zebra.conf @@ -0,0 +1,12 @@ +ipv6 forwarding +! +interface lo + ip address 10.254.254.3/32 +! +interface r3-eth0 + ip address 172.16.1.1/24 + ipv6 address 2001:db8:1::1/64 +! +interface r3-eth1 + ipv6 address 2001:db8:2::1/64 +! diff --git a/tests/topotests/bfd-profiles-topo1/r4/bfd-peers-initial.json b/tests/topotests/bfd-profiles-topo1/r4/bfd-peers-initial.json new file mode 100644 index 0000000000..c8bc4c20e9 --- /dev/null +++ b/tests/topotests/bfd-profiles-topo1/r4/bfd-peers-initial.json @@ -0,0 +1,41 @@ +[ + { + "detect-multiplier": 3, + "diagnostic": "ok", + "id": "*", + "interface": "r4-eth0", + "local": "*", + "multihop": false, + "peer": "*", + "receive-interval": 300, + "remote-detect-multiplier": 3, + "remote-diagnostic": "ok", + "remote-id": "*", + "remote-receive-interval": 300, + "remote-transmit-interval": 300, + "status": "up", + "transmit-interval": 300, + "uptime": "*", + "vrf": "default" + }, + { + "detect-multiplier": 3, + "diagnostic": "ok", + "id": "*", + "interface": "r4-eth1", + "local": "*", + "multihop": false, + "peer": "*", + "receive-interval": 300, + "remote-detect-multiplier": 3, + "remote-diagnostic": "ok", + "remote-echo-interval": 50, + "remote-id": "*", + "remote-receive-interval": 300, + "remote-transmit-interval": 300, + "status": "up", + "transmit-interval": 300, + "uptime": "*", + "vrf": "default" + } +] diff --git a/tests/topotests/bfd-profiles-topo1/r4/bfdd.conf b/tests/topotests/bfd-profiles-topo1/r4/bfdd.conf new file mode 100644 index 0000000000..36ef4f0403 --- /dev/null +++ b/tests/topotests/bfd-profiles-topo1/r4/bfdd.conf @@ -0,0 +1,6 @@ +debug bfd peer +debug bfd network +debug bfd zebra +! +bfd +! diff --git a/tests/topotests/bfd-profiles-topo1/r4/bgpd.conf b/tests/topotests/bfd-profiles-topo1/r4/bgpd.conf new file mode 100644 index 0000000000..7c4b39b020 --- /dev/null +++ b/tests/topotests/bfd-profiles-topo1/r4/bgpd.conf @@ -0,0 +1,17 @@ +debug bgp neighbor-events +! +router bgp 200 + bgp router-id 10.254.254.4 + no bgp ebgp-requires-policy + neighbor 2001:db8:1::2 remote-as 100 + neighbor 2001:db8:1::2 ebgp-multihop 2 + neighbor 2001:db8:1::2 bfd profile fasttx + address-family ipv4 unicast + redistribute connected + exit-address-family + address-family ipv6 unicast + redistribute connected + neighbor 2001:db8:1::2 activate + exit-address-family + ! +! diff --git a/tests/topotests/bfd-profiles-topo1/r4/isisd.conf b/tests/topotests/bfd-profiles-topo1/r4/isisd.conf new file mode 100644 index 0000000000..477740087d --- /dev/null +++ b/tests/topotests/bfd-profiles-topo1/r4/isisd.conf @@ -0,0 +1,15 @@ +hostname r4 +! +debug isis adj-packets +debug isis events +debug isis update-packets +! +interface r4-eth0 + ipv6 router isis lan + isis circuit-type level-1 + isis bfd +! +router isis lan + net 10.0000.0000.0000.0000.0000.0000.0000.0000.0002.00 + redistribute ipv6 connected level-1 +! diff --git a/tests/topotests/bfd-profiles-topo1/r4/ospf6d.conf b/tests/topotests/bfd-profiles-topo1/r4/ospf6d.conf new file mode 100644 index 0000000000..84157de24d --- /dev/null +++ b/tests/topotests/bfd-profiles-topo1/r4/ospf6d.conf @@ -0,0 +1,8 @@ +interface r4-eth1 + ipv6 ospf6 bfd +! +router ospf6 + ospf6 router-id 10.254.254.4 + redistribute connected + interface r4-eth1 area 0.0.0.0 +! diff --git a/tests/topotests/bfd-profiles-topo1/r4/zebra.conf b/tests/topotests/bfd-profiles-topo1/r4/zebra.conf new file mode 100644 index 0000000000..753041f952 --- /dev/null +++ b/tests/topotests/bfd-profiles-topo1/r4/zebra.conf @@ -0,0 +1,12 @@ +ipv6 forwarding +! +interface lo + ip address 10.254.254.4/32 +! +interface r4-eth0 + ipv6 address 2001:db8:2::2/64 +! +interface r4-eth1 + ip address 172.16.3.1/24 + ipv6 address 2001:db8:3::1/64 +! diff --git a/tests/topotests/bfd-profiles-topo1/r5/bfd-peers-initial.json b/tests/topotests/bfd-profiles-topo1/r5/bfd-peers-initial.json new file mode 100644 index 0000000000..fcb090959e --- /dev/null +++ b/tests/topotests/bfd-profiles-topo1/r5/bfd-peers-initial.json @@ -0,0 +1,21 @@ +[ + { + "detect-multiplier": 3, + "diagnostic": "ok", + "id": "*", + "interface": "r5-eth0", + "local": "*", + "multihop": false, + "peer": "*", + "receive-interval": 300, + "remote-detect-multiplier": 3, + "remote-diagnostic": "ok", + "remote-id": "*", + "remote-receive-interval": 300, + "remote-transmit-interval": 300, + "status": "up", + "transmit-interval": 300, + "uptime": "*", + "vrf": "default" + } +] diff --git a/tests/topotests/bfd-profiles-topo1/r5/bfdd.conf b/tests/topotests/bfd-profiles-topo1/r5/bfdd.conf new file mode 100644 index 0000000000..74dae5a60d --- /dev/null +++ b/tests/topotests/bfd-profiles-topo1/r5/bfdd.conf @@ -0,0 +1,11 @@ +debug bfd peer +debug bfd network +debug bfd zebra +! +bfd + ! profile is commented out on purpose. + !profile fasttx + ! receive-interval 250 + ! transmit-interval 250 + !! +! diff --git a/tests/topotests/bfd-profiles-topo1/r5/ospf6d.conf b/tests/topotests/bfd-profiles-topo1/r5/ospf6d.conf new file mode 100644 index 0000000000..970c713558 --- /dev/null +++ b/tests/topotests/bfd-profiles-topo1/r5/ospf6d.conf @@ -0,0 +1,8 @@ +interface r5-eth0 + ipv6 ospf6 bfd +! +router ospf6 + ospf6 router-id 10.254.254.5 + redistribute connected + interface r5-eth0 area 0.0.0.0 +! diff --git a/tests/topotests/bfd-profiles-topo1/r5/zebra.conf b/tests/topotests/bfd-profiles-topo1/r5/zebra.conf new file mode 100644 index 0000000000..de8ae1644b --- /dev/null +++ b/tests/topotests/bfd-profiles-topo1/r5/zebra.conf @@ -0,0 +1,6 @@ +interface lo + ip address 10.254.254.5/32 +! +interface r5-eth0 + ipv6 address 2001:db8:3::2/64 +! diff --git a/tests/topotests/bfd-profiles-topo1/r6/bfd-peers-initial.json b/tests/topotests/bfd-profiles-topo1/r6/bfd-peers-initial.json new file mode 100644 index 0000000000..4e6fa869ba --- /dev/null +++ b/tests/topotests/bfd-profiles-topo1/r6/bfd-peers-initial.json @@ -0,0 +1,20 @@ +[ + { + "detect-multiplier": 3, + "diagnostic": "ok", + "id": "*", + "interface": "r6-eth0", + "multihop": false, + "peer": "172.16.100.1", + "receive-interval": 300, + "remote-detect-multiplier": 3, + "remote-diagnostic": "ok", + "remote-id": "*", + "remote-receive-interval": 300, + "remote-transmit-interval": 300, + "status": "up", + "transmit-interval": 300, + "uptime": "*", + "vrf": "default" + } +] diff --git a/tests/topotests/bfd-profiles-topo1/r6/bfdd.conf b/tests/topotests/bfd-profiles-topo1/r6/bfdd.conf new file mode 100644 index 0000000000..74dae5a60d --- /dev/null +++ b/tests/topotests/bfd-profiles-topo1/r6/bfdd.conf @@ -0,0 +1,11 @@ +debug bfd peer +debug bfd network +debug bfd zebra +! +bfd + ! profile is commented out on purpose. + !profile fasttx + ! receive-interval 250 + ! transmit-interval 250 + !! +! diff --git a/tests/topotests/bfd-profiles-topo1/r6/ospfd.conf b/tests/topotests/bfd-profiles-topo1/r6/ospfd.conf new file mode 100644 index 0000000000..f16844401e --- /dev/null +++ b/tests/topotests/bfd-profiles-topo1/r6/ospfd.conf @@ -0,0 +1,8 @@ +interface r6-eth0 + ip ospf area 0 + ip ospf bfd +! +router ospf + ospf router-id 10.254.254.6 + redistribute connected +! diff --git a/tests/topotests/bfd-profiles-topo1/r6/zebra.conf b/tests/topotests/bfd-profiles-topo1/r6/zebra.conf new file mode 100644 index 0000000000..c0804b94a7 --- /dev/null +++ b/tests/topotests/bfd-profiles-topo1/r6/zebra.conf @@ -0,0 +1,6 @@ +interface lo + ip address 10.254.254.6/32 +! +interface r6-eth0 + ip address 172.16.100.2/24 +! diff --git a/tests/topotests/bfd-profiles-topo1/test_bfd_profiles_topo1.dot b/tests/topotests/bfd-profiles-topo1/test_bfd_profiles_topo1.dot new file mode 100644 index 0000000000..a3936093aa --- /dev/null +++ b/tests/topotests/bfd-profiles-topo1/test_bfd_profiles_topo1.dot @@ -0,0 +1,97 @@ +## 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="bfd-profiles-topo1"; + + # Routers + r1 [ + shape=doubleoctagon, + label="r1", + fillcolor="#f08080", + style=filled, + ]; + r2 [ + shape=doubleoctagon + label="r2", + fillcolor="#f08080", + style=filled, + ]; + r3 [ + shape=doubleoctagon + label="r3", + fillcolor="#f08080", + style=filled, + ]; + r4 [ + shape=doubleoctagon + label="r4", + fillcolor="#f08080", + style=filled, + ]; + r5 [ + shape=doubleoctagon + label="r5", + fillcolor="#f08080", + style=filled, + ]; + + # Switches + sw1 [ + shape=oval, + label="sw1\n172.16.0.0/24", + fillcolor="#d0e0d0", + style=filled, + ]; + sw2 [ + shape=oval, + label="sw2\n172.16.1.0/24\n2001:db8:1::/64", + fillcolor="#d0e0d0", + style=filled, + ]; + sw3 [ + shape=oval, + label="sw3\n2001:db8:2::/64", + fillcolor="#d0e0d0", + style=filled, + ]; + sw4 [ + shape=oval, + label="sw4\n2001:db8:3::/64", + fillcolor="#d0e0d0", + style=filled, + ]; + sw5 [ + shape=oval, + label="sw5\n172.16.100.0/24", + fillcolor="#d0e0d0", + style=filled, + ]; + + # Connections + r1 -- sw1 [label="eth0"]; + r2 -- sw1 [label="eth0"]; + + r2 -- sw2 [label="eth1"]; + r3 -- sw2 [label="eth0"]; + + r3 -- sw3 [label="eth1"]; + r4 -- sw3 [label="eth0"]; + + r4 -- sw4 [label="eth1"]; + r5 -- sw4 [label="eth0"]; + + r1 -- sw5 [label="eth1"]; + r6 -- sw5 [label="eth0"]; +} diff --git a/tests/topotests/bfd-profiles-topo1/test_bfd_profiles_topo1.png b/tests/topotests/bfd-profiles-topo1/test_bfd_profiles_topo1.png Binary files differnew file mode 100644 index 0000000000..775fae13f1 --- /dev/null +++ b/tests/topotests/bfd-profiles-topo1/test_bfd_profiles_topo1.png diff --git a/tests/topotests/bfd-profiles-topo1/test_bfd_profiles_topo1.py b/tests/topotests/bfd-profiles-topo1/test_bfd_profiles_topo1.py new file mode 100644 index 0000000000..02385b32e5 --- /dev/null +++ b/tests/topotests/bfd-profiles-topo1/test_bfd_profiles_topo1.py @@ -0,0 +1,198 @@ +#!/usr/bin/env python + +# +# test_bfd_profiles_topo1.py +# Part of NetDEF Topology Tests +# +# Copyright (c) 2020 by +# Network Device Education Foundation, Inc. ("NetDEF") +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +""" +test_bfd_profiles_topo1.py: Test the FRR BFD profile protocol integration. +""" + +import os +import sys +import json +from functools import partial +import pytest + +# Save the Current Working Directory to find configuration files. +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger + +# Required to instantiate the topology builder class. +from mininet.topo import Topo + + +class BFDProfTopo(Topo): + "Test topology builder" + + def build(self, *_args, **_opts): + "Build function" + tgen = get_topogen(self) + + # Create 6 routers + for routern in range(1, 7): + tgen.add_router("r{}".format(routern)) + + switch = tgen.add_switch("s1") + switch.add_link(tgen.gears["r1"]) + switch.add_link(tgen.gears["r2"]) + + switch = tgen.add_switch("s2") + switch.add_link(tgen.gears["r2"]) + switch.add_link(tgen.gears["r3"]) + + switch = tgen.add_switch("s3") + switch.add_link(tgen.gears["r3"]) + switch.add_link(tgen.gears["r4"]) + + 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["r6"]) + + +def setup_module(mod): + "Sets up the pytest environment" + tgen = Topogen(BFDProfTopo, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + for rname, router in router_list.iteritems(): + daemon_file = "{}/{}/bfdd.conf".format(CWD, rname) + if os.path.isfile(daemon_file): + router.load_config(TopoRouter.RD_BFD, daemon_file) + + daemon_file = "{}/{}/bgpd.conf".format(CWD, rname) + if os.path.isfile(daemon_file): + router.load_config(TopoRouter.RD_BGP, daemon_file) + + daemon_file = "{}/{}/isisd.conf".format(CWD, rname) + if os.path.isfile(daemon_file): + router.load_config(TopoRouter.RD_ISIS, daemon_file) + + daemon_file = "{}/{}/ospfd.conf".format(CWD, rname) + if os.path.isfile(daemon_file): + router.load_config(TopoRouter.RD_OSPF, daemon_file) + + daemon_file = "{}/{}/ospf6d.conf".format(CWD, rname) + if os.path.isfile(daemon_file): + router.load_config(TopoRouter.RD_OSPF6, daemon_file) + + daemon_file = "{}/{}/zebra.conf".format(CWD, rname) + if os.path.isfile(daemon_file): + router.load_config(TopoRouter.RD_ZEBRA, daemon_file) + + # Initialize all routers. + tgen.start_router() + + +def teardown_module(_mod): + "Teardown the pytest environment" + tgen = get_topogen() + tgen.stop_topology() + +def test_wait_protocols_convergence(): + "Wait for all protocols to converge" + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("waiting for protocols to converge") + + def expect_loopback_route(router, iptype, route, proto): + "Wait until route is present on RIB for protocol." + logger.info('waiting route {} in {}'.format(route, router)) + test_func = partial( + topotest.router_json_cmp, + tgen.gears[router], + 'show {} route json'.format(iptype), + { route: [{ 'protocol': proto }] } + ) + _, result = topotest.run_and_expect(test_func, None, count=130, wait=1) + assertmsg = '"{}" OSPF convergence failure'.format(router) + assert result is None, assertmsg + + + # Wait for R1 <-> R6 convergence. + expect_loopback_route('r1', 'ip', '10.254.254.6/32', 'ospf') + + # Wait for R6 <-> R1 convergence. + expect_loopback_route('r6', 'ip', '10.254.254.1/32', 'ospf') + + # Wait for R2 <-> R3 convergence. + expect_loopback_route('r2', 'ip', '10.254.254.3/32', 'bgp') + + # Wait for R3 <-> R2 convergence. + expect_loopback_route('r3', 'ip', '10.254.254.2/32', 'bgp') + + # Wait for R3 <-> R4 convergence. + expect_loopback_route('r3', 'ipv6', '2001:db8:3::/64', 'isis') + + # Wait for R4 <-> R3 convergence. + expect_loopback_route('r4', 'ipv6', '2001:db8:1::/64', 'isis') + + # Wait for R4 <-> R5 convergence. + expect_loopback_route('r4', 'ipv6', '2001:db8:3::/64', 'ospf6') + + # Wait for R5 <-> R4 convergence. + expect_loopback_route('r5', 'ipv6', '2001:db8:2::/64', 'ospf6') + + +def test_bfd_profile_values(): + "Assert that the BFD peers can find themselves." + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("waiting for bfd peers to go up and checking profile values") + + for router in tgen.routers().values(): + json_file = "{}/{}/bfd-peers-initial.json".format(CWD, router.name) + expected = json.loads(open(json_file).read()) + test_func = partial( + topotest.router_json_cmp, router, "show bfd peers json", expected + ) + _, result = topotest.run_and_expect(test_func, None, count=12, wait=0.5) + assertmsg = '"{}" JSON output mismatches'.format(router.name) + assert result is None, assertmsg + + +def test_memory_leak(): + "Run the memory leak test and report results." + tgen = get_topogen() + if not tgen.is_memleak_enabled(): + pytest.skip("Memory leak test/report is disabled") + + tgen.report_memory_leaks() + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/lib/topotest.py b/tests/topotests/lib/topotest.py index 9d945d5262..b19c9063e3 100644 --- a/tests/topotests/lib/topotest.py +++ b/tests/topotests/lib/topotest.py @@ -991,14 +991,28 @@ class Router(Node): super(Router, self).terminate() os.system("chmod -R go+rw /tmp/topotests") + # Return count of running daemons + def countDaemons(self): + numRunning = 0 + rundaemons = self.cmd("ls -1 /var/run/%s/*.pid" % self.routertype) + errors = "" + if re.search(r"No such file or directory", rundaemons): + return 0 + if rundaemons is not None: + for d in StringIO.StringIO(rundaemons): + daemonpid = self.cmd("cat %s" % d.rstrip()).rstrip() + if daemonpid.isdigit() and pid_exists(int(daemonpid)): + numRunning += 1 + return numRunning + def stopRouter(self, wait=True, assertOnError=True, minErrorVersion="5.1"): - # Stop Running Quagga or FRR Daemons + # Stop Running FRR Daemons + numRunning = 0 rundaemons = self.cmd("ls -1 /var/run/%s/*.pid" % self.routertype) errors = "" if re.search(r"No such file or directory", rundaemons): return errors if rundaemons is not None: - numRunning = 0 for d in StringIO.StringIO(rundaemons): daemonpid = self.cmd("cat %s" % d.rstrip()).rstrip() if daemonpid.isdigit() and pid_exists(int(daemonpid)): @@ -1011,8 +1025,15 @@ class Router(Node): self.waitOutput() if pid_exists(int(daemonpid)): numRunning += 1 + + if wait and numRunning > 0: + counter = 5 + while counter > 0 and numRunning > 0: + sleep(2, "{}: waiting for daemons stopping".format(self.name)) + numRunning = self.countDaemons() + counter -= 1 + if wait and numRunning > 0: - sleep(2, "{}: waiting for daemons stopping".format(self.name)) # 2nd round of kill if daemons didn't exit for d in StringIO.StringIO(rundaemons): daemonpid = self.cmd("cat %s" % d.rstrip()).rstrip() @@ -1026,6 +1047,7 @@ class Router(Node): self.cmd("kill -7 %s" % daemonpid) self.waitOutput() self.cmd("rm -- {}".format(d.rstrip())) + if wait: errors = self.checkRouterCores(reportOnce=True) if self.checkRouterVersion("<", minErrorVersion): @@ -1144,130 +1166,103 @@ class Router(Node): logger.info("BFD Test, but no bfdd compiled or installed") return "BFD Test, but no bfdd compiled or installed" - self.restartRouter() - return "" + return self.startRouterDaemons() + + + def getStdErr(self, daemon): + return self.getLog("err", daemon) + + def getStdOut(self, daemon): + return self.getLog("out", daemon) + + def getLog(self, log, daemon): + return self.cmd("cat {}/{}/{}.{}".format(self.logdir, self.name, daemon, log)) + + def startRouterDaemons(self, daemons=None): + "Starts all FRR daemons for this router." - def restartRouter(self): # Starts actual daemons without init (ie restart) # cd to per node directory self.cmd("cd {}/{}".format(self.logdir, self.name)) self.cmd("umask 000") + # Re-enable to allow for report per run self.reportCores = True + + # XXX: glue code forward ported from removed function. if self.version == None: self.version = self.cmd( - os.path.join(self.daemondir, "bgpd") + " -v" + os.path.join(self.daemondir, 'bgpd') + ' -v' ).split()[2] logger.info("{}: running version: {}".format(self.name, self.version)) + + # If `daemons` was specified then some upper API called us with + # specific daemons, otherwise just use our own configuration. + daemons_list = [] + if daemons is None: + # Append all daemons configured. + for daemon in self.daemons: + if self.daemons[daemon] == 1: + daemons_list.append(daemon) + # Start Zebra first - if self.daemons["zebra"] == 1: + if 'zebra' in daemons_list: zebra_path = os.path.join(self.daemondir, "zebra") zebra_option = self.daemons_options["zebra"] self.cmd( - "{0} {1} > zebra.out 2> zebra.err &".format( + "{0} {1} --log stdout --log-level debug -d > zebra.out 2> zebra.err".format( zebra_path, zebra_option, self.logdir, self.name ) ) - self.waitOutput() logger.debug("{}: {} zebra started".format(self, self.routertype)) - sleep(1, "{}: waiting for zebra to start".format(self.name)) + + # Remove `zebra` so we don't attempt to start it again. + while 'zebra' in daemons_list: + daemons_list.remove('zebra') + # Start staticd next if required - if self.daemons["staticd"] == 1: + if 'staticd' in daemons_list: staticd_path = os.path.join(self.daemondir, "staticd") staticd_option = self.daemons_options["staticd"] self.cmd( - "{0} {1} > staticd.out 2> staticd.err &".format( + "{0} {1} --log stdout --log-level debug -d > staticd.out 2> staticd.err".format( staticd_path, staticd_option, self.logdir, self.name ) ) - self.waitOutput() logger.debug("{}: {} staticd started".format(self, self.routertype)) + + # Remove `staticd` so we don't attempt to start it again. + while 'staticd' in daemons_list: + daemons_list.remove('staticd') + # Fix Link-Local Addresses # Somehow (on Mininet only), Zebra removes the IPv6 Link-Local addresses on start. Fix this self.cmd( "for i in `ls /sys/class/net/` ; do mac=`cat /sys/class/net/$i/address`; IFS=':'; set $mac; unset IFS; ip address add dev $i scope link fe80::$(printf %02x $((0x$1 ^ 2)))$2:${3}ff:fe$4:$5$6/64; done" ) + # Now start all the other daemons for daemon in self.daemons: # Skip disabled daemons and zebra - if self.daemons[daemon] == 0 or daemon == "zebra" or daemon == "staticd": + if self.daemons[daemon] == 0: continue + daemon_path = os.path.join(self.daemondir, daemon) self.cmd( - "{0} {1} > {2}.out 2> {2}.err &".format( + "{0} {1} --log stdout --log-level debug -d > {2}.out 2> {2}.err".format( daemon_path, self.daemons_options.get(daemon, ""), daemon ) ) - self.waitOutput() logger.debug("{}: {} {} started".format(self, self.routertype, daemon)) - def getStdErr(self, daemon): - return self.getLog("err", daemon) - - def getStdOut(self, daemon): - return self.getLog("out", daemon) - - def getLog(self, log, daemon): - return self.cmd("cat {}/{}/{}.{}".format(self.logdir, self.name, daemon, log)) - - def startRouterDaemons(self, daemons): - # Starts actual daemons without init (ie restart) - # cd to per node directory - self.cmd('cd {}/{}'.format(self.logdir, self.name)) - self.cmd('umask 000') - #Re-enable to allow for report per run - self.reportCores = True + # Check if daemons are running. rundaemons = self.cmd('ls -1 /var/run/%s/*.pid' % self.routertype) - - for daemon in daemons: - if daemon == 'zebra': - # Start Zebra first - if self.daemons['zebra'] == 1: - zebra_path = os.path.join(self.daemondir, 'zebra') - zebra_option = self.daemons_options['zebra'] - self.cmd('{0} {1} > zebra.out 2> zebra.err &'.format( - zebra_path, zebra_option, self.logdir, self.name - )) - self.waitOutput() - logger.debug('{}: {} zebra started'.format(self, self.routertype)) - sleep(1, '{}: waiting for zebra to start'.format(self.name)) - - # Fix Link-Local Addresses - # Somehow (on Mininet only), Zebra removes the IPv6 Link-Local - # addresses on start. Fix this - self.cmd('for i in `ls /sys/class/net/` ; do mac=`cat /sys/class/net/$i/address`; IFS=\':\'; set $mac; unset IFS; ip address add dev $i scope link fe80::$(printf %02x $((0x$1 ^ 2)))$2:${3}ff:fe$4:$5$6/64; done') - - if daemon == 'staticd': - # Start staticd next if required - if self.daemons['staticd'] == 1: - staticd_path = os.path.join(self.daemondir, 'staticd') - staticd_option = self.daemons_options['staticd'] - self.cmd('{0} {1} > staticd.out 2> staticd.err &'.format( - staticd_path, staticd_option, self.logdir, self.name - )) - self.waitOutput() - logger.debug('{}: {} staticd started'.format(self, self.routertype)) - sleep(1, '{}: waiting for staticd to start'.format(self.name)) - - # Now start all the daemons - # Skip disabled daemons and zebra - if self.daemons[daemon] == 0 or daemon == 'zebra' or daemon == 'staticd': - continue - daemon_path = os.path.join(self.daemondir, daemon) - self.cmd('{0} > {1}.out 2> {1}.err &'.format( - daemon_path, daemon - )) - self.waitOutput() - logger.debug('{}: {} {} started'.format(self, self.routertype, daemon)) - sleep(1, '{}: waiting for {} to start'.format(self.name, daemon)) - - rundaemons = self.cmd('ls -1 /var/run/%s/*.pid' % self.routertype) - if re.search(r"No such file or directory", rundaemons): return "Daemons are not running" return "" + def killRouterDaemons(self, daemons, wait=True, assertOnError=True, minErrorVersion='5.1'): # Kill Running Quagga or FRR specific diff --git a/tools/coccinelle/argv_find.cocci b/tools/coccinelle/argv_find.cocci new file mode 100644 index 0000000000..f13b035d7a --- /dev/null +++ b/tools/coccinelle/argv_find.cocci @@ -0,0 +1,16 @@ +@@ +identifier idx; +identifier argv; +identifier argc; +expression e1; +expression e2; +@@ + +- argv_find(argv, argc, e1, &idx); + if ( +- idx ++ argv_find(argv, argc, e1, &idx) + ) + { + e2; + } diff --git a/vtysh/vtysh_config.c b/vtysh/vtysh_config.c index abbb111f9d..61bcf3b658 100644 --- a/vtysh/vtysh_config.c +++ b/vtysh/vtysh_config.c @@ -34,7 +34,7 @@ DEFINE_MTYPE_STATIC(MVTYSH, VTYSH_CONFIG_LINE, "Vtysh configuration line") vector configvec; -PREDECL_RBTREE_UNIQ(config_master); +PREDECL_LIST(config_master); struct config { /* Configuration node name. */ @@ -72,11 +72,6 @@ static struct config *config_new(void) return config; } -static int config_cmp(const struct config *c1, const struct config *c2) -{ - return strcmp(c1->name, c2->name); -} - static void config_del(struct config *config) { list_delete(&config->line); @@ -84,13 +79,15 @@ static void config_del(struct config *config) XFREE(MTYPE_VTYSH_CONFIG, config); } -DECLARE_RBTREE_UNIQ(config_master, struct config, rbt_item, config_cmp) +DECLARE_LIST(config_master, struct config, rbt_item) static struct config *config_get(int index, const char *line) { - struct config *config; + struct config *config, *config_loop; struct config_master_head *master; + config = config_loop = NULL; + master = vector_lookup_ensure(configvec, index); if (!master) { @@ -99,8 +96,12 @@ static struct config *config_get(int index, const char *line) vector_set_index(configvec, index, master); } - const struct config config_ref = { .name = (char *)line }; - config = config_master_find(master, &config_ref); + frr_each (config_master, master, config_loop) { + if (strcmp(config_loop->name, line) == 0) { + config = config_loop; + break; + } + } if (!config) { config = config_new(); @@ -109,7 +110,7 @@ static struct config *config_get(int index, const char *line) config->line->cmp = (int (*)(void *, void *))line_cmp; config->name = XSTRDUP(MTYPE_VTYSH_CONFIG_LINE, line); config->index = index; - config_master_add(master, config); + config_master_add_tail(master, config); } return config; } |
