diff options
73 files changed, 1584 insertions, 782 deletions
diff --git a/.github/workflows/size-label.yml b/.github/workflows/size-label.yml new file mode 100644 index 0000000000..a37700342c --- /dev/null +++ b/.github/workflows/size-label.yml @@ -0,0 +1,25 @@ +name: Add PRs size label + +on: pull_request_target + +jobs: + size-label: + runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: write + steps: + - name: size-label + uses: "pascalgn/size-label-action@v0.4.2" + env: + GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" + with: + sizes: > + { + "0": "XS", + "20": "S", + "50": "M", + "200": "L", + "800": "XL", + "2000": "XXL" + } diff --git a/bfdd/bfd_packet.c b/bfdd/bfd_packet.c index 382f78a0f6..6397aa5747 100644 --- a/bfdd/bfd_packet.c +++ b/bfdd/bfd_packet.c @@ -1397,8 +1397,6 @@ int bp_peer_socket(const struct bfd_session *bs) sin.sin_len = sizeof(sin); #endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */ memcpy(&sin.sin_addr, &bs->key.local, sizeof(sin.sin_addr)); - if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) == 0) - sin.sin_addr.s_addr = INADDR_ANY; pcount = 0; do { diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index b8010364a7..1f8c7dc098 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -904,20 +904,16 @@ static void attrhash_finish(void) static void attr_show_all_iterator(struct hash_bucket *bucket, struct vty *vty) { struct attr *attr = bucket->data; - char sid_str[BUFSIZ]; vty_out(vty, "attr[%ld] nexthop %pI4\n", attr->refcnt, &attr->nexthop); - sid_str[0] = '\0'; - if (attr->srv6_l3vpn) - inet_ntop(AF_INET6, &attr->srv6_l3vpn->sid, sid_str, BUFSIZ); - else if (attr->srv6_vpn) - inet_ntop(AF_INET6, &attr->srv6_vpn->sid, sid_str, BUFSIZ); - vty_out(vty, - "\tflags: %" PRIu64" distance: %u med: %u local_pref: %u origin: %u weight: %u label: %u sid: %s\n", + "\tflags: %" PRIu64 + " distance: %u med: %u local_pref: %u origin: %u weight: %u label: %u sid: %pI6\n", attr->flag, attr->distance, attr->med, attr->local_pref, - attr->origin, attr->weight, attr->label, sid_str); + attr->origin, attr->weight, attr->label, + attr->srv6_l3vpn ? &attr->srv6_l3vpn->sid + : &attr->srv6_vpn->sid); } void attr_show_all(struct vty *vty) @@ -1746,12 +1742,9 @@ enum bgp_attr_parse_ret bgp_attr_nexthop_valid(struct peer *peer, if (ipv4_martian(&attr->nexthop) && !bgp->allow_martian) { uint8_t data[7]; /* type(2) + length(1) + nhop(4) */ - char buf[INET_ADDRSTRLEN]; - inet_ntop(AF_INET, &attr->nexthop.s_addr, buf, - INET_ADDRSTRLEN); - flog_err(EC_BGP_ATTR_MARTIAN_NH, "Martian nexthop %s", - buf); + flog_err(EC_BGP_ATTR_MARTIAN_NH, "Martian nexthop %pI4", + &attr->nexthop); data[0] = BGP_ATTR_FLAG_TRANS; data[1] = BGP_ATTR_NEXT_HOP; data[2] = BGP_ATTR_NHLEN_IPV4; @@ -2758,7 +2751,6 @@ bgp_attr_srv6_service(struct bgp_attr_parser_args *args) uint16_t length, endpoint_behavior; size_t headersz = sizeof(type) + sizeof(length); enum bgp_attr_parse_ret err; - char buf[BUFSIZ]; if (STREAM_READABLE(peer->curr) < headersz) { flog_err( @@ -2789,12 +2781,11 @@ bgp_attr_srv6_service(struct bgp_attr_parser_args *args) stream_getc(peer->curr); /* Log SRv6 Service Sub-TLV */ - if (BGP_DEBUG(vpn, VPN_LEAK_LABEL)) { - inet_ntop(AF_INET6, &ipv6_sid, buf, sizeof(buf)); + if (BGP_DEBUG(vpn, VPN_LEAK_LABEL)) zlog_debug( - "%s: srv6-l3-srv sid %s, sid-flags 0x%02x, end-behaviour 0x%04x", - __func__, buf, sid_flags, endpoint_behavior); - } + "%s: srv6-l3-srv sid %pI6, sid-flags 0x%02x, end-behaviour 0x%04x", + __func__, &ipv6_sid, sid_flags, + endpoint_behavior); /* Configure from Info */ if (attr->srv6_l3vpn) { @@ -2855,7 +2846,6 @@ bgp_attr_psid_sub(uint8_t type, uint16_t length, uint32_t srgb_range; int srgb_count; uint8_t sid_type, sid_flags; - char buf[BUFSIZ]; if (type == BGP_PREFIX_SID_LABEL_INDEX) { if (STREAM_READABLE(peer->curr) < length @@ -2986,12 +2976,10 @@ bgp_attr_psid_sub(uint8_t type, uint16_t length, sizeof(ipv6_sid)); /* sid_value */ /* Log VPN-SID Sub-TLV */ - if (BGP_DEBUG(vpn, VPN_LEAK_LABEL)) { - inet_ntop(AF_INET6, &ipv6_sid, buf, sizeof(buf)); + if (BGP_DEBUG(vpn, VPN_LEAK_LABEL)) zlog_debug( - "%s: vpn-sid: sid %s, sid-type 0x%02x sid-flags 0x%02x", - __func__, buf, sid_type, sid_flags); - } + "%s: vpn-sid: sid %pI6, sid-type 0x%02x sid-flags 0x%02x", + __func__, &ipv6_sid, sid_type, sid_flags); /* Configure from Info */ if (attr->srv6_vpn) { diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c index 92a22d71b3..bfde1c127e 100644 --- a/bgpd/bgp_debug.c +++ b/bgpd/bgp_debug.c @@ -378,8 +378,6 @@ bool bgp_debug_peer_updout_enabled(char *host) /* Dump attribute. */ bool bgp_dump_attr(struct attr *attr, char *buf, size_t size) { - char addrbuf[BUFSIZ]; - if (!attr) return false; @@ -395,15 +393,12 @@ bool bgp_dump_attr(struct attr *attr, char *buf, size_t size) /* Add MP case. */ if (attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL || attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) - snprintf(buf + strlen(buf), size - strlen(buf), - ", mp_nexthop %s", - inet_ntop(AF_INET6, &attr->mp_nexthop_global, addrbuf, - BUFSIZ)); + snprintfrr(buf + strlen(buf), size - strlen(buf), + ", mp_nexthop %pI6", &attr->mp_nexthop_global); if (attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) - snprintf(buf + strlen(buf), size - strlen(buf), "(%s)", - inet_ntop(AF_INET6, &attr->mp_nexthop_local, addrbuf, - BUFSIZ)); + snprintfrr(buf + strlen(buf), size - strlen(buf), "(%pI6)", + &attr->mp_nexthop_local); if (attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV4) snprintfrr(buf, size, "nexthop %pI4", &attr->nexthop); diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c index 589d9af1e5..62fba1f58e 100644 --- a/bgpd/bgp_ecommunity.c +++ b/bgpd/bgp_ecommunity.c @@ -988,13 +988,8 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter) type == ECOMMUNITY_ENCODE_IP) { struct in_addr *ipv4 = (struct in_addr *)pnt; - char ipv4str[INET_ADDRSTRLEN]; - - inet_ntop(AF_INET, ipv4, - ipv4str, - INET_ADDRSTRLEN); - snprintf(encbuf, sizeof(encbuf), - "NH:%s:%d", ipv4str, pnt[5]); + snprintfrr(encbuf, sizeof(encbuf), + "NH:%pI4:%d", ipv4, pnt[5]); } else if (sub_type == ECOMMUNITY_LINK_BANDWIDTH && type == ECOMMUNITY_ENCODE_AS) { diff --git a/bgpd/bgp_evpn_mh.c b/bgpd/bgp_evpn_mh.c index 2a5c5d7ec4..77656dae34 100644 --- a/bgpd/bgp_evpn_mh.c +++ b/bgpd/bgp_evpn_mh.c @@ -2435,7 +2435,7 @@ static char *bgp_evpn_es_vteps_str(char *vtep_str, struct bgp_evpn_es *es, struct listnode *node; struct bgp_evpn_es_vtep *es_vtep; bool first = true; - char ip_buf[INET6_ADDRSTRLEN]; + char ip_buf[INET_ADDRSTRLEN]; vtep_str[0] = '\0'; for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, es_vtep)) { @@ -3903,7 +3903,7 @@ static char *bgp_evpn_es_evi_vteps_str(char *vtep_str, struct listnode *node; struct bgp_evpn_es_evi_vtep *evi_vtep; bool first = true; - char ip_buf[INET6_ADDRSTRLEN]; + char ip_buf[INET_ADDRSTRLEN]; vtep_str[0] = '\0'; for (ALL_LIST_ELEMENTS_RO(es_evi->es_evi_vtep_list, node, evi_vtep)) { diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index 88c1329f48..00545c96ae 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -372,7 +372,6 @@ static void bgp_evpn_show_route_header(struct vty *vty, struct bgp *bgp, static void display_l3vni(struct vty *vty, struct bgp *bgp_vrf, json_object *json) { - char buf1[INET6_ADDRSTRLEN]; char *ecom_str; struct listnode *node, *nnode; struct vrf_route_target *l3rt; @@ -419,9 +418,8 @@ static void display_l3vni(struct vty *vty, struct bgp *bgp_vrf, vty_out(vty, " Advertise-svi-macip : %s\n", "n/a"); vty_out(vty, " Advertise-pip: %s\n", bgp_vrf->evpn_info->advertise_pip ? "Yes" : "No"); - vty_out(vty, " System-IP: %s\n", - inet_ntop(AF_INET, &bgp_vrf->evpn_info->pip_ip, - buf1, INET_ADDRSTRLEN)); + vty_out(vty, " System-IP: %pI4\n", + &bgp_vrf->evpn_info->pip_ip); vty_out(vty, " System-MAC: %s\n", prefix_mac2str(&bgp_vrf->evpn_info->pip_rmac, buf2, sizeof(buf2))); @@ -7071,8 +7069,6 @@ static int vni_cmp(const void **a, const void **b) void bgp_config_write_evpn_info(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi) { - char buf2[INET6_ADDRSTRLEN]; - if (bgp->advertise_all_vni) vty_out(vty, " advertise-all-vni\n"); @@ -7217,10 +7213,8 @@ void bgp_config_write_evpn_info(struct vty *vty, struct bgp *bgp, afi_t afi, if (bgp->evpn_info->advertise_pip) { if (bgp->evpn_info->pip_ip_static.s_addr != INADDR_ANY) { - vty_out(vty, " advertise-pip ip %s", - inet_ntop(AF_INET, - &bgp->evpn_info->pip_ip_static, - buf2, INET_ADDRSTRLEN)); + vty_out(vty, " advertise-pip ip %pI4", + &bgp->evpn_info->pip_ip_static); if (!is_zero_mac(&( bgp->evpn_info->pip_rmac_static))) { char buf[ETHER_ADDR_STRLEN]; diff --git a/bgpd/bgp_flowspec_vty.c b/bgpd/bgp_flowspec_vty.c index 02dcdfcaa3..626e980346 100644 --- a/bgpd/bgp_flowspec_vty.c +++ b/bgpd/bgp_flowspec_vty.c @@ -338,18 +338,14 @@ void route_vty_out_flowspec(struct vty *vty, const struct prefix *p, local_buff[0] = '\0'; if (p->u.prefix_flowspec.family == AF_INET && attr->nexthop.s_addr != INADDR_ANY) - inet_ntop(AF_INET, - &attr->nexthop.s_addr, - local_buff, - INET6_ADDRSTRLEN); + inet_ntop(AF_INET, &attr->nexthop.s_addr, + local_buff, sizeof(local_buff)); else if (p->u.prefix_flowspec.family == AF_INET6 && attr->mp_nexthop_len != 0 && attr->mp_nexthop_len != BGP_ATTR_NHLEN_IPV4 && attr->mp_nexthop_len != BGP_ATTR_NHLEN_VPNV4) - inet_ntop(AF_INET6, - &attr->mp_nexthop_global, - local_buff, - INET6_ADDRSTRLEN); + inet_ntop(AF_INET6, &attr->mp_nexthop_global, + local_buff, sizeof(local_buff)); if (local_buff[0] != '\0') vty_out(vty, "\tNLRI NH %s\n", local_buff); diff --git a/bgpd/bgp_mpath.c b/bgpd/bgp_mpath.c index 64af8a5411..52f6b64c2c 100644 --- a/bgpd/bgp_mpath.c +++ b/bgpd/bgp_mpath.c @@ -278,8 +278,10 @@ void bgp_mp_list_add(struct list *mp_list, struct bgp_path_info *mpinfo) static struct bgp_path_info_mpath *bgp_path_info_mpath_new(void) { struct bgp_path_info_mpath *new_mpath; + new_mpath = XCALLOC(MTYPE_BGP_MPATH_INFO, sizeof(struct bgp_path_info_mpath)); + return new_mpath; } @@ -313,8 +315,6 @@ bgp_path_info_mpath_get(struct bgp_path_info *path) if (!path->mpath) { mpath = bgp_path_info_mpath_new(); - if (!mpath) - return NULL; path->mpath = mpath; mpath->mp_info = path; } diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c index 075350cd2b..25a4a1b521 100644 --- a/bgpd/bgp_nexthop.c +++ b/bgpd/bgp_nexthop.c @@ -768,28 +768,22 @@ static void bgp_show_nexthop_paths(struct vty *vty, struct bgp *bgp, static void bgp_show_nexthops_detail(struct vty *vty, struct bgp *bgp, struct bgp_nexthop_cache *bnc) { - char buf[PREFIX2STR_BUFFER]; struct nexthop *nexthop; for (nexthop = bnc->nexthop; nexthop; nexthop = nexthop->next) { switch (nexthop->type) { case NEXTHOP_TYPE_IPV6: - vty_out(vty, " gate %s\n", - inet_ntop(AF_INET6, &nexthop->gate.ipv6, buf, - sizeof(buf))); + vty_out(vty, " gate %pI6\n", &nexthop->gate.ipv6); break; case NEXTHOP_TYPE_IPV6_IFINDEX: - vty_out(vty, " gate %s, if %s\n", - inet_ntop(AF_INET6, &nexthop->gate.ipv6, buf, - sizeof(buf)), + vty_out(vty, " gate %pI6, if %s\n", + &nexthop->gate.ipv6, ifindex2ifname(bnc->ifindex ? bnc->ifindex : nexthop->ifindex, bgp->vrf_id)); break; case NEXTHOP_TYPE_IPV4: - vty_out(vty, " gate %s\n", - inet_ntop(AF_INET, &nexthop->gate.ipv4, buf, - sizeof(buf))); + vty_out(vty, " gate %pI4\n", &nexthop->gate.ipv4); break; case NEXTHOP_TYPE_IFINDEX: vty_out(vty, " if %s\n", @@ -798,9 +792,8 @@ static void bgp_show_nexthops_detail(struct vty *vty, struct bgp *bgp, bgp->vrf_id)); break; case NEXTHOP_TYPE_IPV4_IFINDEX: - vty_out(vty, " gate %s, if %s\n", - inet_ntop(AF_INET, &nexthop->gate.ipv4, buf, - sizeof(buf)), + vty_out(vty, " gate %pI4, if %s\n", + &nexthop->gate.ipv4, ifindex2ifname(bnc->ifindex ? bnc->ifindex : nexthop->ifindex, bgp->vrf_id)); diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index f3ca3bba0a..5d4cf2a6aa 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -979,10 +979,11 @@ static void bgp_notify_send_internal(struct peer *peer, uint8_t code, peer->notify.code = bgp_notify.code; peer->notify.subcode = bgp_notify.subcode; + peer->notify.length = bgp_notify.length; if (bgp_notify.length && data) { - bgp_notify.data = - XMALLOC(MTYPE_TMP, bgp_notify.length * 3); + bgp_notify.data = XMALLOC(MTYPE_BGP_NOTIFICATION, + bgp_notify.length * 3); for (i = 0; i < bgp_notify.length; i++) if (first) { snprintf(c, sizeof(c), " %02x", @@ -1002,7 +1003,15 @@ static void bgp_notify_send_internal(struct peer *peer, uint8_t code, bgp_notify_print(peer, &bgp_notify, "sending", hard_reset); if (bgp_notify.data) { - XFREE(MTYPE_TMP, bgp_notify.data); + if (data) { + XFREE(MTYPE_BGP_NOTIFICATION, + peer->notify.data); + peer->notify.data = XCALLOC( + MTYPE_BGP_NOTIFICATION, datalen); + memcpy(peer->notify.data, data, datalen); + } + + XFREE(MTYPE_BGP_NOTIFICATION, bgp_notify.data); bgp_notify.length = 0; } } diff --git a/bgpd/bgp_pbr.c b/bgpd/bgp_pbr.c index b71e19ab33..807c4cd5a4 100644 --- a/bgpd/bgp_pbr.c +++ b/bgpd/bgp_pbr.c @@ -1636,9 +1636,8 @@ void bgp_pbr_print_policy_route(struct bgp_pbr_entry_main *api) ptr_ip = &api->actions[i].u.zr.redirect_ip_v4; else ptr_ip = &api->actions[i].u.zr.redirect_ip_v6; - if (inet_ntop(afi2family(api->afi), - ptr_ip, local_buff, - INET6_ADDRSTRLEN) != NULL) { + if (inet_ntop(afi2family(api->afi), ptr_ip, local_buff, + sizeof(local_buff)) != NULL) { delta = snprintf(ptr, len, "@redirect ip nh %s", local_buff); len -= delta; diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index d6e6fc952f..027cb20e41 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -4237,9 +4237,11 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, new_attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF); new_attr.local_pref = BGP_GSHUT_LOCAL_PREF; - /* If graceful-shutdown is configured then add the GSHUT - * community to all paths received from eBGP peers */ - } else if (bgp_in_graceful_shutdown(peer->bgp)) + /* If graceful-shutdown is configured globally or + * per neighbor, then add the GSHUT community to + * all paths received from eBGP peers. */ + } else if (bgp_in_graceful_shutdown(peer->bgp) || + CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_SHUTDOWN)) bgp_attr_add_gshut_community(&new_attr); } @@ -4279,14 +4281,6 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, && (!CHECK_FLAG(dest->flags, BGP_NODE_FIB_INSTALLED))) SET_FLAG(dest->flags, BGP_NODE_FIB_INSTALL_PENDING); - /* If maximum prefix count is configured and current prefix - * count exeed it. - */ - if (bgp_maximum_prefix_overflow(peer, afi, safi, 0)) { - bgp_attr_flush(&new_attr); - return -1; - } - /* If neighbor soo is configured, tag all incoming routes with * this SoO tag and then filter out advertisements in * subgroup_announce_check() if it matches the configured SoO @@ -4789,14 +4783,9 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, CHECK_FLAG(peer->flags, PEER_FLAG_IS_RFAPI_HD)) bgp_path_info_set_flag(dest, new, BGP_PATH_VALID); else { - if (BGP_DEBUG(nht, NHT)) { - char buf1[INET6_ADDRSTRLEN]; - inet_ntop(AF_INET, - (const void *)&attr_new->nexthop, - buf1, INET6_ADDRSTRLEN); - zlog_debug("%s(%s): NH unresolved", __func__, - buf1); - } + if (BGP_DEBUG(nht, NHT)) + zlog_debug("%s(%pI4): NH unresolved", __func__, + &attr_new->nexthop); bgp_path_info_unset_flag(dest, new, BGP_PATH_VALID); } } else { @@ -4806,6 +4795,17 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, bgp_path_info_set_flag(dest, new, BGP_PATH_VALID); } + /* If maximum prefix count is configured and current prefix + * count exeed it. + */ + if (bgp_maximum_prefix_overflow(peer, afi, safi, 0)) { + reason = "maximum-prefix overflow"; + bgp_attr_flush(&new_attr); + bgp_unlink_nexthop(new); + bgp_path_info_delete(dest, new); + goto filtered; + } + /* Addpath ID */ new->addpath_rx_id = addpath_id; @@ -6296,7 +6296,7 @@ void bgp_static_update(struct bgp *bgp, const struct prefix *p, char buf1[INET6_ADDRSTRLEN]; inet_ntop(p->family, &p->u.prefix, buf1, - INET6_ADDRSTRLEN); + sizeof(buf1)); zlog_debug( "%s(%s): Route not in table, not advertising", __func__, buf1); @@ -6346,8 +6346,9 @@ void bgp_static_update(struct bgp *bgp, const struct prefix *p, else { if (BGP_DEBUG(nht, NHT)) { char buf1[INET6_ADDRSTRLEN]; + inet_ntop(p->family, &p->u.prefix, buf1, - INET6_ADDRSTRLEN); + sizeof(buf1)); zlog_debug( "%s(%s): Route not in table, not advertising", __func__, buf1); @@ -8910,7 +8911,7 @@ static void route_vty_out_route(struct bgp_dest *dest, const struct prefix *p, struct vty *vty, json_object *json, bool wide) { int len = 0; - char buf[BUFSIZ]; + char buf[INET6_ADDRSTRLEN]; if (p->family == AF_INET) { if (!json) { @@ -8919,7 +8920,7 @@ static void route_vty_out_route(struct bgp_dest *dest, const struct prefix *p, json_object_string_add(json, "prefix", inet_ntop(p->family, &p->u.prefix, buf, - BUFSIZ)); + sizeof(buf))); json_object_int_add(json, "prefixLen", p->prefixlen); json_object_string_addf(json, "network", "%pFX", p); json_object_int_add(json, "version", dest->version); @@ -8941,9 +8942,9 @@ static void route_vty_out_route(struct bgp_dest *dest, const struct prefix *p, len = vty_out(vty, "%pFX", p); else { json_object_string_add(json, "prefix", - inet_ntop(p->family, - &p->u.prefix, buf, - BUFSIZ)); + inet_ntop(p->family, + &p->u.prefix, buf, + sizeof(buf))); json_object_int_add(json, "prefixLen", p->prefixlen); json_object_string_addf(json, "network", "%pFX", p); json_object_int_add(json, "version", dest->version); @@ -9212,20 +9213,17 @@ void route_vty_out(struct vty *vty, const struct prefix *p, * attr->mp_nexthop_global_in */ if ((safi == SAFI_ENCAP) || (safi == SAFI_MPLS_VPN)) { - char buf[BUFSIZ]; char nexthop[128]; int af = NEXTHOP_FAMILY(attr->mp_nexthop_len); switch (af) { case AF_INET: - snprintf(nexthop, sizeof(nexthop), "%s", - inet_ntop(af, &attr->mp_nexthop_global_in, buf, - BUFSIZ)); + snprintfrr(nexthop, sizeof(nexthop), "%pI4", + &attr->mp_nexthop_global_in); break; case AF_INET6: - snprintf(nexthop, sizeof(nexthop), "%s", - inet_ntop(af, &attr->mp_nexthop_global, buf, - BUFSIZ)); + snprintfrr(nexthop, sizeof(nexthop), "%pI6", + &attr->mp_nexthop_global); break; default: snprintf(nexthop, sizeof(nexthop), "?"); @@ -9696,13 +9694,8 @@ void route_vty_out_tmp(struct vty *vty, struct bgp_dest *dest, vty_out(vty, "%-16pI4", &attr->nexthop); } else if (p->family == AF_INET6 || BGP_ATTR_MP_NEXTHOP_LEN_IP6(attr)) { - char buf[BUFSIZ]; - - len = vty_out( - vty, "%s", - inet_ntop(AF_INET6, - &attr->mp_nexthop_global, buf, - BUFSIZ)); + len = vty_out(vty, "%pI6", + &attr->mp_nexthop_global); len = wide ? (41 - len) : (16 - len); if (len < 1) vty_out(vty, "\n%*s", 36, " "); @@ -10216,7 +10209,6 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, json_object *json_paths) { char buf[INET6_ADDRSTRLEN]; - char buf1[BUFSIZ]; char tag_buf[30]; struct attr *attr = path->attr; time_t tbuf; @@ -10596,10 +10588,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)) vty_out(vty, " (%pI4)", &attr->originator_id); else - vty_out(vty, " (%s)", - inet_ntop(AF_INET, - &path->peer->remote_id, buf1, - sizeof(buf1))); + vty_out(vty, " (%pI4)", &path->peer->remote_id); } } @@ -11012,11 +11001,12 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, /* Remote SID */ if (path->extra && path->extra->num_sids > 0 && safi != SAFI_EVPN) { - inet_ntop(AF_INET6, &path->extra->sid[0].sid, buf, sizeof(buf)); if (json_paths) - json_object_string_add(json_path, "remoteSid", buf); + json_object_string_addf(json_path, "remoteSid", "%pI6", + &path->extra->sid[0].sid); else - vty_out(vty, " Remote SID: %s\n", buf); + vty_out(vty, " Remote SID: %pI6\n", + &path->extra->sid[0].sid); } /* Label Index */ @@ -15517,13 +15507,15 @@ static void bgp_config_write_network_evpn(struct vty *vty, struct bgp *bgp, /* "network" configuration display. */ if (p->u.prefix_evpn.route_type == 5) { char local_buf[PREFIX_STRLEN]; + uint8_t family = is_evpn_prefix_ipaddr_v4(( struct prefix_evpn *)p) ? AF_INET : AF_INET6; inet_ntop(family, - &p->u.prefix_evpn.prefix_addr.ip.ip.addr, - local_buf, PREFIX_STRLEN); + &p->u.prefix_evpn.prefix_addr.ip.ip + .addr, + local_buf, sizeof(local_buf)); snprintf(buf, sizeof(buf), "%s/%u", local_buf, p->u.prefix_evpn.prefix_addr .ip_prefix_length); diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 9422469bca..1ce2eb4352 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -4145,7 +4145,7 @@ static void bgp_route_map_process_update(struct bgp *bgp, const char *rmap_name, safi2str(safi), inet_ntop(bn_p->family, &bn_p->u.prefix, buf, - INET6_ADDRSTRLEN)); + sizeof(buf))); bgp_static_update(bgp, bn_p, bgp_static, afi, safi); } @@ -4197,7 +4197,7 @@ static void bgp_route_map_process_update(struct bgp *bgp, const char *rmap_name, safi2str(safi), inet_ntop(bn_p->family, &bn_p->u.prefix, buf, - INET6_ADDRSTRLEN)); + sizeof(buf))); bgp_aggregate_route(bgp, bn_p, afi, safi, aggregate); } @@ -6852,9 +6852,9 @@ DEFUN_YANG (no_set_vpn_nexthop, } #endif /* KEEP_OLD_VPN_COMMANDS */ -DEFUN_YANG (set_ipx_vpn_nexthop, +DEFPY_YANG (set_ipx_vpn_nexthop, set_ipx_vpn_nexthop_cmd, - "set <ipv4|ipv6> vpn next-hop <A.B.C.D|X:X::X:X>", + "set <ipv4|ipv6> vpn next-hop <A.B.C.D$addrv4|X:X::X:X$addrv6>", SET_STR "IPv4 information\n" "IPv6 information\n" @@ -6870,6 +6870,11 @@ DEFUN_YANG (set_ipx_vpn_nexthop, if (argv_find_and_parse_afi(argv, argc, &idx, &afi)) { if (afi == AFI_IP) { + if (addrv6_str) { + vty_out(vty, "%% IPv4 next-hop expected\n"); + return CMD_WARNING_CONFIG_FAILED; + } + const char *xpath = "./set-action[action='frr-bgp-route-map:ipv4-vpn-address']"; @@ -6879,6 +6884,11 @@ DEFUN_YANG (set_ipx_vpn_nexthop, "%s/rmap-set-action/frr-bgp-route-map:ipv4-address", xpath); } else { + if (addrv4_str) { + vty_out(vty, "%% IPv6 next-hop expected\n"); + return CMD_WARNING_CONFIG_FAILED; + } + const char *xpath = "./set-action[action='frr-bgp-route-map:ipv6-vpn-address']"; diff --git a/bgpd/bgp_snmp_bgp4v2.c b/bgpd/bgp_snmp_bgp4v2.c index d59e63d7e0..1be28e0b2d 100644 --- a/bgpd/bgp_snmp_bgp4v2.c +++ b/bgpd/bgp_snmp_bgp4v2.c @@ -39,6 +39,7 @@ #include "bgpd/bgp_table.h" #include "bgpd/bgp_aspath.h" #include "bgpd/bgp_attr.h" +#include "bgpd/bgp_debug.h" #include "bgpd/bgp_route.h" #include "bgpd/bgp_fsm.h" #include "bgpd/bgp_snmp.h" @@ -270,6 +271,108 @@ static uint8_t *bgpv2PeerTable(struct variable *v, oid name[], size_t *length, case BGP4V2_PEER_DESCRIPTION: if (peer->desc) return SNMP_STRING(peer->desc); + break; + default: + break; + } + + return NULL; +} + +static uint8_t *bgpv2PeerErrorsTable(struct variable *v, oid name[], + size_t *length, int exact, size_t *var_len, + WriteMethod **write_method) +{ + struct peer *peer; + struct ipaddr addr = {}; + + if (smux_header_table(v, name, length, exact, var_len, write_method) == + MATCH_FAILED) + return NULL; + + peer = bgpv2PeerTable_lookup(v, name, length, exact, &addr); + if (!peer) + return NULL; + + switch (v->magic) { + case BGP4V2_PEER_LAST_ERROR_CODE_RECEIVED: + if (peer->last_reset == PEER_DOWN_NOTIFY_RECEIVED) + return SNMP_INTEGER(peer->notify.code); + else + return SNMP_INTEGER(0); + case BGP4V2_PEER_LAST_ERROR_SUBCODE_RECEIVED: + if (peer->last_reset == PEER_DOWN_NOTIFY_RECEIVED) + return SNMP_INTEGER(peer->notify.subcode); + else + return SNMP_INTEGER(0); + case BGP4V2_PEER_LAST_ERROR_RECEIVED_TIME: + if (peer->last_reset == PEER_DOWN_NOTIFY_RECEIVED) + return SNMP_INTEGER(peer->resettime); + else + return SNMP_INTEGER(0); + case BGP4V2_PEER_LAST_ERROR_RECEIVED_TEXT: + if (peer->last_reset == PEER_DOWN_NOTIFY_RECEIVED) { + struct bgp_notify notify = peer->notify; + char msg_buf[255]; + const char *msg_str = NULL; + + if (notify.code == BGP_NOTIFY_CEASE && + (notify.subcode == + BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN || + notify.subcode == BGP_NOTIFY_CEASE_ADMIN_RESET)) { + msg_str = bgp_notify_admin_message( + msg_buf, sizeof(msg_buf), + (uint8_t *)notify.data, notify.length); + return SNMP_STRING(msg_str); + } + } + return SNMP_STRING(""); + case BGP4V2_PEER_LAST_ERROR_RECEIVED_DATA: + if (peer->last_reset == PEER_DOWN_NOTIFY_RECEIVED) + return SNMP_STRING(peer->notify.data); + else + return SNMP_STRING(""); + case BGP4V2_PEER_LAST_ERROR_CODE_SENT: + if (peer->last_reset != PEER_DOWN_NOTIFY_RECEIVED) + return SNMP_INTEGER(peer->notify.code); + else + return SNMP_INTEGER(0); + case BGP4V2_PEER_LAST_ERROR_SUBCODE_SENT: + if (peer->last_reset != PEER_DOWN_NOTIFY_RECEIVED) + return SNMP_INTEGER(peer->notify.subcode); + else + return SNMP_INTEGER(0); + case BGP4V2_PEER_LAST_ERROR_SENT_TIME: + if (peer->last_reset != PEER_DOWN_NOTIFY_RECEIVED) + return SNMP_INTEGER(peer->resettime); + else + return SNMP_INTEGER(0); + case BGP4V2_PEER_LAST_ERROR_SENT_TEXT: + if (peer->last_reset == PEER_DOWN_NOTIFY_SEND || + peer->last_reset == PEER_DOWN_RTT_SHUTDOWN || + peer->last_reset == PEER_DOWN_USER_SHUTDOWN) { + struct bgp_notify notify = peer->notify; + char msg_buf[255]; + const char *msg_str = NULL; + + if (notify.code == BGP_NOTIFY_CEASE && + (notify.subcode == + BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN || + notify.subcode == BGP_NOTIFY_CEASE_ADMIN_RESET)) { + msg_str = bgp_notify_admin_message( + msg_buf, sizeof(msg_buf), + (uint8_t *)notify.data, notify.length); + return SNMP_STRING(msg_str); + } + } + return SNMP_STRING(""); + case BGP4V2_PEER_LAST_ERROR_SENT_DATA: + if (peer->last_reset == PEER_DOWN_NOTIFY_SEND || + peer->last_reset == PEER_DOWN_RTT_SHUTDOWN || + peer->last_reset == PEER_DOWN_USER_SHUTDOWN) + return SNMP_STRING(peer->notify.data); + else + return SNMP_STRING(""); default: break; } @@ -278,6 +381,7 @@ static uint8_t *bgpv2PeerTable(struct variable *v, oid name[], size_t *length, } static struct variable bgpv2_variables[] = { + /* bgp4V2PeerEntry */ {BGP4V2_PEER_INSTANCE, ASN_UNSIGNED, RONLY, @@ -446,6 +550,127 @@ static struct variable bgpv2_variables[] = { bgpv2PeerTable, 6, {1, 2, 1, BGP4V2_PEER_DESCRIPTION, 2, 16}}, + /* bgp4V2PeerErrorsEntry */ + {BGP4V2_PEER_LAST_ERROR_CODE_RECEIVED, + ASN_UNSIGNED, + RONLY, + bgpv2PeerErrorsTable, + 6, + {1, 3, 1, BGP4V2_PEER_LAST_ERROR_CODE_RECEIVED, 1, 4}}, + {BGP4V2_PEER_LAST_ERROR_CODE_RECEIVED, + ASN_UNSIGNED, + RONLY, + bgpv2PeerErrorsTable, + 6, + {1, 3, 1, BGP4V2_PEER_LAST_ERROR_CODE_RECEIVED, 2, 16}}, + {BGP4V2_PEER_LAST_ERROR_SUBCODE_RECEIVED, + ASN_UNSIGNED, + RONLY, + bgpv2PeerErrorsTable, + 6, + {1, 3, 1, BGP4V2_PEER_LAST_ERROR_SUBCODE_RECEIVED, 1, 4}}, + {BGP4V2_PEER_LAST_ERROR_SUBCODE_RECEIVED, + ASN_UNSIGNED, + RONLY, + bgpv2PeerErrorsTable, + 6, + {1, 3, 1, BGP4V2_PEER_LAST_ERROR_SUBCODE_RECEIVED, 2, 16}}, + {BGP4V2_PEER_LAST_ERROR_RECEIVED_TIME, + ASN_UNSIGNED, + RONLY, + bgpv2PeerErrorsTable, + 6, + {1, 3, 1, BGP4V2_PEER_LAST_ERROR_RECEIVED_TIME, 1, 4}}, + {BGP4V2_PEER_LAST_ERROR_RECEIVED_TIME, + ASN_UNSIGNED, + RONLY, + bgpv2PeerErrorsTable, + 6, + {1, 3, 1, BGP4V2_PEER_LAST_ERROR_RECEIVED_TIME, 2, 16}}, + {BGP4V2_PEER_LAST_ERROR_RECEIVED_TEXT, + ASN_OCTET_STR, + RONLY, + bgpv2PeerErrorsTable, + 6, + {1, 3, 1, BGP4V2_PEER_LAST_ERROR_RECEIVED_TEXT, 1, 4}}, + {BGP4V2_PEER_LAST_ERROR_RECEIVED_TEXT, + ASN_OCTET_STR, + RONLY, + bgpv2PeerErrorsTable, + 6, + {1, 3, 1, BGP4V2_PEER_LAST_ERROR_RECEIVED_TEXT, 2, 16}}, + {BGP4V2_PEER_LAST_ERROR_RECEIVED_DATA, + ASN_OCTET_STR, + RONLY, + bgpv2PeerErrorsTable, + 6, + {1, 3, 1, BGP4V2_PEER_LAST_ERROR_RECEIVED_DATA, 1, 4}}, + {BGP4V2_PEER_LAST_ERROR_RECEIVED_DATA, + ASN_OCTET_STR, + RONLY, + bgpv2PeerErrorsTable, + 6, + {1, 3, 1, BGP4V2_PEER_LAST_ERROR_RECEIVED_DATA, 2, 16}}, + {BGP4V2_PEER_LAST_ERROR_CODE_SENT, + ASN_UNSIGNED, + RONLY, + bgpv2PeerErrorsTable, + 6, + {1, 3, 1, BGP4V2_PEER_LAST_ERROR_CODE_SENT, 1, 4}}, + {BGP4V2_PEER_LAST_ERROR_CODE_SENT, + ASN_UNSIGNED, + RONLY, + bgpv2PeerErrorsTable, + 6, + {1, 3, 1, BGP4V2_PEER_LAST_ERROR_CODE_SENT, 2, 16}}, + {BGP4V2_PEER_LAST_ERROR_SUBCODE_SENT, + ASN_UNSIGNED, + RONLY, + bgpv2PeerErrorsTable, + 6, + {1, 3, 1, BGP4V2_PEER_LAST_ERROR_SUBCODE_SENT, 1, 4}}, + {BGP4V2_PEER_LAST_ERROR_SUBCODE_SENT, + ASN_UNSIGNED, + RONLY, + bgpv2PeerErrorsTable, + 6, + {1, 3, 1, BGP4V2_PEER_LAST_ERROR_SUBCODE_SENT, 2, 16}}, + {BGP4V2_PEER_LAST_ERROR_SENT_TIME, + ASN_UNSIGNED, + RONLY, + bgpv2PeerErrorsTable, + 6, + {1, 3, 1, BGP4V2_PEER_LAST_ERROR_SENT_TIME, 1, 4}}, + {BGP4V2_PEER_LAST_ERROR_SENT_TIME, + ASN_UNSIGNED, + RONLY, + bgpv2PeerErrorsTable, + 6, + {1, 3, 1, BGP4V2_PEER_LAST_ERROR_SENT_TIME, 2, 16}}, + {BGP4V2_PEER_LAST_ERROR_SENT_TEXT, + ASN_OCTET_STR, + RONLY, + bgpv2PeerErrorsTable, + 6, + {1, 3, 1, BGP4V2_PEER_LAST_ERROR_SENT_TEXT, 1, 4}}, + {BGP4V2_PEER_LAST_ERROR_SENT_TEXT, + ASN_OCTET_STR, + RONLY, + bgpv2PeerErrorsTable, + 6, + {1, 3, 1, BGP4V2_PEER_LAST_ERROR_SENT_TEXT, 2, 16}}, + {BGP4V2_PEER_LAST_ERROR_SENT_DATA, + ASN_OCTET_STR, + RONLY, + bgpv2PeerErrorsTable, + 6, + {1, 3, 1, BGP4V2_PEER_LAST_ERROR_SENT_DATA, 1, 4}}, + {BGP4V2_PEER_LAST_ERROR_SENT_DATA, + ASN_OCTET_STR, + RONLY, + bgpv2PeerErrorsTable, + 6, + {1, 3, 1, BGP4V2_PEER_LAST_ERROR_SENT_DATA, 2, 16}}, }; int bgp_snmp_bgp4v2_init(struct thread_master *tm) diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 4b17d28968..1f532d4990 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -1308,6 +1308,49 @@ void bgp_clear_soft_in(struct bgp *bgp, afi_t afi, safi_t safi) bgp_clear(NULL, bgp, afi, safi, clear_all, BGP_CLEAR_SOFT_IN, NULL); } +static int peer_flag_modify_vty(struct vty *vty, const char *ip_str, + uint64_t flag, int set) +{ + int ret; + struct peer *peer; + + peer = peer_and_group_lookup_vty(vty, ip_str); + if (!peer) + return CMD_WARNING_CONFIG_FAILED; + + /* + * If 'neighbor <interface>', then this is for directly connected peers, + * we should not accept disable-connected-check. + */ + if (peer->conf_if && (flag == PEER_FLAG_DISABLE_CONNECTED_CHECK)) { + vty_out(vty, + "%s is directly connected peer, cannot accept disable-connected-check\n", + ip_str); + return CMD_WARNING_CONFIG_FAILED; + } + + if (!set && flag == PEER_FLAG_SHUTDOWN) + peer_tx_shutdown_message_unset(peer); + + if (set) + ret = peer_flag_set(peer, flag); + else + ret = peer_flag_unset(peer, flag); + + return bgp_vty_return(vty, ret); +} + +static int peer_flag_set_vty(struct vty *vty, const char *ip_str, uint64_t flag) +{ + return peer_flag_modify_vty(vty, ip_str, flag, 1); +} + +static int peer_flag_unset_vty(struct vty *vty, const char *ip_str, + uint64_t flag) +{ + return peer_flag_modify_vty(vty, ip_str, flag, 0); +} + #include "bgpd/bgp_vty_clippy.c" DEFUN_HIDDEN (bgp_local_mac, @@ -3326,6 +3369,42 @@ DEFUN (no_bgp_neighbor_graceful_restart_disable, return bgp_vty_return(vty, ret); } +DEFPY (neighbor_graceful_shutdown, + neighbor_graceful_shutdown_cmd, + "[no$no] neighbor <A.B.C.D|X:X::X:X|WORD>$neighbor graceful-shutdown", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Graceful shutdown\n") +{ + afi_t afi; + safi_t safi; + struct peer *peer; + VTY_DECLVAR_CONTEXT(bgp, bgp); + int ret; + + peer = peer_and_group_lookup_vty(vty, neighbor); + if (!peer) + return CMD_WARNING_CONFIG_FAILED; + + if (no) + ret = peer_flag_unset_vty(vty, neighbor, + PEER_FLAG_GRACEFUL_SHUTDOWN); + else + ret = peer_flag_set_vty(vty, neighbor, + PEER_FLAG_GRACEFUL_SHUTDOWN); + + FOREACH_AFI_SAFI (afi, safi) { + if (!peer->afc[afi][safi]) + continue; + + bgp_clear(vty, bgp, afi, safi, clear_peer, BGP_CLEAR_SOFT_IN, + neighbor); + } + + return ret; +} + DEFUN_HIDDEN (bgp_graceful_restart_disable_eor, bgp_graceful_restart_disable_eor_cmd, "bgp graceful-restart disable-eor", @@ -5251,51 +5330,6 @@ ALIAS_HIDDEN(no_neighbor_set_peer_group, no_neighbor_set_peer_group_hidden_cmd, "Member of the peer-group\n" "Peer-group name\n") -static int peer_flag_modify_vty(struct vty *vty, const char *ip_str, - uint64_t flag, int set) -{ - int ret; - struct peer *peer; - - peer = peer_and_group_lookup_vty(vty, ip_str); - if (!peer) - return CMD_WARNING_CONFIG_FAILED; - - /* - * If 'neighbor <interface>', then this is for directly connected peers, - * we should not accept disable-connected-check. - */ - if (peer->conf_if && (flag == PEER_FLAG_DISABLE_CONNECTED_CHECK)) { - vty_out(vty, - "%s is directly connected peer, cannot accept disable-connected-check\n", - ip_str); - return CMD_WARNING_CONFIG_FAILED; - } - - if (!set && flag == PEER_FLAG_SHUTDOWN) { - peer_tx_shutdown_message_unset(peer); - UNSET_FLAG(peer->sflags, PEER_STATUS_RTT_SHUTDOWN); - } - - if (set) - ret = peer_flag_set(peer, flag); - else - ret = peer_flag_unset(peer, flag); - - return bgp_vty_return(vty, ret); -} - -static int peer_flag_set_vty(struct vty *vty, const char *ip_str, uint64_t flag) -{ - return peer_flag_modify_vty(vty, ip_str, flag, 1); -} - -static int peer_flag_unset_vty(struct vty *vty, const char *ip_str, - uint64_t flag) -{ - return peer_flag_modify_vty(vty, ip_str, flag, 0); -} - /* neighbor passive. */ DEFUN (neighbor_passive, neighbor_passive_cmd, @@ -9884,7 +9918,6 @@ DEFPY (show_bgp_srv6, struct listnode *node; struct srv6_locator_chunk *chunk; struct bgp_srv6_function *func; - char buf[256]; bgp = bgp_get_default(); if (!bgp) @@ -9903,8 +9936,7 @@ DEFPY (show_bgp_srv6, vty_out(vty, "functions:\n"); for (ALL_LIST_ELEMENTS_RO(bgp->srv6_functions, node, func)) { - inet_ntop(AF_INET6, &func->sid, buf, sizeof(buf)); - vty_out(vty, "- sid: %s\n", buf); + vty_out(vty, "- sid: %pI6\n", &func->sid); vty_out(vty, " locator: %s\n", func->locator_name); } @@ -12850,7 +12882,6 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, json_object *json) { struct bgp *bgp; - char buf1[PREFIX2STR_BUFFER]; char timebuf[BGP_UPTIME_LEN]; char dn_flag[2]; afi_t afi; @@ -13174,11 +13205,8 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, /* BGP Version. */ vty_out(vty, " BGP version 4"); - vty_out(vty, ", remote router ID %s", - inet_ntop(AF_INET, &p->remote_id, buf1, sizeof(buf1))); - vty_out(vty, ", local router ID %s\n", - inet_ntop(AF_INET, &bgp->router_id, buf1, - sizeof(buf1))); + vty_out(vty, ", remote router ID %pI4", &p->remote_id); + vty_out(vty, ", local router ID %pI4\n", &bgp->router_id); /* Confederation */ if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION) @@ -14548,15 +14576,11 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, "bgpConnection", "nonSharedNetwork"); } else { - vty_out(vty, "Nexthop: %s\n", - inet_ntop(AF_INET, &p->nexthop.v4, buf1, - sizeof(buf1))); - vty_out(vty, "Nexthop global: %s\n", - inet_ntop(AF_INET6, &p->nexthop.v6_global, buf1, - sizeof(buf1))); - vty_out(vty, "Nexthop local: %s\n", - inet_ntop(AF_INET6, &p->nexthop.v6_local, buf1, - sizeof(buf1))); + vty_out(vty, "Nexthop: %pI4\n", &p->nexthop.v4); + vty_out(vty, "Nexthop global: %pI6\n", + &p->nexthop.v6_global); + vty_out(vty, "Nexthop local: %pI6\n", + &p->nexthop.v6_local); vty_out(vty, "BGP connection: %s\n", p->shared_network ? "shared network" : "non shared network"); @@ -17220,6 +17244,10 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp, if (peergroup_flag_check(peer, PEER_FLAG_AIGP)) vty_out(vty, " neighbor %s aigp\n", addr); + /* graceful-shutdown */ + if (peergroup_flag_check(peer, PEER_FLAG_GRACEFUL_SHUTDOWN)) + vty_out(vty, " neighbor %s graceful-shutdown\n", addr); + /* role */ if (peergroup_flag_check(peer, PEER_FLAG_ROLE) && peer->local_role != ROLE_UNDEFINED) @@ -18666,6 +18694,9 @@ void bgp_vty_init(void) /* "neighbor aigp" commands. */ install_element(BGP_NODE, &neighbor_aigp_cmd); + /* "neighbor graceful-shutdown" command */ + install_element(BGP_NODE, &neighbor_graceful_shutdown_cmd); + /* bgp disable-ebgp-connected-nh-check */ install_element(BGP_NODE, &bgp_disable_connected_route_check_cmd); install_element(BGP_NODE, &no_bgp_disable_connected_route_check_cmd); diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 2badc25cd8..5ab1a6afa6 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -3682,35 +3682,33 @@ void bgp_zebra_announce_default(struct bgp *bgp, struct nexthop *nh, /* redirect IP */ if (afi == AFI_IP && nh->gate.ipv4.s_addr != INADDR_ANY) { - char buff[PREFIX_STRLEN]; - api_nh->vrf_id = nh->vrf_id; api_nh->gate.ipv4 = nh->gate.ipv4; api_nh->type = NEXTHOP_TYPE_IPV4; - inet_ntop(AF_INET, &(nh->gate.ipv4), buff, INET_ADDRSTRLEN); if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("BGP: %s default route to %s table %d (redirect IP)", - announce ? "adding" : "withdrawing", - buff, table_id); + zlog_debug( + "BGP: %s default route to %pI4 table %d (redirect IP)", + announce ? "adding" : "withdrawing", + &nh->gate.ipv4, table_id); + zclient_route_send(announce ? ZEBRA_ROUTE_ADD : ZEBRA_ROUTE_DELETE, zclient, &api); } else if (afi == AFI_IP6 && memcmp(&nh->gate.ipv6, &in6addr_any, sizeof(struct in6_addr))) { - char buff[PREFIX_STRLEN]; - api_nh->vrf_id = nh->vrf_id; memcpy(&api_nh->gate.ipv6, &nh->gate.ipv6, sizeof(struct in6_addr)); api_nh->type = NEXTHOP_TYPE_IPV6; - inet_ntop(AF_INET6, &(nh->gate.ipv6), buff, INET_ADDRSTRLEN); if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("BGP: %s default route to %s table %d (redirect IP)", - announce ? "adding" : "withdrawing", - buff, table_id); + zlog_debug( + "BGP: %s default route to %pI6 table %d (redirect IP)", + announce ? "adding" : "withdrawing", + &nh->gate.ipv6, table_id); + zclient_route_send(announce ? ZEBRA_ROUTE_ADD : ZEBRA_ROUTE_DELETE, zclient, &api); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 6ad1cf2c06..12ee96ff45 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -4289,6 +4289,7 @@ static const struct peer_flag_action peer_flag_action_list[] = { {PEER_FLAG_ROLE, 0, peer_change_reset}, {PEER_FLAG_PORT, 0, peer_change_reset}, {PEER_FLAG_AIGP, 0, peer_change_none}, + {PEER_FLAG_GRACEFUL_SHUTDOWN, 0, peer_change_none}, {0, 0, 0}}; static const struct peer_flag_action peer_af_flag_action_list[] = { diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 8a0ec5ad2d..b7a329fdcd 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -1413,6 +1413,7 @@ struct peer { #define PEER_FLAG_ROLE (1ULL << 32) #define PEER_FLAG_PORT (1ULL << 33) #define PEER_FLAG_AIGP (1ULL << 34) +#define PEER_FLAG_GRACEFUL_SHUTDOWN (1ULL << 35) /* *GR-Disabled mode means unset PEER_FLAG_GRACEFUL_RESTART diff --git a/bgpd/rfapi/rfapi.c b/bgpd/rfapi/rfapi.c index a5d57748b7..80d0b3e269 100644 --- a/bgpd/rfapi/rfapi.c +++ b/bgpd/rfapi/rfapi.c @@ -1273,13 +1273,15 @@ static int rfapi_open_inner(struct rfapi_descriptor *rfd, struct bgp *bgp, } { /* base code assumes have valid host pointer */ - char buf[BUFSIZ]; + char buf[INET6_ADDRSTRLEN]; buf[0] = 0; if (rfd->vn_addr.addr_family == AF_INET) { - inet_ntop(AF_INET, &rfd->vn_addr.addr.v4, buf, BUFSIZ); + inet_ntop(AF_INET, &rfd->vn_addr.addr.v4, buf, + sizeof(buf)); } else if (rfd->vn_addr.addr_family == AF_INET6) { - inet_ntop(AF_INET6, &rfd->vn_addr.addr.v6, buf, BUFSIZ); + inet_ntop(AF_INET6, &rfd->vn_addr.addr.v6, buf, + sizeof(buf)); } rfd->peer->host = XSTRDUP(MTYPE_BGP_PEER_HOST, buf); } diff --git a/bgpd/rfapi/rfapi_import.c b/bgpd/rfapi/rfapi_import.c index 1dd623d3f3..2aae0bc616 100644 --- a/bgpd/rfapi/rfapi_import.c +++ b/bgpd/rfapi/rfapi_import.c @@ -2908,7 +2908,8 @@ static void rfapiBgpInfoFilteredImportEncap( vnc_zlog_debug_verbose( "%s: entry: %s: prefix %s/%d", __func__, action_str, - inet_ntop(p->family, &p->u.prefix, buf, BUFSIZ), p->prefixlen); + inet_ntop(p->family, &p->u.prefix, buf, sizeof(buf)), + p->prefixlen); memset(&p_firstbpi_old, 0, sizeof(p_firstbpi_old)); memset(&p_firstbpi_new, 0, sizeof(p_firstbpi_new)); diff --git a/bgpd/rfapi/rfapi_vty.c b/bgpd/rfapi/rfapi_vty.c index 23f43fa7d3..719d898e3c 100644 --- a/bgpd/rfapi/rfapi_vty.c +++ b/bgpd/rfapi/rfapi_vty.c @@ -411,9 +411,10 @@ void rfapi_vty_out_vncinfo(struct vty *vty, const struct prefix *p, if (!rfapiGetVncTunnelUnAddr(bpi->attr, &pfx_un)) { char buf[BUFSIZ]; + vty_out(vty, "UN=%s", inet_ntop(pfx_un.family, pfx_un.u.val, buf, - BUFSIZ)); + sizeof(buf))); } } @@ -432,11 +433,7 @@ void rfapi_vty_out_vncinfo(struct vty *vty, const struct prefix *p, decode_label(&bpi->extra->label[0])); if (bpi->extra->num_sids) { - char buf[BUFSIZ]; - - vty_out(vty, " sid=%s", - inet_ntop(AF_INET6, &bpi->extra->sid[0].sid, - buf, sizeof(buf))); + vty_out(vty, " sid=%pI6", &bpi->extra->sid[0].sid); if (bpi->extra->sid[0].loc_block_len != 0) { vty_out(vty, " sid_structure=[%d,%d,%d,%d]", @@ -466,7 +463,6 @@ void rfapiPrintAttrPtrs(void *stream, struct attr *attr) const char *vty_newline; struct transit *transit; struct cluster_list *cluster; - char buf[BUFSIZ]; struct ecommunity *ecomm; struct community *comm; @@ -478,8 +474,7 @@ void rfapiPrintAttrPtrs(void *stream, struct attr *attr) return; /* IPv4 Nexthop */ - inet_ntop(AF_INET, &attr->nexthop, buf, BUFSIZ); - fp(out, " nexthop=%s%s", buf, HVTYNL); + fp(out, " nexthop=%pI4%s", &attr->nexthop, HVTYNL); fp(out, " aspath=%p, refcnt=%d%s", attr->aspath, (attr->aspath ? attr->aspath->refcnt : 0), HVTYNL); @@ -571,15 +566,12 @@ void rfapiPrintBi(void *stream, struct bgp_path_info *bpi) /* Nexthop */ if (af == AF_INET) { - r = snprintf(p, REMAIN, "%s", - inet_ntop(AF_INET, - &bpi->attr->mp_nexthop_global_in, buf, - BUFSIZ)); + r = snprintfrr(p, REMAIN, "%pI4", + &bpi->attr->mp_nexthop_global_in); INCP; } else if (af == AF_INET6) { - r = snprintf(p, REMAIN, "%s", - inet_ntop(AF_INET6, &bpi->attr->mp_nexthop_global, - buf, BUFSIZ)); + r = snprintfrr(p, REMAIN, "%pI6", + &bpi->attr->mp_nexthop_global); INCP; } else { r = snprintf(p, REMAIN, "?"); @@ -590,9 +582,9 @@ void rfapiPrintBi(void *stream, struct bgp_path_info *bpi) * VNC tunnel subtlv, if present, contains UN address */ if (!rfapiGetVncTunnelUnAddr(bpi->attr, &pfx_un)) { - r = snprintf( - p, REMAIN, " un=%s", - inet_ntop(pfx_un.family, pfx_un.u.val, buf, BUFSIZ)); + r = snprintf(p, REMAIN, " un=%s", + inet_ntop(pfx_un.family, pfx_un.u.val, buf, + sizeof(buf))); INCP; } @@ -719,7 +711,8 @@ char *rfapiMonitorVpn2Str(struct rfapi_monitor_vpn *m, char *buf, int size) rc = snprintf(buf, size, "m=%p, next=%p, rfd=%p(vn=%s un=%s), p=%s/%d, node=%p", m, m->next, m->rfd, buf_vn, buf_un, - inet_ntop(m->p.family, &m->p.u.prefix, buf_pfx, BUFSIZ), + inet_ntop(m->p.family, &m->p.u.prefix, buf_pfx, + sizeof(buf_pfx)), m->p.prefixlen, m->node); buf[size - 1] = 0; if (rc >= size) @@ -800,9 +793,9 @@ void rfapiShowImportTable(void *stream, const char *label, struct agg_table *rt, const struct prefix *p = agg_node_get_prefix(rn); if (p->family == AF_ETHERNET) { - rfapiEthAddr2Str(&p->u.prefix_eth, buf, BUFSIZ); + rfapiEthAddr2Str(&p->u.prefix_eth, buf, sizeof(buf)); } else { - inet_ntop(p->family, &p->u.prefix, buf, BUFSIZ); + inet_ntop(p->family, &p->u.prefix, buf, sizeof(buf)); } fp(out, "%s/%d @%p #%d%s", buf, p->prefixlen, rn, @@ -933,7 +926,7 @@ int rfapiShowVncQueries(void *stream, struct prefix *pfx_match) buf_remain, BUFSIZ); fp(out, " %-15s %-10s\n", inet_ntop(m->p.family, &m->p.u.prefix, - buf_pfx, BUFSIZ), + buf_pfx, sizeof(buf_pfx)), buf_remain); } } @@ -1052,9 +1045,10 @@ static int rfapiPrintRemoteRegBi(struct bgp *bgp, void *stream, * Prefix */ buf_pfx[0] = 0; - snprintf(buf_pfx, sizeof(buf_pfx), "%s/%d", - rfapi_ntop(p->family, &p->u.prefix, buf_ntop, BUFSIZ), - p->prefixlen); + snprintf( + buf_pfx, sizeof(buf_pfx), "%s/%d", + rfapi_ntop(p->family, &p->u.prefix, buf_ntop, sizeof(buf_ntop)), + p->prefixlen); buf_pfx[BUFSIZ - 1] = 0; nlines++; @@ -1065,7 +1059,7 @@ static int rfapiPrintRemoteRegBi(struct bgp *bgp, void *stream, if (!rfapiGetUnAddrOfVpnBi(bpi, &pfx_un)) { snprintf(buf_un, sizeof(buf_un), "%s", inet_ntop(pfx_un.family, &pfx_un.u.prefix, buf_ntop, - BUFSIZ)); + sizeof(buf_ntop))); } bgp_attr_extcom_tunnel_type(bpi->attr, &tun_type); @@ -1079,7 +1073,7 @@ static int rfapiPrintRemoteRegBi(struct bgp *bgp, void *stream, */ snprintf(buf_un, sizeof(buf_un), "%s", inet_ntop(pfx_vn.family, &pfx_vn.u.prefix, buf_ntop, - BUFSIZ)); + sizeof(buf_ntop))); if (bpi->extra) { uint32_t l = decode_label(&bpi->extra->label[0]); snprintf(buf_vn, sizeof(buf_vn), "Label: %d", l); @@ -1090,7 +1084,7 @@ static int rfapiPrintRemoteRegBi(struct bgp *bgp, void *stream, } else { snprintf(buf_vn, sizeof(buf_vn), "%s", inet_ntop(pfx_vn.family, &pfx_vn.u.prefix, buf_ntop, - BUFSIZ)); + sizeof(buf_ntop))); } buf_vn[BUFSIZ - 1] = 0; buf_un[BUFSIZ - 1] = 0; diff --git a/doc/developer/workflow.rst b/doc/developer/workflow.rst index 688ce545fb..b8e298dd3c 100644 --- a/doc/developer/workflow.rst +++ b/doc/developer/workflow.rst @@ -139,6 +139,10 @@ March/July/November. Walking backwards from this date: version. Once the release is done, whatever updates we make to changelog files on the release branch need to be cherry-picked to the master branch. + Update essential dates in advance for reference table (below) when + the next freeze, dev/X.Y, RC, and release phases are scheduled. This should + go in the ``master`` branch. + - 2 weeks earlier, a ``frr-X.Y-rc`` release candidate is tagged. .. code-block:: console @@ -163,15 +167,29 @@ as early as possible, i.e. the first 2-week window. For reference, the expected release schedule according to the above is: +---------+------------+------------+------------+------------+------------+ -| Release | 2022-07-05 | 2022-11-01 | 2023-03-07 | 2023-07-04 | 2023-10-31 | +| Release | 2023-03-07 | 2023-07-04 | 2023-10-31 | 2024-02-27 | 2024-06-25 | +---------+------------+------------+------------+------------+------------+ -| RC | 2022-06-21 | 2022-10-18 | 2023-02-21 | 2023-06-20 | 2023-10-17 | +| RC | 2023-02-21 | 2023-06-20 | 2023-10-17 | 2024-02-13 | 2024-06-11 | +---------+------------+------------+------------+------------+------------+ -| dev/X.Y | 2022-06-07 | 2022-10-04 | 2023-02-07 | 2023-06-06 | 2023-10-03 | +| dev/X.Y | 2023-02-07 | 2023-06-06 | 2023-10-03 | 2024-01-30 | 2024-05-28 | +---------+------------+------------+------------+------------+------------+ -| freeze | 2022-05-24 | 2022-09-20 | 2023-01-24 | 2023-05-23 | 2023-09-19 | +| freeze | 2023-01-24 | 2023-05-23 | 2023-09-19 | 2024-01-16 | 2024-05-14 | +---------+------------+------------+------------+------------+------------+ +Here is the hint on how to get the dates easily: + + .. code-block:: console + + ~$ # Last freeze date was 2023-09-19 + ~$ date +%F --date='2023-09-19 +119 days' # Next freeze date + 2024-01-16 + ~$ date +%F --date='2024-01-16 +14 days' # Next dev/X.Y date + 2024-01-30 + ~$ date +%F --date='2024-01-30 +14 days' # Next RC date + 2024-02-13 + ~$ date +%F --date='2024-02-13 +14 days' # Next Release date + 2024-02-27 + Each release is managed by one or more volunteer release managers from the FRR community. These release managers are expected to handle the branch for a period of one year. To spread and distribute this workload, this should be rotated for diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst index 4a812a75e9..98338ebf32 100644 --- a/doc/user/bgp.rst +++ b/doc/user/bgp.rst @@ -1704,6 +1704,11 @@ Configuring Peers Default: disabled. +.. clicmd:: neighbor <A.B.C.D|X:X::X:X|WORD> graceful-shutdown + + Mark all routes from this neighbor as less preferred by setting ``graceful-shutdown`` + community, and local-preference to 0. + .. clicmd:: bgp fast-external-failover This command causes bgp to take down ebgp peers immediately diff --git a/doc/user/setup.rst b/doc/user/setup.rst index dcc7607e48..372494fbce 100644 --- a/doc/user/setup.rst +++ b/doc/user/setup.rst @@ -116,6 +116,16 @@ allow this to happen. :: + FRR_NO_ROOT="yes" + +This option allows you to run FRR as a non-root user. Use this option +only when you know what you are doing since most of the daemons +in FRR will not be able to run under a regular user. This option +is useful for example when you run FRR in a container with a designated +user instead of root. + +:: + zebra_options=" -s 90000000 --daemon -A 127.0.0.1" bgpd_options=" --daemon -A 127.0.0.1" ... diff --git a/doc/user/zebra.rst b/doc/user/zebra.rst index c44642a788..a78731ca94 100644 --- a/doc/user/zebra.rst +++ b/doc/user/zebra.rst @@ -305,7 +305,8 @@ the default route. indicates that the operator wants to see the multicast rib address resolution table. An alternative form of the command is ``show ip import-check`` and this form of the command is deprecated at this point in time. - If the ``json`` option is specified, output is displayed in JSON format. + User can get that information as JSON string when ``json`` key word + at the end of cli is presented. PBR dataplane programming ========================= @@ -447,7 +447,8 @@ static int vty_command(struct vty *vty, char *buf) /* * Log non empty command lines */ - if (do_log_commands) + if (do_log_commands && + strncmp(buf, "echo PING", strlen("echo PING")) != 0) cp = buf; if (cp != NULL) { /* Skip white spaces. */ diff --git a/ospf6d/ospf6_abr.c b/ospf6d/ospf6_abr.c index e9c42bb80c..e007709f99 100644 --- a/ospf6d/ospf6_abr.c +++ b/ospf6d/ospf6_abr.c @@ -1322,7 +1322,7 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa) ospf6_copy_nexthops(tmp_route->nh_list, o_path->nh_list); - if (ospf6_route_cmp_nexthops(tmp_route, route) != 0) { + if (!ospf6_route_cmp_nexthops(tmp_route, route)) { /* adv. router exists in the list, update nhs */ list_delete_all_node(o_path->nh_list); ospf6_copy_nexthops(o_path->nh_list, diff --git a/ospf6d/ospf6_route.c b/ospf6d/ospf6_route.c index db94b85b1b..9603c91a9a 100644 --- a/ospf6d/ospf6_route.c +++ b/ospf6d/ospf6_route.c @@ -246,7 +246,10 @@ void ospf6_merge_nexthops(struct list *dst, struct list *src) } } -int ospf6_route_cmp_nexthops(struct ospf6_route *a, struct ospf6_route *b) +/* + * If the nexthops are the same return true + */ +bool ospf6_route_cmp_nexthops(struct ospf6_route *a, struct ospf6_route *b) { struct listnode *anode, *bnode; struct ospf6_nexthop *anh, *bnh; @@ -264,14 +267,14 @@ int ospf6_route_cmp_nexthops(struct ospf6_route *a, struct ospf6_route *b) /* Currnet List A element not found List B * Non-Identical lists return */ if (identical == false) - return 1; + return false; } - return 0; + return true; } else - return 1; + return false; } /* One of the routes doesn't exist ? */ - return (1); + return false; } int ospf6_num_nexthops(struct list *nh_list) @@ -577,12 +580,7 @@ ospf6_route_lookup_identical(struct ospf6_route *route, for (target = ospf6_route_lookup(&route->prefix, table); target; target = target->next) { - if (target->type == route->type - && prefix_same(&target->prefix, &route->prefix) - && target->path.type == route->path.type - && target->path.cost == route->path.cost - && target->path.u.cost_e2 == route->path.u.cost_e2 - && ospf6_route_cmp_nexthops(target, route) == 0) + if (ospf6_route_is_identical(target, route)) return target; } return NULL; @@ -702,6 +700,27 @@ struct ospf6_route *ospf6_route_add(struct ospf6_route *route, } if (old) { + /* if route does not actually change, return unchanged */ + if (ospf6_route_is_identical(old, route)) { + if (IS_OSPF6_DEBUG_ROUTE(MEMORY)) + zlog_debug( + "%s %p: route add %p: needless update of %p old cost %u", + ospf6_route_table_name(table), + (void *)table, (void *)route, + (void *)old, old->path.cost); + else if (IS_OSPF6_DEBUG_ROUTE(TABLE)) + zlog_debug("%s: route add: needless update", + ospf6_route_table_name(table)); + + ospf6_route_delete(route); + SET_FLAG(old->flag, OSPF6_ROUTE_ADD); + ospf6_route_table_assert(table); + + /* to free the lookup lock */ + route_unlock_node(node); + return old; + } + if (IS_OSPF6_DEBUG_ROUTE(MEMORY)) zlog_debug( "%s %p: route add %p cost %u paths %u nh %u: update of %p cost %u paths %u nh %u", diff --git a/ospf6d/ospf6_route.h b/ospf6d/ospf6_route.h index bb5827a176..71a84a5c5d 100644 --- a/ospf6d/ospf6_route.h +++ b/ospf6d/ospf6_route.h @@ -297,6 +297,14 @@ extern const char *const ospf6_path_type_substr[OSPF6_PATH_TYPE_MAX]; && (ra)->path.origin.type == (rb)->path.origin.type \ && (ra)->path.origin.id == (rb)->path.origin.id \ && (ra)->path.origin.adv_router == (rb)->path.origin.adv_router) +#define ospf6_route_is_identical(ra, rb) \ + ((ra)->type == (rb)->type && \ + prefix_same(&(ra)->prefix, &(rb)->prefix) && \ + (ra)->path.type == (rb)->path.type && \ + (ra)->path.cost == (rb)->path.cost && \ + (ra)->path.u.cost_e2 == (rb)->path.u.cost_e2 && \ + listcount(ra->paths) == listcount(rb->paths) && \ + ospf6_route_cmp_nexthops(ra, rb)) #define ospf6_route_is_best(r) (CHECK_FLAG ((r)->flag, OSPF6_ROUTE_BEST)) @@ -322,8 +330,8 @@ extern void ospf6_add_nexthop(struct list *nh_list, int ifindex, struct in6_addr *addr); extern void ospf6_add_route_nexthop_blackhole(struct ospf6_route *route); extern int ospf6_num_nexthops(struct list *nh_list); -extern int ospf6_route_cmp_nexthops(struct ospf6_route *a, - struct ospf6_route *b); +extern bool ospf6_route_cmp_nexthops(struct ospf6_route *a, + struct ospf6_route *b); extern void ospf6_route_zebra_copy_nexthops(struct ospf6_route *route, struct zapi_nexthop nexthops[], int entries, vrf_id_t vrf_id); diff --git a/ospfd/ospf_api.h b/ospfd/ospf_api.h index 6f569e962d..fd741c3c48 100644 --- a/ospfd/ospf_api.h +++ b/ospfd/ospf_api.h @@ -298,7 +298,7 @@ struct apimsg { } u; }; -#define OSPF_API_MAX_MSG_SIZE (sizeof(struct apimsg) + OSPF_MAX_LSA_SIZE) +#define OSPF_API_MAX_MSG_SIZE (sizeof(struct apimsg) + OSPF_MAX_PACKET_SIZE) /* ----------------------------------------------------------- * Prototypes for specific messages diff --git a/ospfd/ospf_ism.c b/ospfd/ospf_ism.c index ab75ab9a1a..d4565b6651 100644 --- a/ospfd/ospf_ism.c +++ b/ospfd/ospf_ism.c @@ -223,8 +223,10 @@ int ospf_dr_election(struct ospf_interface *oi) new_state = ospf_ism_state(oi); - zlog_debug("DR-Election[1st]: Backup %pI4", &BDR(oi)); - zlog_debug("DR-Election[1st]: DR %pI4", &DR(oi)); + if (IS_DEBUG_OSPF(ism, ISM_STATUS)) { + zlog_debug("DR-Election[1st]: Backup %pI4", &BDR(oi)); + zlog_debug("DR-Election[1st]: DR %pI4", &DR(oi)); + } if (new_state != old_state && !(new_state == ISM_DROther && old_state < ISM_DROther)) { @@ -233,8 +235,10 @@ int ospf_dr_election(struct ospf_interface *oi) new_state = ospf_ism_state(oi); - zlog_debug("DR-Election[2nd]: Backup %pI4", &BDR(oi)); - zlog_debug("DR-Election[2nd]: DR %pI4", &DR(oi)); + if (IS_DEBUG_OSPF(ism, ISM_STATUS)) { + zlog_debug("DR-Election[2nd]: Backup %pI4", &BDR(oi)); + zlog_debug("DR-Election[2nd]: DR %pI4", &DR(oi)); + } } list_delete(&el_list); diff --git a/ospfd/ospf_network.c b/ospfd/ospf_network.c index be06afe532..a8c9493ec8 100644 --- a/ospfd/ospf_network.c +++ b/ospfd/ospf_network.c @@ -104,11 +104,12 @@ int ospf_if_add_alldrouters(struct ospf *top, struct prefix *p, "can't setsockopt IP_ADD_MEMBERSHIP (fd %d, addr %pI4, ifindex %u, AllDRouters): %s; perhaps a kernel limit on # of multicast group memberships has been exceeded?", top->fd, &p->u.prefix4, ifindex, safe_strerror(errno)); - else - zlog_debug( - "interface %pI4 [%u] join AllDRouters Multicast group.", - &p->u.prefix4, ifindex); - + else { + if (IS_DEBUG_OSPF_EVENT) + zlog_debug( + "interface %pI4 [%u] join AllDRouters Multicast group.", + &p->u.prefix4, ifindex); + } return ret; } diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c index 3f82d86921..2403b567a5 100644 --- a/ospfd/ospfd.c +++ b/ospfd/ospfd.c @@ -89,6 +89,25 @@ static int ospf_network_match_iface(const struct connected *, const struct prefix *); static void ospf_finish_final(struct ospf *); +/* API to clean refresh queues and LSAs */ +static void ospf_free_refresh_queue(struct ospf *ospf) +{ + for (int i = 0; i < OSPF_LSA_REFRESHER_SLOTS; i++) { + struct list *list = ospf->lsa_refresh_queue.qs[i]; + struct listnode *node, *nnode; + struct ospf_lsa *lsa; + + if (list) { + for (ALL_LIST_ELEMENTS(list, node, nnode, lsa)) { + listnode_delete(list, lsa); + lsa->refresh_list = -1; + ospf_lsa_unlock(&lsa); + } + list_delete(&list); + ospf->lsa_refresh_queue.qs[i] = NULL; + } + } +} #define OSPF_EXTERNAL_LSA_ORIGINATE_DELAY 1 int p_spaces_compare_func(const struct p_space *a, const struct p_space *b) @@ -895,6 +914,8 @@ static void ospf_finish_final(struct ospf *ospf) route_table_finish(ospf->rt_aggr_tbl); + ospf_free_refresh_queue(ospf); + list_delete(&ospf->areas); list_delete(&ospf->oi_write_q); diff --git a/pimd/pim_cmd_common.c b/pimd/pim_cmd_common.c index b39f688cdb..28e4c488f3 100644 --- a/pimd/pim_cmd_common.c +++ b/pimd/pim_cmd_common.c @@ -2824,21 +2824,35 @@ static int pim_print_vty_pnc_cache_walkcb(struct hash_bucket *bucket, void *arg) struct nexthop *nh_node = NULL; ifindex_t first_ifindex; struct interface *ifp = NULL; + struct ttable *tt = NULL; + char *table = NULL; + + /* Prepare table. */ + tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]); + ttable_add_row(tt, "Address|Interface|Nexthop"); + tt->style.cell.rpad = 2; + tt->style.corner = '+'; + ttable_restyle(tt); for (nh_node = pnc->nexthop; nh_node; nh_node = nh_node->next) { first_ifindex = nh_node->ifindex; ifp = if_lookup_by_index(first_ifindex, pim->vrf->vrf_id); - vty_out(vty, "%-15pPA ", &pnc->rpf.rpf_addr); - vty_out(vty, "%-16s ", ifp ? ifp->name : "NULL"); #if PIM_IPV == 4 - vty_out(vty, "%pI4 ", &nh_node->gate.ipv4); + ttable_add_row(tt, "%pPA|%s|%pI4", &pnc->rpf.rpf_addr, + ifp ? ifp->name : "NULL", &nh_node->gate.ipv4); #else - vty_out(vty, "%pI6 ", &nh_node->gate.ipv6); + ttable_add_row(tt, "%pPA|%s|%pI6", &pnc->rpf.rpf_addr, + ifp ? ifp->name : "NULL", &nh_node->gate.ipv6); #endif - vty_out(vty, "\n"); } + /* Dump the generated table. */ + table = ttable_dump(tt, "\n"); + vty_out(vty, "%s\n", table); + XFREE(MTYPE_TMP, table); + ttable_del(tt); + return CMD_SUCCESS; } @@ -2966,8 +2980,6 @@ void pim_show_nexthop(struct pim_instance *pim, struct vty *vty, bool uj) } else { vty_out(vty, "Number of registered addresses: %lu\n", pim->rpf_hash->count); - vty_out(vty, "Address Interface Nexthop\n"); - vty_out(vty, "---------------------------------------------\n"); } if (uj) { @@ -5355,6 +5367,7 @@ static void pim_show_group_rp_mappings_info(struct pim_instance *pim, json_object *json = NULL; json_object *json_group = NULL; json_object *json_row = NULL; + struct ttable *tt = NULL; if (uj) { json = json_object_new_object(); @@ -5385,10 +5398,15 @@ static void pim_show_group_rp_mappings_info(struct pim_instance *pim, } else { vty_out(vty, "Group Address %pFX\n", &bsgrp->group); vty_out(vty, "--------------------------\n"); - vty_out(vty, "%-15s %-15s %-15s %-15s\n", "Rp Address", - "priority", "Holdtime", "Hash"); - - vty_out(vty, "(ACTIVE)\n"); + /* Prepare table. */ + tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]); + ttable_add_row(tt, "Rp Address|priority|Holdtime|Hash"); + tt->style.cell.rpad = 2; + tt->style.corner = '+'; + ttable_restyle(tt); + + ttable_add_row(tt, "%s|%c|%c|%c", "(ACTIVE)", ' ', ' ', + ' '); } frr_each (bsm_rpinfos, bsgrp->bsrp_list, bsm_rp) { @@ -5408,11 +5426,22 @@ static void pim_show_group_rp_mappings_info(struct pim_instance *pim, &bsm_rp->rp_address); } else { - vty_out(vty, "%-15pPA %-15u %-15u %-15u\n", + ttable_add_row( + tt, "%pPA|%u|%u|%u", &bsm_rp->rp_address, bsm_rp->rp_prio, bsm_rp->rp_holdtime, bsm_rp->hash); } } + /* Dump the generated table. */ + if (tt) { + char *table = NULL; + + table = ttable_dump(tt, "\n"); + vty_out(vty, "%s\n", table); + XFREE(MTYPE_TMP, table); + ttable_del(tt); + tt = NULL; + } if (!bsm_rpinfos_count(bsgrp->bsrp_list) && !uj) vty_out(vty, "Active List is empty.\n"); @@ -5423,10 +5452,16 @@ static void pim_show_group_rp_mappings_info(struct pim_instance *pim, vty_out(vty, "(PENDING)\n"); vty_out(vty, "Pending RP count :%d\n", bsgrp->pend_rp_cnt); - if (bsgrp->pend_rp_cnt) - vty_out(vty, "%-15s %-15s %-15s %-15s\n", - "Rp Address", "priority", "Holdtime", - "Hash"); + if (bsgrp->pend_rp_cnt) { + /* Prepare table. */ + tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]); + ttable_add_row( + tt, + "Rp Address|priority|Holdtime|Hash"); + tt->style.cell.rpad = 2; + tt->style.corner = '+'; + ttable_restyle(tt); + } } frr_each (bsm_rpinfos, bsgrp->partial_bsrp_list, bsm_rp) { @@ -5445,11 +5480,21 @@ static void pim_show_group_rp_mappings_info(struct pim_instance *pim, "%pPA", &bsm_rp->rp_address); } else { - vty_out(vty, "%-15pPA %-15u %-15u %-15u\n", + ttable_add_row( + tt, "%pPA|%u|%u|%u", &bsm_rp->rp_address, bsm_rp->rp_prio, bsm_rp->rp_holdtime, bsm_rp->hash); } } + /* Dump the generated table. */ + if (tt) { + char *table = NULL; + + table = ttable_dump(tt, "\n"); + vty_out(vty, "%s\n", table); + XFREE(MTYPE_TMP, table); + ttable_del(tt); + } if (!bsm_rpinfos_count(bsgrp->partial_bsrp_list) && !uj) vty_out(vty, "Partial List is empty\n"); @@ -5610,7 +5655,7 @@ static void pim_show_bsm_db(struct pim_instance *pim, struct vty *vty, bool uj) bsm_rpinfo = (struct bsmmsg_rpinfo *)buf; /* unaligned, again */ - memcpy(&rp_addr, &bsm_rpinfo->rpaddr, + memcpy(&rp_addr, &bsm_rpinfo->rpaddr.addr, sizeof(rp_addr)); buf += sizeof(struct bsmmsg_rpinfo); diff --git a/staticd/static_nb_config.c b/staticd/static_nb_config.c index 5a7044e9f9..4a3d9e17a4 100644 --- a/staticd/static_nb_config.c +++ b/staticd/static_nb_config.c @@ -370,7 +370,7 @@ static int static_nexthop_color_destroy(struct nb_cb_destroy_args *args) struct static_nexthop *nh; uint32_t old_color; - nh = nb_running_unset_entry(args->dnode); + nh = nb_running_get_entry(args->dnode, NULL, true); old_color = nh->color; nh->color = 0; diff --git a/staticd/static_vty.c b/staticd/static_vty.c index 94a3493477..efae3c53da 100644 --- a/staticd/static_vty.c +++ b/staticd/static_vty.c @@ -41,15 +41,33 @@ #define STATICD_STR "Static route daemon\n" -static int static_route_leak(struct vty *vty, const char *svrf, - const char *nh_svrf, afi_t afi, safi_t safi, - const char *negate, const char *dest_str, - const char *mask_str, const char *src_str, - const char *gate_str, const char *ifname, - const char *flag_str, const char *tag_str, - const char *distance_str, const char *label_str, - const char *table_str, bool onlink, - const char *color_str) +/** All possible route parameters available in CLI. */ +struct static_route_args { + /** "no" command? */ + bool delete; + /** Is VRF obtained from XPath? */ + bool xpath_vrf; + + bool onlink; + afi_t afi; + safi_t safi; + + const char *vrf; + const char *nexthop_vrf; + const char *prefix; + const char *prefix_mask; + const char *source; + const char *gateway; + const char *interface_name; + const char *flag; + const char *tag; + const char *distance; + const char *label; + const char *table; + const char *color; +}; + +static int static_route_nb_run(struct vty *vty, struct static_route_args *args) { int ret; struct prefix p, src; @@ -62,8 +80,8 @@ static int static_route_leak(struct vty *vty, const char *svrf, char xpath_label[XPATH_MAXLEN]; char ab_xpath[XPATH_MAXLEN]; char buf_prefix[PREFIX_STRLEN]; - char buf_src_prefix[PREFIX_STRLEN]; - char buf_nh_type[PREFIX_STRLEN]; + char buf_src_prefix[PREFIX_STRLEN] = {}; + char buf_nh_type[PREFIX_STRLEN] = {}; char buf_tag[PREFIX_STRLEN]; uint8_t label_stack_id = 0; const char *buf_gate_str; @@ -71,37 +89,46 @@ static int static_route_leak(struct vty *vty, const char *svrf, route_tag_t tag = 0; uint32_t table_id = 0; const struct lyd_node *dnode; + const struct lyd_node *vrf_dnode; - memset(buf_src_prefix, 0, PREFIX_STRLEN); - memset(buf_nh_type, 0, PREFIX_STRLEN); + if (args->xpath_vrf) { + vrf_dnode = yang_dnode_get(vty->candidate_config->dnode, + VTY_CURR_XPATH); + if (vrf_dnode == NULL) { + vty_out(vty, + "%% Failed to get vrf dnode in candidate db\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + args->vrf = yang_dnode_get_string(vrf_dnode, "./name"); + } else { + if (args->vrf == NULL) + args->vrf = VRF_DEFAULT_NAME; + } + if (args->nexthop_vrf == NULL) + args->nexthop_vrf = args->vrf; - ret = str2prefix(dest_str, &p); - if (ret <= 0) { - vty_out(vty, "%% Malformed address\n"); - return CMD_WARNING_CONFIG_FAILED; + if (args->interface_name && + !strcasecmp(args->interface_name, "Null0")) { + args->flag = "Null0"; + args->interface_name = NULL; } - switch (afi) { + assert(!!str2prefix(args->prefix, &p)); + + switch (args->afi) { case AFI_IP: /* Cisco like mask notation. */ - if (mask_str) { - ret = inet_aton(mask_str, &mask); - if (ret == 0) { - vty_out(vty, "%% Malformed address\n"); - return CMD_WARNING_CONFIG_FAILED; - } + if (args->prefix_mask) { + assert(inet_pton(AF_INET, args->prefix_mask, &mask) == + 1); p.prefixlen = ip_masklen(mask); } break; case AFI_IP6: /* srcdest routing */ - if (src_str) { - ret = str2prefix(src_str, &src); - if (ret <= 0 || src.family != AF_INET6) { - vty_out(vty, "%% Malformed source address\n"); - return CMD_WARNING_CONFIG_FAILED; - } - } + if (args->source) + assert(!!str2prefix(args->source, &src)); break; default: break; @@ -109,62 +136,64 @@ static int static_route_leak(struct vty *vty, const char *svrf, /* Apply mask for given prefix. */ apply_mask(&p); - prefix2str(&p, buf_prefix, sizeof(buf_prefix)); - if (src_str) + if (args->source) prefix2str(&src, buf_src_prefix, sizeof(buf_src_prefix)); - if (gate_str) - buf_gate_str = gate_str; + if (args->gateway) + buf_gate_str = args->gateway; else buf_gate_str = ""; - if (gate_str == NULL && ifname == NULL) + if (args->gateway == NULL && args->interface_name == NULL) type = STATIC_BLACKHOLE; - else if (gate_str && ifname) { - if (afi == AFI_IP) + else if (args->gateway && args->interface_name) { + if (args->afi == AFI_IP) type = STATIC_IPV4_GATEWAY_IFNAME; else type = STATIC_IPV6_GATEWAY_IFNAME; - } else if (ifname) + } else if (args->interface_name) type = STATIC_IFNAME; else { - if (afi == AFI_IP) + if (args->afi == AFI_IP) type = STATIC_IPV4_GATEWAY; else type = STATIC_IPV6_GATEWAY; } /* Administrative distance. */ - if (distance_str) - distance = atoi(distance_str); + if (args->distance) + distance = strtol(args->distance, NULL, 10); /* tag */ - if (tag_str) - tag = strtoul(tag_str, NULL, 10); + if (args->tag) + tag = strtoul(args->tag, NULL, 10); /* TableID */ - if (table_str) - table_id = atol(table_str); + if (args->table) + table_id = strtol(args->table, NULL, 10); - static_get_nh_type(type, buf_nh_type, PREFIX_STRLEN); - if (!negate) { - if (src_str) + static_get_nh_type(type, buf_nh_type, sizeof(buf_nh_type)); + if (!args->delete) { + if (args->source) snprintf(ab_xpath, sizeof(ab_xpath), FRR_DEL_S_ROUTE_SRC_NH_KEY_NO_DISTANCE_XPATH, - "frr-staticd:staticd", "staticd", svrf, + "frr-staticd:staticd", "staticd", args->vrf, buf_prefix, - yang_afi_safi_value2identity(afi, safi), - buf_src_prefix, table_id, buf_nh_type, nh_svrf, - buf_gate_str, ifname); + yang_afi_safi_value2identity(args->afi, + args->safi), + buf_src_prefix, table_id, buf_nh_type, + args->nexthop_vrf, buf_gate_str, + args->interface_name); else snprintf(ab_xpath, sizeof(ab_xpath), FRR_DEL_S_ROUTE_NH_KEY_NO_DISTANCE_XPATH, - "frr-staticd:staticd", "staticd", svrf, + "frr-staticd:staticd", "staticd", args->vrf, buf_prefix, - yang_afi_safi_value2identity(afi, safi), - table_id, buf_nh_type, nh_svrf, buf_gate_str, - ifname); + yang_afi_safi_value2identity(args->afi, + args->safi), + table_id, buf_nh_type, args->nexthop_vrf, + buf_gate_str, args->interface_name); /* * If there's already the same nexthop but with a different @@ -181,19 +210,21 @@ static int static_route_leak(struct vty *vty, const char *svrf, } /* route + path procesing */ - if (src_str) + if (args->source) snprintf(xpath_prefix, sizeof(xpath_prefix), FRR_S_ROUTE_SRC_INFO_KEY_XPATH, - "frr-staticd:staticd", "staticd", svrf, + "frr-staticd:staticd", "staticd", args->vrf, buf_prefix, - yang_afi_safi_value2identity(afi, safi), + yang_afi_safi_value2identity(args->afi, + args->safi), buf_src_prefix, table_id, distance); else snprintf(xpath_prefix, sizeof(xpath_prefix), FRR_STATIC_ROUTE_INFO_KEY_XPATH, - "frr-staticd:staticd", "staticd", svrf, + "frr-staticd:staticd", "staticd", args->vrf, buf_prefix, - yang_afi_safi_value2identity(afi, safi), + yang_afi_safi_value2identity(args->afi, + args->safi), table_id, distance); nb_cli_enqueue_change(vty, xpath_prefix, NB_OP_CREATE, NULL); @@ -208,8 +239,8 @@ static int static_route_leak(struct vty *vty, const char *svrf, /* nexthop processing */ snprintf(ab_xpath, sizeof(ab_xpath), - FRR_STATIC_ROUTE_NH_KEY_XPATH, buf_nh_type, nh_svrf, - buf_gate_str, ifname); + FRR_STATIC_ROUTE_NH_KEY_XPATH, buf_nh_type, + args->nexthop_vrf, buf_gate_str, args->interface_name); strlcpy(xpath_nexthop, xpath_prefix, sizeof(xpath_nexthop)); strlcat(xpath_nexthop, ab_xpath, sizeof(xpath_nexthop)); nb_cli_enqueue_change(vty, xpath_nexthop, NB_OP_CREATE, NULL); @@ -220,8 +251,8 @@ static int static_route_leak(struct vty *vty, const char *svrf, sizeof(ab_xpath)); /* Route flags */ - if (flag_str) { - switch (flag_str[0]) { + if (args->flag) { + switch (args->flag[0]) { case 'r': bh_type = "reject"; break; @@ -248,7 +279,7 @@ static int static_route_leak(struct vty *vty, const char *svrf, strlcat(ab_xpath, FRR_STATIC_ROUTE_NH_ONLINK_XPATH, sizeof(ab_xpath)); - if (onlink) + if (args->onlink) nb_cli_enqueue_change(vty, ab_xpath, NB_OP_MODIFY, "true"); else @@ -262,11 +293,12 @@ static int static_route_leak(struct vty *vty, const char *svrf, strlcpy(ab_xpath, xpath_nexthop, sizeof(ab_xpath)); strlcat(ab_xpath, FRR_STATIC_ROUTE_NH_COLOR_XPATH, sizeof(ab_xpath)); - if (color_str) + if (args->color) nb_cli_enqueue_change(vty, ab_xpath, - NB_OP_MODIFY, color_str); + NB_OP_MODIFY, + args->color); } - if (label_str) { + if (args->label) { /* copy of label string (start) */ char *ostr; /* pointer to next segment */ @@ -279,7 +311,7 @@ static int static_route_leak(struct vty *vty, const char *svrf, nb_cli_enqueue_change(vty, xpath_mpls, NB_OP_DESTROY, NULL); - ostr = XSTRDUP(MTYPE_TMP, label_str); + ostr = XSTRDUP(MTYPE_TMP, args->label); while ((nump = strsep(&ostr, "/")) != NULL) { snprintf(ab_xpath, sizeof(ab_xpath), FRR_STATIC_ROUTE_NHLB_KEY_XPATH, @@ -302,22 +334,25 @@ static int static_route_leak(struct vty *vty, const char *svrf, } ret = nb_cli_apply_changes(vty, xpath_prefix); } else { - if (src_str) + if (args->source) snprintf(ab_xpath, sizeof(ab_xpath), FRR_DEL_S_ROUTE_SRC_NH_KEY_NO_DISTANCE_XPATH, - "frr-staticd:staticd", "staticd", svrf, + "frr-staticd:staticd", "staticd", args->vrf, buf_prefix, - yang_afi_safi_value2identity(afi, safi), - buf_src_prefix, table_id, buf_nh_type, nh_svrf, - buf_gate_str, ifname); + yang_afi_safi_value2identity(args->afi, + args->safi), + buf_src_prefix, table_id, buf_nh_type, + args->nexthop_vrf, buf_gate_str, + args->interface_name); else snprintf(ab_xpath, sizeof(ab_xpath), FRR_DEL_S_ROUTE_NH_KEY_NO_DISTANCE_XPATH, - "frr-staticd:staticd", "staticd", svrf, + "frr-staticd:staticd", "staticd", args->vrf, buf_prefix, - yang_afi_safi_value2identity(afi, safi), - table_id, buf_nh_type, nh_svrf, buf_gate_str, - ifname); + yang_afi_safi_value2identity(args->afi, + args->safi), + table_id, buf_nh_type, args->nexthop_vrf, + buf_gate_str, args->interface_name); dnode = yang_dnode_get(vty->candidate_config->dnode, ab_xpath); if (!dnode) { @@ -336,22 +371,6 @@ static int static_route_leak(struct vty *vty, const char *svrf, return ret; } -static int static_route(struct vty *vty, afi_t afi, safi_t safi, - const char *negate, const char *dest_str, - const char *mask_str, const char *src_str, - const char *gate_str, const char *ifname, - const char *flag_str, const char *tag_str, - const char *distance_str, const char *vrf_name, - const char *label_str, const char *table_str) -{ - if (!vrf_name) - vrf_name = VRF_DEFAULT_NAME; - - return static_route_leak(vty, vrf_name, vrf_name, afi, safi, negate, - dest_str, mask_str, src_str, gate_str, ifname, - flag_str, tag_str, distance_str, label_str, - table_str, false, NULL); -} /* Static unicast routes for multicast RPF lookup. */ DEFPY_YANG (ip_mroute_dist, @@ -365,9 +384,17 @@ DEFPY_YANG (ip_mroute_dist, "Nexthop interface name\n" "Distance\n") { - return static_route(vty, AFI_IP, SAFI_MULTICAST, no, prefix_str, - NULL, NULL, gate_str, ifname, NULL, NULL, - distance_str, NULL, NULL, NULL); + struct static_route_args args = { + .delete = !!no, + .afi = AFI_IP, + .safi = SAFI_MULTICAST, + .prefix = prefix_str, + .gateway = gate_str, + .interface_name = ifname, + .distance = distance_str, + }; + + return static_route_nb_run(vty, &args); } /* Static route configuration. */ @@ -398,9 +425,21 @@ DEFPY_YANG(ip_route_blackhole, "Table to configure\n" "The table number to configure\n") { - return static_route(vty, AFI_IP, SAFI_UNICAST, no, prefix, - mask_str, NULL, NULL, NULL, flag, tag_str, - distance_str, vrf, label, table_str); + struct static_route_args args = { + .delete = !!no, + .afi = AFI_IP, + .safi = SAFI_UNICAST, + .prefix = prefix, + .prefix_mask = mask_str, + .flag = flag, + .tag = tag_str, + .distance = distance_str, + .label = label, + .table = table_str, + .vrf = vrf, + }; + + return static_route_nb_run(vty, &args); } DEFPY_YANG(ip_route_blackhole_vrf, @@ -428,26 +467,28 @@ DEFPY_YANG(ip_route_blackhole_vrf, "Table to configure\n" "The table number to configure\n") { - const struct lyd_node *vrf_dnode; - const char *vrfname; + struct static_route_args args = { + .delete = !!no, + .afi = AFI_IP, + .safi = SAFI_UNICAST, + .prefix = prefix, + .prefix_mask = mask_str, + .flag = flag, + .tag = tag_str, + .distance = distance_str, + .label = label, + .table = table_str, + .xpath_vrf = true, + }; - vrf_dnode = - yang_dnode_get(vty->candidate_config->dnode, VTY_CURR_XPATH); - if (!vrf_dnode) { - vty_out(vty, "%% Failed to get vrf dnode in candidate db\n"); - return CMD_WARNING_CONFIG_FAILED; - } - vrfname = yang_dnode_get_string(vrf_dnode, "./name"); /* * Coverity is complaining that prefix could * be dereferenced, but we know that prefix will * valid. Add an assert to make it happy */ - assert(prefix); - return static_route_leak(vty, vrfname, vrfname, AFI_IP, SAFI_UNICAST, - no, prefix, mask_str, NULL, NULL, NULL, flag, - tag_str, distance_str, label, table_str, - false, NULL); + assert(args.prefix); + + return static_route_nb_run(vty, &args); } DEFPY_YANG(ip_route_address_interface, @@ -486,25 +527,25 @@ DEFPY_YANG(ip_route_address_interface, "SR-TE color\n" "The SR-TE color to configure\n") { - const char *nh_vrf; - const char *flag = NULL; - - if (ifname && !strncasecmp(ifname, "Null0", 5)) { - flag = "Null0"; - ifname = NULL; - } - if (!vrf) - vrf = VRF_DEFAULT_NAME; - - if (nexthop_vrf) - nh_vrf = nexthop_vrf; - else - nh_vrf = vrf; - - return static_route_leak(vty, vrf, nh_vrf, AFI_IP, SAFI_UNICAST, no, - prefix, mask_str, NULL, gate_str, ifname, flag, - tag_str, distance_str, label, table_str, - !!onlink, color_str); + struct static_route_args args = { + .delete = !!no, + .afi = AFI_IP, + .safi = SAFI_UNICAST, + .prefix = prefix, + .prefix_mask = mask_str, + .gateway = gate_str, + .interface_name = ifname, + .tag = tag_str, + .distance = distance_str, + .label = label, + .table = table_str, + .color = color_str, + .onlink = !!onlink, + .vrf = vrf, + .nexthop_vrf = nexthop_vrf, + }; + + return static_route_nb_run(vty, &args); } DEFPY_YANG(ip_route_address_interface_vrf, @@ -541,32 +582,25 @@ DEFPY_YANG(ip_route_address_interface_vrf, "SR-TE color\n" "The SR-TE color to configure\n") { - const char *nh_vrf; - const char *flag = NULL; - const struct lyd_node *vrf_dnode; - const char *vrfname; - - vrf_dnode = - yang_dnode_get(vty->candidate_config->dnode, VTY_CURR_XPATH); - if (!vrf_dnode) { - vty_out(vty, "%% Failed to get vrf dnode in candidate db\n"); - return CMD_WARNING_CONFIG_FAILED; - } - vrfname = yang_dnode_get_string(vrf_dnode, "./name"); - - if (ifname && !strncasecmp(ifname, "Null0", 5)) { - flag = "Null0"; - ifname = NULL; - } - if (nexthop_vrf) - nh_vrf = nexthop_vrf; - else - nh_vrf = vrfname; - - return static_route_leak(vty, vrfname, nh_vrf, AFI_IP, SAFI_UNICAST, no, - prefix, mask_str, NULL, gate_str, ifname, flag, - tag_str, distance_str, label, table_str, - !!onlink, color_str); + struct static_route_args args = { + .delete = !!no, + .afi = AFI_IP, + .safi = SAFI_UNICAST, + .prefix = prefix, + .prefix_mask = mask_str, + .gateway = gate_str, + .interface_name = ifname, + .tag = tag_str, + .distance = distance_str, + .label = label, + .table = table_str, + .color = color_str, + .onlink = !!onlink, + .xpath_vrf = true, + .nexthop_vrf = nexthop_vrf, + }; + + return static_route_nb_run(vty, &args); } DEFPY_YANG(ip_route, @@ -602,26 +636,24 @@ DEFPY_YANG(ip_route, "SR-TE color\n" "The SR-TE color to configure\n") { - const char *nh_vrf; - const char *flag = NULL; - - if (ifname && !strncasecmp(ifname, "Null0", 5)) { - flag = "Null0"; - ifname = NULL; - } - - if (!vrf) - vrf = VRF_DEFAULT_NAME; - - if (nexthop_vrf) - nh_vrf = nexthop_vrf; - else - nh_vrf = vrf; - - return static_route_leak(vty, vrf, nh_vrf, AFI_IP, SAFI_UNICAST, no, - prefix, mask_str, NULL, gate_str, ifname, flag, - tag_str, distance_str, label, table_str, - false, color_str); + struct static_route_args args = { + .delete = !!no, + .afi = AFI_IP, + .safi = SAFI_UNICAST, + .prefix = prefix, + .prefix_mask = mask_str, + .gateway = gate_str, + .interface_name = ifname, + .tag = tag_str, + .distance = distance_str, + .label = label, + .table = table_str, + .color = color_str, + .vrf = vrf, + .nexthop_vrf = nexthop_vrf, + }; + + return static_route_nb_run(vty, &args); } DEFPY_YANG(ip_route_vrf, @@ -655,33 +687,24 @@ DEFPY_YANG(ip_route_vrf, "SR-TE color\n" "The SR-TE color to configure\n") { - const char *nh_vrf; - const char *flag = NULL; - const struct lyd_node *vrf_dnode; - const char *vrfname; - - vrf_dnode = - yang_dnode_get(vty->candidate_config->dnode, VTY_CURR_XPATH); - if (!vrf_dnode) { - vty_out(vty, "%% Failed to get vrf dnode in candidate db\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - vrfname = yang_dnode_get_string(vrf_dnode, "./name"); - - if (ifname && !strncasecmp(ifname, "Null0", 5)) { - flag = "Null0"; - ifname = NULL; - } - if (nexthop_vrf) - nh_vrf = nexthop_vrf; - else - nh_vrf = vrfname; - - return static_route_leak(vty, vrfname, nh_vrf, AFI_IP, SAFI_UNICAST, no, - prefix, mask_str, NULL, gate_str, ifname, flag, - tag_str, distance_str, label, table_str, - false, color_str); + struct static_route_args args = { + .delete = !!no, + .afi = AFI_IP, + .safi = SAFI_UNICAST, + .prefix = prefix, + .prefix_mask = mask_str, + .gateway = gate_str, + .interface_name = ifname, + .tag = tag_str, + .distance = distance_str, + .label = label, + .table = table_str, + .color = color_str, + .xpath_vrf = true, + .nexthop_vrf = nexthop_vrf, + }; + + return static_route_nb_run(vty, &args); } DEFPY_YANG(ipv6_route_blackhole, @@ -711,9 +734,21 @@ DEFPY_YANG(ipv6_route_blackhole, "Table to configure\n" "The table number to configure\n") { - return static_route(vty, AFI_IP6, SAFI_UNICAST, no, prefix_str, - NULL, from_str, NULL, NULL, flag, tag_str, - distance_str, vrf, label, table_str); + struct static_route_args args = { + .delete = !!no, + .afi = AFI_IP6, + .safi = SAFI_UNICAST, + .prefix = prefix_str, + .source = from_str, + .flag = flag, + .tag = tag_str, + .distance = distance_str, + .label = label, + .table = table_str, + .vrf = vrf, + }; + + return static_route_nb_run(vty, &args); } DEFPY_YANG(ipv6_route_blackhole_vrf, @@ -741,28 +776,28 @@ DEFPY_YANG(ipv6_route_blackhole_vrf, "Table to configure\n" "The table number to configure\n") { - const struct lyd_node *vrf_dnode; - const char *vrfname; - - vrf_dnode = - yang_dnode_get(vty->candidate_config->dnode, VTY_CURR_XPATH); - if (!vrf_dnode) { - vty_out(vty, "%% Failed to get vrf dnode in candidate db\n"); - return CMD_WARNING_CONFIG_FAILED; - } - vrfname = yang_dnode_get_string(vrf_dnode, "./name"); + struct static_route_args args = { + .delete = !!no, + .afi = AFI_IP6, + .safi = SAFI_UNICAST, + .prefix = prefix_str, + .source = from_str, + .flag = flag, + .tag = tag_str, + .distance = distance_str, + .label = label, + .table = table_str, + .xpath_vrf = true, + }; /* * Coverity is complaining that prefix could * be dereferenced, but we know that prefix will * valid. Add an assert to make it happy */ - assert(prefix); + assert(args.prefix); - return static_route_leak(vty, vrfname, vrfname, AFI_IP6, SAFI_UNICAST, - no, prefix_str, NULL, from_str, NULL, NULL, - flag, tag_str, distance_str, label, table_str, - false, NULL); + return static_route_nb_run(vty, &args); } DEFPY_YANG(ipv6_route_address_interface, @@ -801,26 +836,25 @@ DEFPY_YANG(ipv6_route_address_interface, "SR-TE color\n" "The SR-TE color to configure\n") { - const char *nh_vrf; - const char *flag = NULL; - - if (ifname && !strncasecmp(ifname, "Null0", 5)) { - flag = "Null0"; - ifname = NULL; - } - - if (!vrf) - vrf = VRF_DEFAULT_NAME; - - if (nexthop_vrf) - nh_vrf = nexthop_vrf; - else - nh_vrf = vrf; - - return static_route_leak(vty, vrf, nh_vrf, AFI_IP6, SAFI_UNICAST, no, - prefix_str, NULL, from_str, gate_str, ifname, - flag, tag_str, distance_str, label, table_str, - !!onlink, color_str); + struct static_route_args args = { + .delete = !!no, + .afi = AFI_IP6, + .safi = SAFI_UNICAST, + .prefix = prefix_str, + .source = from_str, + .gateway = gate_str, + .interface_name = ifname, + .tag = tag_str, + .distance = distance_str, + .label = label, + .table = table_str, + .color = color_str, + .onlink = !!onlink, + .vrf = vrf, + .nexthop_vrf = nexthop_vrf, + }; + + return static_route_nb_run(vty, &args); } DEFPY_YANG(ipv6_route_address_interface_vrf, @@ -857,32 +891,25 @@ DEFPY_YANG(ipv6_route_address_interface_vrf, "SR-TE color\n" "The SR-TE color to configure\n") { - const char *nh_vrf; - const char *flag = NULL; - const struct lyd_node *vrf_dnode; - const char *vrfname; - - vrf_dnode = - yang_dnode_get(vty->candidate_config->dnode, VTY_CURR_XPATH); - if (!vrf_dnode) { - vty_out(vty, "%% Failed to get vrf dnode in candidate db\n"); - return CMD_WARNING_CONFIG_FAILED; - } - vrfname = yang_dnode_get_string(vrf_dnode, "./name"); - - if (nexthop_vrf) - nh_vrf = nexthop_vrf; - else - nh_vrf = vrfname; - - if (ifname && !strncasecmp(ifname, "Null0", 5)) { - flag = "Null0"; - ifname = NULL; - } - return static_route_leak(vty, vrfname, nh_vrf, AFI_IP6, SAFI_UNICAST, - no, prefix_str, NULL, from_str, gate_str, - ifname, flag, tag_str, distance_str, label, - table_str, !!onlink, color_str); + struct static_route_args args = { + .delete = !!no, + .afi = AFI_IP6, + .safi = SAFI_UNICAST, + .prefix = prefix_str, + .source = from_str, + .gateway = gate_str, + .interface_name = ifname, + .tag = tag_str, + .distance = distance_str, + .label = label, + .table = table_str, + .color = color_str, + .onlink = !!onlink, + .xpath_vrf = true, + .nexthop_vrf = nexthop_vrf, + }; + + return static_route_nb_run(vty, &args); } DEFPY_YANG(ipv6_route, @@ -918,25 +945,24 @@ DEFPY_YANG(ipv6_route, "SR-TE color\n" "The SR-TE color to configure\n") { - const char *nh_vrf; - const char *flag = NULL; - - if (!vrf) - vrf = VRF_DEFAULT_NAME; - - if (nexthop_vrf) - nh_vrf = nexthop_vrf; - else - nh_vrf = vrf; - - if (ifname && !strncasecmp(ifname, "Null0", 5)) { - flag = "Null0"; - ifname = NULL; - } - return static_route_leak(vty, vrf, nh_vrf, AFI_IP6, SAFI_UNICAST, no, - prefix_str, NULL, from_str, gate_str, ifname, - flag, tag_str, distance_str, label, table_str, - false, color_str); + struct static_route_args args = { + .delete = !!no, + .afi = AFI_IP6, + .safi = SAFI_UNICAST, + .prefix = prefix_str, + .source = from_str, + .gateway = gate_str, + .interface_name = ifname, + .tag = tag_str, + .distance = distance_str, + .label = label, + .table = table_str, + .color = color_str, + .vrf = vrf, + .nexthop_vrf = nexthop_vrf, + }; + + return static_route_nb_run(vty, &args); } DEFPY_YANG(ipv6_route_vrf, @@ -970,32 +996,24 @@ DEFPY_YANG(ipv6_route_vrf, "SR-TE color\n" "The SR-TE color to configure\n") { - const char *nh_vrf; - const char *flag = NULL; - const struct lyd_node *vrf_dnode; - const char *vrfname; - - vrf_dnode = - yang_dnode_get(vty->candidate_config->dnode, VTY_CURR_XPATH); - if (!vrf_dnode) { - vty_out(vty, "%% Failed to get vrf dnode in candidate db\n"); - return CMD_WARNING_CONFIG_FAILED; - } - vrfname = yang_dnode_get_string(vrf_dnode, "./name"); - - if (nexthop_vrf) - nh_vrf = nexthop_vrf; - else - nh_vrf = vrfname; - - if (ifname && !strncasecmp(ifname, "Null0", 5)) { - flag = "Null0"; - ifname = NULL; - } - return static_route_leak(vty, vrfname, nh_vrf, AFI_IP6, SAFI_UNICAST, - no, prefix_str, NULL, from_str, gate_str, - ifname, flag, tag_str, distance_str, label, - table_str, false, color_str); + struct static_route_args args = { + .delete = !!no, + .afi = AFI_IP6, + .safi = SAFI_UNICAST, + .prefix = prefix_str, + .source = from_str, + .gateway = gate_str, + .interface_name = ifname, + .tag = tag_str, + .distance = distance_str, + .label = label, + .table = table_str, + .color = color_str, + .xpath_vrf = true, + .nexthop_vrf = nexthop_vrf, + }; + + return static_route_nb_run(vty, &args); } void static_cli_show(struct vty *vty, const struct lyd_node *dnode, diff --git a/tests/topotests/bgp_comm_list_delete/test_bgp_comm-list_delete.py b/tests/topotests/bgp_comm_list_delete/test_bgp_comm-list_delete.py index 4db4e37f7f..a2904e6e1e 100644 --- a/tests/topotests/bgp_comm_list_delete/test_bgp_comm-list_delete.py +++ b/tests/topotests/bgp_comm_list_delete/test_bgp_comm-list_delete.py @@ -34,11 +34,13 @@ import os import sys import json import pytest +import functools CWD = os.path.dirname(os.path.realpath(__file__)) sys.path.append(os.path.join(CWD, "../")) # pylint: disable=C0413 +from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen pytestmark = [pytest.mark.bgpd] @@ -81,30 +83,34 @@ def test_bgp_maximum_prefix_invalid(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - def _bgp_converge(router): - while True: - output = json.loads( - tgen.gears[router].vtysh_cmd("show ip bgp neighbor 192.168.255.1 json") - ) - if output["192.168.255.1"]["bgpState"] == "Established": - if ( - output["192.168.255.1"]["addressFamilyInfo"]["ipv4Unicast"][ - "acceptedPrefixCounter" - ] - == 2 - ): - return True - - def _bgp_comm_list_delete(router): - output = json.loads( - tgen.gears[router].vtysh_cmd("show ip bgp 172.16.255.254/32 json") - ) - if "333:333" in output["paths"][0]["community"]["list"]: - return False - return True - - if _bgp_converge("r2"): - assert _bgp_comm_list_delete("r2") == True + r2 = tgen.gears["r2"] + + def _bgp_converge(): + output = json.loads(r2.vtysh_cmd("show ip bgp neighbor 192.168.255.1 json")) + expected = { + "192.168.255.1": { + "bgpState": "Established", + "addressFamilyInfo": { + "ipv4Unicast": { + "acceptedPrefixCounter": 2, + } + }, + } + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial(_bgp_converge) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Can't converge initially" + + def _bgp_comm_list_delete(): + output = json.loads(r2.vtysh_cmd("show ip bgp 172.16.255.254/32 json")) + expected = {"paths": [{"community": {"list": ["333:333"]}}]} + return topotest.json_cmp(output, expected) + + test_func = functools.partial(_bgp_comm_list_delete) + _, result = topotest.run_and_expect(test_func, not None, count=60, wait=0.5) + assert result is not None, "333:333 community SHOULD be stripped from r1" if __name__ == "__main__": diff --git a/tests/topotests/bgp_local_as_private_remove/test_bgp_local_as_private_remove.py b/tests/topotests/bgp_local_as_private_remove/test_bgp_local_as_private_remove.py index bb2c43d1fc..2b4c4e816b 100644 --- a/tests/topotests/bgp_local_as_private_remove/test_bgp_local_as_private_remove.py +++ b/tests/topotests/bgp_local_as_private_remove/test_bgp_local_as_private_remove.py @@ -31,13 +31,14 @@ used together with `remove-private-AS`. 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 pytestmark = [pytest.mark.bgpd] @@ -84,29 +85,43 @@ def test_bgp_remove_private_as(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - def _bgp_converge(router): - while True: - output = json.loads( - tgen.gears[router].vtysh_cmd("show ip bgp neighbor 192.168.255.1 json") - ) - if output["192.168.255.1"]["bgpState"] == "Established": - time.sleep(1) - return True - - def _bgp_as_path(router): - output = json.loads( - tgen.gears[router].vtysh_cmd("show ip bgp 172.16.255.254/32 json") - ) - if output["prefix"] == "172.16.255.254/32": - return output["paths"][0]["aspath"]["segments"][0]["list"] - - if _bgp_converge("r2"): - assert len(_bgp_as_path("r2")) == 1 - assert 65000 not in _bgp_as_path("r2") - - if _bgp_converge("r4"): - assert len(_bgp_as_path("r4")) == 2 - assert 3000 in _bgp_as_path("r4") + r2 = tgen.gears["r2"] + r4 = tgen.gears["r4"] + + def _bgp_converge(): + output = json.loads(r2.vtysh_cmd("show ip bgp neighbor 192.168.255.1 json")) + expected = { + "192.168.255.1": { + "bgpState": "Established", + } + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial(_bgp_converge) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Can't converge initially" + + def _bgp_as_path(router, asn_path, asn_length): + output = json.loads(router.vtysh_cmd("show ip bgp 172.16.255.254/32 json")) + expected = { + "paths": [ + { + "aspath": { + "string": asn_path, + "length": asn_length, + } + } + ] + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial(_bgp_as_path, r2, "500", 1) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Private ASNs not stripped" + + test_func = functools.partial(_bgp_as_path, r4, "500 3000", 2) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Private ASNs not stripped" if __name__ == "__main__": diff --git a/tests/topotests/bgp_maximum_prefix_invalid_update/r1/bgpd.conf b/tests/topotests/bgp_maximum_prefix_invalid_update/r1/bgpd.conf index 62110429cf..271a5bb1b1 100644 --- a/tests/topotests/bgp_maximum_prefix_invalid_update/r1/bgpd.conf +++ b/tests/topotests/bgp_maximum_prefix_invalid_update/r1/bgpd.conf @@ -1,6 +1,13 @@ router bgp 65000 - no bgp ebgp-requires-policy - neighbor 192.168.255.2 remote-as 65001 - neighbor 192.168.255.2 timers 3 10 - address-family ipv4 unicast - redistribute connected + no bgp ebgp-requires-policy + neighbor 192.168.255.2 remote-as 65001 + neighbor 192.168.255.2 timers 3 10 + address-family ipv4 unicast + redistribute connected + neighbor 192.168.255.2 prefix-list r2 out + exit-address-family + ! +! +ip prefix-list r2 seq 5 permit 172.16.255.253/32 +ip prefix-list r2 seq 10 permit 172.16.255.254/32 +! diff --git a/tests/topotests/bgp_maximum_prefix_invalid_update/r1/zebra.conf b/tests/topotests/bgp_maximum_prefix_invalid_update/r1/zebra.conf index 0a283c06d5..68c5021636 100644 --- a/tests/topotests/bgp_maximum_prefix_invalid_update/r1/zebra.conf +++ b/tests/topotests/bgp_maximum_prefix_invalid_update/r1/zebra.conf @@ -1,6 +1,7 @@ ! interface lo ip address 172.16.255.254/32 + ip address 172.16.255.253/32 ! interface r1-eth0 ip address 192.168.255.1/24 diff --git a/tests/topotests/bgp_maximum_prefix_invalid_update/r2/bgpd.conf b/tests/topotests/bgp_maximum_prefix_invalid_update/r2/bgpd.conf index 005425e850..cb30808f41 100644 --- a/tests/topotests/bgp_maximum_prefix_invalid_update/r2/bgpd.conf +++ b/tests/topotests/bgp_maximum_prefix_invalid_update/r2/bgpd.conf @@ -1,6 +1,9 @@ router bgp 65001 - no bgp ebgp-requires-policy - neighbor 192.168.255.1 remote-as 65000 - neighbor 192.168.255.1 timers 3 10 - address-family ipv4 - neighbor 192.168.255.1 maximum-prefix 1 + no bgp ebgp-requires-policy + neighbor 192.168.255.1 remote-as 65000 + neighbor 192.168.255.1 timers 3 10 + address-family ipv4 + neighbor 192.168.255.1 maximum-prefix 1 + exit-address-family + ! +! diff --git a/tests/topotests/bgp_maximum_prefix_invalid_update/test_bgp_maximum_prefix_invalid_update.py b/tests/topotests/bgp_maximum_prefix_invalid_update/test_bgp_maximum_prefix_invalid_update.py index 5c34ebf919..ee68ecd7b6 100644 --- a/tests/topotests/bgp_maximum_prefix_invalid_update/test_bgp_maximum_prefix_invalid_update.py +++ b/tests/topotests/bgp_maximum_prefix_invalid_update/test_bgp_maximum_prefix_invalid_update.py @@ -36,11 +36,13 @@ import os import sys import json import pytest +import functools CWD = os.path.dirname(os.path.realpath(__file__)) sys.path.append(os.path.join(CWD, "../")) # pylint: disable=C0413 +from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen pytestmark = [pytest.mark.bgpd] @@ -83,29 +85,21 @@ def test_bgp_maximum_prefix_invalid(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - def _bgp_converge(router): - while True: - output = json.loads( - tgen.gears[router].vtysh_cmd("show ip bgp neighbor 192.168.255.1 json") - ) - if output["192.168.255.1"]["connectionsEstablished"] > 0: - return True - - def _bgp_parsing_nlri(router): - cmd_max_exceeded = ( - 'grep "%MAXPFXEXCEED: No. of IPv4 Unicast prefix received" bgpd.log' - ) - cmdt_error_parsing_nlri = 'grep "Error parsing NLRI" bgpd.log' - output_max_exceeded = tgen.gears[router].run(cmd_max_exceeded) - output_error_parsing_nlri = tgen.gears[router].run(cmdt_error_parsing_nlri) - - if len(output_max_exceeded) > 0: - if len(output_error_parsing_nlri) > 0: - return False - return True - - if _bgp_converge("r2"): - assert _bgp_parsing_nlri("r2") == True + r2 = tgen.gears["r2"] + + def _bgp_parsing_nlri(): + output = json.loads(r2.vtysh_cmd("show ip bgp neighbor 192.168.255.1 json")) + expected = { + "192.168.255.1": { + "lastNotificationReason": "Cease/Maximum Number of Prefixes Reached", + "lastResetDueTo": "BGP Notification send", + } + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial(_bgp_parsing_nlri) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + assert result is None, "Didn't send NOTIFICATION when hitting maximum-prefix" if __name__ == "__main__": diff --git a/tests/topotests/bgp_peer_graceful_shutdown/__init__.py b/tests/topotests/bgp_peer_graceful_shutdown/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/topotests/bgp_peer_graceful_shutdown/__init__.py diff --git a/tests/topotests/bgp_peer_graceful_shutdown/r1/bgpd.conf b/tests/topotests/bgp_peer_graceful_shutdown/r1/bgpd.conf new file mode 100644 index 0000000000..8e5909839a --- /dev/null +++ b/tests/topotests/bgp_peer_graceful_shutdown/r1/bgpd.conf @@ -0,0 +1,8 @@ +! +router bgp 65001 + no bgp ebgp-requires-policy + neighbor 192.168.1.2 remote-as external + address-family ipv4 unicast + redistribute connected + exit-address-family +! diff --git a/tests/topotests/bgp_peer_graceful_shutdown/r1/zebra.conf b/tests/topotests/bgp_peer_graceful_shutdown/r1/zebra.conf new file mode 100644 index 0000000000..376a19a808 --- /dev/null +++ b/tests/topotests/bgp_peer_graceful_shutdown/r1/zebra.conf @@ -0,0 +1,7 @@ +! +int lo + ip address 10.10.10.1/32 +! +int r1-eth0 + ip address 192.168.1.1/24 +! diff --git a/tests/topotests/bgp_peer_graceful_shutdown/r2/bgpd.conf b/tests/topotests/bgp_peer_graceful_shutdown/r2/bgpd.conf new file mode 100644 index 0000000000..0ee1821003 --- /dev/null +++ b/tests/topotests/bgp_peer_graceful_shutdown/r2/bgpd.conf @@ -0,0 +1,8 @@ +router bgp 65002 + no bgp ebgp-requires-policy + neighbor 192.168.1.1 remote-as external + neighbor 192.168.2.2 remote-as internal + address-family ipv4 unicast + neighbor 192.168.2.2 next-hop-self + exit-address-family +! diff --git a/tests/topotests/bgp_peer_graceful_shutdown/r2/zebra.conf b/tests/topotests/bgp_peer_graceful_shutdown/r2/zebra.conf new file mode 100644 index 0000000000..67ca02f10a --- /dev/null +++ b/tests/topotests/bgp_peer_graceful_shutdown/r2/zebra.conf @@ -0,0 +1,7 @@ +! +int r2-eth0 + ip address 192.168.1.2/24 +! +int r2-eth1 + ip address 192.168.2.1/24 +! diff --git a/tests/topotests/bgp_peer_graceful_shutdown/r3/bgpd.conf b/tests/topotests/bgp_peer_graceful_shutdown/r3/bgpd.conf new file mode 100644 index 0000000000..5945a024b9 --- /dev/null +++ b/tests/topotests/bgp_peer_graceful_shutdown/r3/bgpd.conf @@ -0,0 +1,5 @@ +! +router bgp 65002 + no bgp ebgp-requires-policy + neighbor 192.168.2.1 remote-as internal +! diff --git a/tests/topotests/bgp_peer_graceful_shutdown/r3/zebra.conf b/tests/topotests/bgp_peer_graceful_shutdown/r3/zebra.conf new file mode 100644 index 0000000000..e5a37c98ca --- /dev/null +++ b/tests/topotests/bgp_peer_graceful_shutdown/r3/zebra.conf @@ -0,0 +1,4 @@ +! +int r3-eth0 + ip address 192.168.2.2/24 +! diff --git a/tests/topotests/bgp_peer_graceful_shutdown/test_bgp_peer_graceful_shutdown.py b/tests/topotests/bgp_peer_graceful_shutdown/test_bgp_peer_graceful_shutdown.py new file mode 100644 index 0000000000..de62889a0e --- /dev/null +++ b/tests/topotests/bgp_peer_graceful_shutdown/test_bgp_peer_graceful_shutdown.py @@ -0,0 +1,120 @@ +#!/usr/bin/env python + +# Copyright (c) 2022 by +# Donatas Abraitis <donatas@opensourcerouting.org> +# +# 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. +# + +""" +Check if routes from R1 has local-preference set to 0 and graceful-shutdown +community. +""" + +import os +import sys +import json +import pytest +import functools + +pytestmark = pytest.mark.bgpd + +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.common_config import step + +pytestmark = [pytest.mark.bgpd] + + +def setup_module(mod): + topodef = {"s1": ("r1", "r2"), "s2": ("r2", "r3")} + tgen = Topogen(topodef, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + for i, (rname, router) in enumerate(router_list.items(), 1): + router.load_config( + TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname)) + ) + + tgen.start_router() + + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + + +def test_bgp_orf(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r2 = tgen.gears["r2"] + r3 = tgen.gears["r3"] + + def _bgp_converge(): + output = json.loads( + r2.vtysh_cmd( + "show bgp ipv4 unicast neighbor 192.168.2.2 advertised-routes json" + ) + ) + expected = {"advertisedRoutes": {"10.10.10.1/32": {"locPrf": 100}}} + return topotest.json_cmp(output, expected) + + test_func = functools.partial(_bgp_converge) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Can't converge at R2" + + step("Mark routes from R1 as graceful-shutdown") + r2.vtysh_cmd( + """ + configure terminal + router bgp + neighbor 192.168.1.1 graceful-shutdown + """ + ) + + def _bgp_check_peer_graceful_shutdown(): + output = json.loads(r3.vtysh_cmd("show bgp ipv4 unicast 10.10.10.1/32 json")) + expected = { + "paths": [ + { + "locPrf": 0, + "community": {"string": "graceful-shutdown"}, + } + ] + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial(_bgp_check_peer_graceful_shutdown) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert ( + result is None + ), "local-preference is not 0 and/or graceful-shutdown community missing" + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r1/bgpd.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r1/bgpd.conf index c06175193e..30a0f8fe78 100644 --- a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r1/bgpd.conf +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r1/bgpd.conf @@ -1,5 +1,7 @@ frr defaults traditional ! +bgp send-extra-data zebra +! hostname r1 password zebra ! diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r2/bgpd.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r2/bgpd.conf index 05170572a4..7ca23002ac 100644 --- a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r2/bgpd.conf +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r2/bgpd.conf @@ -1,5 +1,7 @@ frr defaults traditional ! +bgp send-extra-data zebra +! hostname r2 password zebra ! diff --git a/tests/topotests/isis_lfa_topo1/test_isis_lfa_topo1.py b/tests/topotests/isis_lfa_topo1/test_isis_lfa_topo1.py index 61caf257eb..012814919d 100755 --- a/tests/topotests/isis_lfa_topo1/test_isis_lfa_topo1.py +++ b/tests/topotests/isis_lfa_topo1/test_isis_lfa_topo1.py @@ -1054,7 +1054,7 @@ def test_rib_ipv6_step24(): rname, "show ipv6 route isis json", outputs[rname][15]["show_ipv6_route.ref"], - count=5, + count=10, ) diff --git a/tests/topotests/isis_tilfa_topo1/test_isis_tilfa_topo1.py b/tests/topotests/isis_tilfa_topo1/test_isis_tilfa_topo1.py index fa76072b4a..213439d3f5 100755 --- a/tests/topotests/isis_tilfa_topo1/test_isis_tilfa_topo1.py +++ b/tests/topotests/isis_tilfa_topo1/test_isis_tilfa_topo1.py @@ -831,19 +831,19 @@ def test_rt6_step11(): rname, "show ip route isis json", outputs[rname][11]["show_ip_route.ref"], - count=5, + count=10, ) router_compare_json_output( rname, "show ipv6 route isis json", outputs[rname][11]["show_ipv6_route.ref"], - count=5, + count=10, ) router_compare_json_output( rname, "show mpls table json", outputs[rname][11]["show_mpls_table.ref"], - count=5, + count=10, ) @@ -1028,19 +1028,19 @@ def test_rt6_step14(): rname, "show ip route isis json", outputs[rname][11]["show_ip_route.ref"], - count=5, + count=10, ) router_compare_json_output( rname, "show ipv6 route isis json", outputs[rname][11]["show_ipv6_route.ref"], - count=5, + count=10, ) router_compare_json_output( rname, "show mpls table json", outputs[rname][11]["show_mpls_table.ref"], - count=5, + count=10, ) diff --git a/tests/topotests/lib/topotest.py b/tests/topotests/lib/topotest.py index 5a3f586f82..61cf16944f 100644 --- a/tests/topotests/lib/topotest.py +++ b/tests/topotests/lib/topotest.py @@ -355,6 +355,16 @@ def run_and_expect(func, what, count=20, wait=3): else: func_name = func.__name__ + # Just a safety-check to avoid running topotests with very + # small wait/count arguments. + wait_time = wait * count + if wait_time < 5: + assert ( + wait_time >= 5 + ), "Waiting time is too small (count={}, wait={}), adjust timer values".format( + count, wait + ) + logger.info( "'{}' polling started (interval {} secs, maximum {} tries)".format( func_name, wait, count @@ -402,6 +412,16 @@ def run_and_expect_type(func, etype, count=20, wait=3, avalue=None): else: func_name = func.__name__ + # Just a safety-check to avoid running topotests with very + # small wait/count arguments. + wait_time = wait * count + if wait_time < 5: + assert ( + wait_time >= 5 + ), "Waiting time is too small (count={}, wait={}), adjust timer values".format( + count, wait + ) + logger.info( "'{}' polling started (interval {} secs, maximum wait {} secs)".format( func_name, wait, int(wait * count) diff --git a/tests/topotests/ospf6_gr_topo1/test_ospf6_gr_topo1.py b/tests/topotests/ospf6_gr_topo1/test_ospf6_gr_topo1.py index e59333ebd2..1876dabed7 100755 --- a/tests/topotests/ospf6_gr_topo1/test_ospf6_gr_topo1.py +++ b/tests/topotests/ospf6_gr_topo1/test_ospf6_gr_topo1.py @@ -224,7 +224,7 @@ def check_routers(initial_convergence=False, exiting=None, restarting=None): if restarting != None: tries = 40 else: - tries = 1 + tries = 10 router_compare_json_output( rname, "show ipv6 route ospf json", "show_ipv6_route.json", tries ) @@ -246,7 +246,7 @@ def check_routers(initial_convergence=False, exiting=None, restarting=None): if initial_convergence == True or restarting == rname: tries = 240 else: - tries = 1 + tries = 10 router_compare_json_output( rname, "show ipv6 ospf database json", diff --git a/tests/topotests/ospf6_topo2/test_ospf6_topo2.py b/tests/topotests/ospf6_topo2/test_ospf6_topo2.py index d17aeda3ea..f16e8f396e 100644 --- a/tests/topotests/ospf6_topo2/test_ospf6_topo2.py +++ b/tests/topotests/ospf6_topo2/test_ospf6_topo2.py @@ -243,7 +243,7 @@ def test_ospf6_default_route(): "show ipv6 route json", {route: [{"metric": metric}]}, ) - _, result = topotest.run_and_expect(test_func, None, count=4, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=5, wait=1) assertmsg = '"{}" convergence failure'.format(router) assert result is None, assertmsg diff --git a/tests/topotests/ospf_gr_topo1/test_ospf_gr_topo1.py b/tests/topotests/ospf_gr_topo1/test_ospf_gr_topo1.py index debf7ad766..429b7dc96d 100755 --- a/tests/topotests/ospf_gr_topo1/test_ospf_gr_topo1.py +++ b/tests/topotests/ospf_gr_topo1/test_ospf_gr_topo1.py @@ -233,7 +233,7 @@ def check_routers(initial_convergence=False, exiting=None, restarting=None): if restarting != None: tries = 60 else: - tries = 1 + tries = 10 router_compare_json_output( rname, "show ip route ospf json", "show_ip_route.json", tries ) @@ -252,7 +252,7 @@ def check_routers(initial_convergence=False, exiting=None, restarting=None): if initial_convergence == True or restarting == rname: tries = 240 else: - tries = 1 + tries = 10 router_compare_json_output( rname, "show ip ospf database json", "show_ip_ospf_database.json", tries ) diff --git a/tests/topotests/pim_basic/test_pim.py b/tests/topotests/pim_basic/test_pim.py index 6cea521aa9..2c1bc52d09 100644 --- a/tests/topotests/pim_basic/test_pim.py +++ b/tests/topotests/pim_basic/test_pim.py @@ -225,7 +225,7 @@ def test_pim_igmp_report(): test_func = partial( topotest.router_json_cmp, r1, "show ip pim upstream json", expected ) - _, result = topotest.run_and_expect(test_func, None, count=5, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assertmsg = '"{}" JSON output mismatches'.format(r1.name) assert result is None, assertmsg finally: diff --git a/tests/topotests/pim_basic_topo2/test_pim_basic_topo2.py b/tests/topotests/pim_basic_topo2/test_pim_basic_topo2.py index 9506c3c6d1..5aa313137f 100644 --- a/tests/topotests/pim_basic_topo2/test_pim_basic_topo2.py +++ b/tests/topotests/pim_basic_topo2/test_pim_basic_topo2.py @@ -175,7 +175,7 @@ def test_pim_reconvergence(): "show ip pim neighbor json", {interface: {peer: None}}, ) - _, result = topotest.run_and_expect(test_func, None, count=4, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=5, wait=1) assertmsg = '"{}" PIM convergence failure'.format(router) assert result is None, assertmsg @@ -201,7 +201,7 @@ def test_pim_bfd_profile(): "show bfd peers json", [settings], ) - _, result = topotest.run_and_expect(test_func, None, count=4, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=5, wait=1) assertmsg = '"{}" BFD convergence failure'.format(router) assert result is None, assertmsg diff --git a/tests/topotests/srv6_locator/test_srv6_locator.py b/tests/topotests/srv6_locator/test_srv6_locator.py index bc5fa409d2..b918da0655 100755 --- a/tests/topotests/srv6_locator/test_srv6_locator.py +++ b/tests/topotests/srv6_locator/test_srv6_locator.py @@ -94,12 +94,12 @@ def test_srv6(): def check_srv6_locator(router, expected_file): func = functools.partial(_check_srv6_locator, router, expected_file) - success, result = topotest.run_and_expect(func, None, count=5, wait=0.5) + success, result = topotest.run_and_expect(func, None, count=10, wait=0.5) assert result is None, "Failed" def check_sharpd_chunk(router, expected_file): func = functools.partial(_check_sharpd_chunk, router, expected_file) - success, result = topotest.run_and_expect(func, None, count=5, wait=0.5) + success, result = topotest.run_and_expect(func, None, count=10, wait=0.5) assert result is None, "Failed" # FOR DEVELOPER: diff --git a/tests/topotests/srv6_locator_custom_bits_length/test_srv6_locator.py b/tests/topotests/srv6_locator_custom_bits_length/test_srv6_locator.py index ecc0856371..4bd0682bde 100755 --- a/tests/topotests/srv6_locator_custom_bits_length/test_srv6_locator.py +++ b/tests/topotests/srv6_locator_custom_bits_length/test_srv6_locator.py @@ -90,12 +90,12 @@ def test_srv6(): def check_srv6_locator(router, expected_file): func = functools.partial(_check_srv6_locator, router, expected_file) - success, result = topotest.run_and_expect(func, None, count=5, wait=0.5) + success, result = topotest.run_and_expect(func, None, count=10, wait=0.5) assert result is None, "Failed" def check_sharpd_chunk(router, expected_file): func = functools.partial(_check_sharpd_chunk, router, expected_file) - success, result = topotest.run_and_expect(func, None, count=5, wait=0.5) + success, result = topotest.run_and_expect(func, None, count=10, wait=0.5) assert result is None, "Failed" # FOR DEVELOPER: @@ -124,7 +124,7 @@ def test_srv6(): srv6 locators locator loc3 - prefix 2001:db8:3::/48 func-bits 16 block-len 32 node-len 16 + prefix 2001:db8:3::/48 block-len 32 node-len 16 func-bits 16 """ ) check_srv6_locator(router, "expected_locators4.json") diff --git a/tests/topotests/srv6_locator_usid/r1/zebra.conf b/tests/topotests/srv6_locator_usid/r1/zebra.conf index 78ef1e9d40..190e831ac1 100644 --- a/tests/topotests/srv6_locator_usid/r1/zebra.conf +++ b/tests/topotests/srv6_locator_usid/r1/zebra.conf @@ -12,7 +12,7 @@ segment-routing srv6 locators locator loc1 - prefix fc00:0:1::/48 func-bits 16 block-len 32 node-len 16 + prefix fc00:0:1::/48 block-len 32 node-len 16 func-bits 16 behavior usid ! ! diff --git a/tests/topotests/srv6_locator_usid/test_srv6_locator_usid.py b/tests/topotests/srv6_locator_usid/test_srv6_locator_usid.py index 37fd736d2b..4023555524 100755 --- a/tests/topotests/srv6_locator_usid/test_srv6_locator_usid.py +++ b/tests/topotests/srv6_locator_usid/test_srv6_locator_usid.py @@ -54,12 +54,10 @@ def setup_module(mod): for rname, router in tgen.routers().items(): router.run("/bin/bash {}/{}/setup.sh".format(CWD, rname)) router.load_config( - TopoRouter.RD_ZEBRA, os.path.join( - CWD, "{}/zebra.conf".format(rname)) + TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) router.load_config( - TopoRouter.RD_SHARP, os.path.join( - CWD, "{}/sharpd.conf".format(rname)) + TopoRouter.RD_SHARP, os.path.join(CWD, "{}/sharpd.conf".format(rname)) ) tgen.start_router() @@ -71,18 +69,14 @@ def teardown_module(mod): def _check_srv6_locator(router, expected_locator_file): logger.info("checking zebra locator status") - output = json.loads( - router.vtysh_cmd("show segment-routing srv6 locator json") - ) + output = json.loads(router.vtysh_cmd("show segment-routing srv6 locator json")) expected = open_json_file("{}/{}".format(CWD, expected_locator_file)) return topotest.json_cmp(output, expected) def _check_sharpd_chunk(router, expected_chunk_file): logger.info("checking sharpd locator chunk status") - output = json.loads( - router.vtysh_cmd("show sharp segment-routing srv6 json") - ) + output = json.loads(router.vtysh_cmd("show sharp segment-routing srv6 json")) expected = open_json_file("{}/{}".format(CWD, expected_chunk_file)) return topotest.json_cmp(output, expected) @@ -164,7 +158,7 @@ def test_srv6_usid_locator_create_locator(): srv6 locators locator loc2 - prefix fc00:0:2::/48 func-bits 16 block-len 32 node-len 16 + prefix fc00:0:2::/48 block-len 32 node-len 16 func-bits 16 """ ) check_srv6_locator(router, "expected_locators_4.json") @@ -181,9 +175,7 @@ def test_srv6_usid_locator_set_behavior_usid(): # If you want to stop some specific line and start interactive shell, # please use tgen.mininet_cli() to start it. - logger.info( - "Specify the SRv6 Locator loc2 as a Micro-segment (uSID) Locator" - ) + logger.info("Specify the SRv6 Locator loc2 as a Micro-segment (uSID) Locator") router.vtysh_cmd( """ configure terminal diff --git a/tools/etc/frr/daemons b/tools/etc/frr/daemons index 8aa08871e3..2427bfff77 100644 --- a/tools/etc/frr/daemons +++ b/tools/etc/frr/daemons @@ -91,6 +91,11 @@ pathd_options=" -A 127.0.0.1" # #MAX_FDS=1024 +# Uncomment this option if you want to run FRR as a non-root user. Note that +# you should know what you are doing since most of the daemons need root +# to work. This could be useful if you want to run FRR in a container +# for instance. +# FRR_NO_ROOT="yes" # For any daemon, you can specify a "wrap" command to start instead of starting # the daemon directly. This will simply be prepended to the daemon invocation. diff --git a/tools/frrcommon.sh.in b/tools/frrcommon.sh.in index 3c16c27c6d..4f095a176e 100755 --- a/tools/frrcommon.sh.in +++ b/tools/frrcommon.sh.in @@ -43,6 +43,10 @@ RELOAD_SCRIPT="$D_PATH/frr-reload.py" # is_user_root () { + if [[ ! -z $FRR_NO_ROOT && "${FRR_NO_ROOT}" == "yes" ]]; then + return 0 + fi + [ "${EUID:-$(id -u)}" -eq 0 ] || { log_failure_msg "Only users having EUID=0 can start/stop daemons" return 1 diff --git a/zebra/interface.c b/zebra/interface.c index d61d3620f1..81ee995dd7 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -4646,7 +4646,7 @@ static int if_config_write(struct vty *vty) ? "" : "no "); if (if_data->mpls == IF_ZEBRA_DATA_ON) - vty_out(vty, " mpls\n"); + vty_out(vty, " mpls enable\n"); } hook_call(zebra_if_config_wr, vty, ifp); diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c index 7934a9d206..599c679864 100644 --- a/zebra/zebra_rnh.c +++ b/zebra/zebra_rnh.c @@ -62,7 +62,8 @@ static void free_state(vrf_id_t vrf_id, struct route_entry *re, static void copy_state(struct rnh *rnh, const struct route_entry *re, struct route_node *rn); static bool compare_state(struct route_entry *r1, struct route_entry *r2); -static void print_rnh(struct route_node *rn, struct vty *vty); +static void print_rnh(struct route_node *rn, struct vty *vty, + json_object *json); static int zebra_client_cleanup_rnh(struct zserv *client); void zebra_rnh_init(void) @@ -803,7 +804,8 @@ void zebra_evaluate_rnh(struct zebra_vrf *zvrf, afi_t afi, int force, } void zebra_print_rnh_table(vrf_id_t vrfid, afi_t afi, safi_t safi, - struct vty *vty, const struct prefix *p) + struct vty *vty, const struct prefix *p, + json_object *json) { struct route_table *table; struct route_node *rn; @@ -820,7 +822,7 @@ void zebra_print_rnh_table(vrf_id_t vrfid, afi_t afi, safi_t safi, continue; if (rn->info) - print_rnh(rn, vty); + print_rnh(rn, vty, json); } } @@ -1268,73 +1270,178 @@ failure: return -1; } -static void print_nh(struct nexthop *nexthop, struct vty *vty) +static void print_nh(struct nexthop *nexthop, struct vty *vty, + json_object *json) { - char buf[BUFSIZ]; struct zebra_ns *zns = zebra_ns_lookup(nexthop->vrf_id); switch (nexthop->type) { case NEXTHOP_TYPE_IPV4: case NEXTHOP_TYPE_IPV4_IFINDEX: - vty_out(vty, " via %pI4", &nexthop->gate.ipv4); - if (nexthop->ifindex) - vty_out(vty, ", %s", - ifindex2ifname_per_ns(zns, nexthop->ifindex)); + if (json) { + json_object_string_addf(json, "ip", "%pI4", + &nexthop->gate.ipv4); + if (nexthop->ifindex) + json_object_string_add( + json, "interface", + ifindex2ifname_per_ns( + zns, nexthop->ifindex)); + } else { + vty_out(vty, " via %pI4", &nexthop->gate.ipv4); + if (nexthop->ifindex) + vty_out(vty, ", %s", + ifindex2ifname_per_ns( + zns, nexthop->ifindex)); + } break; case NEXTHOP_TYPE_IPV6: case NEXTHOP_TYPE_IPV6_IFINDEX: - vty_out(vty, " %s", - inet_ntop(AF_INET6, &nexthop->gate.ipv6, buf, BUFSIZ)); - if (nexthop->ifindex) - vty_out(vty, ", via %s", - ifindex2ifname_per_ns(zns, nexthop->ifindex)); + if (json) { + json_object_string_addf(json, "ip", "%pI6", + &nexthop->gate.ipv6); + if (nexthop->ifindex) + json_object_string_add( + json, "interface", + ifindex2ifname_per_ns( + zns, nexthop->ifindex)); + } else { + vty_out(vty, " %pI6", &nexthop->gate.ipv6); + if (nexthop->ifindex) + vty_out(vty, ", via %s", + ifindex2ifname_per_ns( + zns, nexthop->ifindex)); + } break; case NEXTHOP_TYPE_IFINDEX: - vty_out(vty, " is directly connected, %s", - ifindex2ifname_per_ns(zns, nexthop->ifindex)); + if (json) { + json_object_string_add( + json, "interface", + ifindex2ifname_per_ns(zns, nexthop->ifindex)); + json_object_boolean_true_add(json, "directlyConnected"); + } else { + vty_out(vty, " is directly connected, %s", + ifindex2ifname_per_ns(zns, nexthop->ifindex)); + } break; case NEXTHOP_TYPE_BLACKHOLE: - vty_out(vty, " is directly connected, Null0"); + if (json) { + json_object_string_add(json, "interface", "Null0"); + json_object_boolean_true_add(json, "directlyConnected"); + } else { + vty_out(vty, " is directly connected, Null0"); + } break; default: break; } - vty_out(vty, "\n"); + + if (!json) + vty_out(vty, "\n"); } -static void print_rnh(struct route_node *rn, struct vty *vty) +static void print_rnh(struct route_node *rn, struct vty *vty, json_object *json) { struct rnh *rnh; struct nexthop *nexthop; struct listnode *node; struct zserv *client; char buf[BUFSIZ]; + json_object *json_nht = NULL; + json_object *json_client_array = NULL; + json_object *json_client = NULL; + json_object *json_nexthop_array = NULL; + json_object *json_nexthop = NULL; rnh = rn->info; - vty_out(vty, "%s%s\n", - inet_ntop(rn->p.family, &rn->p.u.prefix, buf, BUFSIZ), - CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED) ? "(Connected)" - : ""); - if (rnh->state) { - vty_out(vty, " resolved via %s\n", - zebra_route_string(rnh->state->type)); - for (nexthop = rnh->state->nhe->nhg.nexthop; nexthop; - nexthop = nexthop->next) - print_nh(nexthop, vty); - } else - vty_out(vty, " unresolved%s\n", + + if (json) { + json_nht = json_object_new_object(); + json_nexthop_array = json_object_new_array(); + json_client_array = json_object_new_array(); + + json_object_object_add( + json, + inet_ntop(rn->p.family, &rn->p.u.prefix, buf, BUFSIZ), + json_nht); + json_object_boolean_add( + json_nht, "nhtConnected", + CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED)); + json_object_object_add(json_nht, "clientList", + json_client_array); + json_object_object_add(json_nht, "gates", json_nexthop_array); + } else { + vty_out(vty, "%s%s\n", + inet_ntop(rn->p.family, &rn->p.u.prefix, buf, BUFSIZ), CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED) ? "(Connected)" : ""); + } + + if (rnh->state) { + if (json) + json_object_string_add( + json_nht, "resolvedProtocol", + zebra_route_string(rnh->state->type)); + else + vty_out(vty, " resolved via %s\n", + zebra_route_string(rnh->state->type)); + + for (nexthop = rnh->state->nhe->nhg.nexthop; nexthop; + nexthop = nexthop->next) { + if (json) { + json_nexthop = json_object_new_object(); + json_object_array_add(json_nexthop_array, + json_nexthop); + } + print_nh(nexthop, vty, json_nexthop); + } + } else { + if (json) + json_object_boolean_add( + json_nht, "unresolved", + CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED)); + else + vty_out(vty, " unresolved%s\n", + CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED) + ? "(Connected)" + : ""); + } + + if (!json) + vty_out(vty, " Client list:"); + + for (ALL_LIST_ELEMENTS_RO(rnh->client_list, node, client)) { + if (json) { + json_client = json_object_new_object(); + json_object_array_add(json_client_array, json_client); + + json_object_string_add( + json_client, "protocol", + zebra_route_string(client->proto)); + json_object_int_add(json_client, "socket", + client->sock); + json_object_string_add(json_client, "protocolFiltered", + (rnh->filtered[client->proto] + ? "(filtered)" + : "none")); + } else { + vty_out(vty, " %s(fd %d)%s", + zebra_route_string(client->proto), client->sock, + rnh->filtered[client->proto] ? "(filtered)" + : ""); + } + } + + if (!list_isempty(rnh->zebra_pseudowire_list)) { + if (json) + json_object_boolean_true_add(json_nht, + "zebraPseudowires"); + else + vty_out(vty, " zebra[pseudowires]"); + } - vty_out(vty, " Client list:"); - for (ALL_LIST_ELEMENTS_RO(rnh->client_list, node, client)) - vty_out(vty, " %s(fd %d)%s", zebra_route_string(client->proto), - client->sock, - rnh->filtered[client->proto] ? "(filtered)" : ""); - if (!list_isempty(rnh->zebra_pseudowire_list)) - vty_out(vty, " zebra[pseudowires]"); - vty_out(vty, "\n"); + if (!json) + vty_out(vty, "\n"); } static int zebra_cleanup_rnh_client(vrf_id_t vrf_id, afi_t afi, safi_t safi, diff --git a/zebra/zebra_rnh.h b/zebra/zebra_rnh.h index 70eda725c4..44ce65b4b6 100644 --- a/zebra/zebra_rnh.h +++ b/zebra/zebra_rnh.h @@ -46,7 +46,8 @@ extern void zebra_remove_rnh_client(struct rnh *rnh, struct zserv *client); extern void zebra_evaluate_rnh(struct zebra_vrf *zvrf, afi_t afi, int force, const struct prefix *p, safi_t safi); extern void zebra_print_rnh_table(vrf_id_t vrfid, afi_t afi, safi_t safi, - struct vty *vty, const struct prefix *p); + struct vty *vty, const struct prefix *p, + json_object *json); extern int rnh_resolve_via_default(struct zebra_vrf *zvrf, int family); diff --git a/zebra/zebra_srv6_vty.c b/zebra/zebra_srv6_vty.c index 1221365d4d..13ad9d71bb 100644 --- a/zebra/zebra_srv6_vty.c +++ b/zebra/zebra_srv6_vty.c @@ -276,16 +276,16 @@ DEFUN (no_srv6_locator, DEFPY (locator_prefix, locator_prefix_cmd, - "prefix X:X::X:X/M$prefix [func-bits (0-64)$func_bit_len] \ - [block-len (16-64)$block_bit_len] [node-len (16-64)$node_bit_len]", + "prefix X:X::X:X/M$prefix [block-len (16-64)$block_bit_len] \ + [node-len (16-64)$node_bit_len] [func-bits (0-64)$func_bit_len]", "Configure SRv6 locator prefix\n" "Specify SRv6 locator prefix\n" - "Configure SRv6 locator function length in bits\n" - "Specify SRv6 locator function length in bits\n" "Configure SRv6 locator block length in bits\n" "Specify SRv6 locator block length in bits\n" "Configure SRv6 locator node length in bits\n" - "Specify SRv6 locator node length in bits\n") + "Specify SRv6 locator node length in bits\n" + "Configure SRv6 locator function length in bits\n" + "Specify SRv6 locator function length in bits\n") { VTY_DECLVAR_CONTEXT(srv6_locator, locator); struct srv6_locator_chunk *chunk = NULL; diff --git a/zebra/zebra_trace.h b/zebra/zebra_trace.h index 49a0c8e793..374305fcda 100644 --- a/zebra/zebra_trace.h +++ b/zebra/zebra_trace.h @@ -123,6 +123,49 @@ TRACEPOINT_EVENT( ) ) +TRACEPOINT_EVENT( + frr_zebra, + netlink_tc_qdisc_change, + TP_ARGS( + struct nlmsghdr *, header, + ns_id_t, ns_id, + int, startup), + TP_FIELDS( + ctf_integer_hex(intptr_t, header, header) + ctf_integer(uint32_t, ns_id, ns_id) + ctf_integer(uint32_t, startup, startup) + ) + ) + +TRACEPOINT_EVENT( + frr_zebra, + netlink_tc_class_change, + TP_ARGS( + struct nlmsghdr *, header, + ns_id_t, ns_id, + int, startup), + TP_FIELDS( + ctf_integer_hex(intptr_t, header, header) + ctf_integer(uint32_t, ns_id, ns_id) + ctf_integer(uint32_t, startup, startup) + ) + ) + + +TRACEPOINT_EVENT( + frr_zebra, + netlink_tc_filter_change, + TP_ARGS( + struct nlmsghdr *, header, + ns_id_t, ns_id, + int, startup), + TP_FIELDS( + ctf_integer_hex(intptr_t, header, header) + ctf_integer(uint32_t, ns_id, ns_id) + ctf_integer(uint32_t, startup, startup) + ) + ) + #include <lttng/tracepoint-event.h> #endif /* HAVE_LTTNG */ diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 6561ac95fa..91a0c1dd31 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -1370,7 +1370,7 @@ static int do_show_ip_route(struct vty *vty, const char *vrf_name, afi_t afi, DEFPY (show_ip_nht, show_ip_nht_cmd, - "show <ip$ipv4|ipv6$ipv6> <nht|import-check>$type [<A.B.C.D|X:X::X:X>$addr|vrf NAME$vrf_name [<A.B.C.D|X:X::X:X>$addr]|vrf all$vrf_all] [mrib$mrib]", + "show <ip$ipv4|ipv6$ipv6> <nht|import-check>$type [<A.B.C.D|X:X::X:X>$addr|vrf NAME$vrf_name [<A.B.C.D|X:X::X:X>$addr]|vrf all$vrf_all] [mrib$mrib] [json]", SHOW_STR IP_STR IP6_STR @@ -1382,23 +1382,48 @@ DEFPY (show_ip_nht, "IPv4 Address\n" "IPv6 Address\n" VRF_ALL_CMD_HELP_STR - "Show Multicast (MRIB) NHT state\n") + "Show Multicast (MRIB) NHT state\n" + JSON_STR) { afi_t afi = ipv4 ? AFI_IP : AFI_IP6; vrf_id_t vrf_id = VRF_DEFAULT; struct prefix prefix, *p = NULL; safi_t safi = mrib ? SAFI_MULTICAST : SAFI_UNICAST; + bool uj = use_json(argc, argv); + json_object *json = NULL; + json_object *json_vrf = NULL; + json_object *json_nexthop = NULL; + + if (uj) + json = json_object_new_object(); if (vrf_all) { struct vrf *vrf; struct zebra_vrf *zvrf; - RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) + RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { if ((zvrf = vrf->info) != NULL) { - vty_out(vty, "\nVRF %s:\n", zvrf_name(zvrf)); + if (uj) { + json_vrf = json_object_new_object(); + json_nexthop = json_object_new_object(); + json_object_object_add(json, + zvrf_name(zvrf), + json_vrf); + json_object_object_add(json_vrf, + "nexthops", + json_nexthop); + } else { + vty_out(vty, "\nVRF %s:\n", + zvrf_name(zvrf)); + } zebra_print_rnh_table(zvrf_id(zvrf), afi, safi, - vty, NULL); + vty, NULL, json_nexthop); } + } + + if (uj) + vty_json(vty, json); + return CMD_SUCCESS; } if (vrf_name) @@ -1407,11 +1432,29 @@ DEFPY (show_ip_nht, memset(&prefix, 0, sizeof(prefix)); if (addr) { p = sockunion2hostprefix(addr, &prefix); - if (!p) + if (!p) { + if (uj) + json_object_free(json); return CMD_WARNING; + } } - zebra_print_rnh_table(vrf_id, afi, safi, vty, p); + if (uj) { + json_vrf = json_object_new_object(); + json_nexthop = json_object_new_object(); + if (vrf_name) + json_object_object_add(json, vrf_name, json_vrf); + else + json_object_object_add(json, "default", json_vrf); + + json_object_object_add(json_vrf, "nexthops", json_nexthop); + } + + zebra_print_rnh_table(vrf_id, afi, safi, vty, p, json_nexthop); + + if (uj) + vty_json(vty, json); + return CMD_SUCCESS; } |
