diff options
95 files changed, 982 insertions, 190 deletions
diff --git a/bfdd/subdir.am b/bfdd/subdir.am index ed1d3962bf..9aa522f3f0 100644 --- a/bfdd/subdir.am +++ b/bfdd/subdir.am @@ -8,7 +8,7 @@ sbin_PROGRAMS += bfdd/bfdd dist_examples_DATA += bfdd/bfdd.conf.sample vtysh_scan += $(top_srcdir)/bfdd/bfdd_vty.c vtysh_scan += $(top_srcdir)/bfdd/bfdd_cli.c -man8 += $(MANBUILD)/bfdd.8 +man8 += $(MANBUILD)/frr-bfdd.8 endif bfdd_libbfd_a_SOURCES = \ diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c index f17bc7b8c0..23b893c1c8 100644 --- a/bgpd/bgp_open.c +++ b/bgpd/bgp_open.c @@ -747,6 +747,12 @@ static int bgp_capability_hostname(struct peer *peer, if (len) { str[len] = '\0'; + + if (peer->domainname != NULL) { + XFREE(MTYPE_BGP_PEER_HOST, peer->domainname); + peer->domainname = NULL; + } + peer->domainname = XSTRDUP(MTYPE_BGP_PEER_HOST, str); } diff --git a/bgpd/bgp_pbr.c b/bgpd/bgp_pbr.c index 83194e010a..14f5fefb20 100644 --- a/bgpd/bgp_pbr.c +++ b/bgpd/bgp_pbr.c @@ -1725,7 +1725,7 @@ static void bgp_pbr_policyroute_remove_from_zebra_unit( temp.type = IPSET_NET_NET; } if (bpf->vrf_id == VRF_UNKNOWN) /* XXX case BGP destroy */ - temp.vrf_id = 0; + temp.vrf_id = VRF_DEFAULT; else temp.vrf_id = bpf->vrf_id; bpme = &temp2; diff --git a/bgpd/bgp_updgrp.c b/bgpd/bgp_updgrp.c index 5f3f5cde9a..5b3eb2c719 100644 --- a/bgpd/bgp_updgrp.c +++ b/bgpd/bgp_updgrp.c @@ -143,6 +143,7 @@ static void conf_copy(struct peer *dst, struct peer *src, afi_t afi, dst->v_routeadv = src->v_routeadv; dst->flags = src->flags; dst->af_flags[afi][safi] = src->af_flags[afi][safi]; + dst->pmax_out[afi][safi] = src->pmax_out[afi][safi]; XFREE(MTYPE_BGP_PEER_HOST, dst->host); dst->host = XSTRDUP(MTYPE_BGP_PEER_HOST, src->host); diff --git a/bgpd/bgp_updgrp.h b/bgpd/bgp_updgrp.h index bb547454f2..fe654bb3e3 100644 --- a/bgpd/bgp_updgrp.h +++ b/bgpd/bgp_updgrp.h @@ -208,7 +208,7 @@ struct update_subgroup { struct bgp_synchronize *sync; /* send prefix count */ - unsigned long scount; + uint32_t scount; /* announcement attribute hash */ struct hash *hash; diff --git a/bgpd/bgp_updgrp_adv.c b/bgpd/bgp_updgrp_adv.c index 07aa3eafb6..26dda8ebda 100644 --- a/bgpd/bgp_updgrp_adv.c +++ b/bgpd/bgp_updgrp_adv.c @@ -64,6 +64,12 @@ static int bgp_adj_out_compare(const struct bgp_adj_out *o1, if (o1->subgroup > o2->subgroup) return 1; + if (o1->addpath_tx_id < o2->addpath_tx_id) + return -1; + + if (o1->addpath_tx_id > o2->addpath_tx_id) + return 1; + return 0; } RB_GENERATE(bgp_adj_out_rb, bgp_adj_out, adj_entry, bgp_adj_out_compare); @@ -72,32 +78,17 @@ static inline struct bgp_adj_out *adj_lookup(struct bgp_node *rn, struct update_subgroup *subgrp, uint32_t addpath_tx_id) { - struct bgp_adj_out *adj, lookup; - struct peer *peer; - afi_t afi; - safi_t safi; - int addpath_capable; + struct bgp_adj_out lookup; if (!rn || !subgrp) return NULL; - peer = SUBGRP_PEER(subgrp); - afi = SUBGRP_AFI(subgrp); - safi = SUBGRP_SAFI(subgrp); - addpath_capable = bgp_addpath_encode_tx(peer, afi, safi); - /* update-groups that do not support addpath will pass 0 for - * addpath_tx_id so do not both matching against it */ + * addpath_tx_id. */ lookup.subgroup = subgrp; - adj = RB_FIND(bgp_adj_out_rb, &rn->adj_out, &lookup); - if (adj) { - if (addpath_capable) { - if (adj->addpath_tx_id == addpath_tx_id) - return adj; - } else - return adj; - } - return NULL; + lookup.addpath_tx_id = addpath_tx_id; + + return RB_FIND(bgp_adj_out_rb, &rn->adj_out, &lookup); } static void adj_free(struct bgp_adj_out *adj) @@ -403,13 +394,14 @@ struct bgp_adj_out *bgp_adj_out_alloc(struct update_subgroup *subgrp, adj = XCALLOC(MTYPE_BGP_ADJ_OUT, sizeof(struct bgp_adj_out)); adj->subgroup = subgrp; + adj->addpath_tx_id = addpath_tx_id; + if (rn) { RB_INSERT(bgp_adj_out_rb, &rn->adj_out, adj); bgp_lock_node(rn); adj->rn = rn; } - adj->addpath_tx_id = addpath_tx_id; TAILQ_INSERT_TAIL(&(subgrp->adjq), adj, subgrp_adj_train); SUBGRP_INCR_STAT(subgrp, adj_count); return adj; diff --git a/bgpd/bgp_updgrp_packet.c b/bgpd/bgp_updgrp_packet.c index 9329c8d892..39eb065288 100644 --- a/bgpd/bgp_updgrp_packet.c +++ b/bgpd/bgp_updgrp_packet.c @@ -744,6 +744,22 @@ struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp) addpath_tx_id = adj->addpath_tx_id; path = adv->pathi; + /* Check if we need to add a prefix to the packet if + * maximum-prefix-out is set for the peer. + */ + if (CHECK_FLAG(peer->af_flags[afi][safi], + PEER_FLAG_MAX_PREFIX_OUT) + && subgrp->scount >= peer->pmax_out[afi][safi]) { + if (BGP_DEBUG(update, UPDATE_OUT) + || BGP_DEBUG(update, UPDATE_PREFIX)) { + zlog_debug( + "%s reached maximum prefix to be send (%" PRIu32 + ")", + peer->host, peer->pmax_out[afi][safi]); + } + goto next; + } + space_remaining = STREAM_CONCAT_REMAIN(s, snlri, STREAM_SIZE(s)) - BGP_MAX_PACKET_SIZE_OVERFLOW; space_needed = @@ -894,7 +910,7 @@ struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp) subgrp->scount++; adj->attr = bgp_attr_intern(adv->baa->attr); - +next: adv = bgp_advertise_clean_subgroup(subgrp, adj); } diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 53d9732956..9dc6549d9c 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -6058,6 +6058,56 @@ static int peer_maximum_prefix_unset_vty(struct vty *vty, const char *ip_str, return bgp_vty_return(vty, ret); } +/* Maximum number of prefix to be sent to the neighbor. */ +DEFUN(neighbor_maximum_prefix_out, + neighbor_maximum_prefix_out_cmd, + "neighbor <A.B.C.D|X:X::X:X|WORD> maximum-prefix-out (1-4294967295)", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Maximum number of prefixes to be sent to this peer\n" + "Maximum no. of prefix limit\n") +{ + int idx_peer = 1; + int idx_number = 3; + struct peer *peer; + uint32_t max; + afi_t afi = bgp_node_afi(vty); + safi_t safi = bgp_node_safi(vty); + + peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg); + if (!peer) + return CMD_WARNING_CONFIG_FAILED; + + max = strtoul(argv[idx_number]->arg, NULL, 10); + + SET_FLAG(peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_OUT); + peer->pmax_out[afi][safi] = max; + + return CMD_SUCCESS; +} + +DEFUN(no_neighbor_maximum_prefix_out, + no_neighbor_maximum_prefix_out_cmd, + "no neighbor <A.B.C.D|X:X::X:X|WORD> maximum-prefix-out", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Maximum number of prefixes to be sent to this peer\n") +{ + int idx_peer = 2; + struct peer *peer; + afi_t afi = bgp_node_afi(vty); + safi_t safi = bgp_node_safi(vty); + + peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg); + if (!peer) + return CMD_WARNING_CONFIG_FAILED; + + peer->pmax_out[afi][safi] = 0; + + return CMD_SUCCESS; +} + /* Maximum number of prefix configuration. prefix count is different for each peer configuration. So this configuration can be set for each peer configuration. */ @@ -9191,6 +9241,11 @@ static void bgp_show_peer_afi(struct vty *vty, struct peer *p, afi_t afi, (PAF_SUBGRP(paf))->scount); /* Maximum prefix */ + if (CHECK_FLAG(p->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_OUT)) + json_object_int_add(json_addr, "prefixOutAllowedMax", + p->pmax_out[afi][safi]); + + /* Maximum prefix */ if (CHECK_FLAG(p->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX)) { json_object_int_add(json_addr, "prefixAllowedMax", p->pmax[afi][safi]); @@ -9476,6 +9531,13 @@ static void bgp_show_peer_afi(struct vty *vty, struct peer *p, afi_t afi, vty_out(vty, " %" PRIu32 " accepted prefixes\n", p->pcount[afi][safi]); + /* maximum-prefix-out */ + if (CHECK_FLAG(p->af_flags[afi][safi], + PEER_FLAG_MAX_PREFIX_OUT)) + vty_out(vty, + " Maximum allowed prefixes sent %" PRIu32 "\n", + p->pmax_out[afi][safi]); + /* Maximum prefix */ if (CHECK_FLAG(p->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX)) { vty_out(vty, @@ -13579,6 +13641,11 @@ static void bgp_config_write_peer_af(struct vty *vty, struct bgp *bgp, vty_out(vty, "\n"); } + /* maximum-prefix-out */ + if (peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_MAX_PREFIX_OUT)) + vty_out(vty, " neighbor %s maximum-prefix-out %" PRIu32 "\n", + addr, peer->pmax_out[afi][safi]); + /* Route server client. */ if (peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_RSERVER_CLIENT)) { @@ -15115,6 +15182,26 @@ void bgp_vty_init(void) install_element(BGP_VPNV6_NODE, &neighbor_unsuppress_map_cmd); install_element(BGP_VPNV6_NODE, &no_neighbor_unsuppress_map_cmd); + /* neighbor maximum-prefix-out commands. */ + install_element(BGP_NODE, &neighbor_maximum_prefix_out_cmd); + install_element(BGP_NODE, &no_neighbor_maximum_prefix_out_cmd); + install_element(BGP_IPV4_NODE, &neighbor_maximum_prefix_out_cmd); + install_element(BGP_IPV4_NODE, &no_neighbor_maximum_prefix_out_cmd); + install_element(BGP_IPV4M_NODE, &neighbor_maximum_prefix_out_cmd); + install_element(BGP_IPV4M_NODE, &no_neighbor_maximum_prefix_out_cmd); + install_element(BGP_IPV4L_NODE, &neighbor_maximum_prefix_out_cmd); + install_element(BGP_IPV4L_NODE, &no_neighbor_maximum_prefix_out_cmd); + install_element(BGP_IPV6_NODE, &neighbor_maximum_prefix_out_cmd); + install_element(BGP_IPV6_NODE, &no_neighbor_maximum_prefix_out_cmd); + install_element(BGP_IPV6M_NODE, &neighbor_maximum_prefix_out_cmd); + install_element(BGP_IPV6M_NODE, &no_neighbor_maximum_prefix_out_cmd); + install_element(BGP_IPV6L_NODE, &neighbor_maximum_prefix_out_cmd); + install_element(BGP_IPV6L_NODE, &no_neighbor_maximum_prefix_out_cmd); + install_element(BGP_VPNV4_NODE, &neighbor_maximum_prefix_out_cmd); + install_element(BGP_VPNV4_NODE, &no_neighbor_maximum_prefix_out_cmd); + install_element(BGP_VPNV6_NODE, &neighbor_maximum_prefix_out_cmd); + install_element(BGP_VPNV6_NODE, &no_neighbor_maximum_prefix_out_cmd); + /* "neighbor maximum-prefix" commands. */ install_element(BGP_NODE, &neighbor_maximum_prefix_hidden_cmd); install_element(BGP_NODE, diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 069c53d7df..c99ddaf0a6 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -1384,6 +1384,8 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p, if (bgp_debug_zebra(p)) { char prefix_buf[PREFIX_STRLEN]; char nh_buf[INET6_ADDRSTRLEN]; + char eth_buf[ETHER_ADDR_STRLEN + 7] = {'\0'}; + char buf1[ETHER_ADDR_STRLEN]; char label_buf[20]; int i; @@ -1421,13 +1423,19 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p, } label_buf[0] = '\0'; + eth_buf[0] = '\0'; if (has_valid_label && !CHECK_FLAG(api.flags, ZEBRA_FLAG_EVPN_ROUTE)) - sprintf(label_buf, "label %u", - api_nh->labels[0]); - zlog_debug(" nhop [%d]: %s if %u VRF %u %s", + snprintf(label_buf, sizeof(label_buf), + "label %u", api_nh->labels[0]); + if (CHECK_FLAG(api.flags, ZEBRA_FLAG_EVPN_ROUTE) + && !is_zero_mac(&api_nh->rmac)) + snprintf(eth_buf, sizeof(eth_buf), " RMAC %s", + prefix_mac2str(&api_nh->rmac, + buf1, sizeof(buf1))); + zlog_debug(" nhop [%d]: %s if %u VRF %u %s %s", i + 1, nh_buf, api_nh->ifindex, - api_nh->vrf_id, label_buf); + api_nh->vrf_id, label_buf, eth_buf); } } diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 7d81579009..4c4787ed5b 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -988,6 +988,7 @@ struct peer { #define PEER_FLAG_WEIGHT (1 << 24) /* weight */ #define PEER_FLAG_ALLOWAS_IN_ORIGIN (1 << 25) /* allowas-in origin */ #define PEER_FLAG_SEND_LARGE_COMMUNITY (1 << 26) /* Send large Communities */ +#define PEER_FLAG_MAX_PREFIX_OUT (1 << 27) /* outgoing maximum prefix */ enum bgp_addpath_strat addpath_type[AFI_MAX][SAFI_MAX]; @@ -1120,9 +1121,6 @@ struct peer { /* timestamp when the last msg was written */ _Atomic time_t last_update; - /* Send prefix count. */ - unsigned long scount[AFI_MAX][SAFI_MAX]; - /* Notify data. */ struct bgp_notify notify; @@ -1173,6 +1171,9 @@ struct peer { uint16_t pmax_restart[AFI_MAX][SAFI_MAX]; #define MAXIMUM_PREFIX_THRESHOLD_DEFAULT 75 + /* Send prefix count. */ + uint32_t pmax_out[AFI_MAX][SAFI_MAX]; + /* allowas-in. */ char allowas_in[AFI_MAX][SAFI_MAX]; diff --git a/bgpd/subdir.am b/bgpd/subdir.am index 203cf779b9..ff15248a98 100644 --- a/bgpd/subdir.am +++ b/bgpd/subdir.am @@ -46,7 +46,7 @@ endif if BGP_BMP module_LTLIBRARIES += bgpd/bgpd_bmp.la endif -man8 += $(MANBUILD)/bgpd.8 +man8 += $(MANBUILD)/frr-bgpd.8 endif bgpd_libbgp_a_SOURCES = \ diff --git a/configure.ac b/configure.ac index 0694e3ed2c..c8371f304e 100755 --- a/configure.ac +++ b/configure.ac @@ -7,7 +7,7 @@ ## AC_PREREQ([2.60]) -AC_INIT([frr], [7.3-dev], [https://github.com/frrouting/frr/issues]) +AC_INIT([frr], [7.4-dev], [https://github.com/frrouting/frr/issues]) PACKAGE_URL="https://frrouting.org/" AC_SUBST([PACKAGE_URL]) PACKAGE_FULLNAME="FRRouting" @@ -30,7 +30,7 @@ build_clippy="true" dnl case 1: external clippy if test -n "$with_clippy" -a "$with_clippy" != "no" -a "$with_clippy" != "yes"; then - if test "$enable_clippy_only" == "yes"; then + if test "$enable_clippy_only" = "yes"; then AC_MSG_ERROR([--enable-clippy-only does not make sense with --with-clippy]) fi @@ -249,7 +249,18 @@ if test "x${enable_gcov}" = "xyes"; then fi LDFLAGS="${LDFLAGS} -lgcov" -elif test "x${enable_dev_build}" = "xyes"; then +fi + +if test "x${enable_clang_coverage}" = "xyes"; then + AC_C_FLAG([-fprofile-instr-generate], [ + AC_MSG_ERROR([$CC does not support -fprofile-instr-generate.]) + ]) + AC_C_FLAG([-fcoverage-mapping], [ + AC_MSG_ERROR([$CC does not support -fcoverage-mapping.]) + ]) +fi + +if test "x${enable_dev_build}" = "xyes"; then AC_DEFINE([DEV_BUILD], [1], [Build for development]) if test "z$orig_cflags" = "z"; then AC_C_FLAG([-g3]) @@ -574,7 +585,9 @@ AC_ARG_ENABLE([clippy-only], AC_ARG_ENABLE([numeric_version], AS_HELP_STRING([--enable-numeric-version], [Only numeric digits allowed in version (for Alpine)])) AC_ARG_ENABLE([gcov], - AS_HELP_STRING([--enable-gcov], [Add code coverage information])) + AS_HELP_STRING([--enable-gcov], [Collect coverage information with gcov])) +AC_ARG_ENABLE([clang_coverage], + AS_HELP_STRING([--enable-clang-coverage], [Collect coverage information with Clang Coverage])) AC_ARG_ENABLE([bfdd], AS_HELP_STRING([--disable-bfdd], [do not build bfdd])) AC_ARG_ENABLE([address-sanitizer], @@ -2100,6 +2113,19 @@ if test x"${enable_backtrace}" != x"no" ; then AC_DEFINE([HAVE_LIBUNWIND], [1], [libunwind]) backtrace_ok=yes ], [ + true + ]) + + if test "$backtrace_ok" = "no"; then + AC_CHECK_HEADER([unwind.h], [ + AC_SEARCH_LIBS([unw_getcontext], [unwind], [ + AC_DEFINE([HAVE_LIBUNWIND], [1], [libunwind]) + backtrace_ok=yes + ]) + ]) + fi + + if test "$backtrace_ok" = "no"; then case "$host_os" in sunos* | solaris2*) AC_CHECK_FUNCS([printstack], [ @@ -2116,7 +2142,7 @@ if test x"${enable_backtrace}" != x"no" ; then ],, [-lm]) ]) fi - ]) + fi if test x"${enable_backtrace}" = x"yes" -a x"${backtrace_ok}" = x"no"; then dnl user explicitly requested backtrace but we failed to find support diff --git a/debian/frr.manpages b/debian/frr.manpages index f5aa972304..5075fd763d 100644 --- a/debian/frr.manpages +++ b/debian/frr.manpages @@ -1,16 +1,16 @@ +doc/manpages/_build/man/frr-bgpd.8 +doc/manpages/_build/man/frr-eigrpd.8 +doc/manpages/_build/man/frr-fabricd.8 +doc/manpages/_build/man/frr-isisd.8 +doc/manpages/_build/man/frr-ldpd.8 +doc/manpages/_build/man/frr-nhrpd.8 +doc/manpages/_build/man/frr-ospf6d.8 +doc/manpages/_build/man/frr-ospfd.8 +doc/manpages/_build/man/frr-pimd.8 +doc/manpages/_build/man/frr-ripd.8 +doc/manpages/_build/man/frr-ripngd.8 +doc/manpages/_build/man/frr-watchfrr.8 +doc/manpages/_build/man/frr-zebra.8 doc/manpages/_build/man/frr.1 -doc/manpages/_build/man/bgpd.8 -doc/manpages/_build/man/pimd.8 -doc/manpages/_build/man/eigrpd.8 -doc/manpages/_build/man/ldpd.8 -doc/manpages/_build/man/nhrpd.8 -doc/manpages/_build/man/ospf6d.8 -doc/manpages/_build/man/ospfd.8 -doc/manpages/_build/man/ripd.8 -doc/manpages/_build/man/ripngd.8 -doc/manpages/_build/man/vtysh.1 -doc/manpages/_build/man/zebra.8 -doc/manpages/_build/man/isisd.8 -doc/manpages/_build/man/watchfrr.8 doc/manpages/_build/man/mtracebis.8 -doc/manpages/_build/man/fabricd.8 +doc/manpages/_build/man/vtysh.1 diff --git a/doc/manpages/conf.py b/doc/manpages/conf.py index e7813d8176..9121d38fe0 100644 --- a/doc/manpages/conf.py +++ b/doc/manpages/conf.py @@ -313,28 +313,28 @@ latex_documents = [ fwfrr = "{0} routing engine for use with FRRouting." man_pages = [ - ('bgpd', 'bgpd', fwfrr.format("a BGPv4, BGPv4+, BGPv4- "), [], 8), - ('eigrpd', 'eigrpd', fwfrr.format("an EIGRP "), [], 8), - ('ospf6d', 'ospf6d', fwfrr.format("an OSPFv3 "), [], 8), - ('ospfd', 'ospfd', fwfrr.format("an OSPFv2 "), [], 8), - ('isisd', 'isisd', fwfrr.format("an IS-IS "), [], 8), - ('ospfclient', 'ospfclient', 'an example ospf-api client', [], 8), - ('ldpd', 'ldpd', fwfrr.format("an LDP "), [], 8), - ('nhrpd', 'nhrpd', fwfrr.format("a Next Hop Routing Protocol "), [], 8), - ('pimd', 'pimd', fwfrr.format("a PIM "), [], 8), - ('pbrd', 'pbrd', fwfrr.format("a PBR "), [], 8), - ('sharpd', 'sharpd', fwfrr.format("a SHARP "), [], 8), - ('staticd', 'staticd', fwfrr.format("a static route manager "), [], 8), - ('mtracebis', 'mtracebis', "a multicast trace client", [], 8), - ('ripd', 'ripd', fwfrr.format("a RIP "), [], 8), - ('ripngd', 'ripngd', fwfrr.format("a RIPNG "), [], 8), - ('zebra', 'zebra', 'a routing manager for use with associated FRRouting components.', [], 8), - ('watchfrr', 'watchfrr', 'a program to monitor the status of FRRouting daemons', [], 8), - ('vtysh', 'vtysh', 'an integrated shell for FRRouting.', [], 1), + ('frr-bfdd', 'frr-bfdd', fwfrr.format("a bfd"), [], 8), + ('frr-bgpd', 'frr-bgpd', fwfrr.format("a BGPv4, BGPv4+, BGPv4-"), [], 8), + ('frr-eigrpd', 'frr-eigrpd', fwfrr.format("an EIGRP"), [], 8), + ('frr-fabricd', 'frr-fabricd', fwfrr.format("an OpenFabric"), [], 8), + ('frr-isisd', 'frr-isisd', fwfrr.format("an IS-IS"), [], 8), + ('frr-ldpd', 'frr-ldpd', fwfrr.format("an LDP"), [], 8), + ('frr-nhrpd', 'frr-nhrpd', fwfrr.format("a Next Hop Routing Protocol"), [], 8), + ('frr-ospf6d', 'frr-ospf6d', fwfrr.format("an OSPFv3"), [], 8), + ('frr-ospfclient', 'frr-ospfclient', 'an example ospf-api client', [], 8), + ('frr-ospfd', 'frr-ospfd', fwfrr.format("an OSPFv2"), [], 8), + ('frr-pbrd', 'frr-pbrd', fwfrr.format("a PBR"), [], 8), + ('frr-pimd', 'frr-pimd', fwfrr.format("a PIM"), [], 8), + ('frr-ripd', 'frr-ripd', fwfrr.format("a RIP"), [], 8), + ('frr-ripngd', 'frr-ripngd', fwfrr.format("a RIPNG"), [], 8), + ('frr-sharpd', 'frr-sharpd', fwfrr.format("a SHARP"), [], 8), + ('frr-staticd', 'frr-staticd', fwfrr.format("a static route manager"), [], 8), + ('frr-vrrpd', 'frr-vrrpd', fwfrr.format("a VRRP"), [], 8), + ('frr-watchfrr', 'frr-watchfrr', 'a program to monitor the status of FRRouting daemons', [], 8), + ('frr-zebra', 'frr-zebra', 'a routing manager for use with associated FRRouting components.', [], 8), ('frr', 'frr', 'a systemd interaction script', [], 1), - ('bfdd', 'bfdd', fwfrr.format("a bfd"), [], 8), - ('fabricd', 'fabricd', fwfrr.format("an OpenFabric "), [], 8), - ('vrrpd', 'vrrpd', fwfrr.format("a VRRP"), [], 8), + ('mtracebis', 'mtracebis', "a multicast trace client", [], 8), + ('vtysh', 'vtysh', 'an integrated shell for FRRouting.', [], 1), ] # -- Options for Texinfo output ------------------------------------------- diff --git a/doc/manpages/defines.rst b/doc/manpages/defines.rst index 2a6a9fd1bd..ac24cfa8dc 100644 --- a/doc/manpages/defines.rst +++ b/doc/manpages/defines.rst @@ -1,3 +1,3 @@ .. |synopsis-options| replace:: [-d|-t|-dt] [-C] [-f config-file] [-i pid-file] [-z zclient-path] [-u user] [-g group] [-A vty-addr] [-P vty-port] [-M module[:options]] [-N pathspace] [--vty_socket vty-path] [--moduledir module-path] .. |synopsis-options-hv| replace:: [-h] [-v] -.. |seealso-programs| replace:: zebra(8), vtysh(1), ripd(8), ripngd(8), ospfd(8), ospf6d(8), bgpd(8), isisd(8), babeld(8), nhrpd(8), pimd(8), pbrd(8), ldpd(8), eigrpd(8), staticd(8), fabricd(8), vrrpd(8), mtracebis(8) +.. |seealso-programs| replace:: frr-zebra(8), vtysh(1), frr-ripd(8), frr-ripngd(8), frr-ospfd(8), frr-ospf6d(8), frr-bgpd(8), frr-isisd(8), frr-babeld(8), frr-nhrpd(8), frr-pimd(8), frr-pbrd(8), frr-ldpd(8), frr-eigrpd(8), frr-staticd(8), frr-fabricd(8), frr-vrrpd(8), mtracebis(8) diff --git a/doc/manpages/bfdd.rst b/doc/manpages/frr-bfdd.rst index 1f8b1475f4..1f8b1475f4 100644 --- a/doc/manpages/bfdd.rst +++ b/doc/manpages/frr-bfdd.rst diff --git a/doc/manpages/bgpd.rst b/doc/manpages/frr-bgpd.rst index f7e20265e5..f7e20265e5 100644 --- a/doc/manpages/bgpd.rst +++ b/doc/manpages/frr-bgpd.rst diff --git a/doc/manpages/eigrpd.rst b/doc/manpages/frr-eigrpd.rst index bc824468d0..bc824468d0 100644 --- a/doc/manpages/eigrpd.rst +++ b/doc/manpages/frr-eigrpd.rst diff --git a/doc/manpages/fabricd.rst b/doc/manpages/frr-fabricd.rst index c14c07661e..c14c07661e 100644 --- a/doc/manpages/fabricd.rst +++ b/doc/manpages/frr-fabricd.rst diff --git a/doc/manpages/isisd.rst b/doc/manpages/frr-isisd.rst index 68761f642c..68761f642c 100644 --- a/doc/manpages/isisd.rst +++ b/doc/manpages/frr-isisd.rst diff --git a/doc/manpages/ldpd.rst b/doc/manpages/frr-ldpd.rst index 113f06673e..113f06673e 100644 --- a/doc/manpages/ldpd.rst +++ b/doc/manpages/frr-ldpd.rst diff --git a/doc/manpages/nhrpd.rst b/doc/manpages/frr-nhrpd.rst index cae01c677b..cae01c677b 100644 --- a/doc/manpages/nhrpd.rst +++ b/doc/manpages/frr-nhrpd.rst diff --git a/doc/manpages/ospf6d.rst b/doc/manpages/frr-ospf6d.rst index cfc6860d5c..cfc6860d5c 100644 --- a/doc/manpages/ospf6d.rst +++ b/doc/manpages/frr-ospf6d.rst diff --git a/doc/manpages/ospfclient.rst b/doc/manpages/frr-ospfclient.rst index c52b108767..c52b108767 100644 --- a/doc/manpages/ospfclient.rst +++ b/doc/manpages/frr-ospfclient.rst diff --git a/doc/manpages/ospfd.rst b/doc/manpages/frr-ospfd.rst index 951a0229aa..951a0229aa 100644 --- a/doc/manpages/ospfd.rst +++ b/doc/manpages/frr-ospfd.rst diff --git a/doc/manpages/pbrd.rst b/doc/manpages/frr-pbrd.rst index d9a80b1f84..d9a80b1f84 100644 --- a/doc/manpages/pbrd.rst +++ b/doc/manpages/frr-pbrd.rst diff --git a/doc/manpages/pimd.rst b/doc/manpages/frr-pimd.rst index d7582668d2..d7582668d2 100644 --- a/doc/manpages/pimd.rst +++ b/doc/manpages/frr-pimd.rst diff --git a/doc/manpages/ripd.rst b/doc/manpages/frr-ripd.rst index af4590c824..af4590c824 100644 --- a/doc/manpages/ripd.rst +++ b/doc/manpages/frr-ripd.rst diff --git a/doc/manpages/ripngd.rst b/doc/manpages/frr-ripngd.rst index aedd689876..aedd689876 100644 --- a/doc/manpages/ripngd.rst +++ b/doc/manpages/frr-ripngd.rst diff --git a/doc/manpages/sharpd.rst b/doc/manpages/frr-sharpd.rst index 016f3f9254..016f3f9254 100644 --- a/doc/manpages/sharpd.rst +++ b/doc/manpages/frr-sharpd.rst diff --git a/doc/manpages/staticd.rst b/doc/manpages/frr-staticd.rst index ccbcf32e36..ccbcf32e36 100644 --- a/doc/manpages/staticd.rst +++ b/doc/manpages/frr-staticd.rst diff --git a/doc/manpages/vrrpd.rst b/doc/manpages/frr-vrrpd.rst index 0e73b07cda..0e73b07cda 100644 --- a/doc/manpages/vrrpd.rst +++ b/doc/manpages/frr-vrrpd.rst diff --git a/doc/manpages/watchfrr.rst b/doc/manpages/frr-watchfrr.rst index dceb423f82..dceb423f82 100644 --- a/doc/manpages/watchfrr.rst +++ b/doc/manpages/frr-watchfrr.rst diff --git a/doc/manpages/zebra.rst b/doc/manpages/frr-zebra.rst index cfb368bf44..cfb368bf44 100644 --- a/doc/manpages/zebra.rst +++ b/doc/manpages/frr-zebra.rst diff --git a/doc/manpages/index.rst b/doc/manpages/index.rst index 40f06efdfe..58a1d9e0db 100644 --- a/doc/manpages/index.rst +++ b/doc/manpages/index.rst @@ -6,25 +6,25 @@ .. toctree:: :maxdepth: 2 - bfdd - bgpd - eigrpd - isisd - fabricd - ldpd - nhrpd - ospf6d - ospfclient - ospfd - pimd - pbrd + frr + frr-bfdd + frr-bgpd + frr-eigrpd + frr-isisd + frr-fabricd + frr-ldpd + frr-nhrpd + frr-ospf6d + frr-ospfclient + frr-ospfd + frr-pimd + frr-pbrd + frr-ripd + frr-ripngd + frr-sharpd + frr-staticd + frr-watchfrr + frr-zebra + frr-vrrpd mtracebis - ripd - ripngd - sharpd - staticd - watchfrr - zebra vtysh - vrrpd - frr diff --git a/doc/manpages/subdir.am b/doc/manpages/subdir.am index 19d2d8d6ae..9284212099 100644 --- a/doc/manpages/subdir.am +++ b/doc/manpages/subdir.am @@ -3,34 +3,34 @@ # man_RSTFILES = \ - doc/manpages/bgpd.rst \ + doc/manpages/bfd-options.rst \ doc/manpages/common-options.rst \ doc/manpages/conf.py \ doc/manpages/defines.rst \ - doc/manpages/eigrpd.rst \ doc/manpages/epilogue.rst \ - doc/manpages/fabricd.rst \ + doc/manpages/frr-bfdd.rst \ + doc/manpages/frr-bgpd.rst \ + doc/manpages/frr-eigrpd.rst \ + doc/manpages/frr-fabricd.rst \ + doc/manpages/frr-isisd.rst \ + doc/manpages/frr-ldpd.rst \ + doc/manpages/frr-nhrpd.rst \ + doc/manpages/frr-ospf6d.rst \ + doc/manpages/frr-ospfclient.rst \ + doc/manpages/frr-ospfd.rst \ + doc/manpages/frr-pbrd.rst \ + doc/manpages/frr-pimd.rst \ + doc/manpages/frr-ripd.rst \ + doc/manpages/frr-ripngd.rst \ + doc/manpages/frr-sharpd.rst \ + doc/manpages/frr-staticd.rst \ + doc/manpages/frr-vrrpd.rst \ + doc/manpages/frr-watchfrr.rst \ + doc/manpages/frr-zebra.rst \ doc/manpages/frr.rst \ doc/manpages/index.rst \ - doc/manpages/isisd.rst \ - doc/manpages/ldpd.rst \ doc/manpages/mtracebis.rst \ - doc/manpages/nhrpd.rst \ - doc/manpages/ospf6d.rst \ - doc/manpages/ospfclient.rst \ - doc/manpages/ospfd.rst \ - doc/manpages/pimd.rst \ - doc/manpages/ripd.rst \ - doc/manpages/pbrd.rst \ - doc/manpages/ripngd.rst \ - doc/manpages/sharpd.rst \ - doc/manpages/staticd.rst \ doc/manpages/vtysh.rst \ - doc/manpages/watchfrr.rst \ - doc/manpages/zebra.rst \ - doc/manpages/bfdd.rst \ - doc/manpages/bfd-options.rst \ - doc/manpages/vrrpd.rst \ # end EXTRA_DIST += $(man_RSTFILES) diff --git a/doc/user/bfd.rst b/doc/user/bfd.rst index b3fc7f15a6..e6a3c4977a 100644 --- a/doc/user/bfd.rst +++ b/doc/user/bfd.rst @@ -476,3 +476,13 @@ You can also clear packet counters per session with the following commands, only Session down events: 0 Zebra notifications: 4 +Logging / debugging +=================== + +There are no fine grained debug controls for bfdd. Just enable debug logs. + +:: + + config + log file /var/log/frr/frr.log debugging + log syslog debugging diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst index 2d4d0c4945..d3ac4b22ab 100644 --- a/doc/user/bgp.rst +++ b/doc/user/bgp.rst @@ -1075,6 +1075,11 @@ Configuring Peers granular and offers much smarter matching criterion than number of received prefixes, making it more suited to implementing policy. +.. index:: [no] neighbor PEER maximum-prefix-out NUMBER +.. clicmd:: [no] neighbor PEER maximum-prefix-out NUMBER + + Sets a maximum number of prefixes we can send to a given peer. + .. index:: [no] neighbor PEER local-as AS-NUMBER [no-prepend] [replace-as] .. clicmd:: [no] neighbor PEER local-as AS-NUMBER [no-prepend] [replace-as] diff --git a/eigrpd/subdir.am b/eigrpd/subdir.am index 5a65c654e9..e59c88b471 100644 --- a/eigrpd/subdir.am +++ b/eigrpd/subdir.am @@ -12,7 +12,7 @@ vtysh_scan += \ $(top_srcdir)/eigrpd/eigrp_vty.c \ # end # $(top_srcdir)/eigrpd/eigrp_routemap.c -man8 += $(MANBUILD)/eigrpd.8 +man8 += $(MANBUILD)/frr-eigrpd.8 endif eigrpd_libeigrp_a_SOURCES = \ diff --git a/isisd/subdir.am b/isisd/subdir.am index e77fef41dd..5dddb7d345 100644 --- a/isisd/subdir.am +++ b/isisd/subdir.am @@ -14,7 +14,7 @@ vtysh_scan += \ $(top_srcdir)/isisd/isis_vty_fabricd.c \ $(top_srcdir)/isisd/isisd.c \ # end -man8 += $(MANBUILD)/isisd.8 +man8 += $(MANBUILD)/frr-isisd.8 endif if FABRICD diff --git a/ldpd/subdir.am b/ldpd/subdir.am index 42c5ad024b..f464bad9e7 100644 --- a/ldpd/subdir.am +++ b/ldpd/subdir.am @@ -7,7 +7,7 @@ noinst_LIBRARIES += ldpd/libldp.a sbin_PROGRAMS += ldpd/ldpd dist_examples_DATA += ldpd/ldpd.conf.sample vtysh_scan += $(top_srcdir)/ldpd/ldp_vty_cmds.c -man8 += $(MANBUILD)/ldpd.8 +man8 += $(MANBUILD)/frr-ldpd.8 endif ldpd_libldp_a_SOURCES = \ diff --git a/lib/gitversion.pl b/lib/gitversion.pl index 2718046d0b..dd25c8976a 100644 --- a/lib/gitversion.pl +++ b/lib/gitversion.pl @@ -6,7 +6,7 @@ chdir $dir || die "$dir: $!\n"; my $gitdesc = `git describe --always --first-parent --tags --dirty --match 'frr-*' || echo -- \"0-gUNKNOWN\"`; chomp $gitdesc; -my $gitsuffix = ($gitdesc =~ /([0-9a-fA-F]{7}(-dirty)?)$/) ? "-g$1" : "-gUNKNOWN"; +my $gitsuffix = ($gitdesc =~ /-g([0-9a-fA-F]+(-dirty)?)$/) ? "-g$1" : "-gUNKNOWN"; printf STDERR "git suffix: %s\n", $gitsuffix; printf "#define GIT_SUFFIX \"%s\"\n", $gitsuffix; diff --git a/lib/nexthop.c b/lib/nexthop.c index d2ab70e209..e23f8b0792 100644 --- a/lib/nexthop.c +++ b/lib/nexthop.c @@ -34,6 +34,7 @@ #include "jhash.h" #include "printfrr.h" #include "vrf.h" +#include "nexthop_group.h" DEFINE_MTYPE_STATIC(LIB, NEXTHOP, "Nexthop") DEFINE_MTYPE_STATIC(LIB, NH_LABEL, "Nexthop label") @@ -565,8 +566,9 @@ uint32_t nexthop_hash(const struct nexthop *nexthop) return key; } -void nexthop_copy(struct nexthop *copy, const struct nexthop *nexthop, - struct nexthop *rparent) +void nexthop_copy_no_recurse(struct nexthop *copy, + const struct nexthop *nexthop, + struct nexthop *rparent) { copy->vrf_id = nexthop->vrf_id; copy->ifindex = nexthop->ifindex; @@ -583,6 +585,28 @@ void nexthop_copy(struct nexthop *copy, const struct nexthop *nexthop, &nexthop->nh_label->label[0]); } +void nexthop_copy(struct nexthop *copy, const struct nexthop *nexthop, + struct nexthop *rparent) +{ + nexthop_copy_no_recurse(copy, nexthop, rparent); + + /* Bit of a special case here, we need to handle the case + * of a nexthop resolving to agroup. Hence, we need to + * use a nexthop_group API. + */ + if (CHECK_FLAG(copy->flags, NEXTHOP_FLAG_RECURSIVE)) + copy_nexthops(©->resolved, nexthop->resolved, copy); +} + +struct nexthop *nexthop_dup_no_recurse(const struct nexthop *nexthop, + struct nexthop *rparent) +{ + struct nexthop *new = nexthop_new(); + + nexthop_copy_no_recurse(new, nexthop, rparent); + return new; +} + struct nexthop *nexthop_dup(const struct nexthop *nexthop, struct nexthop *rparent) { diff --git a/lib/nexthop.h b/lib/nexthop.h index 040b643a84..cb5efe00cc 100644 --- a/lib/nexthop.h +++ b/lib/nexthop.h @@ -187,9 +187,16 @@ extern unsigned int nexthop_level(struct nexthop *nexthop); /* Copies to an already allocated nexthop struct */ extern void nexthop_copy(struct nexthop *copy, const struct nexthop *nexthop, struct nexthop *rparent); +/* Copies to an already allocated nexthop struct, not including recurse info */ +extern void nexthop_copy_no_recurse(struct nexthop *copy, + const struct nexthop *nexthop, + struct nexthop *rparent); /* Duplicates a nexthop and returns the newly allocated nexthop */ extern struct nexthop *nexthop_dup(const struct nexthop *nexthop, struct nexthop *rparent); +/* Duplicates a nexthop and returns the newly allocated nexthop */ +extern struct nexthop *nexthop_dup_no_recurse(const struct nexthop *nexthop, + struct nexthop *rparent); #ifdef __cplusplus } diff --git a/lib/nexthop_group.c b/lib/nexthop_group.c index 0051cba625..3005a51c71 100644 --- a/lib/nexthop_group.c +++ b/lib/nexthop_group.c @@ -250,8 +250,7 @@ static void _nexthop_add_sorted(struct nexthop **head, { struct nexthop *position, *prev; - /* Ensure this gets set */ - nexthop->next = NULL; + assert(!nexthop->next); for (position = *head, prev = NULL; position; prev = position, position = position->next) { @@ -281,6 +280,8 @@ void nexthop_group_add_sorted(struct nexthop_group *nhg, { struct nexthop *tail; + assert(!nexthop->next); + /* Try to just append to the end first; * trust the list is already sorted */ @@ -363,10 +364,6 @@ void copy_nexthops(struct nexthop **tnh, const struct nexthop *nh, for (nh1 = nh; nh1; nh1 = nh1->next) { nexthop = nexthop_dup(nh1, rparent); _nexthop_add(tnh, nexthop); - - if (CHECK_FLAG(nh1->flags, NEXTHOP_FLAG_RECURSIVE)) - copy_nexthops(&nexthop->resolved, nh1->resolved, - nexthop); } } diff --git a/lib/zclient.c b/lib/zclient.c index 093af44389..b2c74cd0b9 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -143,6 +143,18 @@ void redist_del_instance(struct redist_proto *red, unsigned short instance) } } +void redist_del_all_instances(struct redist_proto *red) +{ + struct listnode *ln, *nn; + unsigned short *id; + + if (!red->instances) + return; + + for (ALL_LIST_ELEMENTS(red->instances, ln, nn, id)) + redist_del_instance(red, *id); +} + /* Stop zebra client services. */ void zclient_stop(struct zclient *zclient) { @@ -899,8 +911,6 @@ int zapi_nexthop_encode(struct stream *s, const struct zapi_nexthop *api_nh, stream_putc(s, api_nh->bh_type); break; case NEXTHOP_TYPE_IPV4: - stream_put_in_addr(s, &api_nh->gate.ipv4); - break; case NEXTHOP_TYPE_IPV4_IFINDEX: stream_put_in_addr(s, &api_nh->gate.ipv4); stream_putl(s, api_nh->ifindex); @@ -909,9 +919,6 @@ int zapi_nexthop_encode(struct stream *s, const struct zapi_nexthop *api_nh, stream_putl(s, api_nh->ifindex); break; case NEXTHOP_TYPE_IPV6: - stream_write(s, (uint8_t *)&api_nh->gate.ipv6, - 16); - break; case NEXTHOP_TYPE_IPV6_IFINDEX: stream_write(s, (uint8_t *)&api_nh->gate.ipv6, 16); @@ -1059,9 +1066,6 @@ static int zapi_nexthop_decode(struct stream *s, struct zapi_nexthop *api_nh, STREAM_GETC(s, api_nh->bh_type); break; case NEXTHOP_TYPE_IPV4: - STREAM_GET(&api_nh->gate.ipv4.s_addr, s, - IPV4_MAX_BYTELEN); - break; case NEXTHOP_TYPE_IPV4_IFINDEX: STREAM_GET(&api_nh->gate.ipv4.s_addr, s, IPV4_MAX_BYTELEN); @@ -1071,8 +1075,6 @@ static int zapi_nexthop_decode(struct stream *s, struct zapi_nexthop *api_nh, STREAM_GETL(s, api_nh->ifindex); break; case NEXTHOP_TYPE_IPV6: - STREAM_GET(&api_nh->gate.ipv6, s, 16); - break; case NEXTHOP_TYPE_IPV6_IFINDEX: STREAM_GET(&api_nh->gate.ipv6, s, 16); STREAM_GETL(s, api_nh->ifindex); diff --git a/lib/zclient.h b/lib/zclient.h index 38b6030fa3..d1aa42da6d 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -574,6 +574,7 @@ extern unsigned short *redist_check_instance(struct redist_proto *, unsigned short); extern void redist_add_instance(struct redist_proto *, unsigned short); extern void redist_del_instance(struct redist_proto *, unsigned short); +extern void redist_del_all_instances(struct redist_proto *red); /* * Send to zebra that the specified vrf is using label to resolve diff --git a/m4/ax_python.m4 b/m4/ax_python.m4 index 66338511a3..69809184ee 100644 --- a/m4/ax_python.m4 +++ b/m4/ax_python.m4 @@ -186,7 +186,7 @@ AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl AC_MSG_RESULT([yes]) PYTHON_CFLAGS="`\"$pycfg\" --includes`" - if test x"${py_ver}" == x"3.8" || test x"{py_ver}" == x"3.9"; then + if test x"${py_ver}" = x"3.8" || test x"{py_ver}" = x"3.9"; then PYTHON_LIBS="`\"$pycfg\" --ldflags --embed`" else PYTHON_LIBS="`\"$pycfg\" --ldflags`" diff --git a/nhrpd/nhrp_peer.c b/nhrpd/nhrp_peer.c index 3a74b75696..c5e985cdac 100644 --- a/nhrpd/nhrp_peer.c +++ b/nhrpd/nhrp_peer.c @@ -896,8 +896,10 @@ void nhrp_peer_recv(struct nhrp_peer *p, struct zbuf *zb) extoff = htons(hdr->extension_offset); if (extoff) { - if (extoff >= realsize) { - info = "extoff larger than packet"; + assert(zb->head > zb->buf); + uint32_t header_offset = zb->head - zb->buf; + if ((extoff >= realsize) || (extoff < (header_offset))) { + info = "extoff larger than packet, or smaller than header"; goto drop; } paylen = extoff - (zb->head - zb->buf); diff --git a/nhrpd/subdir.am b/nhrpd/subdir.am index fe76623ac3..42a6380b17 100644 --- a/nhrpd/subdir.am +++ b/nhrpd/subdir.am @@ -5,7 +5,7 @@ if NHRPD sbin_PROGRAMS += nhrpd/nhrpd vtysh_scan += $(top_srcdir)/nhrpd/nhrp_vty.c -man8 += $(MANBUILD)/nhrpd.8 +man8 += $(MANBUILD)/frr-nhrpd.8 endif nhrpd_nhrpd_LDADD = lib/libfrr.la lib/libfrrcares.la $(LIBCAP) diff --git a/ospf6d/subdir.am b/ospf6d/subdir.am index eac0eee45f..570b077cb1 100644 --- a/ospf6d/subdir.am +++ b/ospf6d/subdir.am @@ -26,7 +26,7 @@ vtysh_scan += \ if SNMP module_LTLIBRARIES += ospf6d/ospf6d_snmp.la endif -man8 += $(MANBUILD)/ospf6d.8 +man8 += $(MANBUILD)/frr-ospf6d.8 endif ospf6d_libospf6_a_SOURCES = \ diff --git a/ospfclient/subdir.am b/ospfclient/subdir.am index 94d489358c..756ad88f15 100644 --- a/ospfclient/subdir.am +++ b/ospfclient/subdir.am @@ -5,7 +5,7 @@ if OSPFCLIENT lib_LTLIBRARIES += ospfclient/libfrrospfapiclient.la noinst_PROGRAMS += ospfclient/ospfclient -man8 += $(MANBUILD)/ospfclient.8 +#man8 += $(MANBUILD)/frr-ospfclient.8 endif ospfclient_libfrrospfapiclient_la_LDFLAGS = -version-info 0:0:0 diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index 152a7e83b7..1542ef88fb 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -9679,7 +9679,7 @@ DEFUN (show_ip_ospf_vrfs, if (uj) json_vrf = json_object_new_object(); - if (ospf->vrf_id == 0) + if (ospf->vrf_id == VRF_DEFAULT) name = VRF_DEFAULT_NAME; else name = ospf->name; diff --git a/ospfd/subdir.am b/ospfd/subdir.am index 48dd741b24..6de4099c5b 100644 --- a/ospfd/subdir.am +++ b/ospfd/subdir.am @@ -19,7 +19,7 @@ vtysh_scan += \ if SNMP module_LTLIBRARIES += ospfd/ospfd_snmp.la endif -man8 += $(MANBUILD)/ospfd.8 +man8 += $(MANBUILD)/frr-ospfd.8 endif ospfd_libfrrospf_a_SOURCES = \ diff --git a/pbrd/subdir.am b/pbrd/subdir.am index 41d0e5a0b8..c55f0b41cc 100644 --- a/pbrd/subdir.am +++ b/pbrd/subdir.am @@ -10,7 +10,7 @@ vtysh_scan += \ $(top_srcdir)/pbrd/pbr_vty.c \ $(top_srcdir)/pbrd/pbr_debug.c \ # end -man8 += $(MANBUILD)/pbrd.8 +man8 += $(MANBUILD)/frr-pbrd.8 endif pbrd_libpbr_a_SOURCES = \ diff --git a/pimd/subdir.am b/pimd/subdir.am index 5407e566a5..b5d135d032 100644 --- a/pimd/subdir.am +++ b/pimd/subdir.am @@ -9,7 +9,7 @@ bin_PROGRAMS += pimd/mtracebis noinst_PROGRAMS += pimd/test_igmpv3_join dist_examples_DATA += pimd/pimd.conf.sample vtysh_scan += $(top_srcdir)/pimd/pim_cmd.c -man8 += $(MANBUILD)/pimd.8 +man8 += $(MANBUILD)/frr-pimd.8 man8 += $(MANBUILD)/mtracebis.8 endif diff --git a/ripd/subdir.am b/ripd/subdir.am index dfdfc88a56..00984672ed 100644 --- a/ripd/subdir.am +++ b/ripd/subdir.am @@ -15,7 +15,7 @@ vtysh_scan += \ if SNMP module_LTLIBRARIES += ripd/ripd_snmp.la endif -man8 += $(MANBUILD)/ripd.8 +man8 += $(MANBUILD)/frr-ripd.8 endif ripd_librip_a_SOURCES = \ diff --git a/ripngd/subdir.am b/ripngd/subdir.am index 07d0cb892c..4e219c9947 100644 --- a/ripngd/subdir.am +++ b/ripngd/subdir.am @@ -10,7 +10,7 @@ vtysh_scan += \ $(top_srcdir)/ripngd/ripng_debug.c \ $(top_srcdir)/ripngd/ripngd.c \ # end -man8 += $(MANBUILD)/ripngd.8 +man8 += $(MANBUILD)/frr-ripngd.8 endif ripngd_libripng_a_SOURCES = \ diff --git a/sharpd/subdir.am b/sharpd/subdir.am index 4a9028f6fe..89b183d832 100644 --- a/sharpd/subdir.am +++ b/sharpd/subdir.am @@ -7,7 +7,7 @@ noinst_LIBRARIES += sharpd/libsharp.a sbin_PROGRAMS += sharpd/sharpd dist_examples_DATA += sharpd/sharpd.conf.sample vtysh_scan += $(top_srcdir)/sharpd/sharp_vty.c -man8 += $(MANBUILD)/sharpd.8 +man8 += $(MANBUILD)/frr-sharpd.8 endif sharpd_libsharp_a_SOURCES = \ diff --git a/solaris/prototype.doc.in b/solaris/prototype.doc.in index a8644b3145..9f7995350a 100644 --- a/solaris/prototype.doc.in +++ b/solaris/prototype.doc.in @@ -8,10 +8,10 @@ d none @mandir@=$DESTDIR/@mandir@ 0755 root bin d none @mandir@/man1=$DESTDIR/@mandir@/man1 0755 root bin f none @mandir@/man1/vtysh.1=$DESTDIR/@mandir@/man1/vtysh.1 0644 root bin d none @mandir@/man8=$DESTDIR/@mandir@/man8 0755 root bin -f none @mandir@/man8/bgpd.8=$DESTDIR/@mandir@/man8/bgpd.8 0644 root bin -f none @mandir@/man8/ospf6d.8=$DESTDIR/@mandir@/man8/ospf6d.8 0644 root bin -f none @mandir@/man8/ospfd.8=$DESTDIR/@mandir@/man8/ospfd.8 0644 root bin -f none @mandir@/man8/ripd.8=$DESTDIR/@mandir@/man8/ripd.8 0644 root bin -f none @mandir@/man8/ripngd.8=$DESTDIR/@mandir@/man8/ripngd.8 0644 root bin -f none @mandir@/man8/zebra.8=$DESTDIR/@mandir@/man8/zebra.8 0644 root bin -f none @mandir@/man8/isisd.8=$DESTDIR/@mandir@/man8/isisd.8 0644 root bin +f none @mandir@/man8/frr-bgpd.8=$DESTDIR/@mandir@/man8/bgpd.8 0644 root bin +f none @mandir@/man8/frr-ospf6d.8=$DESTDIR/@mandir@/man8/frr-ospf6d.8 0644 root bin +f none @mandir@/man8/frr-ospfd.8=$DESTDIR/@mandir@/man8/frr-ospfd.8 0644 root bin +f none @mandir@/man8/frr-ripd.8=$DESTDIR/@mandir@/man8/frr-ripd.8 0644 root bin +f none @mandir@/man8/frr-ripngd.8=$DESTDIR/@mandir@/man8/frr-ripngd.8 0644 root bin +f none @mandir@/man8/frr-zebra.8=$DESTDIR/@mandir@/man8/frr-zebra.8 0644 root bin +f none @mandir@/man8/frr-isisd.8=$DESTDIR/@mandir@/man8/frr-isisd.8 0644 root bin diff --git a/staticd/static_debug.c b/staticd/static_debug.c new file mode 100644 index 0000000000..9906e805a7 --- /dev/null +++ b/staticd/static_debug.c @@ -0,0 +1,124 @@ +/* + * Staticd debug related functions + * Copyright (C) 2019 Volta Networks Inc. + * Mark Stapp + * + * This file is part of Free Range Routing (FRR). + * + * 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, 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 "lib/command.h" +#include "lib/debug.h" + +#include "static_debug.h" + +/* + * Debug infra: a debug struct for each category, and a corresponding + * string. + */ + +/* clang-format off */ +struct debug static_dbg_events = {0, "Staticd events"}; + +struct debug *static_debug_arr[] = { + &static_dbg_events +}; + +const char *static_debugs_conflines[] = { + "debug static events" +}; +/* clang-format on */ + + +/* + * Set or unset all staticd debugs + * + * flags + * The flags to set + * + * set + * Whether to set or unset the specified flags + */ +static void static_debug_set_all(uint32_t flags, bool set) +{ + for (unsigned int i = 0; i < array_size(static_debug_arr); i++) { + DEBUG_FLAGS_SET(static_debug_arr[i], flags, set); + + /* if all modes have been turned off, don't preserve options */ + if (!DEBUG_MODE_CHECK(static_debug_arr[i], DEBUG_MODE_ALL)) + DEBUG_CLEAR(static_debug_arr[i]); + } +} + +static int static_debug_config_write_helper(struct vty *vty, bool config) +{ + uint32_t mode = DEBUG_MODE_ALL; + + if (config) + mode = DEBUG_MODE_CONF; + + for (unsigned int i = 0; i < array_size(static_debug_arr); i++) + if (DEBUG_MODE_CHECK(static_debug_arr[i], mode)) + vty_out(vty, "%s\n", static_debugs_conflines[i]); + + return 0; +} + +int static_config_write_debug(struct vty *vty) +{ + return static_debug_config_write_helper(vty, true); +} + +int static_debug_status_write(struct vty *vty) +{ + return static_debug_config_write_helper(vty, false); +} + +/* + * Set debugging status. + * + * vtynode + * vty->node + * + * onoff + * Whether to turn the specified debugs on or off + * + * events + * Debug general internal events + * + */ +void static_debug_set(int vtynode, bool onoff, bool events) +{ + uint32_t mode = DEBUG_NODE2MODE(vtynode); + + if (events) + DEBUG_MODE_SET(&static_dbg_events, mode, onoff); +} + +/* + * Debug lib initialization + */ + +struct debug_callbacks static_dbg_cbs = { + .debug_set_all = static_debug_set_all +}; + +void static_debug_init(void) +{ + debug_init(&static_dbg_cbs); +} diff --git a/staticd/static_debug.h b/staticd/static_debug.h new file mode 100644 index 0000000000..6e58118ed0 --- /dev/null +++ b/staticd/static_debug.h @@ -0,0 +1,73 @@ +/* + * Staticd debug related functions + * Copyright (C) 2019 Volta Networks Inc. + * Mark Stapp + * + * This file is part of Free Range Routing (FRR). + * + * GNU Zebra 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. + * + * GNU Zebra 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_DEBUG_H +#define _STATIC_DEBUG_H + + +#include <zebra.h> + +#include "lib/debug.h" + +/* staticd debugging records */ +struct debug static_dbg_events; + +/* + * Initialize staticd debugging. + * + * Installs VTY commands and registers callbacks. + */ +void static_debug_init(void); + +/* + * Print staticd debugging configuration. + * + * vty + * VTY to print debugging configuration to. + */ +int static_config_write_debug(struct vty *vty); + +/* + * Print staticd debugging configuration, human readable form. + * + * vty + * VTY to print debugging configuration to. + */ +int static_debug_status_write(struct vty *vty); + +/* + * Set debugging status. + * + * vtynode + * vty->node + * + * onoff + * Whether to turn the specified debugs on or off + * + * events + * Debug general internal events + * + */ +void static_debug_set(int vtynode, bool onoff, bool events); + + +#endif /* _STATIC_DEBUG_H */ diff --git a/staticd/static_main.c b/staticd/static_main.c index 18cb9638c9..43cb7db51d 100644 --- a/staticd/static_main.c +++ b/staticd/static_main.c @@ -36,6 +36,7 @@ #include "static_vty.h" #include "static_routes.h" #include "static_zebra.h" +#include "static_debug.h" char backup_config_file[256]; @@ -141,6 +142,7 @@ int main(int argc, char **argv, char **envp) master = frr_init(); access_list_init(); + static_debug_init(); static_vrf_init(); static_zebra_init(); diff --git a/staticd/static_vty.c b/staticd/static_vty.c index 8db37589af..6390fd811f 100644 --- a/staticd/static_vty.c +++ b/staticd/static_vty.c @@ -32,9 +32,13 @@ #include "static_memory.h" #include "static_vty.h" #include "static_routes.h" +#include "static_debug.h" #ifndef VTYSH_EXTRACT_PL #include "staticd/static_vty_clippy.c" #endif + +#define STATICD_STR "Static route daemon\n" + static struct static_vrf *static_vty_get_unknown_vrf(struct vty *vty, const char *vrf_name) { @@ -1439,21 +1443,43 @@ DEFPY(ipv6_route_vrf, from_str, gate_str, ifname, flag, tag_str, distance_str, label, table_str, false); } +DEFPY(debug_staticd, + debug_staticd_cmd, + "[no] debug static [{events$events}]", + NO_STR + DEBUG_STR + STATICD_STR + "Debug events\n") +{ + /* If no specific category, change all */ + if (strmatch(argv[argc - 1]->text, "static")) + static_debug_set(vty->node, !no, true); + else + static_debug_set(vty->node, !no, !!events); -DEFUN_NOSH (show_debugging_staticd, - show_debugging_staticd_cmd, + return CMD_SUCCESS; +} + +DEFUN_NOSH (show_debugging_static, + show_debugging_static_cmd, "show debugging [static]", SHOW_STR DEBUG_STR "Static Information\n") { - vty_out(vty, "Static debugging status\n"); + vty_out(vty, "Staticd debugging status\n"); + + static_debug_status_write(vty); return CMD_SUCCESS; } +static struct cmd_node debug_node = {DEBUG_NODE, "", 1}; + void static_vty_init(void) { + install_node(&debug_node, static_config_write_debug); + install_element(CONFIG_NODE, &ip_mroute_dist_cmd); install_element(CONFIG_NODE, &ip_route_blackhole_cmd); @@ -1470,7 +1496,9 @@ void static_vty_init(void) install_element(CONFIG_NODE, &ipv6_route_cmd); install_element(VRF_NODE, &ipv6_route_vrf_cmd); - install_element(VIEW_NODE, &show_debugging_staticd_cmd); + install_element(VIEW_NODE, &show_debugging_static_cmd); + install_element(VIEW_NODE, &debug_staticd_cmd); + install_element(CONFIG_NODE, &debug_staticd_cmd); static_list = list_new(); static_list->cmp = (int (*)(void *, void *))static_list_compare; diff --git a/staticd/subdir.am b/staticd/subdir.am index 17c4536fe9..30c69231c9 100644 --- a/staticd/subdir.am +++ b/staticd/subdir.am @@ -7,10 +7,11 @@ noinst_LIBRARIES += staticd/libstatic.a sbin_PROGRAMS += staticd/staticd dist_examples_DATA += staticd/staticd.conf.sample vtysh_scan += $(top_srcdir)/staticd/static_vty.c -man8 += $(MANBUILD)/staticd.8 +man8 += $(MANBUILD)/frr-staticd.8 endif staticd_libstatic_a_SOURCES = \ + staticd/static_debug.c \ staticd/static_memory.c \ staticd/static_nht.c \ staticd/static_routes.c \ @@ -20,6 +21,7 @@ staticd_libstatic_a_SOURCES = \ # end noinst_HEADERS += \ + staticd/static_debug.h \ staticd/static_memory.h \ staticd/static_nht.h \ staticd/static_zebra.h \ diff --git a/tests/topotests/all-protocol-startup/r1/ipv4_routes.ref b/tests/topotests/all-protocol-startup/r1/ipv4_routes.ref index a7d6fe11a6..61d17a61b3 100644 --- a/tests/topotests/all-protocol-startup/r1/ipv4_routes.ref +++ b/tests/topotests/all-protocol-startup/r1/ipv4_routes.ref @@ -10,6 +10,8 @@ C>* 192.168.8.0/26 is directly connected, r1-eth8, XX:XX:XX C>* 192.168.9.0/26 is directly connected, r1-eth9, XX:XX:XX O 192.168.0.0/24 [110/10] is directly connected, r1-eth0, XX:XX:XX O 192.168.3.0/26 [110/10] is directly connected, r1-eth3, XX:XX:XX +S>* 1.1.1.1/32 [1/0] is directly connected, r1-eth0, XX:XX:XX +S>* 1.1.1.2/32 [1/0] is directly connected, r1-eth1, XX:XX:XX S>* 4.5.6.10/32 [1/0] via 192.168.0.2, r1-eth0, XX:XX:XX S>* 4.5.6.11/32 [1/0] via 192.168.0.2, r1-eth0, XX:XX:XX S>* 4.5.6.12/32 [1/0] is directly connected, r1-eth0, XX:XX:XX diff --git a/tests/topotests/all-protocol-startup/r1/zebra.conf b/tests/topotests/all-protocol-startup/r1/zebra.conf index 85c8676964..fbf827604f 100644 --- a/tests/topotests/all-protocol-startup/r1/zebra.conf +++ b/tests/topotests/all-protocol-startup/r1/zebra.conf @@ -26,6 +26,11 @@ ipv6 route 4:5::6:12/128 r1-eth0 # by zebra but not installed. ip route 4.5.6.15/32 192.168.0.2 255 ipv6 route 4:5::6:15/128 fc00:0:0:0::2 255 + +# Routes to put into a nexthop-group +ip route 1.1.1.1/32 r1-eth0 +ip route 1.1.1.2/32 r1-eth1 + ! interface r1-eth0 description to sw0 - no routing protocol 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 9658c080c0..16609221c1 100755 --- a/tests/topotests/all-protocol-startup/test_all_protocol_startup.py +++ b/tests/topotests/all-protocol-startup/test_all_protocol_startup.py @@ -120,6 +120,7 @@ def setup_module(module): if net['r%s' % i].daemon_available('ldpd'): # Only test LDPd if it's installed and Kernel >= 4.5 net['r%s' % i].loadConf('ldpd', '%s/r%s/ldpd.conf' % (thisDir, i)) + net['r%s' % i].loadConf('sharpd') net['r%s' % i].startRouter() # For debugging after starting Quagga/FRR daemons, uncomment the next line @@ -346,6 +347,36 @@ def test_converge_protocols(): # For debugging after starting FRR/Quagga daemons, uncomment the next line ## CLI(net) +def test_nexthop_groups(): + global fatal_error + global net + + # Skip if previous fatal error condition is raised + if (fatal_error != ""): + pytest.skip(fatal_error) + + print("\n\n** Verifying Nexthop Groups") + print("******************************************\n") + + # Create a lib nexthop-group + net["r1"].cmd('vtysh -c "c t" -c "nexthop-group red" -c "nexthop 1.1.1.1" -c "nexthop 1.1.1.2"') + + # Create with sharpd using nexthop-group + net["r1"].cmd('vtysh -c "sharp install routes 2.2.2.1 nexthop-group red 1"') + + # Verify route and that zebra created NHGs for and they are valid/installed + output = net["r1"].cmd('vtysh -c "show ip route 2.2.2.1/32 nexthop-group"') + match = re.search(r"Nexthop Group ID: (\d+)", output); + assert match is not None, "Nexthop Group ID not found for sharpd route 2.2.2.1/32" + + nhe_id = int(match.group(1)) + + output = net["r1"].cmd('vtysh -c "show nexthop-group rib %d"' % nhe_id) + match = re.search(r"Valid", output) + assert match is not None, "Nexthop Group ID=%d not marked Valid" % nhe_id + + match = re.search(r"Installed", output) + assert match is not None, "Nexthop Group ID=%d not marked Installed" % nhe_id def test_rip_status(): global fatal_error diff --git a/tests/topotests/bgp_maximum_prefix_out/__init__.py b/tests/topotests/bgp_maximum_prefix_out/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/topotests/bgp_maximum_prefix_out/__init__.py diff --git a/tests/topotests/bgp_maximum_prefix_out/r1/bgpd.conf b/tests/topotests/bgp_maximum_prefix_out/r1/bgpd.conf new file mode 100644 index 0000000000..9a68809631 --- /dev/null +++ b/tests/topotests/bgp_maximum_prefix_out/r1/bgpd.conf @@ -0,0 +1,9 @@ +! +router bgp 65001 + neighbor 192.168.255.1 remote-as 65002 + address-family ipv4 unicast + redistribute connected + neighbor 192.168.255.1 maximum-prefix-out 2 + exit-address-family + ! +! diff --git a/tests/topotests/bgp_maximum_prefix_out/r1/zebra.conf b/tests/topotests/bgp_maximum_prefix_out/r1/zebra.conf new file mode 100644 index 0000000000..24162258b7 --- /dev/null +++ b/tests/topotests/bgp_maximum_prefix_out/r1/zebra.conf @@ -0,0 +1,13 @@ +! +interface lo + ip address 172.16.255.250/32 + ip address 172.16.255.251/32 + ip address 172.16.255.252/32 + ip address 172.16.255.253/32 + ip address 172.16.255.254/32 +! +interface r1-eth0 + ip address 192.168.255.2/30 +! +ip forwarding +! diff --git a/tests/topotests/bgp_maximum_prefix_out/r2/bgpd.conf b/tests/topotests/bgp_maximum_prefix_out/r2/bgpd.conf new file mode 100644 index 0000000000..1659c4bec4 --- /dev/null +++ b/tests/topotests/bgp_maximum_prefix_out/r2/bgpd.conf @@ -0,0 +1,6 @@ +! +router bgp 65002 + neighbor 192.168.255.2 remote-as 65001 + exit-address-family + ! +! diff --git a/tests/topotests/bgp_maximum_prefix_out/r2/zebra.conf b/tests/topotests/bgp_maximum_prefix_out/r2/zebra.conf new file mode 100644 index 0000000000..08dd374dee --- /dev/null +++ b/tests/topotests/bgp_maximum_prefix_out/r2/zebra.conf @@ -0,0 +1,6 @@ +! +interface r2-eth0 + ip address 192.168.255.1/30 +! +ip forwarding +! diff --git a/tests/topotests/bgp_maximum_prefix_out/test_bgp_maximum_prefix_out.py b/tests/topotests/bgp_maximum_prefix_out/test_bgp_maximum_prefix_out.py new file mode 100644 index 0000000000..d77aa5aff2 --- /dev/null +++ b/tests/topotests/bgp_maximum_prefix_out/test_bgp_maximum_prefix_out.py @@ -0,0 +1,108 @@ +#!/usr/bin/env python + +# +# test_bgp_maximum_prefix_out.py +# Part of NetDEF Topology Tests +# +# Copyright (c) 2020 by +# Donatas Abraitis <donatas.abraitis@gmail.com> +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +""" +Test if `neighbor <X.X.X.X> maximum-prefix-out <Y>` is working +correctly. +""" + +import os +import sys +import json +import time +import pytest +import functools + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, '../')) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger +from mininet.topo import Topo + +class TemplateTopo(Topo): + def build(self, *_args, **_opts): + tgen = get_topogen(self) + + for routern in range(1, 3): + tgen.add_router('r{}'.format(routern)) + + switch = tgen.add_switch('s1') + switch.add_link(tgen.gears['r1']) + switch.add_link(tgen.gears['r2']) + +def setup_module(mod): + tgen = Topogen(TemplateTopo, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + for i, (rname, router) in enumerate(router_list.iteritems(), 1): + router.load_config( + TopoRouter.RD_ZEBRA, + os.path.join(CWD, '{}/zebra.conf'.format(rname)) + ) + router.load_config( + TopoRouter.RD_BGP, + os.path.join(CWD, '{}/bgpd.conf'.format(rname)) + ) + + tgen.start_router() + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + +def test_bgp_maximum_prefix_out(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + router = tgen.gears['r2'] + + def _bgp_converge(router): + output = json.loads(router.vtysh_cmd("show ip bgp neighbor 192.168.255.2 json")) + expected = { + '192.168.255.2': { + 'bgpState': 'Established', + 'addressFamilyInfo': { + 'ipv4Unicast': { + 'acceptedPrefixCounter': 2 + } + } + } + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial(_bgp_converge, router) + success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + + assert result is None, 'Failed bgp convergence in "{}"'.format(router) + +if __name__ == '__main__': + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/pim-basic/r1/bgpd.conf b/tests/topotests/pim-basic/r1/bgpd.conf new file mode 100644 index 0000000000..8acaac96a0 --- /dev/null +++ b/tests/topotests/pim-basic/r1/bgpd.conf @@ -0,0 +1,3 @@ +router bgp 65001 + neighbor 10.0.30.3 remote-as external + redistribute connected diff --git a/tests/topotests/pim-basic/r1/pimd.conf b/tests/topotests/pim-basic/r1/pimd.conf index 5740c66e24..cec765699d 100644 --- a/tests/topotests/pim-basic/r1/pimd.conf +++ b/tests/topotests/pim-basic/r1/pimd.conf @@ -2,9 +2,12 @@ hostname r1 ! interface r1-eth0 ip igmp - ip pim sm + ip pim +! +interface r1-eth1 + ip pim ! interface lo - ip pim sm + ip pim ! -ip pim rp 10.254.0.1 +ip pim rp 10.254.0.3 diff --git a/tests/topotests/pim-basic/r1/rp-info.json b/tests/topotests/pim-basic/r1/rp-info.json new file mode 100644 index 0000000000..1f713c2d28 --- /dev/null +++ b/tests/topotests/pim-basic/r1/rp-info.json @@ -0,0 +1,9 @@ +{ + "10.254.0.3":[ + { + "outboundInterface":"r1-eth1", + "group":"224.0.0.0\/4", + "source":"Static" + } + ] +} diff --git a/tests/topotests/pim-basic/r1/zebra.conf b/tests/topotests/pim-basic/r1/zebra.conf index 2bf71294d0..b0a25f12aa 100644 --- a/tests/topotests/pim-basic/r1/zebra.conf +++ b/tests/topotests/pim-basic/r1/zebra.conf @@ -3,6 +3,9 @@ hostname r1 interface r1-eth0 ip address 10.0.20.1/24 ! +interface r1-eth1 + ip address 10.0.30.1/24 +! interface lo ip address 10.254.0.1/32 ! diff --git a/tests/topotests/pim-basic/rp/bgpd.conf b/tests/topotests/pim-basic/rp/bgpd.conf new file mode 100644 index 0000000000..6b16c067a5 --- /dev/null +++ b/tests/topotests/pim-basic/rp/bgpd.conf @@ -0,0 +1,3 @@ +router bgp 65003 + neighbor 10.0.30.1 remote-as external + redistribute connected diff --git a/tests/topotests/pim-basic/rp/pimd.conf b/tests/topotests/pim-basic/rp/pimd.conf new file mode 100644 index 0000000000..3f1b4d65c9 --- /dev/null +++ b/tests/topotests/pim-basic/rp/pimd.conf @@ -0,0 +1,9 @@ +hostname rp +! +interface rp-eth0 + ip pim +! +interface lo + ip pim +! +ip pim rp 10.254.0.3 diff --git a/tests/topotests/pim-basic/rp/upstream.json b/tests/topotests/pim-basic/rp/upstream.json new file mode 100644 index 0000000000..c33dea49e9 --- /dev/null +++ b/tests/topotests/pim-basic/rp/upstream.json @@ -0,0 +1,17 @@ +{ + "229.1.1.1":{ + "10.0.20.2":{ + "sourceStream":true, + "inboundInterface":"rp-eth0", + "rpfAddress":"10.0.20.2", + "source":"10.0.20.2", + "group":"229.1.1.1", + "state":"NotJ", + "joinState":"NotJoined", + "regState":"RegNoInfo", + "resetTimer":"--:--:--", + "refCount":1, + "sptBit":0 + } + } +} diff --git a/tests/topotests/pim-basic/rp/zebra.conf b/tests/topotests/pim-basic/rp/zebra.conf new file mode 100644 index 0000000000..0a1359ecd0 --- /dev/null +++ b/tests/topotests/pim-basic/rp/zebra.conf @@ -0,0 +1,8 @@ +hostname rp +! +interface rp-eth0 + ip address 10.0.30.3/24 +! +interface lo + ip address 10.254.0.3/32 +! diff --git a/tests/topotests/pim-basic/test_pim.py b/tests/topotests/pim-basic/test_pim.py index 6d54b8f2f0..0e0569e234 100644 --- a/tests/topotests/pim-basic/test_pim.py +++ b/tests/topotests/pim-basic/test_pim.py @@ -28,6 +28,8 @@ test_pim.py: Test pim import os import sys import pytest +import json +from functools import partial CWD = os.path.dirname(os.path.realpath(__file__)) sys.path.append(os.path.join(CWD, '../')) @@ -47,11 +49,27 @@ class PIMTopo(Topo): for routern in range(1, 3): tgen.add_router('r{}'.format(routern)) + tgen.add_router('rp') + + # r1 -> .1 + # r2 -> .2 + # rp -> .3 + # loopback network is 10.254.0.X/32 + # # r1 <- sw1 -> r2 + # r1-eth0 <-> r2-eth0 + # 10.0.20.0/24 sw = tgen.add_switch('sw1') sw.add_link(tgen.gears['r1']) sw.add_link(tgen.gears['r2']) + # r1 <- sw2 -> rp + # r1-eth1 <-> rp-eth0 + # 10.0.30.0/24 + sw = tgen.add_switch('sw2') + sw.add_link(tgen.gears['r1']) + sw.add_link(tgen.gears['rp']) + def setup_module(mod): "Sets up the pytest environment" @@ -68,9 +86,14 @@ def setup_module(mod): TopoRouter.RD_PIM, os.path.join(CWD, '{}/pimd.conf'.format(rname)) ) + router.load_config( + TopoRouter.RD_BGP, + os.path.join(CWD, '{}/bgpd.conf'.format(rname)) + ) # After loading the configurations, this function loads configured daemons. tgen.start_router() + #tgen.mininet_cli() def teardown_module(mod): @@ -80,6 +103,22 @@ def teardown_module(mod): # This function tears down the whole topology. tgen.stop_topology() +def test_pim_rp_setup(): + "Ensure basic routing has come up and the rp has an outgoing interface" + #Ensure rp and r1 establish pim neighbor ship and bgp has come up + #Finally ensure that the rp has an outgoing interface on r1 + tgen = get_topogen() + + r1 = tgen.gears['r1'] + json_file = '{}/{}/rp-info.json'.format(CWD, r1.name) + expected = json.loads(open(json_file).read()) + + test_func = partial(topotest.router_json_cmp, + r1, 'show ip pim rp-info json', expected) + _, result = topotest.run_and_expect(test_func, None, count=15, wait=5) + assertmsg = '"{}" JSON output mismatches'.format(r1.name) + assert result is None, assertmsg + #tgen.mininet_cli() def test_pim_send_mcast_stream(): "Establish a Multicast stream from r2 -> r1 and then ensure S,G is created as appropriate" @@ -90,6 +129,7 @@ def test_pim_send_mcast_stream(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) + rp = tgen.gears['rp'] r2 = tgen.gears['r2'] r1 = tgen.gears['r1'] @@ -111,7 +151,21 @@ def test_pim_send_mcast_stream(): } assert topotest.json_cmp(out, expected) is None, 'failed to converge pim' + #tgen.mininet_cli() + +def test_pim_rp_sees_stream(): + "Ensure that the RP sees the stream and has acted accordingly" + tgen = get_topogen() + + rp = tgen.gears['rp'] + json_file = '{}/{}/upstream.json'.format(CWD, rp.name) + expected = json.loads(open(json_file).read()) + test_func = partial(topotest.router_json_cmp, + rp, 'show ip pim upstream json', expected) + _, result = topotest.run_and_expect(test_func, None, count=20, wait=.5) + assertmsg = '"{}" JSON output mismatches'.format(rp.name) + assert result is None, assertmsg def test_pim_igmp_report(): "Send a igmp report from r2->r1 and ensure that the *,G state is created on r1" diff --git a/tools/frr-reload.py b/tools/frr-reload.py index 3e97635dfe..45843faf13 100755 --- a/tools/frr-reload.py +++ b/tools/frr-reload.py @@ -934,6 +934,16 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del): lines_to_del_to_del.append((ctx_keys, route_target_export_line)) lines_to_add_to_del.append((ctx_keys, route_target_both_line)) + # Deleting static routes under a vrf can lead to time-outs if each is sent + # as separate vtysh -c commands. Change them from being in lines_to_del and + # put the "no" form in lines_to_add + if ctx_keys[0].startswith('vrf ') and line: + if (line.startswith('ip route') or + line.startswith('ipv6 route')): + add_cmd = ('no ' + line) + lines_to_add.append((ctx_keys, add_cmd)) + lines_to_del_to_del.append((ctx_keys, line)) + if not deleted: found_add_line = line_exist(lines_to_add, ctx_keys, line) @@ -1054,6 +1064,19 @@ def compare_context_objects(newconf, running): for line in running_ctx.lines: lines_to_del.append((running_ctx_keys, line)) + # Some commands can happen at higher counts that make + # doing vtysh -c inefficient (and can time out.) For + # these commands, instead of adding them to lines_to_del, + # add the "no " version to lines_to_add. + elif (running_ctx_keys[0].startswith('ip route') or + running_ctx_keys[0].startswith('ipv6 route') or + running_ctx_keys[0].startswith('access-list') or + running_ctx_keys[0].startswith('ipv6 access-list') or + running_ctx_keys[0].startswith('ip prefix-list') or + running_ctx_keys[0].startswith('ipv6 prefix-list')): + add_cmd = ('no ' + running_ctx_keys[0],) + lines_to_add.append((add_cmd, None)) + # Non-global context elif running_ctx_keys and not any("address-family" in key for key in running_ctx_keys): lines_to_del.append((running_ctx_keys, None)) @@ -1392,6 +1415,11 @@ if __name__ == '__main__': if line == '!': continue + # Don't run "no" commands twice since they can error + # out the second time due to first deletion + if x == 1 and ctx_keys[0].startswith('no '): + continue + cmd = line_for_vtysh_file(ctx_keys, line, False) lines_to_configure.append(cmd) diff --git a/vrrpd/subdir.am b/vrrpd/subdir.am index d81594ad93..07358e0383 100644 --- a/vrrpd/subdir.am +++ b/vrrpd/subdir.am @@ -7,7 +7,7 @@ noinst_LIBRARIES += vrrpd/libvrrp.a sbin_PROGRAMS += vrrpd/vrrpd # dist_examples_DATA += staticd/staticd.conf.sample vtysh_scan += $(top_srcdir)/vrrpd/vrrp_vty.c -man8 += $(MANBUILD)/vrrpd.8 +man8 += $(MANBUILD)/frr-vrrpd.8 endif vrrpd_libvrrp_a_SOURCES = \ diff --git a/watchfrr/subdir.am b/watchfrr/subdir.am index 30f606c202..36af57cf82 100644 --- a/watchfrr/subdir.am +++ b/watchfrr/subdir.am @@ -5,7 +5,7 @@ if WATCHFRR sbin_PROGRAMS += watchfrr/watchfrr vtysh_scan += $(top_srcdir)/watchfrr/watchfrr_vty.c -man8 += $(MANBUILD)/watchfrr.8 +man8 += $(MANBUILD)/frr-watchfrr.8 endif noinst_HEADERS += \ diff --git a/zebra/label_manager.c b/zebra/label_manager.c index 6e58f4b925..caebdc0f08 100644 --- a/zebra/label_manager.c +++ b/zebra/label_manager.c @@ -262,8 +262,12 @@ assign_specific_label_chunk(uint8_t proto, unsigned short instance, * included in the previous one */ for (node = first_node; node && (node != last_node); node = next) { + struct label_manager_chunk *death; + next = listnextnode(node); + death = listgetdata(node); list_delete_node(lbl_mgr.lc_list, node); + delete_label_chunk(death); } lmc = create_label_chunk(proto, instance, keep, base, end); diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 29a341abbd..dd6e62ee6c 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -2353,7 +2353,7 @@ int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) unsigned char family; int type; afi_t afi = AFI_UNSPEC; - vrf_id_t vrf_id = 0; + vrf_id_t vrf_id = VRF_DEFAULT; struct interface *ifp = NULL; struct nhmsg *nhm = NULL; struct nexthop nh = {}; diff --git a/zebra/subdir.am b/zebra/subdir.am index 916f6cb5d1..77ed5a6caa 100644 --- a/zebra/subdir.am +++ b/zebra/subdir.am @@ -36,7 +36,7 @@ if LINUX module_LTLIBRARIES += zebra/zebra_cumulus_mlag.la endif -man8 += $(MANBUILD)/zebra.8 +man8 += $(MANBUILD)/frr-zebra.8 ## endif ZEBRA endif diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index 651babdeba..db54e6f25b 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -41,6 +41,7 @@ #include "lib/vrf.h" #include "lib/libfrr.h" #include "lib/sockopt.h" +#include "lib/lib_errors.h" #include "zebra/zebra_router.h" #include "zebra/rib.h" @@ -1416,7 +1417,7 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) struct nexthop *nexthop = NULL; struct nexthop_group *ng = NULL; int i, ret; - vrf_id_t vrf_id = 0; + vrf_id_t vrf_id; struct ipaddr vtep_ip; s = msg; @@ -1612,6 +1613,14 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) if (CHECK_FLAG(api.message, ZAPI_MESSAGE_SRCPFX)) src_p = &api.src_prefix; + if (api.safi != SAFI_UNICAST && api.safi != SAFI_MULTICAST) { + flog_warn(EC_LIB_ZAPI_MISSMATCH, + "%s: Received safi: %d but we can only accept UNICAST or MULTICAST", + __func__, api.safi); + nexthop_group_delete(&ng); + XFREE(MTYPE_RE, re); + return; + } ret = rib_add_multipath(afi, api.safi, &api.prefix, src_p, re, ng); /* Stats */ @@ -2382,14 +2391,19 @@ static inline void zread_rule(ZAPI_HANDLER_ARGS) if (!(zpr.rule.filter.src_ip.family == AF_INET || zpr.rule.filter.src_ip.family == AF_INET6)) { - zlog_warn("Unsupported PBR source IP family: %s\n", - family2str(zpr.rule.filter.src_ip.family)); + zlog_warn( + "Unsupported PBR source IP family: %s (%" PRIu8 + ")\n", + family2str(zpr.rule.filter.src_ip.family), + zpr.rule.filter.src_ip.family); return; } if (!(zpr.rule.filter.dst_ip.family == AF_INET || zpr.rule.filter.dst_ip.family == AF_INET6)) { - zlog_warn("Unsupported PBR dest IP family: %s\n", - family2str(zpr.rule.filter.dst_ip.family)); + zlog_warn("Unsupported PBR IP family: %s (%" PRIu8 + ")\n", + family2str(zpr.rule.filter.dst_ip.family), + zpr.rule.filter.dst_ip.family); return; } diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 4f41406a5c..7430307320 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -478,7 +478,7 @@ static void handle_recursive_depend(struct nhg_connected_tree_head *nhg_depends, struct nhg_hash_entry *depend = NULL; struct nexthop_group resolved_ng = {}; - nexthop_group_add_sorted(&resolved_ng, nh); + resolved_ng.nexthop = nh; depend = zebra_nhg_rib_find(0, &resolved_ng, afi); depends_add(nhg_depends, depend); @@ -507,7 +507,7 @@ static bool zebra_nhg_find(struct nhg_hash_entry **nhe, uint32_t id, if (lookup.nhg->nexthop->next) { /* Groups can have all vrfs and AF's in them */ lookup.afi = AFI_UNSPEC; - lookup.vrf_id = 0; + lookup.vrf_id = VRF_DEFAULT; } else { switch (lookup.nhg->nexthop->type) { case (NEXTHOP_TYPE_IFINDEX): @@ -1048,25 +1048,55 @@ int zebra_nhg_kernel_del(uint32_t id) } /* Some dependency helper functions */ -static struct nhg_hash_entry *depends_find(const struct nexthop *nh, afi_t afi) +static struct nhg_hash_entry *depends_find_recursive(const struct nexthop *nh, + afi_t afi) { - struct nexthop lookup; - struct nhg_hash_entry *nhe = NULL; + struct nhg_hash_entry *nhe; + struct nexthop *lookup = NULL; - if (!nh) - goto done; + lookup = nexthop_dup(nh, NULL); + + nhe = zebra_nhg_find_nexthop(0, lookup, afi, 0); + + nexthops_free(lookup); + + return nhe; +} + +static struct nhg_hash_entry *depends_find_singleton(const struct nexthop *nh, + afi_t afi) +{ + struct nhg_hash_entry *nhe; + struct nexthop lookup = {}; /* Capture a snapshot of this single nh; it might be part of a list, * so we need to make a standalone copy. */ - memset(&lookup, 0, sizeof(lookup)); - nexthop_copy(&lookup, nh, NULL); + nexthop_copy_no_recurse(&lookup, nh, NULL); nhe = zebra_nhg_find_nexthop(0, &lookup, afi, 0); /* The copy may have allocated labels; free them if necessary. */ nexthop_del_labels(&lookup); + return nhe; +} + +static struct nhg_hash_entry *depends_find(const struct nexthop *nh, afi_t afi) +{ + struct nhg_hash_entry *nhe = NULL; + + if (!nh) + goto done; + + /* We are separating these functions out to increase handling speed + * in the non-recursive case (by not alloc/freeing) + */ + if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_RECURSIVE)) + nhe = depends_find_recursive(nh, afi); + else + nhe = depends_find_singleton(nh, afi); + done: return nhe; } diff --git a/zebra/zebra_pbr.c b/zebra/zebra_pbr.c index 0c3adcdfa1..fe7a93a50c 100644 --- a/zebra/zebra_pbr.c +++ b/zebra/zebra_pbr.c @@ -652,12 +652,22 @@ static void *pbr_iptable_alloc_intern(void *arg) { struct zebra_pbr_iptable *zpi; struct zebra_pbr_iptable *new; + struct listnode *ln; + char *ifname; zpi = (struct zebra_pbr_iptable *)arg; new = XCALLOC(MTYPE_TMP, sizeof(struct zebra_pbr_iptable)); + /* Deep structure copy */ memcpy(new, zpi, sizeof(*zpi)); + new->interface_name_list = list_new(); + + if (zpi->interface_name_list) { + for (ALL_LIST_ELEMENTS_RO(zpi->interface_name_list, ln, ifname)) + listnode_add(new->interface_name_list, + XSTRDUP(MTYPE_PBR_IPTABLE_IFNAME, ifname)); + } return new; } diff --git a/zebra/zebra_ptm.c b/zebra/zebra_ptm.c index 757623a04e..d7bbe779bd 100644 --- a/zebra/zebra_ptm.c +++ b/zebra/zebra_ptm.c @@ -1295,6 +1295,7 @@ static void zebra_ptm_send_bfdd(struct stream *msg) } stream_free(msgc); + stream_free(msg); } static void zebra_ptm_send_clients(struct stream *msg) @@ -1326,6 +1327,7 @@ static void zebra_ptm_send_clients(struct stream *msg) } stream_free(msgc); + stream_free(msg); } static int _zebra_ptm_bfd_client_deregister(struct zserv *zs) @@ -1367,8 +1369,6 @@ static int _zebra_ptm_bfd_client_deregister(struct zserv *zs) zebra_ptm_send_bfdd(msg); - stream_free(msg); - pp_free(pp); return 0; @@ -1423,6 +1423,7 @@ static void _zebra_ptm_reroute(struct zserv *zs, struct zebra_vrf *zvrf, stream_putw_at(msgc, 0, STREAM_READABLE(msgc)); zebra_ptm_send_bfdd(msgc); + msgc = NULL; /* Registrate process PID for shutdown hook. */ STREAM_GETL(msg, ppid); @@ -1431,7 +1432,8 @@ static void _zebra_ptm_reroute(struct zserv *zs, struct zebra_vrf *zvrf, return; stream_failure: - stream_free(msgc); + if (msgc) + stream_free(msgc); zlog_err("%s:%d failed to registrate client pid", __FILE__, __LINE__); } diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 564573dcb3..ffb2528a24 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -8624,9 +8624,8 @@ void zebra_vxlan_macvlan_down(struct interface *ifp) struct interface *ifp; ifp = if_lookup_by_index_all_vrf(zif->link_ifindex); - zlog_debug("macvlan %s parent link is not found. Parent index %d ifp %s", - ifp->name, zif->link_ifindex, - ifp ? ifp->name : " "); + zlog_debug("macvlan parent link is not found. Parent index %d ifp %s", + zif->link_ifindex, ifp ? ifp->name : " "); } return; } @@ -9487,7 +9486,7 @@ void zebra_vxlan_advertise_subnet(ZAPI_HANDLER_ARGS) s = msg; STREAM_GETC(s, advertise); - vni = stream_get3(s); + STREAM_GET(&vni, s, 3); zvni = zvni_lookup(vni); if (!zvni) diff --git a/zebra/zserv.c b/zebra/zserv.c index 419f30e6d3..cca926f3b0 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -591,8 +591,10 @@ static void zserv_client_free(struct zserv *client) /* Free bitmaps. */ for (afi_t afi = AFI_IP; afi < AFI_MAX; afi++) { - for (int i = 0; i < ZEBRA_ROUTE_MAX; i++) + for (int i = 0; i < ZEBRA_ROUTE_MAX; i++) { vrf_bitmap_free(client->redist[afi][i]); + redist_del_all_instances(&client->mi_redist[afi][i]); + } vrf_bitmap_free(client->redist_default[afi]); } |
