diff options
83 files changed, 936 insertions, 522 deletions
diff --git a/alpine/APKBUILD.in b/alpine/APKBUILD.in index dfedf0b52b..e6776cb3a2 100644 --- a/alpine/APKBUILD.in +++ b/alpine/APKBUILD.in @@ -41,7 +41,6 @@ build() { --sysconfdir=$_sysconfdir \ --libdir=$_libdir \ --localstatedir=$_localstatedir \ - --enable-systemd=no \ --enable-rpki \ --enable-vtysh \ --enable-multipath=64 \ diff --git a/bfdd/dplane.c b/bfdd/dplane.c index 6fb301d46a..4b7f9ba7ac 100644 --- a/bfdd/dplane.c +++ b/bfdd/dplane.c @@ -651,8 +651,6 @@ static struct bfd_dplane_ctx *bfd_dplane_ctx_new(int sock) struct bfd_dplane_ctx *bdc; bdc = XCALLOC(MTYPE_BFDD_DPLANE_CTX, sizeof(*bdc)); - if (bdc == NULL) - return NULL; bdc->sock = sock; bdc->inbuf = stream_new(BFD_DPLANE_CLIENT_BUF_SIZE); diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c index 25109e030b..3c67017dc7 100644 --- a/bgpd/bgp_aspath.c +++ b/bgpd/bgp_aspath.c @@ -193,7 +193,8 @@ static struct assegment *assegment_prepend_asns(struct assegment *seg, if (num >= AS_SEGMENT_MAX) return seg; /* we don't do huge prepends */ - if ((newas = assegment_data_new(seg->length + num)) == NULL) + newas = assegment_data_new(seg->length + num); + if (newas == NULL) return seg; for (i = 0; i < num; i++) diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 2f0751a5f0..24b48178d2 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -1509,16 +1509,6 @@ static int bgp_attr_aspath(struct bgp_attr_parser_args *args) 0); } - /* Codification of AS 0 Processing */ - if (aspath_check_as_zero(attr->aspath)) { - flog_err( - EC_BGP_ATTR_MAL_AS_PATH, - "Malformed AS path, AS number is 0 in the path from %s", - peer->host); - return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_MAL_AS_PATH, - 0); - } - /* Set aspath attribute flag. */ attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_AS_PATH); @@ -1558,6 +1548,15 @@ static bgp_attr_parse_ret_t bgp_attr_aspath_check(struct peer *const peer, } } + /* Codification of AS 0 Processing */ + if (peer->sort == BGP_PEER_EBGP && aspath_check_as_zero(attr->aspath)) { + flog_err( + EC_BGP_ATTR_MAL_AS_PATH, + "Malformed AS path, AS number is 0 in the path from %s", + peer->host); + return BGP_ATTR_PARSE_WITHDRAW; + } + /* local-as prepend */ if (peer->change_local_as && !CHECK_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND)) { @@ -1590,16 +1589,6 @@ static int bgp_attr_as4_path(struct bgp_attr_parser_args *args, 0); } - /* Codification of AS 0 Processing */ - if (aspath_check_as_zero(*as4_path)) { - flog_err( - EC_BGP_ATTR_MAL_AS_PATH, - "Malformed AS path, AS number is 0 in the path from %s", - peer->host); - return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_MAL_AS_PATH, - 0); - } - /* Set aspath attribute flag. */ attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH); @@ -3317,7 +3306,8 @@ bgp_attr_parse_ret_t bgp_attr_parse(struct peer *peer, struct attr *attr, } /* Check all mandatory well-known attributes are present */ - if ((ret = bgp_attr_check(peer, attr)) < 0) + ret = bgp_attr_check(peer, attr); + if (ret < 0) goto done; /* diff --git a/bgpd/bgp_evpn_mh.c b/bgpd/bgp_evpn_mh.c index 4b90937f62..34094a0bde 100644 --- a/bgpd/bgp_evpn_mh.c +++ b/bgpd/bgp_evpn_mh.c @@ -1311,7 +1311,7 @@ static void bgp_evpn_es_vtep_re_eval_active(struct bgp *bgp, bool old_active; bool new_active; - old_active = !!CHECK_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ACTIVE); + old_active = CHECK_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ACTIVE); /* currently we need an active EVI reference to use the VTEP as * a nexthop. this may change... */ @@ -1320,7 +1320,7 @@ static void bgp_evpn_es_vtep_re_eval_active(struct bgp *bgp, else UNSET_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ACTIVE); - new_active = !!CHECK_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ACTIVE); + new_active = CHECK_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ACTIVE); if ((old_active != new_active) || (new_active && param_change)) { @@ -3119,7 +3119,7 @@ static void bgp_evpn_es_evi_vtep_re_eval_active(struct bgp *bgp, bool new_active; uint32_t ead_activity_flags; - old_active = !!CHECK_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_ACTIVE); + old_active = CHECK_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_ACTIVE); if (bgp_mh_info->ead_evi_rx) /* Both EAD-per-ES and EAD-per-EVI routes must be rxed from a PE @@ -3135,7 +3135,7 @@ static void bgp_evpn_es_evi_vtep_re_eval_active(struct bgp *bgp, else UNSET_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_ACTIVE); - new_active = !!CHECK_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_ACTIVE); + new_active = CHECK_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_ACTIVE); if (old_active == new_active) return; diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index 4cc096d8e7..79dc0aec9d 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -256,6 +256,7 @@ static struct peer *peer_xfer_conn(struct peer *from_peer) from_peer->last_major_event = last_maj_evt; peer->remote_id = from_peer->remote_id; peer->last_reset = from_peer->last_reset; + peer->max_packet_size = from_peer->max_packet_size; peer->peer_gr_present_state = from_peer->peer_gr_present_state; peer->peer_gr_new_status_flag = from_peer->peer_gr_new_status_flag; diff --git a/bgpd/bgp_mpath.c b/bgpd/bgp_mpath.c index d5fce115de..8127428bc7 100644 --- a/bgpd/bgp_mpath.c +++ b/bgpd/bgp_mpath.c @@ -411,7 +411,8 @@ static void bgp_path_info_mpath_lb_update(struct bgp_path_info *path, bool set, { struct bgp_path_info_mpath *mpath; - if ((mpath = path->mpath) == NULL) { + mpath = path->mpath; + if (mpath == NULL) { if (!set || (cum_bw == 0 && !all_paths_lb)) return; diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c index 742ef217d9..eb00a4641c 100644 --- a/bgpd/bgp_nht.c +++ b/bgpd/bgp_nht.c @@ -793,7 +793,18 @@ static int make_prefix(int afi, struct bgp_path_info *pi, struct prefix *p) || IN6_IS_ADDR_LINKLOCAL( &pi->attr->mp_nexthop_global))) p->u.prefix6 = pi->attr->mp_nexthop_local; - else + /* If we receive MR_REACH with (GA)::(LL) + * then check for route-map to choose GA or LL + */ + else if (pi->attr->mp_nexthop_len + == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) { + if (pi->attr->mp_nexthop_prefer_global) + p->u.prefix6 = + pi->attr->mp_nexthop_global; + else + p->u.prefix6 = + pi->attr->mp_nexthop_local; + } else p->u.prefix6 = pi->attr->mp_nexthop_global; p->prefixlen = IPV6_MAX_BITLEN; } @@ -1042,7 +1053,7 @@ void evaluate_paths(struct bgp_nexthop_cache *bnc) || path->attr->srte_color != 0) SET_FLAG(path->flags, BGP_PATH_IGP_CHANGED); - path_valid = !!CHECK_FLAG(path->flags, BGP_PATH_VALID); + path_valid = CHECK_FLAG(path->flags, BGP_PATH_VALID); if (path_valid != bnc_is_valid_nexthop) { if (path_valid) { /* No longer valid, clear flag; also for EVPN diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 4637cef3eb..bd45314350 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -6052,6 +6052,7 @@ int bgp_static_set(struct bgp *bgp, const char *negate, struct prefix *pfx, && (label_index != bgp_static->label_index)) { snprintf(errmsg, errmsg_len, "label-index doesn't match static route\n"); + bgp_dest_unlock_node(dest); return -1; } @@ -6059,6 +6060,7 @@ int bgp_static_set(struct bgp *bgp, const char *negate, struct prefix *pfx, && strcmp(rmap, bgp_static->rmap.name)) { snprintf(errmsg, errmsg_len, "route-map name doesn't match static route\n"); + bgp_dest_unlock_node(dest); return -1; } @@ -11643,7 +11645,8 @@ static int bgp_show_route_in_table(struct vty *vty, struct bgp *bgp, if (!table) continue; - if ((rm = bgp_node_match(table, &match)) == NULL) + rm = bgp_node_match(table, &match); + if (rm == NULL) continue; const struct prefix *rm_p = bgp_dest_get_prefix(rm); @@ -11735,7 +11738,8 @@ static int bgp_show_route_in_table(struct vty *vty, struct bgp *bgp, json_object_free(json_paths); } } else { - if ((dest = bgp_node_match(rib, &match)) != NULL) { + dest = bgp_node_match(rib, &match); + if (dest != NULL) { const struct prefix *dest_p = bgp_dest_get_prefix(dest); if (!prefix_check || dest_p->prefixlen == match.prefixlen) { @@ -14377,6 +14381,7 @@ int bgp_distance_unset(uint8_t distance, const char *ip_str, if (bdistance->distance != distance) { snprintf(errmsg, errmsg_len, "Distance does not match configured\n"); + bgp_dest_unlock_node(dest); return CMD_WARNING_CONFIG_FAILED; } @@ -14758,7 +14763,8 @@ static int bgp_clear_damp_route(struct vty *vty, const char *view_name, table = bgp_dest_get_bgp_table_info(dest); if (!table) continue; - if ((rm = bgp_node_match(table, &match)) == NULL) + rm = bgp_node_match(table, &match); + if (rm == NULL) continue; const struct prefix *rm_p = bgp_dest_get_prefix(dest); @@ -14782,8 +14788,8 @@ static int bgp_clear_damp_route(struct vty *vty, const char *view_name, bgp_dest_unlock_node(rm); } } else { - if ((dest = bgp_node_match(bgp->rib[afi][safi], &match)) - != NULL) { + dest = bgp_node_match(bgp->rib[afi][safi], &match); + if (dest != NULL) { const struct prefix *dest_p = bgp_dest_get_prefix(dest); if (!prefix_check diff --git a/bgpd/bgp_routemap_nb_config.c b/bgpd/bgp_routemap_nb_config.c index e541d117be..88e3f6438f 100644 --- a/bgpd/bgp_routemap_nb_config.c +++ b/bgpd/bgp_routemap_nb_config.c @@ -70,8 +70,8 @@ static int bgp_route_match_delete(struct route_map_index *index, if (type != RMAP_EVENT_MATCH_DELETED) { /* ignore the mundane, the types without any dependency */ if (arg == NULL) { - if ((tmpstr = route_map_get_match_arg(index, command)) - != NULL) + tmpstr = route_map_get_match_arg(index, command); + if (tmpstr != NULL) dep_name = XSTRDUP(MTYPE_ROUTE_MAP_RULE, tmpstr); } else { diff --git a/bgpd/bgp_updgrp.c b/bgpd/bgp_updgrp.c index b8545188a4..dd3309dad9 100644 --- a/bgpd/bgp_updgrp.c +++ b/bgpd/bgp_updgrp.c @@ -339,6 +339,7 @@ static unsigned int updgrp_hash_key_make(const void *p) key); key = jhash_1word(peer->v_routeadv, key); key = jhash_1word(peer->change_local_as, key); + key = jhash_1word(peer->max_packet_size, key); if (peer->group) key = jhash_1word(jhash(peer->group->name, @@ -572,6 +573,7 @@ static int update_group_show_walkcb(struct update_group *updgrp, void *arg) struct update_subgroup *subgrp; struct peer_af *paf; struct bgp_filter *filter; + struct peer *peer = UPDGRP_PEER(updgrp); int match = 0; if (!ctx) @@ -663,6 +665,9 @@ static int update_group_show_walkcb(struct update_group *updgrp, void *arg) CHECK_FLAG(subgrp->flags, SUBGRP_FLAG_NEEDS_REFRESH) ? "R" : ""); + if (peer) + vty_out(vty, " Max packet size: %d\n", + peer->max_packet_size); if (subgrp->peer_count > 0) { vty_out(vty, " Peers:\n"); SUBGRP_FOREACH_PEER (subgrp, paf) diff --git a/bgpd/bgp_updgrp_adv.c b/bgpd/bgp_updgrp_adv.c index 18829aa747..9c2288cba3 100644 --- a/bgpd/bgp_updgrp_adv.c +++ b/bgpd/bgp_updgrp_adv.c @@ -572,7 +572,8 @@ void bgp_adj_out_unset_subgroup(struct bgp_dest *dest, return; /* Lookup existing adjacency */ - if ((adj = adj_lookup(dest, subgrp, addpath_tx_id)) != NULL) { + adj = adj_lookup(dest, subgrp, addpath_tx_id); + if (adj != NULL) { /* Clean up previous advertisement. */ if (adj->adv) bgp_advertise_clean_subgroup(subgrp, adj); diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index e713894eb1..9d7e88bb1c 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -1857,9 +1857,8 @@ void cli_show_router_bgp_med_config(struct vty *vty, struct lyd_node *dnode, uint32_t med_admin_val; vty_out(vty, " bgp max-med administrative"); - if ((med_admin_val = - yang_dnode_get_uint32(dnode, "./max-med-admin")) - != BGP_MAXMED_VALUE_DEFAULT) + med_admin_val = yang_dnode_get_uint32(dnode, "./max-med-admin"); + if (med_admin_val != BGP_MAXMED_VALUE_DEFAULT) vty_out(vty, " %u", med_admin_val); vty_out(vty, "\n"); } @@ -10196,7 +10195,8 @@ static int bgp_clear_prefix(struct vty *vty, const char *view_name, if (table == NULL) continue; - if ((rm = bgp_node_match(table, &match)) != NULL) { + rm = bgp_node_match(table, &match); + if (rm != NULL) { const struct prefix *rm_p = bgp_dest_get_prefix(rm); @@ -10209,7 +10209,8 @@ static int bgp_clear_prefix(struct vty *vty, const char *view_name, } } } else { - if ((dest = bgp_node_match(rib, &match)) != NULL) { + dest = bgp_node_match(rib, &match); + if (dest != NULL) { const struct prefix *dest_p = bgp_dest_get_prefix(dest); if (dest_p->prefixlen == match.prefixlen) { diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 197133cbb4..01ea300557 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -1369,7 +1369,7 @@ struct peer *peer_new(struct bgp *bgp) peer->bgp = bgp_lock(bgp); peer = peer_lock(peer); /* initial reference */ peer->password = NULL; - peer->max_packet_size = BGP_MAX_PACKET_SIZE; + peer->max_packet_size = BGP_STANDARD_MESSAGE_MAX_PACKET_SIZE; /* Set default flags. */ FOREACH_AFI_SAFI (afi, safi) { @@ -1466,6 +1466,8 @@ void peer_xfer_config(struct peer *peer_dst, struct peer *peer_src) (void)peer_sort(peer_dst); peer_dst->rmap_type = peer_src->rmap_type; + peer_dst->max_packet_size = peer_src->max_packet_size; + /* Timers */ peer_dst->holdtime = peer_src->holdtime; peer_dst->keepalive = peer_src->keepalive; @@ -2315,13 +2317,6 @@ int peer_deactivate(struct peer *peer, afi_t afi, safi_t safi) peer->afc[afi][safi] = 0; group = peer->group; - if (peer_af_delete(peer, afi, safi) != 0) { - flog_err( - EC_BGP_PEER_DELETE, - "couldn't delete af structure for peer %s(%s, %s)", - peer->host, afi2str(afi), safi2str(safi)); - } - for (ALL_LIST_ELEMENTS(group->peer, node, nnode, tmp_peer)) { ret |= non_peergroup_deactivate_af(tmp_peer, afi, safi); } @@ -3097,8 +3092,7 @@ static struct bgp *bgp_create(as_t *as, const char *name, afi_t afi; safi_t safi; - if ((bgp = XCALLOC(MTYPE_BGP, sizeof(struct bgp))) == NULL) - return NULL; + bgp = XCALLOC(MTYPE_BGP, sizeof(struct bgp)); if (BGP_DEBUG(zebra, ZEBRA)) { if (inst_type == BGP_INSTANCE_TYPE_DEFAULT) diff --git a/configure.ac b/configure.ac index 2a8411d122..564588cca7 100644 --- a/configure.ac +++ b/configure.ac @@ -672,8 +672,6 @@ AC_ARG_ENABLE([fpm], AS_HELP_STRING([--enable-fpm], [enable Forwarding Plane Manager support])) AC_ARG_ENABLE([pcep], AS_HELP_STRING([--enable-pcep], [enable PCEP support for pathd])) -AC_ARG_ENABLE([systemd], - AS_HELP_STRING([--enable-systemd], [enable Systemd support])) AC_ARG_ENABLE([werror], AS_HELP_STRING([--enable-werror], [enable -Werror (recommended for developers only)])) AC_ARG_ENABLE([cumulus], @@ -768,19 +766,6 @@ case "${enable_cpu_time}" in ;; esac -case "${enable_systemd}" in - "no") ;; - "yes") - AC_CHECK_LIB([systemd], [sd_notify], [LIBS="$LIBS -lsystemd"]) - if test "$ac_cv_lib_systemd_sd_notify" = "no"; then - AC_MSG_ERROR([enable systemd has been specified but systemd development env not found on your system]) - else - AC_DEFINE([HAVE_SYSTEMD], [1], [Compile systemd support in]) - fi - ;; - "*") ;; -esac - if test "$enable_rr_semantics" != "no" ; then AC_DEFINE([HAVE_V6_RR_SEMANTICS], [1], [Compile in v6 Route Replacement Semantics]) fi diff --git a/debian/README.Debian b/debian/README.Debian index a23a0efcac..53fb6c9d0e 100644 --- a/debian/README.Debian +++ b/debian/README.Debian @@ -31,10 +31,6 @@ The following Build Profiles have been added: controls whether the RPKI module is built. Will be enabled by default at some point, adds some extra dependencies. -- pkg.frr.nosystemd - Disables both systemd unit file installation as well as watchfrr sd_notify - support at startup. Removes libsystemd dependency. - Note that all options have a "no" form; if you want to have your decision be sticky regardless of changes to what it defaults to, then always use one of the two. For example, all occurrences of <pkg.frr.rtrlib> will at some @@ -43,10 +39,6 @@ point be replaced with <!pkg.frr.nortrlib>. The main frr package has the exact same contents regardless of rtrlib or snmp choices. The options only control frr-snmp and frr-rpki-rtrlib packages. -The main frr package does NOT have the same contents if pkg.frr.nosystemd is -used. This option should only be used for systems that do not have systemd, -e.g. Ubuntu 14.04. - * Debian Policy compliance notes ================================ diff --git a/debian/control b/debian/control index 0bbe99b312..0e67ff3730 100644 --- a/debian/control +++ b/debian/control @@ -22,7 +22,6 @@ Build-Depends: bison, librtr-dev <!pkg.frr.nortrlib>, libsnmp-dev, libssh-dev <!pkg.frr.nortrlib>, - libsystemd-dev <!pkg.frr.nosystemd>, libyang2-dev, lsb-base, pkg-config, diff --git a/debian/rules b/debian/rules index 93d0cdb2a0..0fa9c3a3b0 100755 --- a/debian/rules +++ b/debian/rules @@ -21,14 +21,6 @@ else CONF_RPKI=--disable-rpki endif -ifeq ($(filter pkg.frr.nosystemd,$(DEB_BUILD_PROFILES)),) - DH_WITHOUT_SYSTEMD= - CONF_SYSTEMD=--enable-systemd=yes -else - DH_WITHOUT_SYSTEMD=--without=systemd - CONF_SYSTEMD=--enable-systemd=no -endif - ifeq ($(filter pkg.frr.lua,$(DEB_BUILD_PROFILES)),) CONF_LUA=--disable-scripting else @@ -38,7 +30,7 @@ endif export PYTHON=python3 %: - dh $@ $(DH_WITHOUT_SYSTEMD) + dh $@ override_dh_auto_configure: $(shell dpkg-buildflags --export=sh); \ @@ -52,7 +44,6 @@ override_dh_auto_configure: LIBTOOLFLAGS="-rpath /usr/lib/$(DEB_HOST_MULTIARCH)/frr" \ --disable-dependency-tracking \ \ - $(CONF_SYSTEMD) \ $(CONF_RPKI) \ $(CONF_LUA) \ --with-libpam \ @@ -80,9 +71,7 @@ override_dh_auto_install: sed -e '1c #!/usr/bin/python3' -i debian/tmp/usr/lib/frr/generate_support_bundle.py # let dh_systemd_* and dh_installinit do their thing automatically -ifeq ($(filter pkg.frr.nosystemd,$(DEB_BUILD_PROFILES)),) cp tools/frr.service debian/frr.service -endif cp tools/frrinit.sh debian/frr.init -rm -f debian/tmp/usr/lib/frr/frr diff --git a/doc/developer/building-frr-for-archlinux.rst b/doc/developer/building-frr-for-archlinux.rst index e589a9f724..af1677e89e 100644 --- a/doc/developer/building-frr-for-archlinux.rst +++ b/doc/developer/building-frr-for-archlinux.rst @@ -10,8 +10,8 @@ Installing Dependencies sudo pacman -S \ git autoconf automake libtool make cmake pcre readline texinfo \ pkg-config pam json-c bison flex python-pytest \ - c-ares python systemd python2-ipaddress python-sphinx \ - systemd-libs net-snmp perl libcap libelf + c-ares python python2-ipaddress python-sphinx \ + net-snmp perl libcap libelf .. include:: building-libyang.rst diff --git a/doc/developer/building-frr-for-centos7.rst b/doc/developer/building-frr-for-centos7.rst index 93b9993a38..ce11126f70 100644 --- a/doc/developer/building-frr-for-centos7.rst +++ b/doc/developer/building-frr-for-centos7.rst @@ -21,7 +21,7 @@ Add packages: sudo yum install git autoconf automake libtool make \ readline-devel texinfo net-snmp-devel groff pkgconfig \ json-c-devel pam-devel bison flex pytest c-ares-devel \ - python-devel systemd-devel python-sphinx libcap-devel \ + python-devel python-sphinx libcap-devel \ elfutils-libelf-devel .. include:: building-libyang.rst @@ -66,7 +66,6 @@ an example.) --enable-user=frr \ --enable-group=frr \ --enable-vty-group=frrvty \ - --enable-systemd=yes \ --disable-ldpd \ --enable-fpm \ --with-pkg-git-version \ diff --git a/doc/developer/building-frr-for-centos8.rst b/doc/developer/building-frr-for-centos8.rst index 65c93286b7..109a7866d9 100644 --- a/doc/developer/building-frr-for-centos8.rst +++ b/doc/developer/building-frr-for-centos8.rst @@ -14,7 +14,7 @@ Add packages: sudo dnf install --enablerepo=PowerTools git autoconf pcre-devel \ automake libtool make readline-devel texinfo net-snmp-devel pkgconfig \ groff pkgconfig json-c-devel pam-devel bison flex python2-pytest \ - c-ares-devel python2-devel systemd-devel libcap-devel \ + c-ares-devel python2-devel libcap-devel \ elfutils-libelf-devel .. include:: building-libyang.rst @@ -59,7 +59,6 @@ an example.) --enable-user=frr \ --enable-group=frr \ --enable-vty-group=frrvty \ - --enable-systemd=yes \ --disable-ldpd \ --enable-fpm \ --with-pkg-git-version \ diff --git a/doc/developer/building-frr-for-debian8.rst b/doc/developer/building-frr-for-debian8.rst index 475e0303fc..5e58854ed7 100644 --- a/doc/developer/building-frr-for-debian8.rst +++ b/doc/developer/building-frr-for-debian8.rst @@ -17,7 +17,7 @@ Add packages: sudo apt-get install git autoconf automake libtool make \ libreadline-dev texinfo libjson-c-dev pkg-config bison flex python3-pip \ - libc-ares-dev python3-dev python3-sphinx build-essential libsystemd-dev \ + libc-ares-dev python3-dev python3-sphinx build-essential \ libsnmp-dev libcap-dev libelf-dev Install newer pytest (>3.0) from pip diff --git a/doc/developer/building-frr-for-debian9.rst b/doc/developer/building-frr-for-debian9.rst index 1981127b3d..f8d8025f62 100644 --- a/doc/developer/building-frr-for-debian9.rst +++ b/doc/developer/building-frr-for-debian9.rst @@ -11,7 +11,7 @@ Add packages: sudo apt-get install git autoconf automake libtool make \ libreadline-dev texinfo libjson-c-dev pkg-config bison flex \ libc-ares-dev python3-dev python3-pytest python3-sphinx build-essential \ - libsnmp-dev libsystemd-dev libcap-dev libelf-dev + libsnmp-dev libcap-dev libelf-dev .. include:: building-libyang.rst diff --git a/doc/developer/building-frr-for-fedora.rst b/doc/developer/building-frr-for-fedora.rst index 5fecd8a826..6ce76ba158 100644 --- a/doc/developer/building-frr-for-fedora.rst +++ b/doc/developer/building-frr-for-fedora.rst @@ -14,7 +14,7 @@ Installing Dependencies sudo dnf install git autoconf automake libtool make \ readline-devel texinfo net-snmp-devel groff pkgconfig json-c-devel \ pam-devel python3-pytest bison flex c-ares-devel python3-devel \ - python3-sphinx perl-core patch systemd-devel libcap-devel \ + python3-sphinx perl-core patch libcap-devel \ elfutils-libelf-devel .. include:: building-libyang.rst diff --git a/doc/developer/building-frr-for-opensuse.rst b/doc/developer/building-frr-for-opensuse.rst index 4e886e9c25..ee6a36a14b 100644 --- a/doc/developer/building-frr-for-opensuse.rst +++ b/doc/developer/building-frr-for-opensuse.rst @@ -13,7 +13,7 @@ Installing Dependencies zypper in git autoconf automake libtool make \ readline-devel texinfo net-snmp-devel groff pkgconfig libjson-c-devel\ pam-devel python3-pytest bison flex c-ares-devel python3-devel\ - python3-Sphinx perl patch systemd-devel libcap-devel libyang-devel \ + python3-Sphinx perl patch libcap-devel libyang-devel \ libelf-devel Building & Installing FRR diff --git a/doc/developer/building-frr-for-ubuntu1604.rst b/doc/developer/building-frr-for-ubuntu1604.rst index 2cb9536f9b..d79545c859 100644 --- a/doc/developer/building-frr-for-ubuntu1604.rst +++ b/doc/developer/building-frr-for-ubuntu1604.rst @@ -13,8 +13,8 @@ Installing Dependencies apt-get install \ git autoconf automake libtool make libreadline-dev texinfo \ pkg-config libpam0g-dev libjson-c-dev bison flex python3-pytest \ - libc-ares-dev python3-dev libsystemd-dev python-ipaddress python3-sphinx \ - install-info build-essential libsystemd-dev libsnmp-dev perl libcap-dev \ + libc-ares-dev python3-dev python-ipaddress python3-sphinx \ + install-info build-essential libsnmp-dev perl libcap-dev \ libelf-dev .. include:: building-libyang.rst diff --git a/doc/developer/building-frr-for-ubuntu1804.rst b/doc/developer/building-frr-for-ubuntu1804.rst index eb3991c139..39a17fc01c 100644 --- a/doc/developer/building-frr-for-ubuntu1804.rst +++ b/doc/developer/building-frr-for-ubuntu1804.rst @@ -13,8 +13,8 @@ Installing Dependencies sudo apt-get install \ git autoconf automake libtool make libreadline-dev texinfo \ pkg-config libpam0g-dev libjson-c-dev bison flex python3-pytest \ - libc-ares-dev python3-dev libsystemd-dev python-ipaddress python3-sphinx \ - install-info build-essential libsystemd-dev libsnmp-dev perl libcap-dev \ + libc-ares-dev python3-dev python-ipaddress python3-sphinx \ + install-info build-essential libsnmp-dev perl libcap-dev \ libelf-dev .. include:: building-libyang.rst diff --git a/doc/developer/building-frr-for-ubuntu2004.rst b/doc/developer/building-frr-for-ubuntu2004.rst index 58d72e2891..92ddead4a5 100644 --- a/doc/developer/building-frr-for-ubuntu2004.rst +++ b/doc/developer/building-frr-for-ubuntu2004.rst @@ -13,8 +13,8 @@ Installing Dependencies sudo apt-get install \ git autoconf automake libtool make libreadline-dev texinfo \ pkg-config libpam0g-dev libjson-c-dev bison flex python3-pytest \ - libc-ares-dev python3-dev libsystemd-dev python-ipaddress python3-sphinx \ - install-info build-essential libsystemd-dev libsnmp-dev perl \ + libc-ares-dev python3-dev python-ipaddress python3-sphinx \ + install-info build-essential libsnmp-dev perl \ libcap-dev python2 libelf-dev Note that Ubuntu 20 no longer installs python 2.x, so it must be diff --git a/doc/developer/include-compile.rst b/doc/developer/include-compile.rst index d9fa260221..513cac6179 100644 --- a/doc/developer/include-compile.rst +++ b/doc/developer/include-compile.rst @@ -2,11 +2,6 @@ Clone the FRR git repo and use the included ``configure`` script to configure FRR's build time options to your liking. The full option listing can be obtained by running ``./configure -h``. The options shown below are examples. -.. note:: - - If your platform uses ``systemd``, please make sure to add - ``--enable-systemd=yes`` to your configure options. - .. code-block:: console git clone https://github.com/frrouting/frr.git frr diff --git a/doc/developer/packaging-debian.rst b/doc/developer/packaging-debian.rst index 968e960267..a81e052490 100644 --- a/doc/developer/packaging-debian.rst +++ b/doc/developer/packaging-debian.rst @@ -53,7 +53,7 @@ buster.) Where `$options` may contain any or all of the following items: * build profiles specified with ``-P``, e.g. - ``-Ppkg.frr.nortrlib,pkg.frr.nosystemd``. + ``-Ppkg.frr.nortrlib,pkg.frr.rtrlib``. Multiple values are separated by commas and there must not be a space after the ``-P``. @@ -64,14 +64,6 @@ buster.) +================+===================+=========================================+ | pkg.frr.rtrlib | pkg.frr.nortrlib | builds frr-rpki-rtrlib package (or not) | +----------------+-------------------+-----------------------------------------+ - | n/a | pkg.frr.nosystemd | removes libsystemd dependency and | - | | | disables unit file installation | - +----------------+-------------------+-----------------------------------------+ - - .. note:: - - The ``pkg.frr.nosystemd`` option is only intended to support Ubuntu - 14.04 (and should be enabled when building for that.) * the ``-uc -us`` options to disable signing the packages with your GPG key diff --git a/doc/developer/packaging-redhat.rst b/doc/developer/packaging-redhat.rst index 458cfa0ad4..9e64b912f3 100644 --- a/doc/developer/packaging-redhat.rst +++ b/doc/developer/packaging-redhat.rst @@ -18,10 +18,6 @@ Tested on CentOS 6, CentOS 7, CentOS 8 and Fedora 24. yum install rpm-build net-snmp-devel pam-devel libcap-devel - If your platform uses systemd:: - - yum install systemd-devel - For CentOS 7 and CentOS 8, the package will be built using python3 and requires additional python3 packages:: diff --git a/doc/user/installation.rst b/doc/user/installation.rst index 63254555d9..fdf5bab9c9 100644 --- a/doc/user/installation.rst +++ b/doc/user/installation.rst @@ -146,11 +146,6 @@ options from the list below. software available on your machine. This is needed for systemd integration, if you disable watchfrr you cannot have any systemd integration. -.. option:: --enable-systemd - - Build watchfrr with systemd integration, this will allow FRR to communicate with - systemd to tell systemd if FRR has come up properly. - .. option:: --enable-werror Build with all warnings converted to errors as a compile option. This @@ -404,6 +399,12 @@ options to the configuration script. Set StrongSWAN vici interface socket path [/var/run/charon.vici]. +.. note:: + + The former ``--enable-systemd`` option does not exist anymore. Support for + systemd is now always available through built-in functions, without + depending on libsystemd. + Python dependency, documentation and tests ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/doc/user/ospf6d.rst b/doc/user/ospf6d.rst index 04ee1643d8..c4a1bc381e 100644 --- a/doc/user/ospf6d.rst +++ b/doc/user/ospf6d.rst @@ -85,6 +85,61 @@ OSPF6 router change to take effect, user can use this cli instead of restarting the ospf6d daemon. +.. _ospf6-debugging: + +OSPFv3 Debugging +================ + +The following debug commands are supported: + +.. clicmd:: debug ospf6 abr + + Toggle OSPFv3 ABR debugging messages. + +.. clicmd:: debug ospf6 asbr + + Toggle OSPFv3 ASBR debugging messages. + +.. clicmd:: debug ospf6 border-routers + + Toggle OSPFv3 border router debugging messages. + +.. clicmd:: debug ospf6 flooding + + Toggle OSPFv3 flooding debugging messages. + +.. clicmd:: debug ospf6 interface + + Toggle OSPFv3 interface related debugging messages. + +.. clicmd:: debug ospf6 lsa + + Toggle OSPFv3 Link State Advertisements debugging messages. + +.. clicmd:: debug ospf6 message + + Toggle OSPFv3 message exchange debugging messages. + +.. clicmd:: debug ospf6 neighbor + + Toggle OSPFv3 neighbor interaction debugging messages. + +.. clicmd:: debug ospf6 nssa + + Toggle OSPFv3 Not So Stubby Area (NSSA) debugging messages. + +.. clicmd:: debug ospf6 route + + Toggle OSPFv3 routes debugging messages. + +.. clicmd:: debug ospf6 spf + + Toggle OSPFv3 Shortest Path calculation debugging messages. + +.. clicmd:: debug ospf6 zebra + + Toggle OSPFv3 zebra interaction debugging messages. + .. _ospf6-area: OSPF6 area diff --git a/docker/centos-7/Dockerfile b/docker/centos-7/Dockerfile index 303a33fe4a..73097df8fa 100644 --- a/docker/centos-7/Dockerfile +++ b/docker/centos-7/Dockerfile @@ -4,7 +4,7 @@ RUN yum install -y epel-release RUN yum install -y rpm-build autoconf automake libtool make \ readline-devel texinfo net-snmp-devel groff pkgconfig \ json-c-devel pam-devel bison flex pytest c-ares-devel \ - python3-devel python3-sphinx systemd-devel libcap-devel \ + python3-devel python3-sphinx libcap-devel \ https://ci1.netdef.org/artifact/LIBYANG-LIBYANGV2/shared/build-2/CentOS-7-x86_64-Packages/libyang2-2.0.0.10.g2eb910e4-1.el7.x86_64.rpm \ https://ci1.netdef.org/artifact/LIBYANG-LIBYANGV2/shared/build-2/CentOS-7-x86_64-Packages/libyang2-devel-2.0.0.10.g2eb910e4-1.el7.x86_64.rpm \ https://ci1.netdef.org/artifact/RPKI-RTRLIB/shared/build-110/CentOS-7-x86_64-Packages/librtr-0.7.0-1.el7.centos.x86_64.rpm \ diff --git a/docker/centos-8/Dockerfile b/docker/centos-8/Dockerfile index 8a0c28e13b..71378c2451 100644 --- a/docker/centos-8/Dockerfile +++ b/docker/centos-8/Dockerfile @@ -4,7 +4,7 @@ FROM centos:centos8 as centos-8-builder RUN dnf install --enablerepo=powertools -y rpm-build git autoconf pcre-devel \ automake libtool make readline-devel texinfo net-snmp-devel pkgconfig \ groff pkgconfig json-c-devel pam-devel bison flex python3-pytest \ - c-ares-devel python3-devel python3-sphinx systemd-devel libcap-devel platform-python-devel \ + c-ares-devel python3-devel python3-sphinx libcap-devel platform-python-devel \ https://ci1.netdef.org/artifact/LIBYANG-LIBYANGV2/shared/build-2/CentOS-8-x86_64-Packages/libyang2-2.0.0.10.g2eb910e4-1.el8.x86_64.rpm \ https://ci1.netdef.org/artifact/LIBYANG-LIBYANGV2/shared/build-2/CentOS-8-x86_64-Packages/libyang2-devel-2.0.0.10.g2eb910e4-1.el8.x86_64.rpm \ https://ci1.netdef.org/artifact/RPKI-RTRLIB/shared/build-110/CentOS-7-x86_64-Packages/librtr-0.7.0-1.el7.centos.x86_64.rpm \ diff --git a/docker/ubuntu18-ci/Dockerfile b/docker/ubuntu18-ci/Dockerfile index 680b9172ad..766f06dfc2 100644 --- a/docker/ubuntu18-ci/Dockerfile +++ b/docker/ubuntu18-ci/Dockerfile @@ -7,8 +7,8 @@ RUN apt update && \ apt-get install -y \ git autoconf automake libtool make libreadline-dev texinfo \ pkg-config libpam0g-dev libjson-c-dev bison flex python3-pytest \ - libc-ares-dev python3-dev libsystemd-dev python-ipaddress python3-sphinx \ - install-info build-essential libsystemd-dev libsnmp-dev perl libcap-dev \ + libc-ares-dev python3-dev python-ipaddress python3-sphinx \ + install-info build-essential libsnmp-dev perl libcap-dev \ libelf-dev \ sudo gdb iputils-ping time \ mininet python-pip iproute2 iperf && \ diff --git a/docker/ubuntu20-ci/Dockerfile b/docker/ubuntu20-ci/Dockerfile index 47d5b81d3a..b5df98f23e 100644 --- a/docker/ubuntu20-ci/Dockerfile +++ b/docker/ubuntu20-ci/Dockerfile @@ -7,8 +7,8 @@ RUN apt update && \ apt-get install -y \ git autoconf automake libtool make libreadline-dev texinfo \ pkg-config libpam0g-dev libjson-c-dev bison flex python3-pytest \ - libc-ares-dev python3-dev libsystemd-dev python-ipaddress python3-sphinx \ - install-info build-essential libsystemd-dev libsnmp-dev perl \ + libc-ares-dev python3-dev python-ipaddress python3-sphinx \ + install-info build-essential libsnmp-dev perl \ libcap-dev python2 libelf-dev \ sudo gdb curl iputils-ping time \ libgrpc++-dev libgrpc-dev protobuf-compiler-grpc \ diff --git a/lib/buffer.c b/lib/buffer.c index 7929b3709d..41b1adc9fc 100644 --- a/lib/buffer.c +++ b/lib/buffer.c @@ -357,7 +357,8 @@ buffer_status_t buffer_flush_window(struct buffer *b, int fd, int width, iov_size = ((iov_index > IOV_MAX) ? IOV_MAX : iov_index); - if ((nbytes = writev(fd, c_iov, iov_size)) < 0) { + nbytes = writev(fd, c_iov, iov_size); + if (nbytes < 0) { flog_err(EC_LIB_SOCKET, "%s: writev to fd %d failed: %s", __func__, fd, safe_strerror(errno)); @@ -370,7 +371,8 @@ buffer_status_t buffer_flush_window(struct buffer *b, int fd, int width, } } #else /* IOV_MAX */ - if ((nbytes = writev(fd, iov, iov_index)) < 0) + nbytes = writev(fd, iov, iov_index); + if (nbytes < 0) flog_err(EC_LIB_SOCKET, "%s: writev to fd %d failed: %s", __func__, fd, safe_strerror(errno)); #endif /* IOV_MAX */ @@ -472,13 +474,17 @@ buffer_status_t buffer_write(struct buffer *b, int fd, const void *p, /* Buffer is not empty, so do not attempt to write the new data. */ nbytes = 0; - else if ((nbytes = write(fd, p, size)) < 0) { - if (ERRNO_IO_RETRY(errno)) - nbytes = 0; - else { - flog_err(EC_LIB_SOCKET, "%s: write error on fd %d: %s", - __func__, fd, safe_strerror(errno)); - return BUFFER_ERROR; + else { + nbytes = write(fd, p, size); + if (nbytes < 0) { + if (ERRNO_IO_RETRY(errno)) + nbytes = 0; + else { + flog_err(EC_LIB_SOCKET, + "%s: write error on fd %d: %s", + __func__, fd, safe_strerror(errno)); + return BUFFER_ERROR; + } } } /* Add any remaining data to the buffer. */ @@ -641,7 +641,8 @@ static int get_memory_usage(pid_t pid) char *vm; snprintf(status_child, sizeof(status_child), "/proc/%d/status", pid); - if ((fd = open(status_child, O_RDONLY)) < 0) + fd = open(status_child, O_RDONLY); + if (fd < 0) return -1; read(fd, buf, 4095); diff --git a/lib/libfrr.c b/lib/libfrr.c index 0817182f7a..97dab74d9b 100644 --- a/lib/libfrr.c +++ b/lib/libfrr.c @@ -44,6 +44,7 @@ #include "frr_pthread.h" #include "defaults.h" #include "frrscript.h" +#include "systemd.h" DEFINE_HOOK(frr_late_init, (struct thread_master * tm), (tm)); DEFINE_HOOK(frr_config_pre, (struct thread_master * tm), (tm)); @@ -363,6 +364,11 @@ void frr_preinit(struct frr_daemon_info *daemon, int argc, char **argv) startup_fds |= UINT64_C(0x1) << (uint64_t)i; } + + /* note this doesn't do anything, it just grabs state, so doing it + * early in _preinit is perfect. + */ + systemd_init_env(); } bool frr_is_startup_fd(int fd) diff --git a/lib/link_state.c b/lib/link_state.c index e8a6b89f89..062384aac7 100644 --- a/lib/link_state.c +++ b/lib/link_state.c @@ -538,8 +538,6 @@ struct ls_edge *ls_edge_add(struct ls_ted *ted, /* Create Edge and add it to the TED */ new = XCALLOC(MTYPE_LS_DB, sizeof(struct ls_edge)); - if (!new) - return NULL; new->attributes = attributes; new->key = key; @@ -804,8 +802,6 @@ struct ls_ted *ls_ted_new(const uint32_t key, const char *name, struct ls_ted *new; new = XCALLOC(MTYPE_LS_DB, sizeof(struct ls_ted)); - if (new == NULL) - return new; /* Set basic information for this ted */ new->key = key; @@ -1005,8 +1001,6 @@ static struct ls_node *ls_parse_node(struct stream *s) size_t len; node = XCALLOC(MTYPE_LS_DB, sizeof(struct ls_node)); - if (node == NULL) - return NULL; STREAM_GET(&node->adv, s, sizeof(struct ls_node_id)); STREAM_GETW(s, node->flags); @@ -1051,8 +1045,6 @@ static struct ls_attributes *ls_parse_attributes(struct stream *s) size_t len; attr = XCALLOC(MTYPE_LS_DB, sizeof(struct ls_attributes)); - if (attr == NULL) - return NULL; attr->srlgs = NULL; STREAM_GET(&attr->adv, s, sizeof(struct ls_node_id)); @@ -1157,8 +1149,6 @@ static struct ls_prefix *ls_parse_prefix(struct stream *s) size_t len; ls_pref = XCALLOC(MTYPE_LS_DB, sizeof(struct ls_prefix)); - if (ls_pref == NULL) - return NULL; STREAM_GET(&ls_pref->adv, s, sizeof(struct ls_node_id)); STREAM_GETW(s, ls_pref->flags); @@ -1193,8 +1183,6 @@ struct ls_message *ls_parse_msg(struct stream *s) struct ls_message *msg; msg = XCALLOC(MTYPE_LS_DB, sizeof(struct ls_message)); - if (msg == NULL) - return NULL; /* Read LS Message header */ STREAM_GETC(s, msg->event); diff --git a/lib/network.c b/lib/network.c index 411661a5e1..b60ad9a57c 100644 --- a/lib/network.c +++ b/lib/network.c @@ -78,7 +78,8 @@ int set_nonblocking(int fd) /* According to the Single UNIX Spec, the return value for F_GETFL should never be negative. */ - if ((flags = fcntl(fd, F_GETFL)) < 0) { + flags = fcntl(fd, F_GETFL); + if (flags < 0) { flog_err(EC_LIB_SYSTEM_CALL, "fcntl(F_GETFL) failed for fd %d: %s", fd, safe_strerror(errno)); diff --git a/lib/ntop.c b/lib/ntop.c index ccbf8793d3..1b2dd7a6d1 100644 --- a/lib/ntop.c +++ b/lib/ntop.c @@ -40,14 +40,18 @@ static inline void putbyte(uint8_t bytex, char **posx) bool zero = false; int byte = bytex, tmp, a, b; - if ((tmp = byte - 200) >= 0) { + tmp = byte - 200; + if (tmp >= 0) { *pos++ = '2'; zero = true; byte = tmp; - } else if ((tmp = byte - 100) >= 0) { - *pos++ = '1'; - zero = true; - byte = tmp; + } else { + tmp = byte - 100; + if (tmp >= 0) { + *pos++ = '1'; + zero = true; + byte = tmp; + } } /* make sure the compiler knows the value range of "byte" */ diff --git a/lib/prefix.c b/lib/prefix.c index 1c57715e8f..ef7d2e59da 100644 --- a/lib/prefix.c +++ b/lib/prefix.c @@ -1034,7 +1034,8 @@ const char *prefix2str(union prefixconstptr pu, char *str, int size) l = strlen(buf); buf[l++] = '/'; byte = p->prefixlen; - if ((tmp = p->prefixlen - 100) >= 0) { + tmp = p->prefixlen - 100; + if (tmp >= 0) { buf[l++] = '1'; z = true; byte = tmp; diff --git a/lib/prefix.h b/lib/prefix.h index bc4cb7f441..944c94f57f 100644 --- a/lib/prefix.h +++ b/lib/prefix.h @@ -537,20 +537,32 @@ static inline int ipv4_martian(struct in_addr *addr) return 0; } -static inline int is_default_prefix(const struct prefix *p) +static inline bool is_default_prefix4(const struct prefix_ipv4 *p) { - if (!p) - return 0; + return p && p->family == AF_INET && p->prefixlen == 0 + && p->prefix.s_addr == INADDR_ANY; +} - if ((p->family == AF_INET) && (p->u.prefix4.s_addr == INADDR_ANY) - && (p->prefixlen == 0)) - return 1; +static inline bool is_default_prefix6(const struct prefix_ipv6 *p) +{ + return p && p->family == AF_INET6 && p->prefixlen == 0 + && memcmp(&p->prefix, &in6addr_any, sizeof(struct in6_addr)) + == 0; +} - if ((p->family == AF_INET6) && (p->prefixlen == 0) - && (!memcmp(&p->u.prefix6, &in6addr_any, sizeof(struct in6_addr)))) - return 1; +static inline bool is_default_prefix(const struct prefix *p) +{ + if (p == NULL) + return false; + + switch (p->family) { + case AF_INET: + return is_default_prefix4((const struct prefix_ipv4 *)p); + case AF_INET6: + return is_default_prefix6((const struct prefix_ipv6 *)p); + } - return 0; + return false; } static inline int is_host_route(const struct prefix *p) diff --git a/lib/sockopt.c b/lib/sockopt.c index 98bfda5079..150736e00c 100644 --- a/lib/sockopt.c +++ b/lib/sockopt.c @@ -379,14 +379,14 @@ static int setsockopt_ipv4_ifindex(int sock, ifindex_t val) int ret; #if defined(IP_PKTINFO) - if ((ret = setsockopt(sock, IPPROTO_IP, IP_PKTINFO, &val, sizeof(val))) - < 0) + ret = setsockopt(sock, IPPROTO_IP, IP_PKTINFO, &val, sizeof(val)); + if (ret < 0) flog_err(EC_LIB_SOCKET, "Can't set IP_PKTINFO option for fd %d to %d: %s", sock, val, safe_strerror(errno)); #elif defined(IP_RECVIF) - if ((ret = setsockopt(sock, IPPROTO_IP, IP_RECVIF, &val, sizeof(val))) - < 0) + ret = setsockopt(sock, IPPROTO_IP, IP_RECVIF, &val, sizeof(val)); + if (ret < 0) flog_err(EC_LIB_SOCKET, "Can't set IP_RECVIF option for fd %d to %d: %s", sock, val, safe_strerror(errno)); @@ -639,12 +639,8 @@ int sockopt_tcp_signature_ext(int sock, union sockunion *su, uint16_t prefixlen, #endif /* GNU_LINUX */ - if ((ret = setsockopt(sock, IPPROTO_TCP, optname, &md5sig, - sizeof(md5sig))) - < 0) { - /* ENOENT is harmless. It is returned when we clear a password - for which - one was not previously set. */ + ret = setsockopt(sock, IPPROTO_TCP, optname, &md5sig, sizeof(md5sig)); + if (ret < 0) { if (ENOENT == errno) ret = 0; else diff --git a/lib/stream.c b/lib/stream.c index 904ee73b10..1557500c60 100644 --- a/lib/stream.c +++ b/lib/stream.c @@ -1097,7 +1097,8 @@ ssize_t stream_read_try(struct stream *s, int fd, size_t size) return -1; } - if ((nbytes = read(fd, s->data + s->endp, size)) >= 0) { + nbytes = read(fd, s->data + s->endp, size); + if (nbytes >= 0) { s->endp += nbytes; return nbytes; } @@ -1126,9 +1127,8 @@ ssize_t stream_recvfrom(struct stream *s, int fd, size_t size, int flags, return -1; } - if ((nbytes = recvfrom(fd, s->data + s->endp, size, flags, from, - fromlen)) - >= 0) { + nbytes = recvfrom(fd, s->data + s->endp, size, flags, from, fromlen); + if (nbytes >= 0) { s->endp += nbytes; return nbytes; } diff --git a/lib/systemd.c b/lib/systemd.c index c5cc3aa447..2238dc9f3d 100644 --- a/lib/systemd.c +++ b/lib/systemd.c @@ -20,68 +20,56 @@ */ #include <zebra.h> +#include <sys/un.h> #include "thread.h" #include "systemd.h" +#include "lib_errors.h" -#if defined HAVE_SYSTEMD -#include <systemd/sd-daemon.h> -#endif +/* these are cleared from env so they don't "leak" into things we fork(), + * particularly for watchfrr starting individual daemons + * + * watchdog_pid is currently not used since watchfrr starts forking. + * (TODO: handle that better, somehow?) + */ +static pid_t watchdog_pid = -1; +static intmax_t watchdog_msec; + +/* not used yet, but can trigger auto-switch to journald logging */ +bool sd_stdout_is_journal; +bool sd_stderr_is_journal; + +static char *notify_socket; -/* - * Wrapper this silliness if we - * don't have systemd +/* talk to whatever entity claims to be systemd ;) + * + * refer to sd_notify docs for messages systemd accepts over this socket. + * This function should be functionally equivalent to sd_notify(). */ static void systemd_send_information(const char *info) { -#if defined HAVE_SYSTEMD - sd_notify(0, info); -#else - return; -#endif -} + int sock; + struct sockaddr_un sun; -/* - * A return of 0 means that we are not watchdoged - */ -static int systemd_get_watchdog_time(int the_process) -{ -#if defined HAVE_SYSTEMD - uint64_t usec; - char *watchdog = NULL; - int ret; - - ret = sd_watchdog_enabled(0, &usec); - - /* - * If return is 0 -> we don't want watchdog - * if return is < 0, some sort of failure occurred - */ - if (ret < 0) - return 0; - - /* - * systemd can return that this process - * is not the expected sender of the watchdog timer - * If we set the_process = 0 then we expect to - * be able to send the watchdog to systemd - * irrelevant of the pid of this process. - */ - if (ret == 0 && the_process) - return 0; - - if (ret == 0 && !the_process) { - watchdog = getenv("WATCHDOG_USEC"); - if (!watchdog) - return 0; - - usec = atol(watchdog); - } + if (!notify_socket) + return; + + sock = socket(AF_UNIX, SOCK_DGRAM, 0); + if (sock < 0) + return; + + sun.sun_family = AF_UNIX; + strlcpy(sun.sun_path, notify_socket, sizeof(sun.sun_path)); - return (usec / 1000000) / 3; -#else - return 0; -#endif + /* linux abstract unix socket namespace */ + if (sun.sun_path[0] == '@') + sun.sun_path[0] = '\0'; + + /* nothing we can do if this errors out... */ + (void)sendto(sock, info, strlen(info), 0, (struct sockaddr *)&sun, + sizeof(sun)); + + close(sock); } void systemd_send_stopping(void) @@ -90,34 +78,27 @@ void systemd_send_stopping(void) systemd_send_information("STOPPING=1"); } -/* - * How many seconds should we wait between watchdog sends - */ -static int wsecs = 0; static struct thread_master *systemd_master = NULL; static int systemd_send_watchdog(struct thread *t) { systemd_send_information("WATCHDOG=1"); - thread_add_timer(systemd_master, systemd_send_watchdog, NULL, wsecs, - NULL); - + assert(watchdog_msec > 0); + thread_add_timer_msec(systemd_master, systemd_send_watchdog, NULL, + watchdog_msec, NULL); return 1; } -void systemd_send_started(struct thread_master *m, int the_process) +void systemd_send_started(struct thread_master *m) { assert(m != NULL); - wsecs = systemd_get_watchdog_time(the_process); systemd_master = m; systemd_send_information("READY=1"); - if (wsecs != 0) { - systemd_send_information("WATCHDOG=1"); - thread_add_timer(m, systemd_send_watchdog, m, wsecs, NULL); - } + if (watchdog_msec > 0) + systemd_send_watchdog(NULL); } void systemd_send_status(const char *status) @@ -127,3 +108,65 @@ void systemd_send_status(const char *status) snprintf(buffer, sizeof(buffer), "STATUS=%s", status); systemd_send_information(buffer); } + +static intmax_t getenv_int(const char *varname, intmax_t dflt) +{ + char *val, *err; + intmax_t intval; + + val = getenv(varname); + if (!val) + return dflt; + + intval = strtoimax(val, &err, 0); + if (*err || !*val) + return dflt; + return intval; +} + +void systemd_init_env(void) +{ + char *tmp; + uintmax_t dev, ino; + int len; + struct stat st; + + notify_socket = getenv("NOTIFY_SOCKET"); + + /* no point in setting up watchdog w/o notify socket */ + if (notify_socket) { + intmax_t watchdog_usec; + + watchdog_pid = getenv_int("WATCHDOG_PID", -1); + if (watchdog_pid <= 0) + watchdog_pid = -1; + + /* note this is the deadline, hence the divide by 3 */ + watchdog_usec = getenv_int("WATCHDOG_USEC", 0); + if (watchdog_usec >= 3000) + watchdog_msec = watchdog_usec / 3000; + else { + if (watchdog_usec != 0) + flog_err( + EC_LIB_UNAVAILABLE, + "systemd expects a %jd microsecond watchdog timer, but FRR only supports millisecond resolution!", + watchdog_usec); + watchdog_msec = 0; + } + } + + tmp = getenv("JOURNAL_STREAM"); + if (tmp && sscanf(tmp, "%ju:%ju%n", &dev, &ino, &len) == 2 + && (size_t)len == strlen(tmp)) { + if (fstat(1, &st) == 0 && st.st_dev == (dev_t)dev + && st.st_ino == (ino_t)ino) + sd_stdout_is_journal = true; + if (fstat(2, &st) == 0 && st.st_dev == (dev_t)dev + && st.st_ino == (ino_t)ino) + sd_stderr_is_journal = true; + } + + /* these should *not* be passed to any other process we start */ + unsetenv("WATCHDOG_PID"); + unsetenv("WATCHDOG_USEC"); +} diff --git a/lib/systemd.h b/lib/systemd.h index d9885c5d9c..1933f4f688 100644 --- a/lib/systemd.h +++ b/lib/systemd.h @@ -28,9 +28,6 @@ extern "C" { * * Design point is that if systemd is not being used on this system * then these functions becomes a no-op. - * - * To turn on systemd compilation, use --enable-systemd on - * configure run. */ void systemd_send_stopping(void); @@ -39,13 +36,18 @@ void systemd_send_stopping(void); * the_process - Should we send watchdog if we are not the requested * process? */ -void systemd_send_started(struct thread_master *master, int the_process); +void systemd_send_started(struct thread_master *master); /* * status - A status string to send to systemd */ void systemd_send_status(const char *status); +/* + * grab startup state from env vars + */ +void systemd_init_env(void); + #ifdef __cplusplus } #endif diff --git a/lib/zclient.c b/lib/zclient.c index 1b4ac080cd..0815e77d4e 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -1537,7 +1537,7 @@ int zapi_route_decode(struct stream *s, struct zapi_route *api) if (CHECK_FLAG(api->message, ZAPI_MESSAGE_OPAQUE)) { STREAM_GETW(s, api->opaque.length); - assert(api->opaque.length < ZAPI_MESSAGE_OPAQUE_LENGTH); + assert(api->opaque.length <= ZAPI_MESSAGE_OPAQUE_LENGTH); STREAM_GET(api->opaque.data, s, api->opaque.length); } @@ -3812,7 +3812,8 @@ static int zclient_read(struct thread *thread) zclient->t_read = NULL; /* Read zebra header (if we don't have it already). */ - if ((already = stream_get_endp(zclient->ibuf)) < ZEBRA_HEADER_SIZE) { + already = stream_get_endp(zclient->ibuf); + if (already < ZEBRA_HEADER_SIZE) { ssize_t nbyte; if (((nbyte = stream_read_try(zclient->ibuf, zclient->sock, ZEBRA_HEADER_SIZE - already)) @@ -3825,7 +3826,6 @@ static int zclient_read(struct thread *thread) return zclient_failed(zclient); } if (nbyte != (ssize_t)(ZEBRA_HEADER_SIZE - already)) { - /* Try again later. */ zclient_event(ZCLIENT_READ, zclient); return 0; } diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c index d4e52f0ede..3e911a743a 100644 --- a/ospf6d/ospf6_asbr.c +++ b/ospf6d/ospf6_asbr.c @@ -690,7 +690,7 @@ void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa, if (ospf6_check_and_set_router_abr(ospf6)) oa = ospf6->backbone; else - oa = listgetdata(listhead(ospf6->area_list)); + oa = listnode_head(ospf6->area_list); } if (oa == NULL) { @@ -2568,36 +2568,41 @@ int config_write_ospf6_debug_asbr(struct vty *vty) return 0; } -int ospf6_distribute_config_write(struct vty *vty, struct ospf6 *ospf6) +static void ospf6_default_originate_write(struct vty *vty, struct ospf6 *o) { struct ospf6_redist *red; - if (ospf6) { - /* default-route print. */ - if (ospf6->default_originate != DEFAULT_ORIGINATE_NONE) { - vty_out(vty, " default-information originate"); - if (ospf6->default_originate - == DEFAULT_ORIGINATE_ALWAYS) - vty_out(vty, " always"); - - red = ospf6_redist_lookup(ospf6, DEFAULT_ROUTE, 0); - if (red) { - if (red->dmetric.value >= 0) - vty_out(vty, " metric %d", - red->dmetric.value); - - if (red->dmetric.type >= 0) - vty_out(vty, " metric-type %d", - red->dmetric.type); - - if (ROUTEMAP_NAME(red)) - vty_out(vty, " route-map %s", - ROUTEMAP_NAME(red)); - } + vty_out(vty, " default-information originate"); + if (o->default_originate == DEFAULT_ORIGINATE_ALWAYS) + vty_out(vty, " always"); - vty_out(vty, "\n"); - } + red = ospf6_redist_lookup(o, DEFAULT_ROUTE, 0); + if (red == NULL) { + vty_out(vty, "\n"); + return; } + + if (red->dmetric.value >= 0) + vty_out(vty, " metric %d", red->dmetric.value); + + if (red->dmetric.type >= 0) + vty_out(vty, " metric-type %d", red->dmetric.type); + + if (ROUTEMAP_NAME(red)) + vty_out(vty, " route-map %s", ROUTEMAP_NAME(red)); + + vty_out(vty, "\n"); +} + +int ospf6_distribute_config_write(struct vty *vty, struct ospf6 *o) +{ + if (o == NULL) + return 0; + + /* Print default originate configuration. */ + if (o->default_originate != DEFAULT_ORIGINATE_NONE) + ospf6_default_originate_write(vty, o); + return 0; } diff --git a/ospf6d/ospf6_flood.c b/ospf6d/ospf6_flood.c index 05b43189e9..738c2218fa 100644 --- a/ospf6d/ospf6_flood.c +++ b/ospf6d/ospf6_flood.c @@ -299,7 +299,7 @@ void ospf6_flood_interface(struct ospf6_neighbor *from, struct ospf6_lsa *lsa, { struct listnode *node, *nnode; struct ospf6_neighbor *on; - struct ospf6_lsa *req; + struct ospf6_lsa *req, *old; int retrans_added = 0; int is_debug = 0; @@ -408,12 +408,27 @@ void ospf6_flood_interface(struct ospf6_neighbor *from, struct ospf6_lsa *lsa, if (is_debug) zlog_debug("Add retrans-list of neighbor %s ", on->name); - ospf6_increment_retrans_count(lsa); - ospf6_lsdb_add(ospf6_lsa_copy(lsa), on->retrans_list); - thread_add_timer(master, ospf6_lsupdate_send_neighbor, - on, on->ospf6_if->rxmt_interval, - &on->thread_send_lsupdate); - retrans_added++; + + /* Do not increment the retrans count if the lsa is + * already present in the retrans list. + */ + old = ospf6_lsdb_lookup( + lsa->header->type, lsa->header->id, + lsa->header->adv_router, on->retrans_list); + if (!old) { + if (is_debug) + zlog_debug( + "Increment %s from retrans_list of %s", + lsa->name, on->name); + ospf6_increment_retrans_count(lsa); + ospf6_lsdb_add(ospf6_lsa_copy(lsa), + on->retrans_list); + thread_add_timer( + master, ospf6_lsupdate_send_neighbor, + on, on->ospf6_if->rxmt_interval, + &on->thread_send_lsupdate); + retrans_added++; + } } } diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c index 1e75fc60f6..92c88623a0 100644 --- a/ospf6d/ospf6_interface.c +++ b/ospf6d/ospf6_interface.c @@ -733,7 +733,7 @@ int interface_up(struct thread *thread) /* If no area assigned, return */ if (oi->area == NULL) { zlog_warn( - "%s: Not scheduleing Hello for %s as there is no area assigned yet", + "%s: Not scheduling Hello for %s as there is no area assigned yet", __func__, oi->interface->name); return 0; } diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c index 817e5372ea..1f2618ec83 100644 --- a/ospf6d/ospf6_message.c +++ b/ospf6d/ospf6_message.c @@ -444,9 +444,9 @@ static void ospf6_hello_recv(struct in6_addr *src, struct in6_addr *dst, /* check latency against hello period */ if (on->hello_in) latency = monotime_since(&on->last_hello, NULL) - - (oi->hello_interval * 1000000); + - ((int64_t)oi->hello_interval * 1000000); /* log if latency exceeds the hello period */ - if (latency > (oi->hello_interval * 1000000)) + if (latency > ((int64_t)oi->hello_interval * 1000000)) zlog_warn("%s RX %pI4 high latency %" PRId64 "us.", __func__, &on->router_id, latency); on->last_hello = timestamp; @@ -1897,7 +1897,6 @@ static int ospf6_write(struct thread *thread) struct ospf6_header *oh; struct ospf6_packet *op; struct listnode *node; - char srcname[64], dstname[64]; struct iovec iovector[2]; int pkt_count = 0; int len; @@ -1934,26 +1933,45 @@ static int ospf6_write(struct thread *thread) flog_err(EC_LIB_DEVELOPMENT, "Could not send entire message"); - if (IS_OSPF6_DEBUG_MESSAGE(oh->type, SEND)) { - inet_ntop(AF_INET6, &op->dst, dstname, sizeof(dstname)); - inet_ntop(AF_INET6, oi->linklocal_addr, srcname, - sizeof(srcname)); + if (IS_OSPF6_DEBUG_MESSAGE(oh->type, SEND_HDR)) { zlog_debug("%s send on %s", lookup_msg(ospf6_message_type_str, oh->type, NULL), oi->interface->name); - zlog_debug(" src: %s", srcname); - zlog_debug(" dst: %s", dstname); + zlog_debug(" src: %pI6", oi->linklocal_addr); + zlog_debug(" dst: %pI6", &op->dst); + switch (oh->type) { + case OSPF6_MESSAGE_TYPE_HELLO: + ospf6_hello_print(oh, OSPF6_ACTION_SEND); + break; + case OSPF6_MESSAGE_TYPE_DBDESC: + ospf6_dbdesc_print(oh, OSPF6_ACTION_SEND); + break; + case OSPF6_MESSAGE_TYPE_LSREQ: + ospf6_lsreq_print(oh, OSPF6_ACTION_SEND); + break; + case OSPF6_MESSAGE_TYPE_LSUPDATE: + ospf6_lsupdate_print(oh, OSPF6_ACTION_SEND); + break; + case OSPF6_MESSAGE_TYPE_LSACK: + ospf6_lsack_print(oh, OSPF6_ACTION_SEND); + break; + default: + zlog_debug("Unknown message"); + assert(0); + break; + } } switch (oh->type) { case OSPF6_MESSAGE_TYPE_HELLO: monotime(×tamp); if (oi->hello_out) latency = monotime_since(&oi->last_hello, NULL) - - (oi->hello_interval * 1000000); + - ((int64_t)oi->hello_interval + * 1000000); /* log if latency exceeds the hello period */ - if (latency > (oi->hello_interval * 1000000)) + if (latency > ((int64_t)oi->hello_interval * 1000000)) zlog_warn("%s hello TX high latency %" PRId64 "us.", __func__, latency); @@ -1963,19 +1981,15 @@ static int ospf6_write(struct thread *thread) break; case OSPF6_MESSAGE_TYPE_DBDESC: oi->db_desc_out++; - ospf6_dbdesc_print(oh, OSPF6_ACTION_SEND); break; case OSPF6_MESSAGE_TYPE_LSREQ: oi->ls_req_out++; - ospf6_lsreq_print(oh, OSPF6_ACTION_SEND); break; case OSPF6_MESSAGE_TYPE_LSUPDATE: oi->ls_upd_out++; - ospf6_lsupdate_print(oh, OSPF6_ACTION_SEND); break; case OSPF6_MESSAGE_TYPE_LSACK: oi->ls_ack_out++; - ospf6_lsack_print(oh, OSPF6_ACTION_SEND); break; default: zlog_debug("Unknown message"); @@ -2356,7 +2370,19 @@ static void ospf6_send_lsupdate(struct ospf6_neighbor *on, } if (oi) { ospf6_packet_add(oi, op); - OSPF6_MESSAGE_WRITE_ON(oi); + /* If ospf instance is being deleted, send the packet + * immediately + */ + if ((oi->area == NULL) || (oi->area->ospf6 == NULL)) + return; + if (oi->area->ospf6->inst_shutdown) { + if (oi->on_write_q == 0) { + listnode_add(oi->area->ospf6->oi_write_q, oi); + oi->on_write_q = 1; + } + thread_execute(master, ospf6_write, oi->area->ospf6, 0); + } else + OSPF6_MESSAGE_WRITE_ON(oi); } } diff --git a/ospf6d/ospf6_spf.c b/ospf6d/ospf6_spf.c index 032484e288..051b3a63ef 100644 --- a/ospf6d/ospf6_spf.c +++ b/ospf6d/ospf6_spf.c @@ -225,21 +225,25 @@ static char *ospf6_lsdesc_backlink(struct ospf6_lsa *lsa, caddr_t lsdesc, assert(!(OSPF6_LSA_IS_TYPE(NETWORK, lsa) && VERTEX_IS_TYPE(NETWORK, v))); - if (OSPF6_LSA_IS_TYPE(NETWORK, lsa) - && NETWORK_LSDESC_GET_NBR_ROUTERID(backlink) - == v->lsa->header->adv_router) - found = backlink; - else if (VERTEX_IS_TYPE(NETWORK, v) - && ROUTER_LSDESC_IS_TYPE(TRANSIT_NETWORK, backlink) - && ROUTER_LSDESC_GET_NBR_ROUTERID(backlink) - == v->lsa->header->adv_router - && ROUTER_LSDESC_GET_NBR_IFID(backlink) - == ntohl(v->lsa->header->id)) - found = backlink; - else { + if (OSPF6_LSA_IS_TYPE(NETWORK, lsa)) { + if (NETWORK_LSDESC_GET_NBR_ROUTERID(backlink) + == v->lsa->header->adv_router) + found = backlink; + } else if (VERTEX_IS_TYPE(NETWORK, v)) { + if (ROUTER_LSDESC_IS_TYPE(TRANSIT_NETWORK, backlink) + && ROUTER_LSDESC_GET_NBR_ROUTERID(backlink) + == v->lsa->header->adv_router + && ROUTER_LSDESC_GET_NBR_IFID(backlink) + == ntohl(v->lsa->header->id)) + found = backlink; + } else { + assert(OSPF6_LSA_IS_TYPE(ROUTER, lsa) + && VERTEX_IS_TYPE(ROUTER, v)); + if (!ROUTER_LSDESC_IS_TYPE(POINTTOPOINT, backlink) || !ROUTER_LSDESC_IS_TYPE(POINTTOPOINT, lsdesc)) continue; + if (ROUTER_LSDESC_GET_NBR_IFID(backlink) != ROUTER_LSDESC_GET_IFID(lsdesc) || ROUTER_LSDESC_GET_NBR_IFID(lsdesc) diff --git a/ospf6d/ospf6_zebra.c b/ospf6d/ospf6_zebra.c index a7e15c68ae..72bc3a2f3a 100644 --- a/ospf6d/ospf6_zebra.c +++ b/ospf6d/ospf6_zebra.c @@ -194,16 +194,6 @@ static int ospf6_zebra_if_address_update_delete(ZAPI_CALLBACK_ARGS) return 0; } -static int is_prefix_default(struct prefix_ipv6 *p) -{ - struct prefix_ipv6 q = {}; - - q.family = AF_INET6; - q.prefixlen = 0; - - return prefix_same((struct prefix *)p, (struct prefix *)&q); -} - static int ospf6_zebra_read_route(ZAPI_CALLBACK_ARGS) { struct zapi_route api; @@ -239,7 +229,7 @@ static int ospf6_zebra_read_route(ZAPI_CALLBACK_ARGS) ifindex, api.tag); memcpy(&p, &api.prefix, sizeof(p)); - if (is_prefix_default(&p)) + if (is_default_prefix6(&p)) api.type = DEFAULT_ROUTE; if (cmd == ZEBRA_REDISTRIBUTE_ROUTE_ADD) diff --git a/ospfd/ospf_asbr.c b/ospfd/ospf_asbr.c index 192dbe4fc8..53d2ec538c 100644 --- a/ospfd/ospf_asbr.c +++ b/ospfd/ospf_asbr.c @@ -334,7 +334,7 @@ void ospf_redistribute_withdraw(struct ospf *ospf, uint8_t type, struct ospf_external_aggr_rt *aggr; - if (is_prefix_default(&ei->p) + if (is_default_prefix4(&ei->p) && ospf->default_originate != DEFAULT_ORIGINATE_NONE) continue; @@ -862,7 +862,7 @@ static void ospf_handle_external_aggr_add(struct ospf *ospf) continue; ei = rn->info; - if (is_prefix_default(&ei->p)) + if (is_default_prefix4(&ei->p)) continue; /* Check the AS-external-LSA diff --git a/ospfd/ospf_flood.c b/ospfd/ospf_flood.c index d11c441e37..7fddb65a86 100644 --- a/ospfd/ospf_flood.c +++ b/ospfd/ospf_flood.c @@ -98,14 +98,14 @@ struct external_info *ospf_external_info_check(struct ospf *ospf, int redist_on = 0; redist_on = - is_prefix_default(&p) + is_default_prefix4(&p) ? vrf_bitmap_check( - zclient->default_information[AFI_IP], - ospf->vrf_id) + zclient->default_information[AFI_IP], + ospf->vrf_id) : (zclient->mi_redist[AFI_IP][type].enabled || vrf_bitmap_check( - zclient->redist[AFI_IP][type], - ospf->vrf_id)); + zclient->redist[AFI_IP][type], + ospf->vrf_id)); // Pending: check for MI above. if (redist_on) { ext_list = ospf->external[type]; @@ -128,7 +128,7 @@ struct external_info *ospf_external_info_check(struct ospf *ospf, } } - if (is_prefix_default(&p) && ospf->external[DEFAULT_ROUTE]) { + if (is_default_prefix4(&p) && ospf->external[DEFAULT_ROUTE]) { ext_list = ospf->external[DEFAULT_ROUTE]; for (ALL_LIST_ELEMENTS_RO(ext_list, node, ext)) { diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c index 723a54a771..9ef2a6520a 100644 --- a/ospfd/ospf_lsa.c +++ b/ospfd/ospf_lsa.c @@ -1583,8 +1583,8 @@ static void ospf_external_lsa_body_set(struct stream *s, stream_put_ipv4(s, mask.s_addr); /* If prefix is default, specify DEFAULT_ROUTE. */ - type = is_prefix_default(&ei->p) ? DEFAULT_ROUTE : ei->type; - instance = is_prefix_default(&ei->p) ? 0 : ei->instance; + type = is_default_prefix4(&ei->p) ? DEFAULT_ROUTE : ei->type; + instance = is_default_prefix4(&ei->p) ? 0 : ei->instance; mtype = (ROUTEMAP_METRIC_TYPE(ei) != -1) ? ROUTEMAP_METRIC_TYPE(ei) @@ -1986,17 +1986,6 @@ struct ospf_lsa *ospf_translated_nssa_refresh(struct ospf *ospf, return new; } -int is_prefix_default(struct prefix_ipv4 *p) -{ - struct prefix_ipv4 q; - - q.family = AF_INET; - q.prefix.s_addr = INADDR_ANY; - q.prefixlen = 0; - - return prefix_same((struct prefix *)p, (struct prefix *)&q); -} - /* Originate an AS-external-LSA, install and flood. */ struct ospf_lsa *ospf_external_lsa_originate(struct ospf *ospf, struct external_info *ei) @@ -2159,8 +2148,7 @@ void ospf_external_lsa_rid_change(struct ospf *ospf) if (!ei) continue; - if (is_prefix_default( - (struct prefix_ipv4 *)&ei->p)) + if (is_default_prefix4(&ei->p)) continue; lsa = ospf_external_info_find_lsa(ospf, &ei->p); @@ -2330,7 +2318,7 @@ void ospf_external_lsa_refresh_type(struct ospf *ospf, uint8_t type, rn = route_next(rn)) { ei = rn->info; if (ei) { - if (!is_prefix_default(&ei->p)) { + if (!is_default_prefix4(&ei->p)) { struct ospf_lsa *lsa; struct ospf_external_aggr_rt *aggr; diff --git a/ospfd/ospf_lsa.h b/ospfd/ospf_lsa.h index 3808700ccc..d01dc720ba 100644 --- a/ospfd/ospf_lsa.h +++ b/ospfd/ospf_lsa.h @@ -331,7 +331,6 @@ extern void ospf_lsa_maxage_delete(struct ospf *, struct ospf_lsa *); extern void ospf_discard_from_db(struct ospf *, struct ospf_lsdb *, struct ospf_lsa *); -extern int is_prefix_default(struct prefix_ipv4 *); extern int metric_type(struct ospf *, uint8_t, unsigned short); extern int metric_value(struct ospf *, uint8_t, unsigned short); diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index b230e066c4..2cb3ec0894 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -10027,7 +10027,7 @@ DEFUN (ospf_external_route_aggregation, str2prefix_ipv4(argv[idx]->arg, &p); - if (is_prefix_default(&p)) { + if (is_default_prefix4(&p)) { vty_out(vty, "Default address shouldn't be configured as summary address.\n"); return CMD_SUCCESS; @@ -10068,7 +10068,7 @@ DEFUN (no_ospf_external_route_aggregation, str2prefix_ipv4(argv[idx]->arg, &p); - if (is_prefix_default(&p)) { + if (is_default_prefix4(&p)) { vty_out(vty, "Default address shouldn't be configured as summary address.\n"); return CMD_SUCCESS; @@ -10361,7 +10361,7 @@ DEFUN (ospf_external_route_aggregation_no_adrvertise, str2prefix_ipv4(argv[idx]->arg, &p); - if (is_prefix_default(&p)) { + if (is_default_prefix4(&p)) { vty_out(vty, "Default address shouldn't be configured as summary address.\n"); return CMD_SUCCESS; @@ -10397,7 +10397,7 @@ DEFUN (no_ospf_external_route_aggregation_no_adrvertise, str2prefix_ipv4(argv[idx]->arg, &p); - if (is_prefix_default(&p)) { + if (is_default_prefix4(&p)) { vty_out(vty, "Default address shouldn't be configured as summary address.\n"); return CMD_SUCCESS; diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c index de33c9732d..1298a17f55 100644 --- a/ospfd/ospf_zebra.c +++ b/ospfd/ospf_zebra.c @@ -965,7 +965,7 @@ static int ospf_external_lsa_originate_check(struct ospf *ospf, } /* Take care of default-originate. */ - if (is_prefix_default(&ei->p)) + if (is_default_prefix4(&ei->p)) if (ospf->default_originate == DEFAULT_ORIGINATE_NONE) { zlog_info( "LSA[Type5:0.0.0.0]: Not originate AS-external-LSA for default"); @@ -1121,8 +1121,8 @@ int ospf_redistribute_check(struct ospf *ospf, struct external_info *ei, struct route_map_set_values save_values; struct prefix_ipv4 *p = &ei->p; struct ospf_redist *red; - uint8_t type = is_prefix_default(&ei->p) ? DEFAULT_ROUTE : ei->type; - unsigned short instance = is_prefix_default(&ei->p) ? 0 : ei->instance; + uint8_t type = is_default_prefix4(&ei->p) ? DEFAULT_ROUTE : ei->type; + unsigned short instance = is_default_prefix4(&ei->p) ? 0 : ei->instance; route_tag_t saved_tag = 0; /* Default is handled differently. */ @@ -1275,7 +1275,7 @@ static int ospf_zebra_read_route(ZAPI_CALLBACK_ARGS) * originate)ZEBRA_ROUTE_MAX is used to delete the ex-info. * Resolved this inconsistency by maintaining same route type. */ - if (is_prefix_default(&p)) + if (is_default_prefix4(&p)) rt_type = DEFAULT_ROUTE; if (IS_DEBUG_OSPF(zebra, ZEBRA_REDISTRIBUTE)) @@ -1314,7 +1314,7 @@ static int ospf_zebra_read_route(ZAPI_CALLBACK_ARGS) return 0; } if (ospf->router_id.s_addr != INADDR_ANY) { - if (is_prefix_default(&p)) + if (is_default_prefix4(&p)) ospf_external_lsa_refresh_default(ospf); else { struct ospf_external_aggr_rt *aggr; @@ -1436,7 +1436,7 @@ static int ospf_zebra_read_route(ZAPI_CALLBACK_ARGS) ospf_external_info_delete(ospf, rt_type, api.instance, p); - if (is_prefix_default(&p)) + if (is_default_prefix4(&p)) ospf_external_lsa_refresh_default(ospf); else ospf_external_lsa_flush(ospf, rt_type, &p, @@ -1533,7 +1533,7 @@ static int ospf_distribute_list_update_timer(struct thread *thread) if (!ei) continue; - if (is_prefix_default(&ei->p)) + if (is_default_prefix4(&ei->p)) default_refresh = 1; else { struct ospf_external_aggr_rt *aggr; diff --git a/pathd/path_pcep_config.c b/pathd/path_pcep_config.c index 0349618304..4c16b83948 100644 --- a/pathd/path_pcep_config.c +++ b/pathd/path_pcep_config.c @@ -332,6 +332,7 @@ int path_pcep_config_initiate_path(struct path *path) candidate = srte_candidate_add( policy, path->nbkey.preference, SRTE_ORIGIN_PCEP, path->originator); + candidate->policy->srp_id = path->srp_id; strlcpy(candidate->name, path->name, sizeof(candidate->name)); SET_FLAG(candidate->flags, F_CANDIDATE_NEW); @@ -387,6 +388,7 @@ int path_pcep_config_update_path(struct path *path) if (!candidate) return 0; + candidate->policy->srp_id = path->srp_id; // first clean up old segment list if present if (candidate->lsp->segment_list) { SET_FLAG(candidate->lsp->segment_list->flags, diff --git a/pathd/path_pcep_pcc.c b/pathd/path_pcep_pcc.c index 81a338ac63..b72a536ef4 100644 --- a/pathd/path_pcep_pcc.c +++ b/pathd/path_pcep_pcc.c @@ -128,6 +128,8 @@ static struct req_entry *push_new_req(struct pcc_state *pcc_state, struct path *path); static void repush_req(struct pcc_state *pcc_state, struct req_entry *req); static struct req_entry *pop_req(struct pcc_state *pcc_state, uint32_t reqid); +static struct req_entry *pop_req_no_reqid(struct pcc_state *pcc_state, + uint32_t reqid); static bool add_reqid_mapping(struct pcc_state *pcc_state, struct path *path); static void remove_reqid_mapping(struct pcc_state *pcc_state, struct path *path); @@ -558,7 +560,6 @@ void pcep_pcc_send_report(struct ctrl_state *ctrl_state, if (is_stable && (real_status != PCEP_LSP_OPERATIONAL_DOWN)) { PCEP_DEBUG("(%s)%s Send report for candidate path (!DOWN) %s", __func__, pcc_state->tag, path->name); - path->srp_id = 0; path->status = real_status; send_report(pcc_state, path); } @@ -1340,7 +1341,11 @@ void handle_pcep_comp_reply(struct ctrl_state *ctrl_state, struct path *path; path = pcep_lib_parse_path(msg); - req = pop_req(pcc_state, path->req_id); + if (path->no_path) { + req = pop_req_no_reqid(pcc_state, path->req_id); + } else { + req = pop_req(pcc_state, path->req_id); + } if (req == NULL) { /* TODO: check the rate of bad computation reply and close * the connection if more that a given rate. @@ -1372,6 +1377,9 @@ void handle_pcep_comp_reply(struct ctrl_state *ctrl_state, if (path->no_path) { PCEP_DEBUG("%s Computation for path %s did not find any result", pcc_state->tag, path->name); + free_req_entry(req); + pcep_free_path(path); + return; } else if (validate_incoming_path(pcc_state, path, err, sizeof(err))) { /* Updating a dynamic path will automatically delegate it */ pcep_thread_update_path(ctrl_state, pcc_state->id, path); @@ -1847,6 +1855,20 @@ struct req_entry *pop_req(struct pcc_state *pcc_state, uint32_t reqid) return req; } +struct req_entry *pop_req_no_reqid(struct pcc_state *pcc_state, uint32_t reqid) +{ + struct path path = {.req_id = reqid}; + struct req_entry key = {.path = &path}; + struct req_entry *req; + + req = RB_FIND(req_entry_head, &pcc_state->requests, &key); + if (req == NULL) + return NULL; + RB_REMOVE(req_entry_head, &pcc_state->requests, req); + + return req; +} + bool add_reqid_mapping(struct pcc_state *pcc_state, struct path *path) { struct req_map_data *mapping; @@ -1883,6 +1905,33 @@ uint32_t lookup_reqid(struct pcc_state *pcc_state, struct path *path) bool has_pending_req_for(struct pcc_state *pcc_state, struct path *path) { + struct req_entry key = {.path = path}; + struct req_entry *req; + + + PCEP_DEBUG_PATH("(%s) %s", format_path(path), __func__); + /* Looking for request without result */ + if (path->no_path || !path->first_hop) { + PCEP_DEBUG_PATH("%s Path : no_path|!first_hop", __func__); + /* ...and already was handle */ + req = RB_FIND(req_entry_head, &pcc_state->requests, &key); + if (!req) { + /* we must purge remaining reqid */ + PCEP_DEBUG_PATH("%s Purge pending reqid: no_path(%s)", + __func__, + path->no_path ? "TRUE" : "FALSE"); + if (lookup_reqid(pcc_state, path) != 0) { + PCEP_DEBUG_PATH("%s Purge pending reqid: DONE ", + __func__); + remove_reqid_mapping(pcc_state, path); + return true; + } else { + return false; + } + } + } + + return lookup_reqid(pcc_state, path) != 0; } diff --git a/redhat/frr.spec.in b/redhat/frr.spec.in index e24a84d1e4..fbe4c4a1f1 100644 --- a/redhat/frr.spec.in +++ b/redhat/frr.spec.in @@ -199,8 +199,6 @@ Requires: initscripts BuildRequires: pam-devel %endif %if "%{initsystem}" == "systemd" -BuildRequires: systemd -BuildRequires: systemd-devel Requires(post): systemd Requires(preun): systemd Requires(postun): systemd @@ -396,9 +394,6 @@ routing state through standard SNMP MIBs. --disable-bgp-vnc \ %endif --enable-isisd \ -%if "%{initsystem}" == "systemd" - --enable-systemd \ -%endif --enable-rpki \ %if %{with_bfdd} --enable-bfdd \ diff --git a/staticd/static_routes.c b/staticd/static_routes.c index cdafc4a76a..58a29ad25b 100644 --- a/staticd/static_routes.c +++ b/staticd/static_routes.c @@ -278,6 +278,9 @@ static_add_nexthop(struct route_node *rn, struct static_path *pn, safi_t safi, nh->type = type; nh->color = color; + if (nh->type == STATIC_BLACKHOLE) + nh->bh_type = STATIC_BLACKHOLE_NULL; + nh->nh_vrf_id = nh_svrf ? nh_svrf->vrf->vrf_id : VRF_UNKNOWN; strlcpy(nh->nh_vrfname, nh_vrf, sizeof(nh->nh_vrfname)); @@ -325,6 +328,7 @@ static_add_nexthop(struct route_node *rn, struct static_path *pn, safi_t safi, switch (nh->type) { case STATIC_IPV4_GATEWAY: case STATIC_IPV6_GATEWAY: + case STATIC_BLACKHOLE: break; case STATIC_IPV4_GATEWAY_IFNAME: case STATIC_IPV6_GATEWAY_IFNAME: @@ -337,9 +341,6 @@ static_add_nexthop(struct route_node *rn, struct static_path *pn, safi_t safi, ifname); break; - case STATIC_BLACKHOLE: - nh->bh_type = STATIC_BLACKHOLE_NULL; - break; case STATIC_IFNAME: ifp = if_lookup_by_name(ifname, nh->nh_vrf_id); if (ifp && ifp->ifindex != IFINDEX_INTERNAL) { diff --git a/tests/bgpd/test_aspath.c b/tests/bgpd/test_aspath.c index aaf3fd2aa4..c2d39752ab 100644 --- a/tests/bgpd/test_aspath.c +++ b/tests/bgpd/test_aspath.c @@ -469,7 +469,10 @@ static struct aspath_tests { 0, 0, { - COMMON_ATTRS, BGP_ATTR_FLAG_TRANS, BGP_ATTR_AS_PATH, 10, + COMMON_ATTRS, + BGP_ATTR_FLAG_TRANS, + BGP_ATTR_AS_PATH, + 10, }, COMMON_ATTR_SIZE + 3, }, @@ -482,7 +485,10 @@ static struct aspath_tests { -1, 0, { - COMMON_ATTRS, BGP_ATTR_FLAG_TRANS, BGP_ATTR_AS_PATH, 8, + COMMON_ATTRS, + BGP_ATTR_FLAG_TRANS, + BGP_ATTR_AS_PATH, + 8, }, COMMON_ATTR_SIZE + 3, }, @@ -495,7 +501,10 @@ static struct aspath_tests { -1, 0, { - COMMON_ATTRS, BGP_ATTR_FLAG_TRANS, BGP_ATTR_AS_PATH, 12, + COMMON_ATTRS, + BGP_ATTR_FLAG_TRANS, + BGP_ATTR_AS_PATH, + 12, }, COMMON_ATTR_SIZE + 3, }, @@ -510,7 +519,8 @@ static struct aspath_tests { { COMMON_ATTRS, BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL, - BGP_ATTR_AS_PATH, 10, + BGP_ATTR_AS_PATH, + 10, }, COMMON_ATTR_SIZE + 3, }, @@ -525,7 +535,8 @@ static struct aspath_tests { { COMMON_ATTRS, BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL, - BGP_ATTR_AS4_PATH, 10, + BGP_ATTR_AS4_PATH, + 10, }, COMMON_ATTR_SIZE + 3, }, @@ -540,7 +551,8 @@ static struct aspath_tests { { COMMON_ATTRS, BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL, - BGP_ATTR_AS4_PATH, 10, + BGP_ATTR_AS4_PATH, + 10, }, COMMON_ATTR_SIZE + 3, }, @@ -553,7 +565,10 @@ static struct aspath_tests { 0, PEER_CAP_AS4_RCV | PEER_CAP_AS4_ADV, { - COMMON_ATTRS, BGP_ATTR_FLAG_TRANS, BGP_ATTR_AS_PATH, 18, + COMMON_ATTRS, + BGP_ATTR_FLAG_TRANS, + BGP_ATTR_AS_PATH, + 18, }, COMMON_ATTR_SIZE + 3, }, @@ -566,7 +581,10 @@ static struct aspath_tests { -1, PEER_CAP_AS4_RCV | PEER_CAP_AS4_ADV, { - COMMON_ATTRS, BGP_ATTR_FLAG_TRANS, BGP_ATTR_AS_PATH, 16, + COMMON_ATTRS, + BGP_ATTR_FLAG_TRANS, + BGP_ATTR_AS_PATH, + 16, }, COMMON_ATTR_SIZE + 3, }, @@ -579,7 +597,10 @@ static struct aspath_tests { -1, PEER_CAP_AS4_RCV | PEER_CAP_AS4_ADV, { - COMMON_ATTRS, BGP_ATTR_FLAG_TRANS, BGP_ATTR_AS_PATH, 20, + COMMON_ATTRS, + BGP_ATTR_FLAG_TRANS, + BGP_ATTR_AS_PATH, + 20, }, COMMON_ATTR_SIZE + 3, }, @@ -592,7 +613,10 @@ static struct aspath_tests { -1, PEER_CAP_AS4_RCV | PEER_CAP_AS4_ADV, { - COMMON_ATTRS, BGP_ATTR_FLAG_TRANS, BGP_ATTR_AS_PATH, 22, + COMMON_ATTRS, + BGP_ATTR_FLAG_TRANS, + BGP_ATTR_AS_PATH, + 22, }, COMMON_ATTR_SIZE + 3, }, @@ -607,7 +631,8 @@ static struct aspath_tests { { COMMON_ATTRS, BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL, - BGP_ATTR_AS_PATH, 18, + BGP_ATTR_AS_PATH, + 18, }, COMMON_ATTR_SIZE + 3, }, @@ -622,7 +647,8 @@ static struct aspath_tests { { COMMON_ATTRS, BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL, - BGP_ATTR_AS4_PATH, 14, + BGP_ATTR_AS4_PATH, + 14, }, COMMON_ATTR_SIZE + 3, }, @@ -637,7 +663,8 @@ static struct aspath_tests { { COMMON_ATTRS, BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL, - BGP_ATTR_AS4_PATH, 14, + BGP_ATTR_AS4_PATH, + 14, }, COMMON_ATTR_SIZE + 3, &test_segments[0], @@ -648,12 +675,13 @@ static struct aspath_tests { &test_segments[28], "8466 3 52737 0 4096", AS4_DATA, - -1, + -2, PEER_CAP_AS4_RCV | PEER_CAP_AS4_ADV, { COMMON_ATTRS, BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL, - BGP_ATTR_AS4_PATH, 22, + BGP_ATTR_AS4_PATH, + 22, }, COMMON_ATTR_SIZE + 3, }, diff --git a/tests/topotests/bgp_aspath_zero/__init__.py b/tests/topotests/bgp_aspath_zero/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/topotests/bgp_aspath_zero/__init__.py diff --git a/tests/topotests/bgp_aspath_zero/exabgp.env b/tests/topotests/bgp_aspath_zero/exabgp.env new file mode 100644 index 0000000000..28e642360a --- /dev/null +++ b/tests/topotests/bgp_aspath_zero/exabgp.env @@ -0,0 +1,53 @@ +[exabgp.api] +encoder = text +highres = false +respawn = false +socket = '' + +[exabgp.bgp] +openwait = 60 + +[exabgp.cache] +attributes = true +nexthops = true + +[exabgp.daemon] +daemonize = true +pid = '/var/run/exabgp/exabgp.pid' +user = 'exabgp' +##daemonize = false + +[exabgp.log] +all = false +configuration = true +daemon = true +destination = '/var/log/exabgp.log' +enable = true +level = INFO +message = false +network = true +packets = false +parser = false +processes = true +reactor = true +rib = false +routes = false +short = false +timers = false + +[exabgp.pdb] +enable = false + +[exabgp.profile] +enable = false +file = '' + +[exabgp.reactor] +speed = 1.0 + +[exabgp.tcp] +acl = false +bind = '' +delay = 0 +once = false +port = 179 diff --git a/tests/topotests/bgp_aspath_zero/peer1/exabgp.cfg b/tests/topotests/bgp_aspath_zero/peer1/exabgp.cfg new file mode 100644 index 0000000000..fe9ea01eca --- /dev/null +++ b/tests/topotests/bgp_aspath_zero/peer1/exabgp.cfg @@ -0,0 +1,17 @@ +neighbor 10.0.0.1 { + router-id 10.0.0.2; + local-address 10.0.0.2; + local-as 65001; + peer-as 65534; + + static { + route 192.168.100.101/32 { + next-hop 10.0.0.2; + } + + route 192.168.100.102/32 { + as-path [65000 0 65001]; + next-hop 10.0.0.2; + } + } +} diff --git a/tests/topotests/bgp_aspath_zero/r1/bgpd.conf b/tests/topotests/bgp_aspath_zero/r1/bgpd.conf new file mode 100644 index 0000000000..002a5c78c0 --- /dev/null +++ b/tests/topotests/bgp_aspath_zero/r1/bgpd.conf @@ -0,0 +1,6 @@ +! +router bgp 65534 + no bgp ebgp-requires-policy + neighbor 10.0.0.2 remote-as external + neighbor 10.0.0.2 timers 3 10 +! diff --git a/tests/topotests/bgp_aspath_zero/r1/zebra.conf b/tests/topotests/bgp_aspath_zero/r1/zebra.conf new file mode 100644 index 0000000000..22a26ac610 --- /dev/null +++ b/tests/topotests/bgp_aspath_zero/r1/zebra.conf @@ -0,0 +1,6 @@ +! +interface r1-eth0 + ip address 10.0.0.1/24 +! +ip forwarding +! diff --git a/tests/topotests/bgp_aspath_zero/test_bgp_aspath_zero.py b/tests/topotests/bgp_aspath_zero/test_bgp_aspath_zero.py new file mode 100644 index 0000000000..903ab12a13 --- /dev/null +++ b/tests/topotests/bgp_aspath_zero/test_bgp_aspath_zero.py @@ -0,0 +1,121 @@ +#!/usr/bin/env python + +# +# Copyright (c) 2021 by +# Donatas Abraitis <donatas.abraitis@gmail.com> +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +""" +Test if BGP UPDATE with AS-PATH attribute with value zero (0) +is threated as withdrawal. +""" + +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 + +pytestmark = [pytest.mark.bgpd] + + +class BgpAggregatorAsnZero(Topo): + def build(self, *_args, **_opts): + tgen = get_topogen(self) + + r1 = tgen.add_router("r1") + peer1 = tgen.add_exabgp_peer( + "peer1", ip="10.0.0.2", defaultRoute="via 10.0.0.1" + ) + + switch = tgen.add_switch("s1") + switch.add_link(r1) + switch.add_link(peer1) + + +def setup_module(mod): + tgen = Topogen(BgpAggregatorAsnZero, mod.__name__) + tgen.start_topology() + + router = tgen.gears["r1"] + router.load_config(TopoRouter.RD_ZEBRA, os.path.join(CWD, "r1/zebra.conf")) + router.load_config(TopoRouter.RD_BGP, os.path.join(CWD, "r1/bgpd.conf")) + router.start() + + peer = tgen.gears["peer1"] + peer.start(os.path.join(CWD, "peer1"), os.path.join(CWD, "exabgp.env")) + + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + + +def test_bgp_aggregator_zero(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + def _bgp_converge(): + output = json.loads( + tgen.gears["r1"].vtysh_cmd("show ip bgp neighbor 10.0.0.2 json") + ) + expected = { + "10.0.0.2": { + "bgpState": "Established", + "addressFamilyInfo": {"ipv4Unicast": {"acceptedPrefixCounter": 1}}, + } + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial(_bgp_converge) + success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "More than one prefix seen at r1, SHOULD be only one." + + def _bgp_has_correct_routes_without_asn_0(): + output = json.loads(tgen.gears["r1"].vtysh_cmd("show ip bgp json")) + expected = {"routes": {"192.168.100.101/32": [{"valid": True}]}} + return topotest.json_cmp(output, expected) + + test_func = functools.partial(_bgp_has_correct_routes_without_asn_0) + success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Failed listing 192.168.100.101/32, SHOULD be accepted." + + +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/common_config.py b/tests/topotests/lib/common_config.py index 2230fd756f..9e60e523d3 100644 --- a/tests/topotests/lib/common_config.py +++ b/tests/topotests/lib/common_config.py @@ -713,20 +713,36 @@ def generate_support_bundle(): tgen = get_topogen() router_list = tgen.routers() - test_name = sys._getframe(2).f_code.co_name + test_name = os.environ.get('PYTEST_CURRENT_TEST').split(':')[-1].split(' ')[0] + TMPDIR = os.path.join(LOGDIR, tgen.modname) + bundle_procs = {} for rname, rnode in router_list.items(): - logger.info("Generating support bundle for {}".format(rname)) + logger.info("Spawn collection of support bundle for %s", rname) rnode.run("mkdir -p /var/log/frr") + bundle_procs[rname] = tgen.net[rname].popen( + "/usr/lib/frr/generate_support_bundle.py", + stdin=None, + stdout=SUB_PIPE, + stderr=SUB_PIPE, + ) - # Support only python3 going forward - bundle_log = rnode.run("env python3 /usr/lib/frr/generate_support_bundle.py") - - logger.info(bundle_log) - + for rname, rnode in router_list.items(): dst_bundle = "{}/{}/support_bundles/{}".format(TMPDIR, rname, test_name) src_bundle = "/var/log/frr" + + output, error = bundle_procs[rname].communicate() + + logger.info("Saving support bundle for %s", rname) + if output: + logger.info( + "Output from collecting support bundle for %s:\n%s", rname, output + ) + if error: + logger.warning( + "Error from collecting support bundle for %s:\n%s", rname, error + ) rnode.run("rm -rf {}".format(dst_bundle)) rnode.run("mkdir -p {}".format(dst_bundle)) rnode.run("mv -f {}/* {}".format(src_bundle, dst_bundle)) diff --git a/tests/topotests/multicast_pim_sm_topo1/test_multicast_pim_sm_topo1.py b/tests/topotests/multicast_pim_sm_topo1/test_multicast_pim_sm_topo1.py index e55e30270d..b880e0e462 100755 --- a/tests/topotests/multicast_pim_sm_topo1/test_multicast_pim_sm_topo1.py +++ b/tests/topotests/multicast_pim_sm_topo1/test_multicast_pim_sm_topo1.py @@ -526,9 +526,14 @@ def test_multicast_data_traffic_static_RP_send_traffic_then_join_p0(request): {"dut": "r2", "src_address": source, "iif": "r2-f1-eth0", "oil": "r2-l1-eth2"}, {"dut": "f1", "src_address": source, "iif": "f1-i2-eth1", "oil": "f1-r2-eth3"}, ] + # On timeout change from default of 80 to 120: failures logs indicate times 90+ + # seconds for success on the 2nd entry in the above table. Using 100s here restores + # previous 80 retries with 2s wait if we assume .5s per vtysh/show ip mroute runtime + # (41 * (2 + .5)) == 102. for data in input_dict: result = verify_ip_mroutes( - tgen, data["dut"], data["src_address"], IGMP_JOIN, data["iif"], data["oil"] + tgen, data["dut"], data["src_address"], IGMP_JOIN, data["iif"], data["oil"], + retry_timeout=102 ) assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) diff --git a/tools/coccinelle/xcalloc-xmalloc.cocci b/tools/coccinelle/xcalloc-xmalloc.cocci new file mode 100644 index 0000000000..2a091d4cd9 --- /dev/null +++ b/tools/coccinelle/xcalloc-xmalloc.cocci @@ -0,0 +1,17 @@ +// No need checking against NULL for XMALLOC/XCALLOC. +// If that happens, we have more problems with memory. + +@@ +type T; +T *ptr; +@@ + +ptr = +( +XCALLOC(...) +| +XMALLOC(...) +) +... +- if (ptr == NULL) +- return ...; diff --git a/tools/generate_support_bundle.py b/tools/generate_support_bundle.py index 38fdbd46df..56b2872d1e 100755 --- a/tools/generate_support_bundle.py +++ b/tools/generate_support_bundle.py @@ -1,117 +1,89 @@ #!/usr/bin/env python3 +# +# Copyright (c) 2021, LabN Consulting, L.L.C. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; see the file COPYING; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# ######################################################## ### Python Script to generate the FRR support bundle ### ######################################################## +import argparse +import logging import os import subprocess -import datetime - -ETC_DIR = "/etc/frr/" -LOG_DIR = "/var/log/frr/" -SUCCESS = 1 -FAIL = 0 - -inputFile = ETC_DIR + "support_bundle_commands.conf" - -# Create the output file name -def createOutputFile(procName): - fileName = procName + "_support_bundle.log" - oldFile = LOG_DIR + fileName - cpFileCmd = "cp " + oldFile + " " + oldFile + ".prev" - rmFileCmd = "rm -rf " + oldFile - print("Making backup of " + oldFile) - os.system(cpFileCmd) - print("Removing " + oldFile) - os.system(rmFileCmd) - return fileName - - -# Open the output file for this process -def openOutputFile(fileName): - crt_file_cmd = LOG_DIR + fileName - print(crt_file_cmd) - try: - outputFile = open(crt_file_cmd, "w") - return outputFile - except IOError: - return () - - -# Close the output file for this process -def closeOutputFile(f): - try: - f.close() - return SUCCESS - except IOError: - return FAIL - - -# Execute the command over vtysh and store in the -# output file -def executeCommand(cmd, outputFile): - cmd_exec_str = 'vtysh -c "' + cmd + '" ' +import tempfile + +def open_with_backup(path): + if os.path.exists(path): + print("Making backup of " + path) + subprocess.check_call("mv {0} {0}.prev".format(path)) + return open(path, "w") + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("-c", "--config", default="/etc/frr/support_bundle_commands.conf", help="input config") + parser.add_argument("-l", "--log-dir", default="/var/log/frr", help="directory for logfiles") + args = parser.parse_args() + + collecting = False # file format has sentinels (seem superfluous) + proc_cmds = {} + proc = None + temp = None + + # Collect all the commands for each daemon try: - cmd_output = subprocess.check_output(cmd_exec_str, shell=True) - try: - dateTime = datetime.datetime.now() - outputFile.write(">>[" + str(dateTime) + "]" + cmd + "\n") - outputFile.write(str(cmd_output)) - outputFile.write( - "########################################################\n" - ) - outputFile.write("\n") - except Exception as e: - print("Writing to output file Failed: ", e) - except subprocess.CalledProcessError as e: - dateTime = datetime.datetime.now() - outputFile.write(">>[" + str(dateTime) + "]" + cmd + "\n") - outputFile.write(e.output) - outputFile.write("########################################################\n") - outputFile.write("\n") - print("Error:" + e.output) - - -# Process the support bundle configuration file -# and call appropriate functions -def processConfFile(): - - lines = list() - outputFile = None - - try: - with open(inputFile, "r") as supportBundleConfFile: - for l in supportBundleConfFile: - lines.append(l.rstrip()) - except IOError: - print("conf file {} not present".format(inputFile)) - return - - for line in lines: - if len(line) == 0 or line[0] == "#": - continue - - cmd_line = line.split(":") - if cmd_line[0] == "PROC_NAME": - outputFileName = createOutputFile(cmd_line[1]) - if outputFileName: - print(outputFileName, "created for", cmd_line[1]) - elif cmd_line[0] == "CMD_LIST_START": - outputFile = openOutputFile(outputFileName) - if outputFile: - print(outputFileName, "opened") - else: - print(outputFileName, "open failed") - return FAIL - elif cmd_line[0] == "CMD_LIST_END": - if closeOutputFile(outputFile): - print(outputFileName, "closed") + for line in open(args.config): + line = line.rstrip() + if len(line) == 0 or line[0] == "#": + continue + + cmd_line = line.split(":") + if cmd_line[0] == "PROC_NAME": + proc = cmd_line[1] + temp = tempfile.NamedTemporaryFile("w+") + collecting = False + elif cmd_line[0] == "CMD_LIST_START": + collecting = True + elif cmd_line[0] == "CMD_LIST_END": + collecting = False + temp.flush() + proc_cmds[proc] = open(temp.name) + temp.close() + elif collecting: + temp.write(line + "\n") else: - print(outputFileName, "close failed") - else: - print("Execute:", cmd_line[0]) - executeCommand(cmd_line[0], outputFile) - + print("Ignoring unexpected input " + line.rstrip()) + except IOError as error: + logging.fatal("Cannot read config file: %s: %s", args.config, str(error)) + return -# Main Function -processConfFile() + # Spawn a vtysh to fetch each set of commands + procs = [] + for proc in proc_cmds: + ofn = os.path.join(args.log_dir, proc + "_support_bundle.log") + p = subprocess.Popen( + ["/usr/bin/env", "vtysh", "-t"], + stdin=proc_cmds[proc], + stdout=open_with_backup(ofn), + stderr=subprocess.STDOUT, + ) + procs.append(p) + + for p in procs: + p.wait() + +if __name__ == "__main__": + main() diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 507c6ce882..dd3f448674 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -56,6 +56,9 @@ struct vty *vty; /* VTY shell pager name. */ char *vtysh_pager_name = NULL; +/* VTY should add timestamp */ +bool vtysh_add_timestamp; + /* VTY shell client structure */ struct vtysh_client { int fd; @@ -483,6 +486,13 @@ static int vtysh_execute_func(const char *line, int pager) } } + if (vtysh_add_timestamp && strncmp(line, "exit", 4)) { + char ts[48]; + + (void)quagga_timestamp(3, ts, sizeof(ts)); + vty_out(vty, "%% %s\n\n", ts); + } + saved_ret = ret = cmd_execute(vty, line, &cmd, 1); saved_node = vty->node; diff --git a/vtysh/vtysh.h b/vtysh/vtysh.h index 71f672554b..e56d482da2 100644 --- a/vtysh/vtysh.h +++ b/vtysh/vtysh.h @@ -113,4 +113,6 @@ extern struct vty *vty; extern int user_mode; +extern bool vtysh_add_timestamp; + #endif /* VTYSH_H */ diff --git a/vtysh/vtysh_config.c b/vtysh/vtysh_config.c index 6d80cf9d96..d22ec3113f 100644 --- a/vtysh/vtysh_config.c +++ b/vtysh/vtysh_config.c @@ -560,6 +560,7 @@ static int vtysh_read_file(FILE *confp, bool dry_run) int vtysh_read_config(const char *config_default_dir, bool dry_run) { FILE *confp = NULL; + bool save; int ret; confp = fopen(config_default_dir, "r"); @@ -570,9 +571,14 @@ int vtysh_read_config(const char *config_default_dir, bool dry_run) return CMD_ERR_NO_FILE; } + save = vtysh_add_timestamp; + vtysh_add_timestamp = false; + ret = vtysh_read_file(confp, dry_run); fclose(confp); + vtysh_add_timestamp = save; + return (ret); } diff --git a/vtysh/vtysh_main.c b/vtysh/vtysh_main.c index fe33bed7f6..20be81b901 100644 --- a/vtysh/vtysh_main.c +++ b/vtysh/vtysh_main.c @@ -201,6 +201,7 @@ struct option longopts[] = { {"writeconfig", no_argument, NULL, 'w'}, {"pathspace", required_argument, NULL, 'N'}, {"user", no_argument, NULL, 'u'}, + {"timestamp", no_argument, NULL, 't'}, {0}}; /* Read a string, and return a pointer to it. Returns NULL on EOF. */ @@ -308,6 +309,7 @@ int main(int argc, char **argv, char **env) int opt; int dryrun = 0; int boot_flag = 0; + bool ts_flag = false; const char *daemon_name = NULL; const char *inputfile = NULL; struct cmd_rec { @@ -346,7 +348,7 @@ int main(int argc, char **argv, char **env) /* Option handling. */ while (1) { - opt = getopt_long(argc, argv, "be:c:d:nf:H:mEhCwN:u", longopts, + opt = getopt_long(argc, argv, "be:c:d:nf:H:mEhCwN:ut", longopts, 0); if (opt == EOF) @@ -408,6 +410,9 @@ int main(int argc, char **argv, char **env) case 'u': user_mode = 1; break; + case 't': + ts_flag = true; + break; case 'w': writeconfig = 1; break; @@ -624,6 +629,8 @@ int main(int argc, char **argv, char **env) if (!user_mode) vtysh_execute("enable"); + vtysh_add_timestamp = ts_flag; + while (cmd != NULL) { char *eol; @@ -712,6 +719,8 @@ int main(int argc, char **argv, char **env) if (!user_mode) vtysh_execute("enable"); + vtysh_add_timestamp = ts_flag; + /* Preparation for longjmp() in sigtstp(). */ sigsetjmp(jmpbuf, 1); jmpflag = 1; diff --git a/watchfrr/watchfrr.c b/watchfrr/watchfrr.c index faf1777d7f..d0b4be81d4 100644 --- a/watchfrr/watchfrr.c +++ b/watchfrr/watchfrr.c @@ -469,12 +469,10 @@ static int run_job(struct restart_info *restart, const char *cmdtype, return -1; } -#if defined HAVE_SYSTEMD char buffer[512]; snprintf(buffer, sizeof(buffer), "restarting %s", restart->name); systemd_send_status(buffer); -#endif /* Note: time_elapsed test must come before the force test, since we need @@ -506,9 +504,8 @@ static int run_job(struct restart_info *restart, const char *cmdtype, restart->pid = 0; } -#if defined HAVE_SYSTEMD systemd_send_status("FRR Operational"); -#endif + /* Calculate the new restart interval. */ if (update_interval) { if (delay.tv_sec > 2 * gs.max_restart_interval) @@ -718,10 +715,9 @@ static void daemon_send_ready(int exitcode) fp = fopen(started, "w"); if (fp) fclose(fp); -#if defined HAVE_SYSTEMD - systemd_send_started(master, 0); + + systemd_send_started(master); systemd_send_status("FRR Operational"); -#endif sent = 1; } diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 51f19a3c03..b204b30ca7 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -915,6 +915,7 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, json_object_string_add(json_route, "prefix", srcdest_rnode2str(rn, buf, sizeof(buf))); + json_object_int_add(json_route, "prefixLen", rn->p.prefixlen); json_object_string_add(json_route, "protocol", zebra_route_string(re->type)); @@ -1121,8 +1122,10 @@ static void vty_show_ip_route_detail_json(struct vty *vty, prefix2str(&rn->p, buf, sizeof(buf)); json_object_object_add(json, buf, json_prefix); - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); + vty_out(vty, "%s\n", + json_object_to_json_string_ext( + json, JSON_C_TO_STRING_PRETTY + | JSON_C_TO_STRING_NOSLASHESCAPE)); json_object_free(json); } @@ -1234,8 +1237,11 @@ static void do_show_route_helper(struct vty *vty, struct zebra_vrf *zvrf, } if (use_json) { - vty_out(vty, "%s\n", json_object_to_json_string_ext(json, - JSON_C_TO_STRING_PRETTY)); + vty_out(vty, "%s\n", + json_object_to_json_string_ext( + json, + JSON_C_TO_STRING_PRETTY + | JSON_C_TO_STRING_NOSLASHESCAPE)); json_object_free(json); } } |
