diff options
| author | David Lamparter <equinox@diac24.net> | 2019-05-15 21:32:50 +0200 |
|---|---|---|
| committer | David Lamparter <equinox@diac24.net> | 2019-05-15 21:32:50 +0200 |
| commit | cd4f050587c444509ec286247f95606fe6f7f756 (patch) | |
| tree | db21369925a50a674b5fa2426737c45209a031d5 | |
| parent | 0189e6d73cdbabf2b320b40248d75db1791d7424 (diff) | |
| parent | 33e56da60666cd26ca18787104e721b9df9ed4a2 (diff) | |
Merge tag 'frr-6.0.3' into debian/master
FRRouting Release 6.0.3
62 files changed, 1107 insertions, 922 deletions
diff --git a/Makefile.am b/Makefile.am index 5be32649fa..bcf6ac0edc 100644 --- a/Makefile.am +++ b/Makefile.am @@ -165,9 +165,6 @@ EXTRA_DIST += \ python/clidef.py \ python/clippy/__init__.py \ \ - redhat/frr.init \ - redhat/frr.service \ - redhat/daemons \ redhat/frr.logrotate \ redhat/frr.pam \ redhat/frr.spec \ diff --git a/bfdd/bfd.c b/bfdd/bfd.c index 66c781c290..d6e0230d2d 100644 --- a/bfdd/bfd.c +++ b/bfdd/bfd.c @@ -817,10 +817,10 @@ void integer2timestr(uint64_t time, char *buf, size_t buflen) int rv; #define MINUTES (60) -#define HOURS (24 * MINUTES) -#define DAYS (30 * HOURS) -#define MONTHS (12 * DAYS) -#define YEARS (MONTHS) +#define HOURS (60 * MINUTES) +#define DAYS (24 * HOURS) +#define MONTHS (30 * DAYS) +#define YEARS (12 * MONTHS) if (time >= YEARS) { year = time / YEARS; time -= year * YEARS; diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c index b532927e80..49e43c39e2 100644 --- a/bgpd/bgp_aspath.c +++ b/bgpd/bgp_aspath.c @@ -1380,39 +1380,45 @@ static struct aspath *aspath_merge(struct aspath *as1, struct aspath *as2) /* Prepend as1 to as2. as2 should be uninterned aspath. */ struct aspath *aspath_prepend(struct aspath *as1, struct aspath *as2) { - struct assegment *seg1; - struct assegment *seg2; + struct assegment *as1segtail; + struct assegment *as2segtail; + struct assegment *as2seghead; if (!as1 || !as2) return NULL; - seg1 = as1->segments; - seg2 = as2->segments; - /* If as2 is empty, only need to dupe as1's chain onto as2 */ - if (seg2 == NULL) { + if (as2->segments == NULL) { as2->segments = assegment_dup_all(as1->segments); aspath_str_update(as2, false); return as2; } /* If as1 is empty AS, no prepending to do. */ - if (seg1 == NULL) + if (as1->segments == NULL) return as2; /* find the tail as1's segment chain. */ - while (seg1 && seg1->next) - seg1 = seg1->next; + as1segtail = as1->segments; + while (as1segtail && as1segtail->next) + as1segtail = as1segtail->next; /* Delete any AS_CONFED_SEQUENCE segment from as2. */ - if (seg1->type == AS_SEQUENCE && seg2->type == AS_CONFED_SEQUENCE) + if (as1segtail->type == AS_SEQUENCE + && as2->segments->type == AS_CONFED_SEQUENCE) as2 = aspath_delete_confed_seq(as2); + if (!as2->segments) { + as2->segments = assegment_dup_all(as1->segments); + aspath_str_update(as2, false); + return as2; + } + /* Compare last segment type of as1 and first segment type of as2. */ - if (seg1->type != seg2->type) + if (as1segtail->type != as2->segments->type) return aspath_merge(as1, as2); - if (seg1->type == AS_SEQUENCE) { + if (as1segtail->type == AS_SEQUENCE) { /* We have two chains of segments, as1->segments and seg2, * and we have to attach them together, merging the attaching * segments together into one. @@ -1422,23 +1428,28 @@ struct aspath *aspath_prepend(struct aspath *as1, struct aspath *as2) * 3. attach chain after seg2 */ + /* save as2 head */ + as2seghead = as2->segments; + /* dupe as1 onto as2's head */ - seg1 = as2->segments = assegment_dup_all(as1->segments); + as2segtail = as2->segments = assegment_dup_all(as1->segments); - /* refind the tail of as2, reusing seg1 */ - while (seg1 && seg1->next) - seg1 = seg1->next; + /* refind the tail of as2 */ + while (as2segtail && as2segtail->next) + as2segtail = as2segtail->next; /* merge the old head, seg2, into tail, seg1 */ - seg1 = assegment_append_asns(seg1, seg2->as, seg2->length); + assegment_append_asns(as2segtail, as2seghead->as, + as2seghead->length); - /* bypass the merged seg2, and attach any chain after it to - * chain descending from as2's head + /* + * bypass the merged seg2, and attach any chain after it + * to chain descending from as2's head */ - seg1->next = seg2->next; + as2segtail->next = as2seghead->next; - /* seg2 is now referenceless and useless*/ - assegment_free(seg2); + /* as2->segments is now referenceless and useless */ + assegment_free(as2seghead); /* we've now prepended as1's segment chain to as2, merging * the inbetween AS_SEQUENCE of seg2 in the process diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 640c3bdb7a..a8eab9cfec 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -3001,6 +3001,22 @@ void bgp_packet_mpattr_end(struct stream *s, size_t sizep) stream_putw_at(s, sizep, (stream_get_endp(s) - sizep) - 2); } +static int bgp_append_local_as(struct peer *peer, afi_t afi, safi_t safi) +{ + if (!BGP_AS_IS_PRIVATE(peer->local_as) + || (BGP_AS_IS_PRIVATE(peer->local_as) + && !CHECK_FLAG(peer->af_flags[afi][safi], + PEER_FLAG_REMOVE_PRIVATE_AS) + && !CHECK_FLAG(peer->af_flags[afi][safi], + PEER_FLAG_REMOVE_PRIVATE_AS_ALL) + && !CHECK_FLAG(peer->af_flags[afi][safi], + PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE) + && !CHECK_FLAG(peer->af_flags[afi][safi], + PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE))) + return 1; + return 0; +} + /* Make attribute packet. */ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer, struct stream *s, struct attr *attr, @@ -3066,12 +3082,12 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer, /* If replace-as is specified, we only use the change_local_as when advertising routes. */ - if (!CHECK_FLAG( - peer->flags, - PEER_FLAG_LOCAL_AS_REPLACE_AS)) { - aspath = aspath_add_seq(aspath, - peer->local_as); - } + if (!CHECK_FLAG(peer->flags, + PEER_FLAG_LOCAL_AS_REPLACE_AS)) + if (bgp_append_local_as(peer, afi, + safi)) + aspath = aspath_add_seq( + aspath, peer->local_as); aspath = aspath_add_seq(aspath, peer->change_local_as); } else { diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index 7ee920aba8..4810b73bc7 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -4694,7 +4694,7 @@ int bgp_nlri_parse_evpn(struct peer *peer, struct attr *attr, if (addpath_encoded) { /* When packet overflow occurs return immediately. */ if (pnt + BGP_ADDPATH_ID_LEN > lim) - return -1; + return BGP_NLRI_PARSE_ERROR_PACKET_OVERFLOW; addpath_id = ntohl(*((uint32_t *)pnt)); pnt += BGP_ADDPATH_ID_LEN; @@ -4702,14 +4702,14 @@ int bgp_nlri_parse_evpn(struct peer *peer, struct attr *attr, /* All EVPN NLRI types start with type and length. */ if (pnt + 2 > lim) - return -1; + return BGP_NLRI_PARSE_ERROR_EVPN_MISSING_TYPE; rtype = *pnt++; psize = *pnt++; /* When packet overflow occur return immediately. */ if (pnt + psize > lim) - return -1; + return BGP_NLRI_PARSE_ERROR_PACKET_OVERFLOW; switch (rtype) { case BGP_EVPN_MAC_IP_ROUTE: @@ -4720,7 +4720,7 @@ int bgp_nlri_parse_evpn(struct peer *peer, struct attr *attr, BGP_ERR_EVPN_FAIL, "%u:%s - Error in processing EVPN type-2 NLRI size %d", peer->bgp->vrf_id, peer->host, psize); - return -1; + return BGP_NLRI_PARSE_ERROR_EVPN_TYPE2_SIZE; } break; @@ -4732,7 +4732,7 @@ int bgp_nlri_parse_evpn(struct peer *peer, struct attr *attr, BGP_ERR_PKT_PROCESS, "%u:%s - Error in processing EVPN type-3 NLRI size %d", peer->bgp->vrf_id, peer->host, psize); - return -1; + return BGP_NLRI_PARSE_ERROR_EVPN_TYPE3_SIZE; } break; @@ -4744,7 +4744,7 @@ int bgp_nlri_parse_evpn(struct peer *peer, struct attr *attr, BGP_ERR_PKT_PROCESS, "%u:%s - Error in processing EVPN type-4 NLRI size %d", peer->bgp->vrf_id, peer->host, psize); - return -1; + return BGP_NLRI_PARSE_ERROR_EVPN_TYPE4_SIZE; } break; @@ -4755,7 +4755,7 @@ int bgp_nlri_parse_evpn(struct peer *peer, struct attr *attr, BGP_ERR_PKT_PROCESS, "%u:%s - Error in processing EVPN type-5 NLRI size %d", peer->bgp->vrf_id, peer->host, psize); - return -1; + return BGP_NLRI_PARSE_ERROR_EVPN_TYPE5_SIZE; } break; @@ -4766,9 +4766,9 @@ int bgp_nlri_parse_evpn(struct peer *peer, struct attr *attr, /* Packet length consistency check. */ if (pnt != lim) - return -1; + return BGP_NLRI_PARSE_ERROR_PACKET_LENGTH; - return 0; + return BGP_NLRI_PARSE_OK; } /* diff --git a/bgpd/bgp_flowspec.c b/bgpd/bgp_flowspec.c index e29508bf36..418ad7c48a 100644 --- a/bgpd/bgp_flowspec.c +++ b/bgpd/bgp_flowspec.c @@ -106,14 +106,14 @@ int bgp_nlri_parse_flowspec(struct peer *peer, struct attr *attr, if (afi == AFI_IP6) { flog_err(LIB_ERR_DEVELOPMENT, "BGP flowspec IPv6 not supported"); - return -1; + return BGP_NLRI_PARSE_ERROR_FLOWSPEC_IPV6_NOT_SUPPORTED; } if (packet->length >= FLOWSPEC_NLRI_SIZELIMIT) { flog_err(BGP_ERR_FLOWSPEC_PACKET, "BGP flowspec nlri length maximum reached (%u)", packet->length); - return -1; + return BGP_NLRI_PARSE_ERROR_FLOWSPEC_NLRI_SIZELIMIT; } for (; pnt < lim; pnt += psize) { @@ -122,7 +122,7 @@ int bgp_nlri_parse_flowspec(struct peer *peer, struct attr *attr, /* All FlowSpec NLRI begin with length. */ if (pnt + 1 > lim) - return -1; + return BGP_NLRI_PARSE_ERROR_PACKET_OVERFLOW; psize = *pnt++; @@ -131,12 +131,12 @@ int bgp_nlri_parse_flowspec(struct peer *peer, struct attr *attr, flog_err(BGP_ERR_FLOWSPEC_PACKET, "Flowspec NLRI length inconsistent ( size %u seen)", psize); - return -1; + return BGP_NLRI_PARSE_ERROR_PACKET_OVERFLOW; } if (bgp_fs_nlri_validate(pnt, psize) < 0) { flog_err(BGP_ERR_FLOWSPEC_PACKET, "Bad flowspec format or NLRI options not supported"); - return -1; + return BGP_NLRI_PARSE_ERROR_FLOWSPEC_BAD_FORMAT; } p.family = AF_FLOWSPEC; p.prefixlen = 0; @@ -191,8 +191,8 @@ int bgp_nlri_parse_flowspec(struct peer *peer, struct attr *attr, flog_err(BGP_ERR_FLOWSPEC_INSTALLATION, "Flowspec NLRI failed to be %s.", attr ? "added" : "withdrawn"); - return -1; + return BGP_NLRI_PARSE_ERROR; } } - return 0; + return BGP_NLRI_PARSE_OK; } diff --git a/bgpd/bgp_label.c b/bgpd/bgp_label.c index 633e589333..a93cafcb25 100644 --- a/bgpd/bgp_label.c +++ b/bgpd/bgp_label.c @@ -232,7 +232,7 @@ int bgp_nlri_parse_label(struct peer *peer, struct attr *attr, /* When packet overflow occurs return immediately. */ if (pnt + BGP_ADDPATH_ID_LEN > lim) - return -1; + return BGP_NLRI_PARSE_ERROR_PACKET_OVERFLOW; addpath_id = ntohl(*((uint32_t *)pnt)); pnt += BGP_ADDPATH_ID_LEN; @@ -249,7 +249,7 @@ int bgp_nlri_parse_label(struct peer *peer, struct attr *attr, BGP_ERR_UPDATE_RCV, "%s [Error] Update packet error / L-U (prefix length %d exceeds packet size %u)", peer->host, prefixlen, (uint)(lim - pnt)); - return -1; + return BGP_NLRI_PARSE_ERROR_PACKET_OVERFLOW; } /* Fill in the labels */ @@ -264,12 +264,12 @@ int bgp_nlri_parse_label(struct peer *peer, struct attr *attr, peer->host, prefixlen); bgp_notify_send(peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_INVAL_NETWORK); - return -1; + return BGP_NLRI_PARSE_ERROR_LABEL_LENGTH; } if ((afi == AFI_IP && p.prefixlen > 32) || (afi == AFI_IP6 && p.prefixlen > 128)) - return -1; + return BGP_NLRI_PARSE_ERROR_PREFIX_LENGTH; /* Fetch prefix from NLRI packet */ memcpy(&p.u.prefix, pnt + llen, psize - llen); @@ -340,8 +340,8 @@ int bgp_nlri_parse_label(struct peer *peer, struct attr *attr, BGP_ERR_UPDATE_RCV, "%s [Error] Update packet error / L-U (%zu data remaining after parsing)", peer->host, lim - pnt); - return -1; + return BGP_NLRI_PARSE_ERROR_PACKET_LENGTH; } - return 0; + return BGP_NLRI_PARSE_OK; } diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index b89edfe459..4fff2faa7e 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -139,7 +139,7 @@ int bgp_nlri_parse_vpn(struct peer *peer, struct attr *attr, /* When packet overflow occurs return immediately. */ if (pnt + BGP_ADDPATH_ID_LEN > lim) - return -1; + return BGP_NLRI_PARSE_ERROR_PACKET_OVERFLOW; addpath_id = ntohl(*((uint32_t *)pnt)); pnt += BGP_ADDPATH_ID_LEN; @@ -155,7 +155,7 @@ int bgp_nlri_parse_vpn(struct peer *peer, struct attr *attr, BGP_ERR_UPDATE_RCV, "%s [Error] Update packet error / VPN (prefix length %d less than VPN min length)", peer->host, prefixlen); - return -1; + return BGP_NLRI_PARSE_ERROR_PREFIX_LENGTH; } /* sanity check against packet data */ @@ -164,7 +164,7 @@ int bgp_nlri_parse_vpn(struct peer *peer, struct attr *attr, BGP_ERR_UPDATE_RCV, "%s [Error] Update packet error / VPN (prefix length %d exceeds packet size %u)", peer->host, prefixlen, (uint)(lim - pnt)); - return -1; + return BGP_NLRI_PARSE_ERROR_PACKET_OVERFLOW; } /* sanity check against storage for the IP address portion */ @@ -175,7 +175,7 @@ int bgp_nlri_parse_vpn(struct peer *peer, struct attr *attr, peer->host, prefixlen - VPN_PREFIXLEN_MIN_BYTES * 8, sizeof(p.u)); - return -1; + return BGP_NLRI_PARSE_ERROR_PACKET_LENGTH; } /* Sanity check against max bitlen of the address family */ @@ -186,7 +186,7 @@ int bgp_nlri_parse_vpn(struct peer *peer, struct attr *attr, peer->host, prefixlen - VPN_PREFIXLEN_MIN_BYTES * 8, p.family, prefix_blen(&p)); - return -1; + return BGP_NLRI_PARSE_ERROR_PACKET_LENGTH; } /* Copy label to prefix. */ @@ -245,7 +245,7 @@ int bgp_nlri_parse_vpn(struct peer *peer, struct attr *attr, BGP_ERR_UPDATE_RCV, "%s [Error] Update packet error / VPN (%zu data remaining after parsing)", peer->host, lim - pnt); - return -1; + return BGP_NLRI_PARSE_ERROR_PACKET_LENGTH; } return 0; diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 6cbb2ec068..8c709f57f2 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -308,7 +308,7 @@ int bgp_nlri_parse(struct peer *peer, struct attr *attr, case SAFI_FLOWSPEC: return bgp_nlri_parse_flowspec(peer, attr, packet, mp_withdraw); } - return -1; + return BGP_NLRI_PARSE_ERROR; } /* @@ -1568,10 +1568,11 @@ static int bgp_update_receive(struct peer *peer, bgp_size_t size) nlri_ret = bgp_nlri_parse(peer, &attr, &nlris[i], 1); break; default: - nlri_ret = -1; + nlri_ret = BGP_NLRI_PARSE_ERROR; } - if (nlri_ret < 0) { + if (nlri_ret < BGP_NLRI_PARSE_OK + && nlri_ret != BGP_NLRI_PARSE_ERROR_PREFIX_OVERFLOW) { flog_err(BGP_ERR_UPDATE_RCV, "%s [Error] Error parsing NLRI", peer->host); if (peer->status == Established) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 9fa0aaa4fd..fead5fe75f 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -4202,7 +4202,7 @@ int bgp_nlri_parse_ip(struct peer *peer, struct attr *attr, /* When packet overflow occurs return immediately. */ if (pnt + BGP_ADDPATH_ID_LEN > lim) - return -1; + return BGP_NLRI_PARSE_ERROR_PACKET_OVERFLOW; addpath_id = ntohl(*((uint32_t *)pnt)); pnt += BGP_ADDPATH_ID_LEN; @@ -4220,7 +4220,7 @@ int bgp_nlri_parse_ip(struct peer *peer, struct attr *attr, BGP_ERR_UPDATE_RCV, "%s [Error] Update packet error (wrong prefix length %d for afi %u)", peer->host, p.prefixlen, packet->afi); - return -1; + return BGP_NLRI_PARSE_ERROR_PREFIX_LENGTH; } /* Packet size overflow check. */ @@ -4232,7 +4232,7 @@ int bgp_nlri_parse_ip(struct peer *peer, struct attr *attr, BGP_ERR_UPDATE_RCV, "%s [Error] Update packet error (prefix length %d overflows packet)", peer->host, p.prefixlen); - return -1; + return BGP_NLRI_PARSE_ERROR_PACKET_OVERFLOW; } /* Defensive coding, double-check the psize fits in a struct @@ -4242,7 +4242,7 @@ int bgp_nlri_parse_ip(struct peer *peer, struct attr *attr, BGP_ERR_UPDATE_RCV, "%s [Error] Update packet error (prefix length %d too large for prefix storage %zu)", peer->host, p.prefixlen, sizeof(p.u)); - return -1; + return BGP_NLRI_PARSE_ERROR_PACKET_LENGTH; } /* Fetch prefix from NLRI packet. */ @@ -4307,10 +4307,14 @@ int bgp_nlri_parse_ip(struct peer *peer, struct attr *attr, BGP_ROUTE_NORMAL, NULL, NULL, 0, NULL); - /* Address family configuration mismatch or maximum-prefix count - overflow. */ + /* Do not send BGP notification twice when maximum-prefix count + * overflow. */ + if (CHECK_FLAG(peer->sflags, PEER_STATUS_PREFIX_OVERFLOW)) + return BGP_NLRI_PARSE_ERROR_PREFIX_OVERFLOW; + + /* Address family configuration mismatch. */ if (ret < 0) - return -1; + return BGP_NLRI_PARSE_ERROR_ADDRESS_FAMILY; } /* Packet length consistency check. */ @@ -4319,10 +4323,10 @@ int bgp_nlri_parse_ip(struct peer *peer, struct attr *attr, BGP_ERR_UPDATE_RCV, "%s [Error] Update packet error (prefix length mismatch with total length)", peer->host); - return -1; + return BGP_NLRI_PARSE_ERROR_PACKET_LENGTH; } - return 0; + return BGP_NLRI_PARSE_OK; } static struct bgp_static *bgp_static_new(void) @@ -10177,7 +10181,11 @@ static void show_adj_route(struct vty *vty, struct peer *peer, afi_t afi, return; } - table = bgp->rib[afi][safi]; + /* labeled-unicast routes live in the unicast table */ + if (safi == SAFI_LABELED_UNICAST) + table = bgp->rib[afi][SAFI_UNICAST]; + else + table = bgp->rib[afi][safi]; output_count = filtered_count = 0; subgrp = peer_subgroup(peer, afi, safi); @@ -10401,10 +10409,6 @@ static int peer_adj_routes(struct vty *vty, struct peer *peer, afi_t afi, if (use_json) json = json_object_new_object(); - /* labeled-unicast routes live in the unicast table */ - if (safi == SAFI_LABELED_UNICAST) - safi = SAFI_UNICAST; - if (!peer || !peer->afc[afi][safi]) { if (use_json) { json_object_string_add( diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index dfef9a8f79..534dd76215 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -72,6 +72,24 @@ enum bgp_show_adj_route_type { */ #define BGP_MAX_LABELS 2 +/* Error codes for handling NLRI */ +#define BGP_NLRI_PARSE_OK 0 +#define BGP_NLRI_PARSE_ERROR_PREFIX_OVERFLOW -1 +#define BGP_NLRI_PARSE_ERROR_PACKET_OVERFLOW -2 +#define BGP_NLRI_PARSE_ERROR_PREFIX_LENGTH -3 +#define BGP_NLRI_PARSE_ERROR_PACKET_LENGTH -4 +#define BGP_NLRI_PARSE_ERROR_LABEL_LENGTH -5 +#define BGP_NLRI_PARSE_ERROR_EVPN_MISSING_TYPE -6 +#define BGP_NLRI_PARSE_ERROR_EVPN_TYPE2_SIZE -7 +#define BGP_NLRI_PARSE_ERROR_EVPN_TYPE3_SIZE -8 +#define BGP_NLRI_PARSE_ERROR_EVPN_TYPE4_SIZE -9 +#define BGP_NLRI_PARSE_ERROR_EVPN_TYPE5_SIZE -10 +#define BGP_NLRI_PARSE_ERROR_FLOWSPEC_IPV6_NOT_SUPPORTED -11 +#define BGP_NLRI_PARSE_ERROR_FLOWSPEC_NLRI_SIZELIMIT -12 +#define BGP_NLRI_PARSE_ERROR_FLOWSPEC_BAD_FORMAT -13 +#define BGP_NLRI_PARSE_ERROR_ADDRESS_FAMILY -14 +#define BGP_NLRI_PARSE_ERROR -32 + /* Ancillary information to struct bgp_info, * used for uncommonly used data (aggregation, MPLS, etc.) * and lazily allocated to save memory. diff --git a/bgpd/bgp_rpki.c b/bgpd/bgp_rpki.c index 2e0bb1ae62..196d1449b7 100644 --- a/bgpd/bgp_rpki.c +++ b/bgpd/bgp_rpki.c @@ -1133,7 +1133,7 @@ DEFPY (no_rpki_cache, { struct cache *cache_p = find_cache(preference); - if (!cache) { + if (!cache_p) { vty_out(vty, "Could not find cache %ld\n", preference); return CMD_WARNING; } @@ -1189,9 +1189,23 @@ DEFUN (show_rpki_cache_server, struct cache *cache; for (ALL_LIST_ELEMENTS_RO(cache_list, cache_node, cache)) { - vty_out(vty, "host: %s port: %s\n", - cache->tr_config.tcp_config->host, - cache->tr_config.tcp_config->port); + if (cache->type == TCP) { + vty_out(vty, "host: %s port: %s\n", + cache->tr_config.tcp_config->host, + cache->tr_config.tcp_config->port); + + } else if (cache->type == SSH) { + vty_out(vty, + "host: %s port: %d username: %s " + "server_hostkey_path: %s client_privkey_path: %s\n", + cache->tr_config.ssh_config->host, + cache->tr_config.ssh_config->port, + cache->tr_config.ssh_config->username, + cache->tr_config.ssh_config + ->server_hostkey_path, + cache->tr_config.ssh_config + ->client_privkey_path); + } } return CMD_SUCCESS; diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index e54a873e15..bdac903b99 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -3834,6 +3834,13 @@ ALIAS_HIDDEN(neighbor_nexthop_self_force, "Disable the next hop calculation for this neighbor\n" "Set the next hop to self for reflected routes\n") +ALIAS_HIDDEN(neighbor_nexthop_self_force, + neighbor_nexthop_self_all_hidden_cmd, + "neighbor <A.B.C.D|X:X::X:X|WORD> next-hop-self all", + NEIGHBOR_STR NEIGHBOR_ADDR_STR2 + "Disable the next hop calculation for this neighbor\n" + "Set the next hop to self for reflected routes\n") + DEFUN (no_neighbor_nexthop_self, no_neighbor_nexthop_self_cmd, "no neighbor <A.B.C.D|X:X::X:X|WORD> next-hop-self", @@ -3875,6 +3882,13 @@ ALIAS_HIDDEN(no_neighbor_nexthop_self_force, "Disable the next hop calculation for this neighbor\n" "Set the next hop to self for reflected routes\n") +ALIAS_HIDDEN(no_neighbor_nexthop_self_force, + no_neighbor_nexthop_self_all_hidden_cmd, + "no neighbor <A.B.C.D|X:X::X:X|WORD> next-hop-self all", + NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 + "Disable the next hop calculation for this neighbor\n" + "Set the next hop to self for reflected routes\n") + /* neighbor as-override */ DEFUN (neighbor_as_override, neighbor_as_override_cmd, @@ -7838,7 +7852,7 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi, json, "ribMemory", ents * sizeof(struct bgp_node)); - ents = listcount(bgp->peer); + ents = bgp->af_peer_count[afi][safi]; json_object_int_add(json, "peerCount", ents); json_object_int_add(json, "peerMemory", ents * sizeof(struct peer)); @@ -7878,7 +7892,7 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi, bgp_node))); /* Peer related usage */ - ents = listcount(bgp->peer); + ents = bgp->af_peer_count[afi][safi]; vty_out(vty, "Peers %ld, using %s of memory\n", ents, mtype_memstr( @@ -8296,7 +8310,7 @@ const char *afi_safi_json(afi_t afi, safi_t safi) } /* Show BGP peer's information. */ -enum show_type { show_all, show_peer }; +enum show_type { show_all, show_peer, show_ipv4_all, show_ipv6_all, show_ipv4_peer, show_ipv6_peer }; static void bgp_show_peer_afi_orf_cap(struct vty *vty, struct peer *p, afi_t afi, safi_t safi, @@ -9001,7 +9015,7 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, uint8_t use_json, } else { if ((p->as_type == AS_SPECIFIED) || (p->as_type == AS_EXTERNAL) || (p->as_type == AS_INTERNAL)) - vty_out(vty, "remote AS %u, ", p->as); + vty_out(vty, "remote AS %" PRIu32 ", ", p->as); else vty_out(vty, "remote AS Unspecified, "); vty_out(vty, "local AS %u%s%s, ", @@ -10690,6 +10704,14 @@ static int bgp_show_neighbor(struct vty *vty, struct bgp *bgp, struct listnode *node, *nnode; struct peer *peer; int find = 0; + afi_t afi = AFI_MAX; + safi_t safi = SAFI_MAX; + + if (type == show_ipv4_peer || type == show_ipv4_all) { + afi = AFI_IP; + } else if (type == show_ipv6_peer || type == show_ipv6_all) { + afi = AFI_IP6; + } for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { if (!CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE)) @@ -10717,10 +10739,45 @@ static int bgp_show_neighbor(struct vty *vty, struct bgp *bgp, } } break; + case show_ipv4_peer: + case show_ipv6_peer: + FOREACH_SAFI (safi) { + if (peer->afc[afi][safi]) { + if (conf_if) { + if ((peer->conf_if + && !strcmp(peer->conf_if, conf_if)) + || (peer->hostname + && !strcmp(peer->hostname, conf_if))) { + find = 1; + bgp_show_peer(vty, peer, use_json, + json); + break; + } + } else { + if (sockunion_same(&peer->su, su)) { + find = 1; + bgp_show_peer(vty, peer, use_json, + json); + break; + } + } + } + } + break; + case show_ipv4_all: + case show_ipv6_all: + FOREACH_SAFI (safi) { + if (peer->afc[afi][safi]) { + bgp_show_peer(vty, peer, use_json, json); + break; + } + } + break; } } - if (type == show_peer && !find) { + if ((type == show_peer || type == show_ipv4_peer || + type == show_ipv6_peer) && !find) { if (use_json) json_object_boolean_true_add(json, "bgpNoSuchNeighbor"); else @@ -10788,7 +10845,8 @@ static void bgp_show_all_instances_neighbors_vty(struct vty *vty, : bgp->name); } - if (type == show_peer) { + if (type == show_peer || type == show_ipv4_peer || + type == show_ipv6_peer) { ret = str2sockunion(ip_str, &su); if (ret < 0) bgp_show_neighbor(vty, bgp, type, NULL, ip_str, @@ -10797,7 +10855,7 @@ static void bgp_show_all_instances_neighbors_vty(struct vty *vty, bgp_show_neighbor(vty, bgp, type, &su, NULL, use_json, json); } else { - bgp_show_neighbor(vty, bgp, show_all, NULL, NULL, + bgp_show_neighbor(vty, bgp, type, NULL, NULL, use_json, json); } } @@ -10884,6 +10942,7 @@ DEFUN (show_ip_bgp_neighbors, char *vrf = NULL; char *sh_arg = NULL; enum show_type sh_type; + afi_t afi = AFI_MAX; uint8_t uj = use_json(argc, argv); @@ -10894,13 +10953,29 @@ DEFUN (show_ip_bgp_neighbors, vrf = argv[idx + 1]->arg; idx++; + + if (argv_find(argv, argc, "ipv4", &idx)) { + sh_type = show_ipv4_all; + afi = AFI_IP; + } else if (argv_find(argv, argc, "ipv6", &idx)) { + sh_type = show_ipv6_all; + afi = AFI_IP6; + } else { + sh_type = show_all; + } + if (argv_find(argv, argc, "A.B.C.D", &idx) || argv_find(argv, argc, "X:X::X:X", &idx) || argv_find(argv, argc, "WORD", &idx)) { sh_type = show_peer; sh_arg = argv[idx]->arg; - } else - sh_type = show_all; + } + + if (sh_type == show_peer && afi == AFI_IP) { + sh_type = show_ipv4_peer; + } else if (sh_type == show_peer && afi == AFI_IP6) { + sh_type = show_ipv6_peer; + } return bgp_show_neighbor_vty(vty, vrf, sh_type, sh_arg, uj); } @@ -11405,11 +11480,11 @@ static int bgp_show_one_peer_group(struct vty *vty, struct peer_group *group) conf = group->conf; if (conf->as_type == AS_SPECIFIED || conf->as_type == AS_EXTERNAL) { - vty_out(vty, "\nBGP peer-group %s, remote AS %d\n", group->name, - conf->as); + vty_out(vty, "\nBGP peer-group %s, remote AS %" PRIu32 "\n", + group->name, conf->as); } else if (conf->as_type == AS_INTERNAL) { - vty_out(vty, "\nBGP peer-group %s, remote AS %d\n", group->name, - group->bgp->as); + vty_out(vty, "\nBGP peer-group %s, remote AS %" PRIu32 "\n", + group->name, group->bgp->as); } else { vty_out(vty, "\nBGP peer-group %s\n", group->name); } @@ -12795,6 +12870,8 @@ void bgp_vty_init(void) /* "neighbor next-hop-self force" commands. */ install_element(BGP_NODE, &neighbor_nexthop_self_force_hidden_cmd); install_element(BGP_NODE, &no_neighbor_nexthop_self_force_hidden_cmd); + install_element(BGP_NODE, &neighbor_nexthop_self_all_hidden_cmd); + install_element(BGP_NODE, &no_neighbor_nexthop_self_all_hidden_cmd); install_element(BGP_IPV4_NODE, &neighbor_nexthop_self_force_cmd); install_element(BGP_IPV4_NODE, &no_neighbor_nexthop_self_force_cmd); install_element(BGP_IPV4M_NODE, &neighbor_nexthop_self_force_cmd); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index a82dd51cc8..94aadda3d6 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -671,6 +671,7 @@ struct peer_af *peer_af_create(struct peer *peer, afi_t afi, safi_t safi) { struct peer_af *af; int afid; + struct bgp *bgp; if (!peer) return NULL; @@ -679,6 +680,7 @@ struct peer_af *peer_af_create(struct peer *peer, afi_t afi, safi_t safi) if (afid >= BGP_AF_MAX) return NULL; + bgp = peer->bgp; assert(peer->peer_af_array[afid] == NULL); /* Allocate new peer af */ @@ -689,6 +691,7 @@ struct peer_af *peer_af_create(struct peer *peer, afi_t afi, safi_t safi) af->safi = safi; af->afid = afid; af->peer = peer; + bgp->af_peer_count[afi][safi]++; return af; } @@ -711,6 +714,7 @@ int peer_af_delete(struct peer *peer, afi_t afi, safi_t safi) { struct peer_af *af; int afid; + struct bgp *bgp; if (!peer) return -1; @@ -723,6 +727,7 @@ int peer_af_delete(struct peer *peer, afi_t afi, safi_t safi) if (!af) return -1; + bgp = peer->bgp; bgp_stop_announce_route_timer(af); if (PAF_SUBGRP(af)) { @@ -734,6 +739,9 @@ int peer_af_delete(struct peer *peer, afi_t afi, safi_t safi) update_subgroup_remove_peer(af->subgroup, af); + if (bgp->af_peer_count[afi][safi]) + bgp->af_peer_count[afi][safi]--; + peer->peer_af_array[afid] = NULL; XFREE(MTYPE_BGP_PEER_AF, af); return 0; @@ -3660,6 +3668,7 @@ static const struct peer_flag_action peer_flag_action_list[] = { {PEER_FLAG_DISABLE_CONNECTED_CHECK, 0, peer_change_reset}, {PEER_FLAG_CAPABILITY_ENHE, 0, peer_change_reset}, {PEER_FLAG_ENFORCE_FIRST_AS, 0, peer_change_reset_in}, + {PEER_FLAG_IFPEER_V6ONLY, 0, peer_change_reset}, {PEER_FLAG_ROUTEADV, 0, peer_change_none}, {PEER_FLAG_TIMER, 0, peer_change_none}, {PEER_FLAG_TIMER_CONNECT, 0, peer_change_none}, diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index fd2157ab9c..a6f0e92da3 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -97,6 +97,9 @@ enum bgp_af_index { for (afi = AFI_IP; afi < AFI_MAX; afi++) \ for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) +#define FOREACH_SAFI(safi) \ + for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) + /* BGP master for system wide configurations and variables. */ struct bgp_master { /* BGP instance list. */ @@ -370,6 +373,9 @@ struct bgp { #define BGP_CONFIG_VRF_TO_VRF_EXPORT (1 << 8) #define BGP_DEFAULT_NAME "default" + /* BGP per AF peer count */ + uint32_t af_peer_count[AFI_MAX][SAFI_MAX]; + /* Route table for next-hop lookup cache. */ struct bgp_table *nexthop_cache_table[AFI_MAX]; diff --git a/changelog-auto.in b/changelog-auto.in index 73ba179c3a..27907e1dcd 100644 --- a/changelog-auto.in +++ b/changelog-auto.in @@ -6,6 +6,29 @@ frr (@VERSION@-0) UNRELEASED; urgency=medium -- FRRouting-Dev <dev@lists.frrouting.org> Thu, 25 Oct 2018 16:36:50 +0200 +frr (6.0-3) testing; urgency=medium + + * bgpd: Fix 'show bgp ipv4/ipv6 neighbors' to show only v4 or v6 neighbors + * bgpd: Fix display issue when showing labeled-unicast routes + * bgpd: Fix incorrect # peers in 'show bgp ipv6 summary' output + * bgpd: Fix issue with remote-private-as in combination with local-as + * bgpd: Fix memory error when prepending to AS-path + * bgpd: Improve error handling when using maximum-prefix + * ldpd: Fix startup permissions error on OpenBSD + * ldpd: add support for FreeBSD IP_BINDANY + * ospfd: Fix incorrect display of millisecond time values + * tools: Fix incorrect systemd dependencies causing failure to start on boot + * vtysh: Fix unnecessary reconnection under multi-instance OSPF + * watchfrr: Fix multi-instance support when using new init script + * zebra: Fix a display bug in 'show ip route ... json' + * zebra: Fix compilation issue on OpenBSD + * zebra: Fix issue with missed selection of system-sourced routes + * zebra: Fix race condition in label manager + * zebra: Reliability improvements to pseudowire route recovery + * zebra: Tweak metric values for macvlan devices + + -- Quentin Young <qlyoung@cumulusnetworks.com> Tue, 7 May 2019 16:31:00 -0500 + frr (6.0-2) testing; urgency=medium * add install-info to build deps diff --git a/configure.ac b/configure.ac index 72747550dd..ef76b5b209 100755 --- a/configure.ac +++ b/configure.ac @@ -7,7 +7,7 @@ ## AC_PREREQ(2.60) -AC_INIT(frr, 6.0.2, [https://github.com/frrouting/frr/issues]) +AC_INIT(frr, 6.0.3, [https://github.com/frrouting/frr/issues]) PACKAGE_URL="https://frrouting.org/" AC_SUBST(PACKAGE_URL) PACKAGE_FULLNAME="FRRouting" @@ -1974,6 +1974,7 @@ AC_SUBST(CFG_SBIN) AC_SUBST(CFG_STATE) AC_SUBST(CFG_MODULE) AC_DEFINE_UNQUOTED(MODULE_PATH, "$CFG_MODULE", path to modules) +AC_DEFINE_UNQUOTED(WATCHFRR_SH_PATH, "${CFG_SBIN%/}/watchfrr.sh", path to watchfrr.sh) dnl ------------------------------------ dnl Enable RPKI and add librtr to libs diff --git a/doc/developer/_static/overrides.css b/doc/developer/_static/overrides.css index 0d871c961a..1d702bb6e9 100644 --- a/doc/developer/_static/overrides.css +++ b/doc/developer/_static/overrides.css @@ -3,6 +3,237 @@ div.body { max-width: none; } +/* Palette URL: http://paletton.com/#uid=70p0p0kt6uvcDRAlhBavokxLJ6w */ + +:root { +--primary-0: #F36F16; /* Main Primary color */ +--primary-1: #FFC39A; +--primary-2: #FF9A55; +--primary-3: #A34403; +--primary-4: #341500; +--primary-9: #FFF3EB; + +--secondary-1-0: #F39C16; /* Main Secondary color (1) */ +--secondary-1-1: #FFD79A; +--secondary-1-2: #FFBC55; +--secondary-1-3: #A36403; +--secondary-1-4: #341F00; +--secondary-1-9: #FFF7EB; + +--secondary-2-0: #1A599F; /* Main Secondary color (2) */ +--secondary-2-1: #92B9E5; +--secondary-2-2: #477CB8; +--secondary-2-3: #0A386B; +--secondary-2-4: #011122; +--secondary-2-9: #E3EBF4; + +--complement-0: #0E9A83; /* Main Complement color */ +--complement-1: #8AE4D4; +--complement-2: #3CB4A0; +--complement-3: #026857; +--complement-4: #00211B; +--complement-9: #E0F4F0; +} + +/* new */ + +body { + font-family: "Fira Sans", Helvetica, Arial, sans-serif; + font-weight:400; +} +h1, h2, h3, h4, h5, h6 { + font-family: "Fira Sans", Helvetica, Arial, sans-serif; + font-weight:500; +} +code, pre, tt { + font-family: "Fira Mono"; +} +h1 { + background-color:var(--secondary-1-1); + border-bottom:1px solid var(--secondary-1-0); + font-weight:300; +} +h2 { + margin-top:36pt; +} + +a, +a:hover, +a:visited, +.code-block-caption a.headerlink:hover, +.rst-content dl:not(.docutils) dt .headerlink { + color: var(--complement-0); +} +.code-block-caption a.headerlink { + visibility:hidden; +} + +/* admonitions */ + +.admonition.warning { + border:1px dashed var(--primary-2); +} +.admonition.warning .admonition-title { + color: var(--primary-3); + background-color: var(--primary-1); +} +.admonition.note, +.admonition.hint { + border:1px dashed var(--complement-2); +} +.admonition.note .admonition-title, +.admonition.hint .admonition-title { + color: var(--complement-3); + background-color: var(--complement-1); +} +.admonition.seealso, +div.seealso { + background-color:var(--complement-9); +} +.admonition.seealso .admonition-title { + color: var(--complement-3); + background-color:var(--complement-1); + border-bottom:1px solid var(--complement-2); +} +.admonition.admonition-todo .admonition-title { + background-image: repeating-linear-gradient( + 135deg, + #ffa, + #ffa 14.14213452px, + #bbb 14.14213452px, + #bbb 28.28427124px + ); + color:#000; +} +.admonition.admonition-todo { + background-image: repeating-linear-gradient( + 135deg, + #ffd, + #ffd 14.14213452px, + #eed 14.14213452px, + #eed 28.28427124px + ); +} + +.rst-content dl .admonition p.last { + margin-bottom:0 !important; +} + +/* file block */ + +.code-block-caption { +/* border-radius: 4px; */ + font-style:italic; + font-weight:300; + border-bottom: 1px solid var(--secondary-2-1); + background-color: var(--secondary-2-9); + padding:2px 8px; +} + +/* navbar */ + +.wy-nav-side { + background-color: var(--secondary-1-4); + border-right:2px solid var(--primary-3); +} +.wy-menu-vertical a, +.wy-menu-vertical a:visited, +.wy-menu-vertical a:hover, +.wy-side-nav-search>a, +.wy-side-nav-search .wy-dropdown>a { + color: var(--primary-0); +} + +nav div.wy-side-nav-search { + background-color: #eee; +} +nav div.wy-side-scroll { + background-color: var(--secondary-1-4); +} +nav .wy-menu-vertical a:hover { + background-color:var(--primary-0); + color:var(--primary-4); +} +nav .wy-menu-vertical li.current ul a:hover { + background-color:var(--secondary-1-2); + color:var(--primary-4); +} +nav .wy-menu-vertical li.current ul a { + background-color:var(--secondary-1-1); + color:var(--primary-3); +} +nav .wy-menu-vertical li.on a:hover, +nav .wy-menu-vertical li.current>a:hover { + background-color:#fcfcfc; +} +.wy-side-nav-search input[type=text] { + border-color:var(--primary-2); +} +.wy-menu-vertical li.toctree-l1.current>a { + border-top:1px solid var(--secondary-1-3); + border-bottom:1px solid var(--secondary-1-3); +} +.wy-menu-vertical li.toctree-l2.current>a { + background-color:var(--secondary-1-2); +} +.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a { + background-color:var(--secondary-1-9); +} + +.wy-nav-content { + padding: 25pt 40pt; +} +div[role=navigation] > hr { + display:none; +} +div[role=navigation] { + margin-bottom:15pt; +} +h1 { + margin-left:-40pt; + margin-right:-40pt; + padding:5pt 40pt 5pt 40pt; +} + +.rst-content pre.literal-block, .rst-content div[class^='highlight'] { + border-color:var(--secondary-1-1); +} + +span.pre { + color: var(--complement-3); +} pre { - background-color: #e2e2e2; + background-color: var(--secondary-1-9); + border-color: var(--secondary-1-1); +} +.highlight .p { color: var(--secondary-2-3); } +.highlight .k { color: var(--secondary-2-0); } +.highlight .kt { color: var(--complement-0); } +.highlight .cm { color: var(--primary-3); } +.highlight .ow { color: var(--primary-3); } +.highlight .na { color: var(--primary-2); } +.highlight .nv { color: var(--complement-0); } + +strong { + font-weight:500; +} +.rst-content dl:not(.docutils) dt { + font-family:Fira Mono; + font-weight:600; + background-color:var(--secondary-2-9); + color:var(--secondary-2-3); + border-top:2px solid var(--secondary-2-2); +} +dt code.descname { + color: var(--secondary-2-4); +} + +@media (min-width: 1200px) { + .container { width: auto; } +} +@media (min-width: 992px) { + .container { width: auto; } +} +@media (min-width: 768px) { + .container { width: auto; } } diff --git a/doc/developer/conf.py b/doc/developer/conf.py index 61253c4b2f..6a339480fa 100644 --- a/doc/developer/conf.py +++ b/doc/developer/conf.py @@ -167,12 +167,19 @@ todo_include_todos = True # a list of builtin themes. html_theme = 'default' +try: + import sphinx_rtd_theme + + html_theme = 'sphinx_rtd_theme' +except ImportError: + pass + # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. -html_theme_options = { - 'sidebarbgcolor': '#374249' -} +#html_theme_options = { +# 'sidebarbgcolor': '#374249' +#} # Add any paths that contain custom themes here, relative to this directory. #html_theme_path = [] diff --git a/doc/manpages/watchfrr.rst b/doc/manpages/watchfrr.rst index f0b733298d..dceb423f82 100644 --- a/doc/manpages/watchfrr.rst +++ b/doc/manpages/watchfrr.rst @@ -22,21 +22,6 @@ In order to avoid restarting the daemons in quick succession, you can supply the OPTIONS ======= -The following 3 options specify scripts that |DAEMON| uses to perform start/stop/restart actions. These options are mandatory unless the --dry option is used: - -.. option:: -s command, --start-command command - - Supply a Bourne shell command to start a single daemon. The command string should contain the '%s' placeholder to be sub‐ stituted with the daemon name. - -.. option:: -k command, --kill-command command - - Supply a Bourne shell command to stop a single daemon. The command string should contain the '%s' placeholder to be substituted with the daemon name. - -.. option:: -r command, --restart command - - Supply a Bourne shell command to restart a single daemon. The command string should contain the '%s' placeholder to be substituted with the daemon name. - -Other options: .. option:: --dry @@ -92,6 +77,20 @@ Other options: Display the usage information and exit. +The following 3 options specify scripts that |DAEMON| uses to perform start/stop/restart actions. Reasonable default values are built into watchfrr, so the use of these options should no longer be necessary: + +.. option:: -s command, --start-command command + + Supply a Bourne shell command to start a single daemon. The command string should contain the '%s' placeholder to be substituted with the daemon name. + +.. option:: -k command, --kill-command command + + Supply a Bourne shell command to stop a single daemon. The command string should contain the '%s' placeholder to be substituted with the daemon name. + +.. option:: -r command, --restart command + + Supply a Bourne shell command to restart a single daemon. The command string should contain the '%s' placeholder to be substituted with the daemon name. + PREVIOUS OPTIONS ================ Prior versions of |DAEMON| supported some additional options that no longer exist::: diff --git a/doc/user/_static/overrides.css b/doc/user/_static/overrides.css index 41fcc66f8d..638f61986f 100644 --- a/doc/user/_static/overrides.css +++ b/doc/user/_static/overrides.css @@ -3,10 +3,6 @@ div.body { max-width: none; } -pre { - background-color: #e2e2e2; -} - /* styling for the protocols vs. OS table in overview.rst */ /* first, general bits */ div.body td.mark { @@ -40,6 +36,7 @@ td.mark span { border: 1px dotted #666; width: 36pt; margin:auto; + text-align:center; } table.mark tr td:first-child { padding-left:1.5em; @@ -61,3 +58,238 @@ li span.mark { width: 36pt; text-align: center; } + +/* Palette URL: http://paletton.com/#uid=70p0p0kt6uvcDRAlhBavokxLJ6w */ + +:root { +--primary-0: #F36F16; /* Main Primary color */ +--primary-1: #FFC39A; +--primary-2: #FF9A55; +--primary-3: #A34403; +--primary-4: #341500; +--primary-9: #FFF3EB; + +--secondary-1-0: #F39C16; /* Main Secondary color (1) */ +--secondary-1-1: #FFD79A; +--secondary-1-2: #FFBC55; +--secondary-1-3: #A36403; +--secondary-1-4: #341F00; +--secondary-1-9: #FFF7EB; + +--secondary-2-0: #1A599F; /* Main Secondary color (2) */ +--secondary-2-1: #92B9E5; +--secondary-2-2: #477CB8; +--secondary-2-3: #0A386B; +--secondary-2-4: #011122; +--secondary-2-9: #E3EBF4; + +--complement-0: #0E9A83; /* Main Complement color */ +--complement-1: #8AE4D4; +--complement-2: #3CB4A0; +--complement-3: #026857; +--complement-4: #00211B; +--complement-9: #E0F4F0; +} + +/* new */ + +body { + font-family: "Fira Sans", Helvetica, Arial, sans-serif; + font-weight:400; +} +h1, h2, h3, h4, h5, h6 { + font-family: "Fira Sans", Helvetica, Arial, sans-serif; + font-weight:500; +} +code, pre, tt { + font-family: "Fira Mono"; +} +h1 { + background-color:var(--secondary-1-1); + border-bottom:1px solid var(--secondary-1-0); + font-weight:300; +} +h2 { + margin-top:36pt; +} + +a, +a:hover, +a:visited, +.code-block-caption a.headerlink:hover, +.rst-content dl:not(.docutils) dt .headerlink { + color: var(--complement-0); +} +.code-block-caption a.headerlink { + visibility:hidden; +} + +/* admonitions */ + +.admonition.warning { + border:1px dashed var(--primary-2); +} +.admonition.warning .admonition-title { + color: var(--primary-3); + background-color: var(--primary-1); +} +.admonition.note, +.admonition.hint { + border:1px dashed var(--complement-2); +} +.admonition.note .admonition-title, +.admonition.hint .admonition-title { + color: var(--complement-3); + background-color: var(--complement-1); +} +.admonition.seealso, +div.seealso { + background-color:var(--complement-9); +} +.admonition.seealso .admonition-title { + color: var(--complement-3); + background-color:var(--complement-1); + border-bottom:1px solid var(--complement-2); +} +.admonition.admonition-todo .admonition-title { + background-image: repeating-linear-gradient( + 135deg, + #ffa, + #ffa 14.14213452px, + #bbb 14.14213452px, + #bbb 28.28427124px + ); + color:#000; +} +.admonition.admonition-todo { + background-image: repeating-linear-gradient( + 135deg, + #ffd, + #ffd 14.14213452px, + #eed 14.14213452px, + #eed 28.28427124px + ); +} + +.rst-content dl .admonition p.last { + margin-bottom:0 !important; +} + +/* file block */ + +.code-block-caption { +/* border-radius: 4px; */ + font-style:italic; + font-weight:300; + border-bottom: 1px solid var(--secondary-2-1); + background-color: var(--secondary-2-9); + padding:2px 8px; +} + +/* navbar */ + +.wy-nav-side { + background-color: var(--secondary-1-4); + border-right:2px solid var(--primary-3); +} +.wy-menu-vertical a, +.wy-menu-vertical a:visited, +.wy-menu-vertical a:hover, +.wy-side-nav-search>a, +.wy-side-nav-search .wy-dropdown>a { + color: var(--primary-0); +} + +nav div.wy-side-nav-search { + background-color: #eee; +} +nav div.wy-side-scroll { + background-color: var(--secondary-1-4); +} +nav .wy-menu-vertical a:hover { + background-color:var(--primary-0); + color:var(--primary-4); +} +nav .wy-menu-vertical li.current ul a:hover { + background-color:var(--secondary-1-2); + color:var(--primary-4); +} +nav .wy-menu-vertical li.current ul a { + background-color:var(--secondary-1-1); + color:var(--primary-3); +} +nav .wy-menu-vertical li.on a:hover, +nav .wy-menu-vertical li.current>a:hover { + background-color:#fcfcfc; +} +.wy-side-nav-search input[type=text] { + border-color:var(--primary-2); +} +.wy-menu-vertical li.toctree-l1.current>a { + border-top:1px solid var(--secondary-1-3); + border-bottom:1px solid var(--secondary-1-3); +} +.wy-menu-vertical li.toctree-l2.current>a { + background-color:var(--secondary-1-2); +} +.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a { + background-color:var(--secondary-1-9); +} + +.wy-nav-content { + padding: 25pt 40pt; +} +div[role=navigation] > hr { + display:none; +} +div[role=navigation] { + margin-bottom:15pt; +} +h1 { + margin-left:-40pt; + margin-right:-40pt; + padding:5pt 40pt 5pt 40pt; +} + +.rst-content pre.literal-block, .rst-content div[class^='highlight'] { + border-color:var(--secondary-1-1); +} + +span.pre { + color: var(--complement-3); +} +pre { + background-color: var(--secondary-1-9); + border-color: var(--secondary-1-1); +} +.highlight .p { color: var(--secondary-2-3); } +.highlight .k { color: var(--secondary-2-0); } +.highlight .kt { color: var(--complement-0); } +.highlight .cm { color: var(--primary-3); } +.highlight .ow { color: var(--primary-3); } +.highlight .na { color: var(--primary-2); } +.highlight .nv { color: var(--complement-0); } + +strong { + font-weight:500; +} +.rst-content dl:not(.docutils) dt { + font-family:Fira Mono; + font-weight:600; + background-color:var(--secondary-2-9); + color:var(--secondary-2-3); + border-top:2px solid var(--secondary-2-2); +} +dt code.descname { + color: var(--secondary-2-4); +} + +@media (min-width: 1200px) { + .container { width: auto; } +} +@media (min-width: 992px) { + .container { width: auto; } +} +@media (min-width: 768px) { + .container { width: auto; } +} diff --git a/doc/user/conf.py b/doc/user/conf.py index 2231989fe5..635dbaa3c7 100644 --- a/doc/user/conf.py +++ b/doc/user/conf.py @@ -168,12 +168,19 @@ todo_include_todos = True # a list of builtin themes. html_theme = 'default' +try: + import sphinx_rtd_theme + + html_theme = 'sphinx_rtd_theme' +except ImportError: + pass + # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. -html_theme_options = { - 'sidebarbgcolor': '#374249' -} +#html_theme_options = { +# 'sidebarbgcolor': '#374249' +#} # Add any paths that contain custom themes here, relative to this directory. #html_theme_path = [] diff --git a/doc/user/setup.rst b/doc/user/setup.rst index 8b27a8f771..acc8217ec4 100644 --- a/doc/user/setup.rst +++ b/doc/user/setup.rst @@ -70,13 +70,14 @@ This file has several parts. Here is an example: bfdd_options=" --daemon -A 127.0.0.1" # The list of daemons to watch is automatically generated by the init script. - watchfrr_enable=yes - watchfrr_options=(-d -r /usr/sbin/servicebBfrrbBrestartbB%s -s /usr/sbin/servicebBfrrbBstartbB%s -k /usr/sbin/servicebBfrrbBstopbB%s -b bB) + #watchfrr_options="" - # If valgrind_enable is 'yes' the frr daemons will be started via valgrind. - # The use case for doing so is tracking down memory leaks, etc in frr. - valgrind_enable=no - valgrind=/usr/bin/valgrind + # for debugging purposes, you can specify a "wrap" command to start instead + # of starting the daemon directly, e.g. to use valgrind on ospfd: + # ospfd_wrap="/usr/bin/valgrind" + # or you can use "all_wrap" for all daemons, e.g. to use perf record: + # all_wrap="/usr/bin/perf record --call-graph -" + # the normal daemon command is added to this at the end. Breaking this file down: @@ -99,22 +100,8 @@ from the service script. Usually daemons will have ``--daemon`` and ``-A <address>`` specified in order to daemonize and listen for VTY commands on a particular address. -:: - - # The list of daemons to watch is automatically generated by the init script. - watchfrr_enable=yes - watchfrr_options=(-d -r /usr/sbin/servicebBfrrbBrestartbB%s -s /usr/sbin/servicebBfrrbBstartbB%s -k /usr/sbin/servicebBfrrbBstopbB%s -b bB) - -Options for the ``watchfrr``, the watchdog daemon. - -:: - - valgrind_enable=no - valgrind=/usr/bin/valgrind - -Whether or not to start FRR daemons under Valgrind. This is primarily useful -for gathering information for bug reports and for developers. -``valgrind_enable`` should be ``no`` for production use. +The remaining file content regarding `watchfrr_options` and `*_wrap` settings +should not normally be needed; refer to the comments in case they are. Services -------- diff --git a/doc/user/vtysh.rst b/doc/user/vtysh.rst index 07109a0e54..6d569f5fb0 100644 --- a/doc/user/vtysh.rst +++ b/doc/user/vtysh.rst @@ -22,6 +22,37 @@ administrator with an external editor. have effect for vtysh) need to be manually updated in :file:`vtysh.conf`. +Pager usage +=========== + +*vtysh* can call an external paging program (e.g. *more* or *less*) to +paginate long output from commands. This feature used to be enabled by +default but is now controlled by the ``VTYSH_PAGER`` environment variable +and the :clicmd:`terminal paginate` command: + +.. envvar:: VTYSH_PAGER + + If set, the ``VTYSH_PAGER`` environment variable causes *vtysh* to pipe + output from commands through the given command. Note that this happens + regardless of the length of the output. As such, standard pager behavior + (particularly waiting at the end of output) tends to be annoying to the + user. Using ``less -EFX`` is recommended for a better user experience. + + If this environment variable is unset, *vtysh* defaults to not using any + pager. + + This variable should be set by the user according to their preferences, + in their :file:`~/.profile` file. + +.. index:: [no] terminal paginate +.. clicmd:: [no] terminal paginate + + Enables/disables vtysh output pagination. This command is intended to + be placed in :file:`vtysh.conf` to set a system-wide default. If this + is enabled but ``VTYSH_PAGER`` is not set, the system default pager + (likely ``more`` or ``/usr/bin/pager``) will be used. + + Permissions and setup requirements ================================== diff --git a/include/linux/if_addr.h b/include/linux/if_addr.h new file mode 100644 index 0000000000..a924606f36 --- /dev/null +++ b/include/linux/if_addr.h @@ -0,0 +1,69 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef __LINUX_IF_ADDR_H +#define __LINUX_IF_ADDR_H + +#include <linux/types.h> +#include <linux/netlink.h> + +struct ifaddrmsg { + __u8 ifa_family; + __u8 ifa_prefixlen; /* The prefix length */ + __u8 ifa_flags; /* Flags */ + __u8 ifa_scope; /* Address scope */ + __u32 ifa_index; /* Link index */ +}; + +/* + * Important comment: + * IFA_ADDRESS is prefix address, rather than local interface address. + * It makes no difference for normally configured broadcast interfaces, + * but for point-to-point IFA_ADDRESS is DESTINATION address, + * local address is supplied in IFA_LOCAL attribute. + * + * IFA_FLAGS is a u32 attribute that extends the u8 field ifa_flags. + * If present, the value from struct ifaddrmsg will be ignored. + */ +enum { + IFA_UNSPEC, + IFA_ADDRESS, + IFA_LOCAL, + IFA_LABEL, + IFA_BROADCAST, + IFA_ANYCAST, + IFA_CACHEINFO, + IFA_MULTICAST, + IFA_FLAGS, + IFA_RT_PRIORITY, /* u32, priority/metric for prefix route */ + __IFA_MAX, +}; + +#define IFA_MAX (__IFA_MAX - 1) + +/* ifa_flags */ +#define IFA_F_SECONDARY 0x01 +#define IFA_F_TEMPORARY IFA_F_SECONDARY + +#define IFA_F_NODAD 0x02 +#define IFA_F_OPTIMISTIC 0x04 +#define IFA_F_DADFAILED 0x08 +#define IFA_F_HOMEADDRESS 0x10 +#define IFA_F_DEPRECATED 0x20 +#define IFA_F_TENTATIVE 0x40 +#define IFA_F_PERMANENT 0x80 +#define IFA_F_MANAGETEMPADDR 0x100 +#define IFA_F_NOPREFIXROUTE 0x200 +#define IFA_F_MCAUTOJOIN 0x400 +#define IFA_F_STABLE_PRIVACY 0x800 + +struct ifa_cacheinfo { + __u32 ifa_prefered; + __u32 ifa_valid; + __u32 cstamp; /* created timestamp, hundredths of seconds */ + __u32 tstamp; /* updated timestamp, hundredths of seconds */ +}; + +/* backwards compatibility for userspace */ +#define IFA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifaddrmsg)))) +#define IFA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifaddrmsg)) + +#endif diff --git a/include/subdir.am b/include/subdir.am index 731785d4b4..0d7fed2852 100644 --- a/include/subdir.am +++ b/include/subdir.am @@ -1,4 +1,5 @@ noinst_HEADERS += \ + include/linux/if_addr.h \ include/linux/if_bridge.h \ include/linux/if_link.h \ include/linux/lwtunnel.h \ diff --git a/ldpd/labelmapping.c b/ldpd/labelmapping.c index 944f93331f..5e1b422a41 100644 --- a/ldpd/labelmapping.c +++ b/ldpd/labelmapping.c @@ -37,7 +37,7 @@ enqueue_pdu(struct nbr *nbr, uint16_t type, struct ibuf *buf, uint16_t size) struct ldp_hdr *ldp_hdr; ldp_hdr = ibuf_seek(buf, 0, sizeof(struct ldp_hdr)); - ldp_hdr->length = htons(size); + ldp_hdr->length = htons(size - LDP_HDR_DEAD_LEN); evbuf_enqueue(&nbr->tcp->wbuf, buf); } @@ -65,7 +65,7 @@ send_labelmessage(struct nbr *nbr, uint16_t type, struct mapping_head *mh) /* real size will be set up later */ err |= gen_ldp_hdr(buf, 0); - size = LDP_HDR_PDU_LEN; + size = LDP_HDR_SIZE; first = 0; } diff --git a/ldpd/ldpe.c b/ldpd/ldpe.c index 56af76d94e..c16d92f28b 100644 --- a/ldpd/ldpe.c +++ b/ldpd/ldpe.c @@ -139,6 +139,16 @@ ldpe(void) void ldpe_init(struct ldpd_init *init) { +#ifdef __OpenBSD__ + /* This socket must be open before dropping privileges. */ + global.pfkeysock = pfkey_init(); + if (sysdep.no_pfkey == 0) { + pfkey_ev = NULL; + thread_add_read(master, ldpe_dispatch_pfkey, NULL, global.pfkeysock, + &pfkey_ev); + } +#endif + /* drop privileges */ ldpe_privs.user = init->user; ldpe_privs.group = init->group; @@ -159,14 +169,6 @@ ldpe_init(struct ldpd_init *init) fatal("inet_pton"); if (inet_pton(AF_INET6, AllRouters_v6, &global.mcast_addr_v6) != 1) fatal("inet_pton"); -#ifdef __OpenBSD__ - global.pfkeysock = pfkey_init(); - if (sysdep.no_pfkey == 0) { - pfkey_ev = NULL; - thread_add_read(master, ldpe_dispatch_pfkey, NULL, global.pfkeysock, - &pfkey_ev); - } -#endif /* mark sockets as closed */ global.ipv4.ldp_disc_socket = -1; diff --git a/ldpd/socket.c b/ldpd/socket.c index bebd7a7d61..78a07b1ed4 100644 --- a/ldpd/socket.c +++ b/ldpd/socket.c @@ -268,9 +268,18 @@ sock_set_bindany(int fd, int enable) return (-1); } return (0); +#elif defined(IP_BINDANY) + frr_elevate_privs(&ldpd_privs) { + if (setsockopt(fd, IPPROTO_IP, IP_BINDANY, &enable, sizeof(int)) + < 0) { + log_warn("%s: error setting IP_BINDANY", __func__); + return (-1); + } + } #else - log_warnx("%s: missing SO_BINDANY and IP_FREEBIND, unable to bind " - "to a nonlocal IP address", __func__); + log_warnx( + "%s: missing SO_BINDANY, IP_FREEBIND and IP_BINDANY, unable to bind to a nonlocal IP address", + __func__); return (-1); #endif /* HAVE_SO_BINDANY */ } diff --git a/lib/command.c b/lib/command.c index 850980bd4e..ead8cf5efe 100644 --- a/lib/command.c +++ b/lib/command.c @@ -2542,8 +2542,6 @@ DEFUN (config_log_syslog, { int idx_log_levels = 2; - disable_log_file(); - if (argc == 3) { int level; if ((level = level_match(argv[idx_log_levels]->arg)) @@ -345,6 +345,8 @@ DECLARE_QOBJ_TYPE(interface) DECLARE_HOOK(if_add, (struct interface * ifp), (ifp)) DECLARE_KOOH(if_del, (struct interface * ifp), (ifp)) +#define METRIC_MAX (~0) + /* Connected address structure. */ struct connected { /* Attached interface. */ @@ -392,6 +394,13 @@ struct connected { /* Label for Linux 2.2.X and upper. */ char *label; + + /* + * Used for setting the connected route's cost. If the metric + * here is set to METRIC_MAX the connected route falls back to + * "struct interface" + */ + uint32_t metric; }; /* Nbr Connected address structure. */ @@ -29,6 +29,7 @@ #include "memory.h" #include "command.h" #include "lib_errors.h" +#include "lib/hook.h" #ifndef SUNOS_5 #include <sys/un.h> @@ -40,6 +41,10 @@ DEFINE_MTYPE_STATIC(LIB, ZLOG, "Logging") +/* hook for external logging */ +DEFINE_HOOK(zebra_ext_log, (int priority, const char *format, va_list args), + (priority, format, args)); + static int logfile_fd = -1; /* Used in signal handler. */ struct zlog *zlog_default = NULL; @@ -207,6 +212,9 @@ void vzlog(int priority, const char *format, va_list args) tsctl.already_rendered = 0; struct zlog *zl = zlog_default; + /* call external hook */ + hook_call(zebra_ext_log, priority, format, args); + /* When zlog_default is also NULL, use stderr for logging. */ if (zl == NULL) { tsctl.precision = 0; @@ -26,6 +26,12 @@ #include <stdint.h> #include <stdbool.h> #include <stdio.h> +#include <stdarg.h> +#include "lib/hook.h" + +/* Hook for external logging function */ +DECLARE_HOOK(zebra_ext_log, (int priority, const char *format, va_list args), + (priority, format, args)); /* Here is some guidance on logging levels to use: * diff --git a/nhrpd/nhrp_interface.c b/nhrpd/nhrp_interface.c index 3a42712748..13297aa344 100644 --- a/nhrpd/nhrp_interface.c +++ b/nhrpd/nhrp_interface.c @@ -323,9 +323,11 @@ int nhrp_interface_delete(int cmd, struct zclient *client, zebra_size_t length, return 0; debugf(NHRP_DEBUG_IF, "if-delete: %s", ifp->name); - if_set_index(ifp, ifp->ifindex); + nhrp_interface_update(ifp); - /* if_delete(ifp); */ + + if_set_index(ifp, IFINDEX_INTERNAL); + return 0; } diff --git a/ospfd/ospf_interface.c b/ospfd/ospf_interface.c index 24584f6713..7d77c38660 100644 --- a/ospfd/ospf_interface.c +++ b/ospfd/ospf_interface.c @@ -920,6 +920,23 @@ static void ospf_vl_if_delete(struct ospf_vl_data *vl_data) vlink_count--; } +/* for a defined area, count the number of configured vl + */ +int ospf_vl_count(struct ospf *ospf, struct ospf_area *area) +{ + int count = 0; + struct ospf_vl_data *vl_data; + struct listnode *node; + + for (ALL_LIST_ELEMENTS_RO(ospf->vlinks, node, vl_data)) { + if (area + && !IPV4_ADDR_SAME(&vl_data->vl_area_id, &area->area_id)) + continue; + count++; + } + return count; +} + /* Look up vl_data for given peer, optionally qualified to be in the * specified area. NULL area returns first found.. */ diff --git a/ospfd/ospf_interface.h b/ospfd/ospf_interface.h index 73ded208cf..b88d405875 100644 --- a/ospfd/ospf_interface.h +++ b/ospfd/ospf_interface.h @@ -300,6 +300,7 @@ extern struct ospf_vl_data *ospf_vl_data_new(struct ospf_area *, struct in_addr); extern struct ospf_vl_data *ospf_vl_lookup(struct ospf *, struct ospf_area *, struct in_addr); +extern int ospf_vl_count(struct ospf *ospf, struct ospf_area *area); extern void ospf_vl_data_free(struct ospf_vl_data *); extern void ospf_vl_add(struct ospf *, struct ospf_vl_data *); extern void ospf_vl_delete(struct ospf *, struct ospf_vl_data *); diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index fb9770d09a..0ac9d4ac82 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -1199,14 +1199,17 @@ DEFUN (no_ospf_area_vlink, return CMD_WARNING_CONFIG_FAILED; } + vl_data = ospf_vl_lookup(ospf, area, vl_config.vl_peer); + if (!vl_data) { + vty_out(vty, "Virtual link does not exist\n"); + return CMD_WARNING_CONFIG_FAILED; + } + if (argc <= 5) { /* Basic VLink no command */ /* Thats all folks! - BUGS B. strikes again!!!*/ - if ((vl_data = ospf_vl_lookup(ospf, area, vl_config.vl_peer))) - ospf_vl_delete(ospf, vl_data); - + ospf_vl_delete(ospf, vl_data); ospf_area_check_free(ospf, vl_config.area_id); - return CMD_SUCCESS; } @@ -3021,13 +3024,13 @@ static int show_ip_ospf_common(struct vty *vty, struct ospf *ospf, if (ospf->stub_router_startup_time != OSPF_STUB_ROUTER_UNCONFIGURED) json_object_int_add( - json_vrf, "postStartEnabledMsecs", - ospf->stub_router_startup_time / 1000); + json_vrf, "postStartEnabledSecs", + ospf->stub_router_startup_time); if (ospf->stub_router_shutdown_time != OSPF_STUB_ROUTER_UNCONFIGURED) json_object_int_add( - json_vrf, "preShutdownEnabledMsecs", - ospf->stub_router_shutdown_time / 1000); + json_vrf, "preShutdownEnabledSecs", + ospf->stub_router_shutdown_time); } else { vty_out(vty, " Stub router advertisement is configured\n"); @@ -3486,8 +3489,8 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, json_object_int_add(json_interface_sub, "cost", oi->output_cost); json_object_int_add( - json_interface_sub, "transmitDelayMsecs", - 1000 / OSPF_IF_PARAM(oi, transmit_delay)); + json_interface_sub, "transmitDelaySecs", + OSPF_IF_PARAM(oi, transmit_delay)); json_object_string_add(json_interface_sub, "state", lookup_msg(ospf_ism_state_msg, oi->state, NULL)); @@ -3591,20 +3594,20 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, if (OSPF_IF_PARAM(oi, fast_hello) == 0) json_object_int_add( json_interface_sub, "timerMsecs", - 1000 / OSPF_IF_PARAM(oi, v_hello)); + OSPF_IF_PARAM(oi, v_hello) * 1000); else json_object_int_add( json_interface_sub, "timerMsecs", 1000 / OSPF_IF_PARAM(oi, fast_hello)); json_object_int_add(json_interface_sub, - "timerDeadMsecs", - 1000 / OSPF_IF_PARAM(oi, v_wait)); + "timerDeadSecs", + OSPF_IF_PARAM(oi, v_wait)); json_object_int_add(json_interface_sub, - "timerWaitMsecs", - 1000 / OSPF_IF_PARAM(oi, v_wait)); + "timerWaitSecs", + OSPF_IF_PARAM(oi, v_wait)); json_object_int_add( - json_interface_sub, "timerRetransmit", - 1000 / OSPF_IF_PARAM(oi, retransmit_interval)); + json_interface_sub, "timerRetransmitSecs", + OSPF_IF_PARAM(oi, retransmit_interval)); } else { vty_out(vty, " Timer intervals configured,"); vty_out(vty, " Hello "); @@ -5099,12 +5102,15 @@ DEFUN (show_ip_ospf_neighbor_id, uint8_t uj = use_json(argc, argv); struct listnode *node = NULL; int ret = CMD_SUCCESS; + int idx_router_id = 0; + + argv_find(argv, argc, "A.B.C.D", &idx_router_id); for (ALL_LIST_ELEMENTS_RO(om->ospf, node, ospf)) { if (!ospf->oi_running) continue; - ret = show_ip_ospf_neighbor_id_common(vty, ospf, 0, argv, uj, - 0); + ret = show_ip_ospf_neighbor_id_common(vty, ospf, idx_router_id, + argv, uj, 0); } return ret; diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c index b7dfedd15a..6f4a01becf 100644 --- a/ospfd/ospfd.c +++ b/ospfd/ospfd.c @@ -895,6 +895,7 @@ void ospf_area_check_free(struct ospf *ospf, struct in_addr area_id) area = ospf_area_lookup_by_area_id(ospf, area_id); if (area && listcount(area->oiflist) == 0 && area->ranges->top == NULL + && !ospf_vl_count(ospf, area) && area->shortcut_configured == OSPF_SHORTCUT_DEFAULT && area->external_routing == OSPF_AREA_DEFAULT && area->no_summary == 0 && area->default_cost == 1 diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index ad60e8e3a6..30d66c835b 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -152,6 +152,8 @@ static int pim_zebra_if_del(int command, struct zclient *zclient, if (!if_is_operative(ifp)) pim_if_addr_del_all(ifp); + if_set_index(ifp, IFINDEX_INTERNAL); + return 0; } diff --git a/redhat/daemons b/redhat/daemons deleted file mode 100644 index 068d74d596..0000000000 --- a/redhat/daemons +++ /dev/null @@ -1,84 +0,0 @@ -# This file tells the frr package which daemons to start. -# -# Entries are in the format: <daemon>=(yes|no|priority) -# 0, "no" = disabled -# 1, "yes" = highest priority -# 2 .. 10 = lower priorities -# -# For daemons which support multiple instances, a 2nd line listing -# the instances can be added. Eg for ospfd: -# ospfd=yes -# ospfd_instances="1,2" -# -# Priorities were suggested by Dancer <dancer@zeor.simegen.com>. -# They're used to start the FRR daemons in more than one step -# (for example start one or two at network initialization and the -# rest later). The number of FRR daemons being small, priorities -# must be between 1 and 9, inclusive (or the initscript has to be -# changed). /etc/init.d/frr then can be started as -# -# /etc/init.d/frr <start|stop|restart|<priority>> -# -# where priority 0 is the same as 'stop', priority 10 or 'start' -# means 'start all' -# -# Sample configurations for these daemons can be found in -# /usr/share/doc/frr/examples/. -# -# ATTENTION: -# -# When activation a daemon at the first time, a config file, even if it is -# empty, has to be present *and* be owned by the user and group "frr", else -# the daemon will not be started by /etc/init.d/frr. The permissions should -# be u=rw,g=r,o=. -# When using "vtysh" such a config file is also needed. It should be owned by -# group "frrvty" and set to ug=rw,o= though. Check /etc/pam.d/frr, too. -# -watchfrr_enable=yes -watchfrr_options="-r '/usr/lib/frr/frr restart %s' -s '/usr/lib/frr/frr start %s' -k '/usr/lib/frr/frr stop %s'" -# -zebra=no -bgpd=no -ospfd=no -ospf6d=no -ripd=no -ripngd=no -isisd=no -ldpd=no -pimd=no -nhrpd=no -eigrpd=no -babeld=no -sharpd=no -pbrd=no -staticd=no -bfdd=no - -# -# Command line options for the daemons -# -zebra_options=("-A 127.0.0.1") -bgpd_options=("-A 127.0.0.1") -ospfd_options=("-A 127.0.0.1") -ospf6d_options=("-A ::1") -ripd_options=("-A 127.0.0.1") -ripngd_options=("-A ::1") -isisd_options=("-A 127.0.0.1") -ldpd_options=("-A 127.0.0.1") -pimd_options=("-A 127.0.0.1") -nhrpd_options=("-A 127.0.0.1") -eigrpd_options=("-A 127.0.0.1") -babeld_options=("-A 127.0.0.1") -sharpd_options=("-A 127.0.0.1") -pbrd_options=("-A 127.0.0.1") -staticd_options=("-A 127.0.0.1") -bfdd_options=("-A 127.0.0.1") - -# -# If the vtysh_enable is yes, then the unified config is read -# and applied if it exists. If no unified frr.conf exists -# then the per-daemon <daemon>.conf files are used) -# If vtysh_enable is no or non-existant, the frr.conf is ignored. -# it is highly suggested to have this set to yes -vtysh_enable=yes - diff --git a/redhat/frr.init b/redhat/frr.init deleted file mode 100755 index 4c4d59c77a..0000000000 --- a/redhat/frr.init +++ /dev/null @@ -1,577 +0,0 @@ -#!/bin/bash -# -# /etc/rc.d/init.d/frr -# -# Start/Stop the FRR Routing daemons -# <any general comments about this init script> -# -# chkconfig: 2345 15 85 -# -# description: FRRouting (FRR) is a routing suite for IP routing protocols -# like BGP, OSPF, RIP and others. This script contols the main -# daemon "frr" as well as the individual protocol daemons. -# -### BEGIN INIT INFO -# Provides: frr -# Required-Start: $local_fs $network $syslog -# Required-Stop: $local_fs $syslog -# Should-Start: $syslog -# Should-Stop: $network $syslog -# Default-Start: 2 3 4 5 -# Default-Stop: 0 1 6 -# Short-Description: Start/Stop the FRR Routing daemons -# Description: FRRouting (FRR) is a routing suite for IP routing protocols -# like BGP, OSPF, RIP and others. This script contols the main -# daemon "frr" as well as the individual protocol daemons. -### END INIT INFO - -PATH=/bin:/usr/bin:/sbin:/usr/sbin -D_PATH=/usr/lib/frr -C_PATH=/etc/frr -V_PATH=/var/run/frr - -# Local Daemon selection may be done by using /etc/frr/daemons. -# See /usr/share/doc/frr/README.Debian.gz for further information. -# Keep zebra first and do not list watchfrr! -DAEMONS="zebra bgpd ripd ripngd ospfd ospf6d isisd pimd pbrd ldpd nhrpd eigrpd babeld staticd sharpd bfdd" -MAX_INSTANCES=5 -RELOAD_SCRIPT=/usr/lib/frr/frr-reload.py - -. /etc/init.d/functions - -# Print the name of the pidfile. -pidfile() -{ - echo "$V_PATH/$1.pid" -} - -# Print the name of the vtysh. -vtyfile() -{ - echo "$V_PATH/$1.vty" -} - -# Check if daemon is started by using the pidfile. -started() -{ - [ ! -e `pidfile $1` ] && return 3 - if [ -n "$2" ] && [ "$2" == "log" ]; then - status -p `pidfile $1` $1 && return 0 || return $? - else - kill -0 `cat \`pidfile $1\`` 2> /dev/null || return 1 - return 0 - fi -} - -# Loads the config via vtysh -b if configured to do so. -vtysh_b () -{ - # Rember, that all variables have been incremented by 1 in convert_daemon_prios() - if [ "$vtysh_enable" = 2 -a -f $C_PATH/frr.conf ]; then - /usr/bin/vtysh -b -n - fi -} - -# Check if the daemon is activated and if its executable and config files -# are in place. -# params: daemon name -# returns: 0=ok, 1=error -check_daemon() -{ - # If the integrated config file is used the others are not checked. - if [ -r "$C_PATH/frr.conf" ]; then - return 0 - fi - - # vtysh_enable has no config file nor binary so skip check. - # (Not sure why vtysh_enable is in this list but does not hurt) - if [ $1 != "watchfrr" -a $1 != "vtysh_enable" ]; then - # check for daemon binary - if [ ! -x "$D_PATH/$1" ]; then return 1; fi - - # check for config file - if [ -n "$2" ]; then - if [ ! -r "$C_PATH/$1-$2.conf" ]; then - touch "$C_PATH/$1-$2.conf" - chown frr:frr "$C_PATH/$1-$2.conf" - fi - elif [ ! -r "$C_PATH/$1.conf" ]; then - touch "$C_PATH/$1.conf" - chown frr:frr "$C_PATH/$1.conf" - fi - fi - return 0 -} - -# Starts the server if it's not already running according to the pid file. -# The Frr daemons creates the pidfile when starting. -start() -{ - local dmn inst - dmn="$1" - inst="$2" - - ulimit -n $MAX_FDS > /dev/null 2> /dev/null - if [ "$dmn" = "watchfrr" ]; then - - # We may need to restart watchfrr if new daemons are added and/or - # removed - if started "$dmn" ; then - stop watchfrr - else - # Echo only once. watchfrr is printed in the stop above - echo -n " $dmn" - fi - - if [ -e /var/run/frr/watchfrr.started ] ; then - rm /var/run/frr/watchfrr.started - fi - # redhat /etc/init.d/functions daemon() re-expands args :( - # eval "set - $watchfrr_options" - daemon --pidfile=`pidfile $dmn` "$D_PATH/$dmn" -d "$watchfrr_options" - RETVAL=$? - [ $RETVAL -ne 0 ] && break - for i in `seq 1 10`; - do - if [ -e /var/run/frr/watchfrr.started ] ; then - RETVAL=0 - break - else - sleep 1 - fi - done - RETVAL=1 - elif [ -n "$inst" ]; then - echo -n " $dmn-$inst" - if ! check_daemon $dmn $inst ; then - echo -n " (binary does not exist)" - return; - fi - daemon --pidfile=`pidfile $dmn-$inst` "$D_PATH/$dmn" -d `eval echo "$""$dmn""_options"` -n "$inst" - RETVAL=$? - else - echo -n " $dmn " - if ! check_daemon $dmn; then - echo " (binary does not exist)" - return; - fi - daemon --pidfile=`pidfile $dmn` "$D_PATH/$dmn" -d `eval echo "$""$dmn""_options"` - RETVAL=$? - fi - echo - [ $RETVAL -eq 0 ] && touch /var/lock/subsys/$dmn - return $RETVAL -} - -# Stop the daemon given in the parameter, printing its name to the terminal. -stop() -{ - local inst - - if [ -n "$2" ]; then - inst="$1-$2" - else - inst="$1" - fi - - if ! started "$inst" ; then - # echo -n " ($inst)" - return 0 - else - echo -n " $inst" - PIDFILE=`pidfile $inst` - PID=`cat $PIDFILE 2>/dev/null` - killproc -p "$PIDFILE" "$D_PATH/$1" - RETVAL=$? - [ $RETVAL -eq 0 ] && rm -f $lockfile - rm -f `pidfile $inst` - rm -f `vtyfile $inst` - echo - return $RETVAL - fi -} - -# Converts values from /etc/frr/daemons to all-numeric values. -convert_daemon_prios() -{ - for name in $DAEMONS zebra vtysh_enable watchfrr_enable; do - # First, assign the value set by the user to $value - eval value=\${${name}:0:3} - - # Daemon not activated or entry missing? - if [ "$value" = "no" -o "$value" = "" ]; then value=0; fi - - # These strings parsed for backwards compatibility. - if [ "$value" = "yes" -o "$value" = "true" ]; then - value=1; - fi - - # Zebra is threatened special. It must be between 0=off and the first - # user assigned value "1" so we increase all other enabled daemons' values. - if [ "$name" != "zebra" -a "$value" -gt 0 ]; then value=`expr "$value" + 1`; fi - - # If e.g. name is zebra then we set "zebra=yes". - eval $name=$value - done -} - -# Starts watchfrr for all wanted daemons. -start_watchfrr() -{ - local daemon_name - local daemon_prio - local found_one - local daemon_inst - - # Start the monitor daemon only if desired. - if [ 0 -eq "$watchfrr_enable" ]; then - return - fi - - # Check variable type - if declare -p watchfrr_options | grep -q '^declare \-a'; then - # old array support - watchfrr_options="${watchfrr_options[@]}" - fi - - # Which daemons have been started? - found_one=0 - for daemon_name in $DAEMONS; do - eval daemon_prio=\$$daemon_name - if [ "$daemon_prio" -gt 0 ]; then - eval "daemon_inst=\${${daemon_name}_instances//,/ }" - if [ -n "$daemon_inst" ]; then - for inst in ${daemon_inst}; do - eval "inst_disable=\${${daemon_name}_${inst}}" - if [ -z ${inst_disable} ] || [ ${inst_disable} != 0 ]; then - if check_daemon $daemon_name $inst; then - watchfrr_options="$watchfrr_options ${daemon_name}-${inst}" - fi - fi - done - else - if check_daemon $daemon_name; then - watchfrr_options="$watchfrr_options $daemon_name" - fi - fi - found_one=1 - fi - done - - # Start if at least one daemon is activated. - if [ $found_one -eq 1 ]; then - echo "Starting FRRouting monitor daemon:" - start watchfrr - fi -} - -# Stopps watchfrr. -stop_watchfrr() -{ - echo "Stopping FRRouting monitor daemon:" - stop watchfrr -} - -# Stops all daemons that have a lower level of priority than the given. -# (technically if daemon_prio >= wanted_prio) -stop_prio() -{ - local wanted_prio - local daemon_prio - local daemon_list - local daemon_inst - local inst - - if [ -n "$2" ] && [[ "$2" =~ (.*)-(.*) ]]; then - daemon=${BASH_REMATCH[1]} - inst=${BASH_REMATCH[2]} - else - daemon="$2" - fi - - wanted_prio=$1 - daemon_list=${daemon:-$DAEMONS} - - echo "Stopping FRRouting daemons (prio:$wanted_prio):" - - for prio_i in `seq 10 -1 $wanted_prio`; do - for daemon_name in $daemon_list; do - eval daemon_prio=\${${daemon_name}:0:3} - daemon_inst="" - if [ $daemon_prio -eq $prio_i ]; then - eval "daemon_inst=\${${daemon_name}_instances//,/ }" - if [ -n "$daemon_inst" ]; then - for i in ${daemon_inst}; do - if [ -n "$inst" ] && [ "$i" == "$inst" ]; then - stop "$daemon_name" "$inst" - elif [ x"$inst" == x ]; then - stop "$daemon_name" "$i" - fi - done - else - stop "$daemon_name" - fi - fi - done - done - - if [ -z "$inst" ]; then - # Now stop other daemons that're prowling, coz the daemons file changed - echo "Stopping other FRRouting daemons" - if [ -n "$daemon" ]; then - eval "file_list_suffix="$V_PATH"/"$daemon*"" - else - eval "file_list_suffix="$V_PATH/*"" - fi - for pidfile in $file_list_suffix.pid; do - if [ -f "$pidfile" ]; then - filename=${pidfile##*/} - daemon=${filename%.*} - echo -n " $daemon" - killproc -p "$pidfile" "$daemon" - RETVAL=$? - [ $RETVAL -eq 0 ] && rm -f $lockfile - rm -f "$pidfile" - echo - fi - done - echo -n "Removing remaining .vty files" - for vtyfile in $file_list_suffix.vty; do - rm -rf "$vtyfile" - done - echo - fi -} - -# Starts all daemons that have a higher level of priority than the given. -# (technically if daemon_prio <= wanted_prio) -start_prio() -{ - local wanted_prio - local daemon_prio - local daemon_list - local daemon_name - local daemon_inst - local inst - - if [ -n "$2" ] && [[ "$2" =~ (.*)-(.*) ]]; then - daemon=${BASH_REMATCH[1]} - inst=${BASH_REMATCH[2]} - else - daemon="$2" - fi - - wanted_prio=$1 - daemon_list=${daemon:-$DAEMONS} - - echo "Starting FRRouting daemons (prio:$wanted_prio):" - - for prio_i in `seq 1 $wanted_prio`; do - for daemon_name in $daemon_list; do - eval daemon_prio=\$${daemon_name} - daemon_inst="" - if [ $daemon_prio -eq $prio_i ]; then - eval "daemon_inst=\${${daemon_name}_instances//,/ }" - if [ -n "$daemon_inst" ]; then - if [ `echo "$daemon_inst" | wc -w` -gt ${MAX_INSTANCES} ]; then - echo "Max instances supported is ${MAX_INSTANCES}. Aborting" - exit 1 - fi - # Check if we're starting again by switching from single instance - # to MI version - if started "$daemon_name"; then - PIDFILE=`pidfile $daemon_name` - killproc -p "$PIDFILE" "$daemon_name" - rm -f `pidfile $1` - rm -f `vtyfile $1` - fi - - for i in ${daemon_inst}; do - if [ -n "$inst" ] && [ "$i" == "$inst" ]; then - start "$daemon_name" "$inst" - elif [ x"$inst" == x ]; then - start "$daemon_name" "$i" - fi - done - else - # Check if we're starting again by switching from - # single instance to MI version - eval "file_list_suffix="$V_PATH"/"$daemon_name-*"" - for pidfile in $file_list_suffix.pid; do - if [ -f "$pidfile" ]; then - killproc -p "$pidfile" "$daemon_name" - rm -rf "$pidfile" - fi - done - for vtyfile in $file_list_suffix.vty; do - rm -rf "$vtyfile" - done - - start "$daemon_name" - fi - fi - done - done -} - -check_status() -{ - local daemon_name - local daemon_prio - local daemon_inst - local failed_status=0 - - if [ -n "$1" ] && [[ "$1" =~ (.*)-(.*) ]]; then - daemon=${BASH_REMATCH[1]} - inst=${BASH_REMATCH[2]} - else - daemon="$1" - fi - - daemon_list=${daemon:-$DAEMONS} - - # Which daemons have been started? - for daemon_name in $daemon_list; do - eval daemon_prio=\$$daemon_name - if [ "$daemon_prio" -gt 0 ]; then - eval "daemon_inst=\${${daemon_name}_instances//,/ }" - if [ -n "$daemon_inst" ]; then - for i in ${daemon_inst}; do - if [ -n "$inst" -a "$inst" = "$i" ]; then - started "$1" "log" || failed_status=$? - elif [ -z "$inst" ]; then - started "$daemon_name-$i" "log" || failed_status=$? - fi - done - else - started "$daemon_name" "log" || failed_status=$? - fi - fi - done - - # All daemons that need to have been started are up and running - return $failed_status -} - -######################################################### -# Main program # -######################################################### - -# Config broken but script must exit silently. -[ ! -r "$C_PATH/daemons" ] && exit 0 - -# Load configuration -. "$C_PATH/daemons" - -# Read configuration variable file if it is present -[ -r /etc/sysconfig/frr ] && . /etc/sysconfig/frr - -MAX_INSTANCES=${MAX_INSTANCES:=5} - -# Set priority of un-startable daemons to 'no' and substitute 'yes' to '0' -convert_daemon_prios - -if [ ! -d $V_PATH ]; then - echo "Creating $V_PATH" - mkdir -p $V_PATH - chown frr:frr $V_PATH - chmod 755 /$V_PATH -fi - -if [ -n "$3" ] && [ "$3" != "all" ]; then - dmn="$2"-"$3" -elif [ -n "$2" ] && [ "$2" != "all" ]; then - dmn="$2" -fi - -case "$1" in - start) - # Try to load this necessary (at least for 2.6) module. - if [ -d /lib/modules/`uname -r` ] ; then - echo "Loading capability module if not yet done." - LC_ALL=C modprobe -a capability 2>&1 | egrep -v "(not found|Can't locate)" - fi - - # Start all daemons - cd $C_PATH/ - if [ "$2" != "watchfrr" ]; then - start_prio 10 $dmn - fi - start_watchfrr - vtysh_b - ;; - - 1|2|3|4|5|6|7|8|9|10) - # Stop/start daemons for the appropriate priority level - stop_prio $1 - start_prio $1 - vtysh_b - ;; - - stop|0) - # Stop all daemons at level '0' or 'stop' - stop_watchfrr - if [ "$dmn" != "watchfrr" ]; then - [ -n "${dmn}" ] && eval "${dmn/-/_}=0" - stop_prio 0 $dmn - fi - - if [ -z "$dmn" -o "$dmn" = "zebra" ]; then - echo "Removing all routes made by zebra." - ip route flush proto zebra - # At least in CentOS/RHEL 6, iproute2 doesn't know - # about the new protocol names, so we have to flush them - # by number (it also doesn't support rt_protos.d - ip route flush proto 186 - ip route flush proto 187 - ip route flush proto 188 - ip route flush proto 189 - ip route flush proto 190 - ip route flush proto 191 - ip route flush proto 192 - ip route flush proto 193 - ip route flush proto 194 - else - [ -n "$dmn" ] && eval "${dmn/-/_}=0" - start_watchfrr - fi - ;; - - reload) - # Just apply the commands that have changed, no restart necessary - if [ ! -x "$RELOAD_SCRIPT" ]; then - echo "frr-reload - reload not supported. Use restart or install frr-pythontools package" - exit 1 - fi - NEW_CONFIG_FILE="${2:-$C_PATH/frr.conf}" - if [ ! -r $NEW_CONFIG_FILE ]; then - echo "Unable to read configuration file $NEW_CONFIG_FILE. Only supporting integrated config" - exit 1 - fi - echo "Applying only incremental changes to running configuration from frr.conf" - "$RELOAD_SCRIPT" --reload /etc/frr/frr.conf - exit $? - ;; - - status) - check_status $dmn - exit $? - ;; - - restart|force-reload) - $0 stop $dmn - sleep 1 - $0 start $dmn - ;; - - *) - echo "Usage: /etc/init.d/frr {start|stop|status|reload|restart|force-reload|<priority>} [daemon]" - echo " E.g. '/etc/init.d/frr 5' would start all daemons with a prio 1-5." - echo " reload applies only modifications from the running config to all daemons." - echo " reload neither restarts starts any daemon nor starts any new ones." - echo " Read /usr/share/doc/frr/README.Debian for details." - exit 1 - ;; -esac - -exit 0 diff --git a/redhat/frr.service b/redhat/frr.service deleted file mode 100644 index 3ae0aabfe2..0000000000 --- a/redhat/frr.service +++ /dev/null @@ -1,23 +0,0 @@ -[Unit] -Description=FRRouting (FRR) -After=syslog.target networking.service -OnFailure=heartbeat-failed@%n.service - -[Service] -Nice=-5 -Type=forking -NotifyAccess=all -StartLimitInterval=3m -StartLimitBurst=3 -TimeoutSec=2m -WatchdogSec=60s -RestartSec=5 -Restart=on-abnormal -LimitNOFILE=1024 -ExecStart=/usr/lib/frr/frr start -ExecStop=/usr/lib/frr/frr stop -ExecReload=/usr/lib/frr/frr reload - -[Install] -WantedBy=network-online.target - diff --git a/redhat/frr.spec.in b/redhat/frr.spec.in index 4e68365362..e5407a2cb9 100644 --- a/redhat/frr.spec.in +++ b/redhat/frr.spec.in @@ -374,15 +374,13 @@ rm -vf %{buildroot}%{_libdir}/*.la # install /etc sources %if "%{initsystem}" == "systemd" mkdir -p %{buildroot}%{_unitdir} -install -m644 %{zeb_rh_src}/frr.service %{buildroot}%{_unitdir}/frr.service -install %{zeb_rh_src}/frr.init %{buildroot}%{_sbindir}/frr +install -m644 %{zeb_src}/tools/frr.service %{buildroot}%{_unitdir}/frr.service %else mkdir -p %{buildroot}%{_initddir} -install %{zeb_rh_src}/frr.init %{buildroot}%{_sbindir}/frr -ln -s %{_sbindir}/frr %{buildroot}%{_initddir}/frr +ln -s %{_sbindir}/frrinit.sh %{buildroot}%{_initddir}/frr %endif -install %{zeb_rh_src}/daemons %{buildroot}%{_sysconfdir}/frr +install %{zeb_src}/tools/etc/frr/daemons %{buildroot}%{_sysconfdir}/frr # add rpki module to daemon %if %{with_rpki} sed -i -e 's/^\(bgpd_options=\)\(.*\)\(".*\)/\1\2 -M rpki\3/' %{buildroot}%{_sysconfdir}/frr/daemons @@ -471,7 +469,7 @@ zebra_spec_add_service isisd 2608/tcp "ISISd vty" # Fix bad path in previous config files # Config files won't get replaced by default, so we do this ugly hack to fix it -%__sed -i 's|/etc/init.d/|%{_sbindir}/|g' %{configdir}/daemons 2> /dev/null || true +%__sed -i 's|watchfrr_options=|#watchfrr_options=|g' %{configdir}/daemons 2> /dev/null || true # With systemd, watchfrr is mandatory. Fix config to make sure it's enabled if # we install or upgrade to a frr built with systemd @@ -627,7 +625,6 @@ fi %else %{_initddir}/frr %endif -%{_sbindir}/frr %config(noreplace) %{_sysconfdir}/pam.d/frr %config(noreplace) %{_sysconfdir}/logrotate.d/frr %{_sbindir}/frr-reload @@ -663,7 +660,28 @@ fi %changelog -* Tue Jan 8 2019 Martin Winter <mwinter@opensourcerouting.org> - %{version} + +* Tue May 7 2019 Quentin Young <qlyoung@cumulusnetworks.com> - %{version} +- bgpd: Fix 'show bgp ipv4/ipv6 neighbors' to show only v4 or v6 neighbors +- bgpd: Fix display issue when showing labeled-unicast routes +- bgpd: Fix incorrect # peers in 'show bgp ipv6 summary' output +- bgpd: Fix issue with remote-private-as in combination with local-as +- bgpd: Fix memory error when prepending to AS-path +- bgpd: Improve error handling when using maximum-prefix +- ldpd: Fix startup permissions error on OpenBSD +- ldpd: add support for FreeBSD IP_BINDANY +- ospfd: Fix incorrect display of millisecond time values +- tools: Fix incorrect systemd dependencies causing failure to start on boot +- vtysh: Fix unnecessary reconnection under multi-instance OSPF +- watchfrr: Fix multi-instance support when using new init script +- zebra: Fix a display bug in 'show ip route ... json' +- zebra: Fix compilation issue on OpenBSD +- zebra: Fix issue with missed selection of system-sourced routes +- zebra: Fix race condition in label manager +- zebra: Reliability improvements to pseudowire route recovery +- zebra: Tweak metric values for macvlan devices + +* Tue Jan 8 2019 Martin Winter <mwinter@opensourcerouting.org> - 6.0.2 - Security Issue (Denial of Service): Fix BGP Attribute 255 (experimental VNC) handling diff --git a/tools/etc/frr/daemons b/tools/etc/frr/daemons index 9077606633..c40ebb598d 100644 --- a/tools/etc/frr/daemons +++ b/tools/etc/frr/daemons @@ -53,7 +53,7 @@ staticd_options="-A 127.0.0.1" bfdd_options=" -A 127.0.0.1" # The list of daemons to watch is automatically generated by the init script. -watchfrr_options="-r '/usr/lib/frr/watchfrr.sh restart %s' -s '/usr/lib/frr/watchfrr.sh start %s' -k '/usr/lib/frr/watchfrr.sh stop %s'" +#watchfrr_options="" # for debugging purposes, you can specify a "wrap" command to start instead # of starting the daemon directly, e.g. to use valgrind on ospfd: diff --git a/tools/frr.service b/tools/frr.service index c7568593b3..aa45f420fe 100644 --- a/tools/frr.service +++ b/tools/frr.service @@ -1,7 +1,9 @@ [Unit] Description=FRRouting Documentation=https://frrouting.readthedocs.io/en/latest/setup.html -After=networking.service +Wants=network.target +After=network-pre.target systemd-sysctl.service +Before=network.target OnFailure=heartbeat-failed@%n.service [Service] @@ -20,4 +22,4 @@ ExecStop=/usr/lib/frr/frrinit.sh stop ExecReload=/usr/lib/frr/frrinit.sh reload [Install] -WantedBy=network-online.target +WantedBy=multi-user.target diff --git a/tools/frrcommon.sh.in b/tools/frrcommon.sh.in index 588aa6d103..897e6d6558 100644 --- a/tools/frrcommon.sh.in +++ b/tools/frrcommon.sh.in @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # # This is a "library" of sorts for use by the other FRR shell scripts. It # has most of the daemon start/stop logic, but expects the following shell @@ -67,9 +67,9 @@ vtysh_b () { daemon_inst() { # note this sets global variables ($dmninst, $daemon, $inst) dmninst="$1" - daemon="${dmninst%:*}" + daemon="${dmninst%-*}" inst="" - [ "$daemon" != "$dmninst" ] && inst="${dmninst#*:}" + [ "$daemon" != "$dmninst" ] && inst="${dmninst#*-}" } daemon_list() { @@ -92,9 +92,12 @@ daemon_list() { enabled="$enabled $daemon" if [ -n "$inst" ]; then debug "$daemon multi-instance $inst" + oldifs="${IFS}" + IFS="${IFS}," for i in $inst; do - enabled="$enabled $daemon:$inst" + enabled="$enabled $daemon-$i" done + IFS="${oldifs}" fi else debug "$daemon disabled" @@ -119,7 +122,7 @@ daemon_prep() { inst="$2" [ "$daemon" = "watchfrr" ] && return 0 [ -x "$D_PATH/$daemon" ] || { - log_failure_msg "cannot start $daemon${inst:+ (instance $inst)}: daemon binary not installed\n" + log_failure_msg "cannot start $daemon${inst:+ (instance $inst)}: daemon binary not installed" return 1 } [ -r "$C_PATH/frr.conf" ] && return 0 @@ -279,7 +282,7 @@ load_old_config() { } [ -r "$C_PATH/daemons" ] || { - log_failure_msg "cannot run $@: $C_PATH/daemons does not exist\n" + log_failure_msg "cannot run $@: $C_PATH/daemons does not exist" exit 1 } . "$C_PATH/daemons" @@ -288,6 +291,13 @@ load_old_config "$C_PATH/daemons.conf" load_old_config "/etc/default/frr" load_old_config "/etc/sysconfig/frr" +if { declare -p watchfrr_options 2>/dev/null || true; } | grep -q '^declare \-a'; then + log_warning_msg "watchfrr_options contains a bash array value." \ + "The configured value is intentionally ignored since it is likely wrong." \ + "Please remove or fix the setting." + unset watchfrr_options +fi + # # other defaults and dispatch # diff --git a/tools/frrinit.sh.in b/tools/frrinit.sh.in index 3dddf5bd44..0f5ed85864 100644 --- a/tools/frrinit.sh.in +++ b/tools/frrinit.sh.in @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # ### BEGIN INIT INFO # Provides: frr diff --git a/tools/tarsource.sh b/tools/tarsource.sh index 110558da0d..2e7ed4411d 100755 --- a/tools/tarsource.sh +++ b/tools/tarsource.sh @@ -133,7 +133,7 @@ onexit() { trap onexit EXIT tmpdir="`mktemp -d -t frrtar.XXXXXX`" -if test -d "$src/.git"; then +if test -e "$src/.git"; then commit="`git -C \"$src\" rev-parse \"${commit:-HEAD}\"`" if $dirty; then diff --git a/tools/watchfrr.sh.in b/tools/watchfrr.sh.in index 3051d91044..712f962a0a 100644 --- a/tools/watchfrr.sh.in +++ b/tools/watchfrr.sh.in @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # # This is NOT the init script! This is the watchfrr start/stop/restart # command handler, passed to watchfrr with the -s/-r/-k commands. It is used diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 2a3b74cdb1..b42b56e9ef 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -104,7 +104,7 @@ static int vty_close_pager(struct vty *vty) return 0; } -static void vtysh_pager_envdef(void) +static void vtysh_pager_envdef(bool fallback) { char *pager_defined; @@ -112,7 +112,7 @@ static void vtysh_pager_envdef(void) if (pager_defined) vtysh_pager_name = strdup(pager_defined); - else + else if (fallback) vtysh_pager_name = strdup(VTYSH_PAGER); } @@ -576,7 +576,7 @@ static int vtysh_execute_func(const char *line, int pager) && (cmd->daemon == vtysh_client[i].flag)) { for (vc = &vtysh_client[i]; vc; vc = vc->next) - if (vc->fd < 0) + if (vc->fd == VTYSH_WAS_ACTIVE) vtysh_reconnect(vc); } if (vtysh_client[i].fd < 0 @@ -2858,7 +2858,7 @@ DEFUN (vtysh_terminal_paginate, vtysh_pager_name = NULL; if (strcmp(argv[0]->text, "no")) - vtysh_pager_envdef(); + vtysh_pager_envdef(true); return CMD_SUCCESS; } @@ -2878,7 +2878,7 @@ DEFUN (vtysh_terminal_length, if (!strcmp(argv[0]->text, "no") || !strcmp(argv[1]->text, "no")) { /* "terminal no length" = use VTYSH_PAGER */ - vtysh_pager_envdef(); + vtysh_pager_envdef(true); return CMD_SUCCESS; } @@ -2887,7 +2887,7 @@ DEFUN (vtysh_terminal_length, vty_out(vty, "%% The \"terminal length\" command is deprecated and its value is ignored.\n" "%% Please use \"terminal paginate\" instead with OS TTY length handling.\n"); - vtysh_pager_envdef(); + vtysh_pager_envdef(true); } return CMD_SUCCESS; @@ -3445,6 +3445,7 @@ void vtysh_init_vty(void) /* set default output */ vty->of = stdout; + vtysh_pager_envdef(false); /* Initialize commands. */ cmd_init(0); @@ -3773,6 +3774,7 @@ void vtysh_init_vty(void) /* "write memory" command. */ install_element(ENABLE_NODE, &vtysh_write_memory_cmd); + install_element(CONFIG_NODE, &vtysh_terminal_paginate_cmd); install_element(VIEW_NODE, &vtysh_terminal_paginate_cmd); install_element(VIEW_NODE, &vtysh_terminal_length_cmd); install_element(VIEW_NODE, &vtysh_terminal_no_length_cmd); diff --git a/watchfrr/watchfrr.c b/watchfrr/watchfrr.c index 7e75bed2d6..757d10419a 100644 --- a/watchfrr/watchfrr.c +++ b/watchfrr/watchfrr.c @@ -53,6 +53,10 @@ #define DEFAULT_MIN_RESTART 60 #define DEFAULT_MAX_RESTART 600 +#define DEFAULT_RESTART_CMD WATCHFRR_SH_PATH " restart %s" +#define DEFAULT_START_CMD WATCHFRR_SH_PATH " start %s" +#define DEFAULT_STOP_CMD WATCHFRR_SH_PATH " stop %s" + #define PING_TOKEN "PING" DEFINE_MGROUP(WATCHFRR, "watchfrr") @@ -124,6 +128,9 @@ static struct global_state { .loglevel = DEFAULT_LOGLEVEL, .min_restart_interval = DEFAULT_MIN_RESTART, .max_restart_interval = DEFAULT_MAX_RESTART, + .restart_command = DEFAULT_RESTART_CMD, + .start_command = DEFAULT_START_CMD, + .stop_command = DEFAULT_STOP_CMD, }; typedef enum { @@ -227,14 +234,17 @@ Otherwise, the interval is doubled (but capped at the -M value).\n\n", -r, --restart Supply a Bourne shell command to use to restart a single\n\ daemon. The command string should include '%%s' where the\n\ name of the daemon should be substituted.\n\ + (default: '%s')\n\ -s, --start-command\n\ Supply a Bourne shell to command to use to start a single\n\ daemon. The command string should include '%%s' where the\n\ name of the daemon should be substituted.\n\ + (default: '%s')\n\ -k, --kill-command\n\ Supply a Bourne shell to command to use to stop a single\n\ daemon. The command string should include '%%s' where the\n\ name of the daemon should be substituted.\n\ + (default: '%s')\n\ --dry Do not start or restart anything, just log.\n\ -p, --pid-file Set process identifier file name\n\ (default is %s/watchfrr.pid).\n\ @@ -247,7 +257,9 @@ Otherwise, the interval is doubled (but capped at the -M value).\n\n", -h, --help Display this help and exit\n", frr_vtydir, DEFAULT_LOGLEVEL, LOG_EMERG, LOG_DEBUG, LOG_DEBUG, DEFAULT_MIN_RESTART, DEFAULT_MAX_RESTART, DEFAULT_PERIOD, - DEFAULT_TIMEOUT, DEFAULT_RESTART_TIMEOUT, frr_vtydir); + DEFAULT_TIMEOUT, DEFAULT_RESTART_TIMEOUT, + DEFAULT_RESTART_CMD, DEFAULT_START_CMD, DEFAULT_STOP_CMD, + frr_vtydir); } static pid_t run_background(char *shell_cmd) diff --git a/zebra/connected.c b/zebra/connected.c index 57bfcc4d16..147715dd16 100644 --- a/zebra/connected.c +++ b/zebra/connected.c @@ -208,6 +208,7 @@ void connected_up(struct interface *ifp, struct connected *ifc) .ifindex = ifp->ifindex, .vrf_id = ifp->vrf_id, }; + uint32_t metric; if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_REAL)) return; @@ -241,11 +242,13 @@ void connected_up(struct interface *ifp, struct connected *ifc) break; } + metric = (ifc->metric < (uint32_t)METRIC_MAX) ? + ifc->metric : ifp->metric; rib_add(afi, SAFI_UNICAST, ifp->vrf_id, ZEBRA_ROUTE_CONNECT, 0, 0, &p, - NULL, &nh, RT_TABLE_MAIN, ifp->metric, 0, 0, 0); + NULL, &nh, RT_TABLE_MAIN, metric, 0, 0, 0); rib_add(afi, SAFI_MULTICAST, ifp->vrf_id, ZEBRA_ROUTE_CONNECT, 0, 0, &p, - NULL, &nh, RT_TABLE_MAIN, ifp->metric, 0, 0, 0); + NULL, &nh, RT_TABLE_MAIN, metric, 0, 0, 0); if (IS_ZEBRA_DEBUG_RIB_DETAILED) { char buf[PREFIX_STRLEN]; @@ -274,7 +277,7 @@ void connected_up(struct interface *ifp, struct connected *ifc) /* Add connected IPv4 route to the interface. */ void connected_add_ipv4(struct interface *ifp, int flags, struct in_addr *addr, uint8_t prefixlen, struct in_addr *broad, - const char *label) + const char *label, uint32_t metric) { struct prefix_ipv4 *p; struct connected *ifc; @@ -286,6 +289,7 @@ void connected_add_ipv4(struct interface *ifp, int flags, struct in_addr *addr, ifc = connected_new(); ifc->ifp = ifp; ifc->flags = flags; + ifc->metric = metric; /* If we get a notification from the kernel, * we can safely assume the address is known to the kernel */ SET_FLAG(ifc->conf, ZEBRA_IFC_QUEUED); @@ -496,7 +500,7 @@ void connected_delete_ipv4(struct interface *ifp, int flags, /* Add connected IPv6 route to the interface. */ void connected_add_ipv6(struct interface *ifp, int flags, struct in6_addr *addr, struct in6_addr *broad, uint8_t prefixlen, - const char *label) + const char *label, uint32_t metric) { struct prefix_ipv6 *p; struct connected *ifc; @@ -508,6 +512,7 @@ void connected_add_ipv6(struct interface *ifp, int flags, struct in6_addr *addr, ifc = connected_new(); ifc->ifp = ifp; ifc->flags = flags; + ifc->metric = metric; /* If we get a notification from the kernel, * we can safely assume the address is known to the kernel */ SET_FLAG(ifc->conf, ZEBRA_IFC_QUEUED); diff --git a/zebra/connected.h b/zebra/connected.h index 75b6e05bda..d9c41b328b 100644 --- a/zebra/connected.h +++ b/zebra/connected.h @@ -36,7 +36,8 @@ extern struct connected *connected_check_ptp(struct interface *ifp, extern void connected_add_ipv4(struct interface *ifp, int flags, struct in_addr *addr, uint8_t prefixlen, - struct in_addr *broad, const char *label); + struct in_addr *broad, const char *label, + uint32_t metric); extern void connected_delete_ipv4(struct interface *ifp, int flags, struct in_addr *addr, uint8_t prefixlen, @@ -49,7 +50,8 @@ extern void connected_down(struct interface *ifp, struct connected *ifc); extern void connected_add_ipv6(struct interface *ifp, int flags, struct in6_addr *address, struct in6_addr *broad, - uint8_t prefixlen, const char *label); + uint8_t prefixlen, const char *label, + uint32_t metric); extern void connected_delete_ipv6(struct interface *ifp, struct in6_addr *address, struct in6_addr *broad, uint8_t prefixlen); diff --git a/zebra/if_ioctl.c b/zebra/if_ioctl.c index 176bb2bbad..d7c6486584 100644 --- a/zebra/if_ioctl.c +++ b/zebra/if_ioctl.c @@ -233,7 +233,8 @@ static int if_getaddrs(void) } connected_add_ipv4(ifp, flags, &addr->sin_addr, - prefixlen, dest_pnt, NULL); + prefixlen, dest_pnt, NULL, + METRIC_MAX); } if (ifap->ifa_addr->sa_family == AF_INET6) { struct sockaddr_in6 *addr; @@ -255,7 +256,7 @@ static int if_getaddrs(void) #endif connected_add_ipv6(ifp, flags, &addr->sin6_addr, NULL, - prefixlen, NULL); + prefixlen, NULL, METRIC_MAX); } } diff --git a/zebra/if_ioctl_solaris.c b/zebra/if_ioctl_solaris.c index 5a58fe1751..20668183bb 100644 --- a/zebra/if_ioctl_solaris.c +++ b/zebra/if_ioctl_solaris.c @@ -298,10 +298,11 @@ static int if_get_addr(struct interface *ifp, struct sockaddr *addr, /* Set address to the interface. */ if (af == AF_INET) connected_add_ipv4(ifp, flags, &SIN(addr)->sin_addr, prefixlen, - (struct in_addr *)dest_pnt, label); + (struct in_addr *)dest_pnt, label, + METRIC_MAX); else if (af == AF_INET6) connected_add_ipv6(ifp, flags, &SIN6(addr)->sin6_addr, NULL, - prefixlen, label); + prefixlen, label, METRIC_MAX); return 0; } diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index a15d914243..bed6fbf3d8 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -889,6 +889,7 @@ int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id, int startup) uint8_t flags = 0; char *label = NULL; struct zebra_ns *zns; + uint32_t metric = METRIC_MAX; zns = zebra_ns_lookup(ns_id); ifa = NLMSG_DATA(h); @@ -996,6 +997,9 @@ int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id, int startup) if (label && strcmp(ifp->name, label) == 0) label = NULL; + if (tb[IFA_RT_PRIORITY]) + metric = *(uint32_t *)RTA_DATA(tb[IFA_RT_PRIORITY]); + /* Register interface address to the interface. */ if (ifa->ifa_family == AF_INET) { if (ifa->ifa_prefixlen > IPV4_MAX_BITLEN) { @@ -1007,7 +1011,8 @@ int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id, int startup) if (h->nlmsg_type == RTM_NEWADDR) connected_add_ipv4(ifp, flags, (struct in_addr *)addr, ifa->ifa_prefixlen, - (struct in_addr *)broad, label); + (struct in_addr *)broad, label, + metric); else connected_delete_ipv4( ifp, flags, (struct in_addr *)addr, @@ -1032,7 +1037,8 @@ int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id, int startup) connected_add_ipv6(ifp, flags, (struct in6_addr *)addr, (struct in6_addr *)broad, - ifa->ifa_prefixlen, label); + ifa->ifa_prefixlen, label, + metric); } else connected_delete_ipv6(ifp, (struct in6_addr *)addr, (struct in6_addr *)broad, diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c index ff035fb353..25007d6c8c 100644 --- a/zebra/kernel_socket.c +++ b/zebra/kernel_socket.c @@ -194,7 +194,9 @@ const struct message rtm_type_str[] = {{RTM_ADD, "RTM_ADD"}, {RTM_LOSING, "RTM_LOSING"}, {RTM_REDIRECT, "RTM_REDIRECT"}, {RTM_MISS, "RTM_MISS"}, +#ifdef RTM_LOCK {RTM_LOCK, "RTM_LOCK"}, +#endif /* RTM_LOCK */ #ifdef OLDADD {RTM_OLDADD, "RTM_OLDADD"}, #endif /* RTM_OLDADD */ @@ -759,7 +761,8 @@ int ifam_read(struct ifa_msghdr *ifam) connected_add_ipv4(ifp, flags, &addr.sin.sin_addr, ip_masklen(mask.sin.sin_addr), &brd.sin.sin_addr, - (isalias ? ifname : NULL)); + (isalias ? ifname : NULL), + METRIC_MAX); else connected_delete_ipv4(ifp, flags, &addr.sin.sin_addr, ip_masklen(mask.sin.sin_addr), @@ -776,7 +779,8 @@ int ifam_read(struct ifa_msghdr *ifam) connected_add_ipv6(ifp, flags, &addr.sin6.sin6_addr, NULL, ip6_masklen(mask.sin6.sin6_addr), - (isalias ? ifname : NULL)); + (isalias ? ifname : NULL), + METRIC_MAX); else connected_delete_ipv6(ifp, &addr.sin6.sin6_addr, NULL, ip6_masklen(mask.sin6.sin6_addr)); diff --git a/zebra/label_manager.c b/zebra/label_manager.c index 65c85f7dee..1dba0a49f7 100644 --- a/zebra/label_manager.c +++ b/zebra/label_manager.c @@ -155,11 +155,9 @@ static int lm_zclient_read(struct thread *t) /* read response and send it back */ ret = relay_response_back(); - /* on error, schedule another read */ - if (ret == -1) - if (!zclient->t_read) - thread_add_read(zclient->master, lm_zclient_read, NULL, - zclient->sock, &zclient->t_read); + /* re-arm read */ + thread_add_read(zclient->master, lm_zclient_read, NULL, + zclient->sock, &zclient->t_read); return ret; } diff --git a/zebra/zebra_ns.c b/zebra/zebra_ns.c index 456253cc30..73260634f3 100644 --- a/zebra/zebra_ns.c +++ b/zebra/zebra_ns.c @@ -93,6 +93,7 @@ static int zebra_ns_new(struct ns *ns) zns = zebra_ns_alloc(); ns->info = zns; zns->ns = ns; + zns->ns_id = ns->ns_id; /* Do any needed per-NS data structure allocation. */ zns->if_table = route_table_init(); diff --git a/zebra/zebra_pw.c b/zebra/zebra_pw.c index c6db1463f2..24ffa162a6 100644 --- a/zebra/zebra_pw.c +++ b/zebra/zebra_pw.c @@ -154,6 +154,7 @@ void zebra_pw_update(struct zebra_pw *pw) { if (zebra_pw_check_reachability(pw) < 0) { zebra_pw_uninstall(pw); + zebra_pw_install_failure(pw); /* wait for NHT and try again later */ } else { /* diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index ab07549ec2..9e56559522 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -1409,7 +1409,7 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf, * from ourselves we don't * over write this pointer */ - dest->selected_fib = NULL; + dest->selected_fib = new; } /* If install succeeded or system route, cleanup flags * for prior route. */ diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index f787d641b4..ffd8482551 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -374,6 +374,7 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, json_object *json_labels = NULL; time_t uptime; struct tm *tm; + rib_dest_t *dest = rib_dest_from_rnode(rn); uptime = time(NULL); uptime -= re->uptime; @@ -398,11 +399,13 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, if (CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED)) json_object_boolean_true_add(json_route, "selected"); - if (re->type != ZEBRA_ROUTE_CONNECT) { - json_object_int_add(json_route, "distance", - re->distance); - json_object_int_add(json_route, "metric", re->metric); - } + if (dest->selected_fib == re) + json_object_boolean_true_add(json_route, + "destSelected"); + + json_object_int_add(json_route, "distance", + re->distance); + json_object_int_add(json_route, "metric", re->metric); if (re->tag) json_object_int_add(json_route, "tag", re->tag); @@ -611,7 +614,9 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, srcdest_rnode2str(rn, buf, sizeof buf)); /* Distance and metric display. */ - if (re->type != ZEBRA_ROUTE_CONNECT) + if (((re->type == ZEBRA_ROUTE_CONNECT) && + (re->distance || re->metric)) || + (re->type != ZEBRA_ROUTE_CONNECT)) len += vty_out(vty, " [%u/%u]", re->distance, re->metric); } else { @@ -741,15 +746,14 @@ static void vty_show_ip_route_detail_json(struct vty *vty, char buf[BUFSIZ]; json = json_object_new_object(); + json_prefix = json_object_new_array(); RNODE_FOREACH_RE (rn, re) { - json_prefix = json_object_new_array(); vty_show_ip_route(vty, rn, re, json_prefix); - prefix2str(&rn->p, buf, sizeof buf); - json_object_object_add(json, buf, json_prefix); - json_prefix = NULL; } + prefix2str(&rn->p, buf, sizeof(buf)); + json_object_object_add(json, buf, json_prefix); vty_out(vty, "%s\n", json_object_to_json_string_ext( json, JSON_C_TO_STRING_PRETTY)); json_object_free(json); |
