summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_table.c2
-rw-r--r--bgpd/bgp_vty.c1752
-rw-r--r--bgpd/bgpd.c26
-rw-r--r--bgpd/bgpd.h2
-rw-r--r--doc/developer/logging.rst144
-rw-r--r--doc/user/bgp.rst5
-rw-r--r--lib/monotime.h75
-rw-r--r--lib/nexthop.c2
-rw-r--r--lib/prefix.c58
-rw-r--r--lib/printf/glue.c4
-rw-r--r--lib/printfrr.h14
-rw-r--r--lib/sockunion.c6
-rw-r--r--lib/srcdest_table.c2
-rw-r--r--lib/strformat.c333
-rw-r--r--lib/thread.c67
-rw-r--r--lib/thread.h4
-rw-r--r--pimd/pim_addr.c4
-rw-r--r--tests/lib/test_printfrr.c114
-rwxr-xr-xtools/checkpatch.pl2
19 files changed, 1622 insertions, 994 deletions
diff --git a/bgpd/bgp_table.c b/bgpd/bgp_table.c
index 4ed8c7c59b..0ca78d0bb6 100644
--- a/bgpd/bgp_table.c
+++ b/bgpd/bgp_table.c
@@ -237,7 +237,7 @@ struct bgp_node *bgp_table_subtree_lookup(const struct bgp_table *table,
return matched;
}
-printfrr_ext_autoreg_p("BD", printfrr_bd)
+printfrr_ext_autoreg_p("BD", printfrr_bd);
static ssize_t printfrr_bd(struct fbuf *buf, struct printfrr_eargs *ea,
const void *ptr)
{
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index 39a35ac558..e07883865a 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -12601,1105 +12601,925 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
" Extended Optional Parameters Length is enabled\n");
}
/* Capability. */
- if (peer_established(p)) {
- if (p->cap || p->afc_adv[AFI_IP][SAFI_UNICAST]
- || p->afc_recv[AFI_IP][SAFI_UNICAST]
- || p->afc_adv[AFI_IP][SAFI_MULTICAST]
- || p->afc_recv[AFI_IP][SAFI_MULTICAST]
- || p->afc_adv[AFI_IP6][SAFI_UNICAST]
- || p->afc_recv[AFI_IP6][SAFI_UNICAST]
- || p->afc_adv[AFI_IP6][SAFI_MULTICAST]
- || p->afc_recv[AFI_IP6][SAFI_MULTICAST]
- || p->afc_adv[AFI_IP6][SAFI_MPLS_VPN]
- || p->afc_recv[AFI_IP6][SAFI_MPLS_VPN]
- || p->afc_adv[AFI_IP6][SAFI_ENCAP]
- || p->afc_recv[AFI_IP6][SAFI_ENCAP]
- || p->afc_adv[AFI_IP6][SAFI_FLOWSPEC]
- || p->afc_recv[AFI_IP6][SAFI_FLOWSPEC]
- || p->afc_adv[AFI_IP][SAFI_ENCAP]
- || p->afc_recv[AFI_IP][SAFI_ENCAP]
- || p->afc_adv[AFI_IP][SAFI_FLOWSPEC]
- || p->afc_recv[AFI_IP][SAFI_FLOWSPEC]
- || p->afc_adv[AFI_IP][SAFI_MPLS_VPN]
- || p->afc_recv[AFI_IP][SAFI_MPLS_VPN]) {
- if (use_json) {
- json_object *json_cap = NULL;
-
- json_cap = json_object_new_object();
+ if (peer_established(p) &&
+ (p->cap || peer_afc_advertised(p) || peer_afc_received(p))) {
+ if (use_json) {
+ json_object *json_cap = NULL;
- /* AS4 */
- if (CHECK_FLAG(p->cap, PEER_CAP_AS4_RCV)
- || CHECK_FLAG(p->cap, PEER_CAP_AS4_ADV)) {
- if (CHECK_FLAG(p->cap, PEER_CAP_AS4_ADV)
- && CHECK_FLAG(p->cap,
- PEER_CAP_AS4_RCV))
- json_object_string_add(
- json_cap, "4byteAs",
- "advertisedAndReceived");
- else if (CHECK_FLAG(p->cap,
- PEER_CAP_AS4_ADV))
- json_object_string_add(
- json_cap, "4byteAs",
- "advertised");
- else if (CHECK_FLAG(p->cap,
- PEER_CAP_AS4_RCV))
- json_object_string_add(
- json_cap, "4byteAs",
- "received");
- }
+ json_cap = json_object_new_object();
- /* Extended Message Support */
- if (CHECK_FLAG(p->cap,
- PEER_CAP_EXTENDED_MESSAGE_ADV)
- && CHECK_FLAG(
- p->cap,
- PEER_CAP_EXTENDED_MESSAGE_RCV))
+ /* AS4 */
+ if (CHECK_FLAG(p->cap, PEER_CAP_AS4_RCV) ||
+ CHECK_FLAG(p->cap, PEER_CAP_AS4_ADV)) {
+ if (CHECK_FLAG(p->cap, PEER_CAP_AS4_ADV) &&
+ CHECK_FLAG(p->cap, PEER_CAP_AS4_RCV))
json_object_string_add(
- json_cap, "extendedMessage",
+ json_cap, "4byteAs",
"advertisedAndReceived");
- else if (CHECK_FLAG(
- p->cap,
- PEER_CAP_EXTENDED_MESSAGE_ADV))
- json_object_string_add(
- json_cap, "extendedMessage",
- "advertised");
- else if (CHECK_FLAG(
- p->cap,
- PEER_CAP_EXTENDED_MESSAGE_RCV))
- json_object_string_add(
- json_cap, "extendedMessage",
- "received");
+ else if (CHECK_FLAG(p->cap, PEER_CAP_AS4_ADV))
+ json_object_string_add(json_cap,
+ "4byteAs",
+ "advertised");
+ else if (CHECK_FLAG(p->cap, PEER_CAP_AS4_RCV))
+ json_object_string_add(json_cap,
+ "4byteAs",
+ "received");
+ }
- /* AddPath */
- if (CHECK_FLAG(p->cap, PEER_CAP_ADDPATH_RCV)
- || CHECK_FLAG(p->cap,
- PEER_CAP_ADDPATH_ADV)) {
- json_object *json_add = NULL;
- const char *print_store;
+ /* Extended Message Support */
+ if (CHECK_FLAG(p->cap, PEER_CAP_EXTENDED_MESSAGE_ADV) &&
+ CHECK_FLAG(p->cap, PEER_CAP_EXTENDED_MESSAGE_RCV))
+ json_object_string_add(json_cap,
+ "extendedMessage",
+ "advertisedAndReceived");
+ else if (CHECK_FLAG(p->cap,
+ PEER_CAP_EXTENDED_MESSAGE_ADV))
+ json_object_string_add(json_cap,
+ "extendedMessage",
+ "advertised");
+ else if (CHECK_FLAG(p->cap,
+ PEER_CAP_EXTENDED_MESSAGE_RCV))
+ json_object_string_add(json_cap,
+ "extendedMessage",
+ "received");
- json_add = json_object_new_object();
+ /* AddPath */
+ if (CHECK_FLAG(p->cap, PEER_CAP_ADDPATH_RCV) ||
+ CHECK_FLAG(p->cap, PEER_CAP_ADDPATH_ADV)) {
+ json_object *json_add = NULL;
+ const char *print_store;
- FOREACH_AFI_SAFI (afi, safi) {
- json_object *json_sub = NULL;
- json_sub =
- json_object_new_object();
- print_store = get_afi_safi_str(
- afi, safi, true);
+ json_add = json_object_new_object();
+ FOREACH_AFI_SAFI (afi, safi) {
+ json_object *json_sub = NULL;
+ json_sub = json_object_new_object();
+ print_store = get_afi_safi_str(
+ afi, safi, true);
+
+ if (CHECK_FLAG(
+ p->af_cap[afi][safi],
+ PEER_CAP_ADDPATH_AF_TX_ADV) ||
+ CHECK_FLAG(
+ p->af_cap[afi][safi],
+ PEER_CAP_ADDPATH_AF_TX_RCV)) {
if (CHECK_FLAG(
p->af_cap[afi]
[safi],
- PEER_CAP_ADDPATH_AF_TX_ADV)
- || CHECK_FLAG(
- p->af_cap[afi]
- [safi],
- PEER_CAP_ADDPATH_AF_TX_RCV)) {
- if (CHECK_FLAG(
- p->af_cap
- [afi]
- [safi],
- PEER_CAP_ADDPATH_AF_TX_ADV)
- && CHECK_FLAG(
- p->af_cap
- [afi]
- [safi],
- PEER_CAP_ADDPATH_AF_TX_RCV))
- json_object_boolean_true_add(
- json_sub,
- "txAdvertisedAndReceived");
- else if (
- CHECK_FLAG(
- p->af_cap
- [afi]
- [safi],
- PEER_CAP_ADDPATH_AF_TX_ADV))
- json_object_boolean_true_add(
- json_sub,
- "txAdvertised");
- else if (
- CHECK_FLAG(
- p->af_cap
- [afi]
- [safi],
- PEER_CAP_ADDPATH_AF_TX_RCV))
- json_object_boolean_true_add(
- json_sub,
- "txReceived");
- }
-
- if (CHECK_FLAG(
+ PEER_CAP_ADDPATH_AF_TX_ADV) &&
+ CHECK_FLAG(
p->af_cap[afi]
[safi],
- PEER_CAP_ADDPATH_AF_RX_ADV)
- || CHECK_FLAG(
- p->af_cap[afi]
- [safi],
- PEER_CAP_ADDPATH_AF_RX_RCV)) {
- if (CHECK_FLAG(
- p->af_cap
- [afi]
- [safi],
- PEER_CAP_ADDPATH_AF_RX_ADV)
- && CHECK_FLAG(
- p->af_cap
- [afi]
- [safi],
- PEER_CAP_ADDPATH_AF_RX_RCV))
- json_object_boolean_true_add(
- json_sub,
- "rxAdvertisedAndReceived");
- else if (
- CHECK_FLAG(
- p->af_cap
- [afi]
- [safi],
- PEER_CAP_ADDPATH_AF_RX_ADV))
- json_object_boolean_true_add(
- json_sub,
- "rxAdvertised");
- else if (
- CHECK_FLAG(
- p->af_cap
- [afi]
- [safi],
- PEER_CAP_ADDPATH_AF_RX_RCV))
- json_object_boolean_true_add(
- json_sub,
- "rxReceived");
- }
+ PEER_CAP_ADDPATH_AF_TX_RCV))
+ json_object_boolean_true_add(
+ json_sub,
+ "txAdvertisedAndReceived");
+ else if (
+ CHECK_FLAG(
+ p->af_cap[afi]
+ [safi],
+ PEER_CAP_ADDPATH_AF_TX_ADV))
+ json_object_boolean_true_add(
+ json_sub,
+ "txAdvertised");
+ else if (
+ CHECK_FLAG(
+ p->af_cap[afi]
+ [safi],
+ PEER_CAP_ADDPATH_AF_TX_RCV))
+ json_object_boolean_true_add(
+ json_sub,
+ "txReceived");
+ }
+ if (CHECK_FLAG(
+ p->af_cap[afi][safi],
+ PEER_CAP_ADDPATH_AF_RX_ADV) ||
+ CHECK_FLAG(
+ p->af_cap[afi][safi],
+ PEER_CAP_ADDPATH_AF_RX_RCV)) {
if (CHECK_FLAG(
p->af_cap[afi]
[safi],
- PEER_CAP_ADDPATH_AF_TX_ADV)
- || CHECK_FLAG(
- p->af_cap[afi]
- [safi],
- PEER_CAP_ADDPATH_AF_TX_RCV)
- || CHECK_FLAG(
- p->af_cap[afi]
- [safi],
- PEER_CAP_ADDPATH_AF_RX_ADV)
- || CHECK_FLAG(
- p->af_cap[afi]
- [safi],
- PEER_CAP_ADDPATH_AF_RX_RCV))
- json_object_object_add(
- json_add,
- print_store,
- json_sub);
- else
- json_object_free(
- json_sub);
+ PEER_CAP_ADDPATH_AF_RX_ADV) &&
+ CHECK_FLAG(
+ p->af_cap[afi]
+ [safi],
+ PEER_CAP_ADDPATH_AF_RX_RCV))
+ json_object_boolean_true_add(
+ json_sub,
+ "rxAdvertisedAndReceived");
+ else if (
+ CHECK_FLAG(
+ p->af_cap[afi]
+ [safi],
+ PEER_CAP_ADDPATH_AF_RX_ADV))
+ json_object_boolean_true_add(
+ json_sub,
+ "rxAdvertised");
+ else if (
+ CHECK_FLAG(
+ p->af_cap[afi]
+ [safi],
+ PEER_CAP_ADDPATH_AF_RX_RCV))
+ json_object_boolean_true_add(
+ json_sub,
+ "rxReceived");
}
- json_object_object_add(
- json_cap, "addPath", json_add);
+ if (CHECK_FLAG(
+ p->af_cap[afi][safi],
+ PEER_CAP_ADDPATH_AF_TX_ADV) ||
+ CHECK_FLAG(
+ p->af_cap[afi][safi],
+ PEER_CAP_ADDPATH_AF_TX_RCV) ||
+ CHECK_FLAG(
+ p->af_cap[afi][safi],
+ PEER_CAP_ADDPATH_AF_RX_ADV) ||
+ CHECK_FLAG(
+ p->af_cap[afi][safi],
+ PEER_CAP_ADDPATH_AF_RX_RCV))
+ json_object_object_add(
+ json_add, print_store,
+ json_sub);
+ else
+ json_object_free(json_sub);
}
- /* Dynamic */
- if (CHECK_FLAG(p->cap, PEER_CAP_DYNAMIC_RCV)
- || CHECK_FLAG(p->cap,
- PEER_CAP_DYNAMIC_ADV)) {
- if (CHECK_FLAG(p->cap,
- PEER_CAP_DYNAMIC_ADV)
- && CHECK_FLAG(p->cap,
- PEER_CAP_DYNAMIC_RCV))
- json_object_string_add(
- json_cap, "dynamic",
- "advertisedAndReceived");
- else if (CHECK_FLAG(
- p->cap,
- PEER_CAP_DYNAMIC_ADV))
- json_object_string_add(
- json_cap, "dynamic",
- "advertised");
- else if (CHECK_FLAG(
- p->cap,
- PEER_CAP_DYNAMIC_RCV))
- json_object_string_add(
- json_cap, "dynamic",
- "received");
- }
+ json_object_object_add(json_cap, "addPath",
+ json_add);
+ }
- /* Extended nexthop */
- if (CHECK_FLAG(p->cap, PEER_CAP_ENHE_RCV)
- || CHECK_FLAG(p->cap, PEER_CAP_ENHE_ADV)) {
- json_object *json_nxt = NULL;
- const char *print_store;
+ /* Dynamic */
+ if (CHECK_FLAG(p->cap, PEER_CAP_DYNAMIC_RCV) ||
+ CHECK_FLAG(p->cap, PEER_CAP_DYNAMIC_ADV)) {
+ if (CHECK_FLAG(p->cap, PEER_CAP_DYNAMIC_ADV) &&
+ CHECK_FLAG(p->cap, PEER_CAP_DYNAMIC_RCV))
+ json_object_string_add(
+ json_cap, "dynamic",
+ "advertisedAndReceived");
+ else if (CHECK_FLAG(p->cap,
+ PEER_CAP_DYNAMIC_ADV))
+ json_object_string_add(json_cap,
+ "dynamic",
+ "advertised");
+ else if (CHECK_FLAG(p->cap,
+ PEER_CAP_DYNAMIC_RCV))
+ json_object_string_add(json_cap,
+ "dynamic",
+ "received");
+ }
+ /* Extended nexthop */
+ if (CHECK_FLAG(p->cap, PEER_CAP_ENHE_RCV) ||
+ CHECK_FLAG(p->cap, PEER_CAP_ENHE_ADV)) {
+ json_object *json_nxt = NULL;
+ const char *print_store;
- if (CHECK_FLAG(p->cap,
- PEER_CAP_ENHE_ADV)
- && CHECK_FLAG(p->cap,
- PEER_CAP_ENHE_RCV))
- json_object_string_add(
- json_cap,
- "extendedNexthop",
- "advertisedAndReceived");
- else if (CHECK_FLAG(p->cap,
- PEER_CAP_ENHE_ADV))
- json_object_string_add(
- json_cap,
- "extendedNexthop",
- "advertised");
- else if (CHECK_FLAG(p->cap,
- PEER_CAP_ENHE_RCV))
- json_object_string_add(
- json_cap,
- "extendedNexthop",
- "received");
- if (CHECK_FLAG(p->cap,
- PEER_CAP_ENHE_RCV)) {
- json_nxt =
- json_object_new_object();
+ if (CHECK_FLAG(p->cap, PEER_CAP_ENHE_ADV) &&
+ CHECK_FLAG(p->cap, PEER_CAP_ENHE_RCV))
+ json_object_string_add(
+ json_cap, "extendedNexthop",
+ "advertisedAndReceived");
+ else if (CHECK_FLAG(p->cap, PEER_CAP_ENHE_ADV))
+ json_object_string_add(
+ json_cap, "extendedNexthop",
+ "advertised");
+ else if (CHECK_FLAG(p->cap, PEER_CAP_ENHE_RCV))
+ json_object_string_add(
+ json_cap, "extendedNexthop",
+ "received");
- for (safi = SAFI_UNICAST;
- safi < SAFI_MAX; safi++) {
- if (CHECK_FLAG(
- p->af_cap
- [AFI_IP]
- [safi],
- PEER_CAP_ENHE_AF_RCV)) {
- print_store = get_afi_safi_str(
+ if (CHECK_FLAG(p->cap, PEER_CAP_ENHE_RCV)) {
+ json_nxt = json_object_new_object();
+
+ for (safi = SAFI_UNICAST;
+ safi < SAFI_MAX; safi++) {
+ if (CHECK_FLAG(
+ p->af_cap[AFI_IP]
+ [safi],
+ PEER_CAP_ENHE_AF_RCV)) {
+ print_store =
+ get_afi_safi_str(
AFI_IP,
- safi, true);
- json_object_string_add(
- json_nxt,
- print_store,
- "recieved"); /* misspelled for compatibility */
- }
+ safi,
+ true);
+ json_object_string_add(
+ json_nxt,
+ print_store,
+ "recieved"); /* misspelled for compatibility */
}
- json_object_object_add(
- json_cap,
- "extendedNexthopFamililesByPeer",
- json_nxt);
}
+ json_object_object_add(
+ json_cap,
+ "extendedNexthopFamililesByPeer",
+ json_nxt);
}
+ }
- /* Long-lived Graceful Restart */
- if (CHECK_FLAG(p->cap, PEER_CAP_LLGR_RCV)
- || CHECK_FLAG(p->cap, PEER_CAP_LLGR_ADV)) {
- json_object *json_llgr = NULL;
- const char *afi_safi_str;
+ /* Long-lived Graceful Restart */
+ if (CHECK_FLAG(p->cap, PEER_CAP_LLGR_RCV) ||
+ CHECK_FLAG(p->cap, PEER_CAP_LLGR_ADV)) {
+ json_object *json_llgr = NULL;
+ const char *afi_safi_str;
- if (CHECK_FLAG(p->cap,
- PEER_CAP_LLGR_ADV)
- && CHECK_FLAG(p->cap,
- PEER_CAP_LLGR_RCV))
- json_object_string_add(
- json_cap,
- "longLivedGracefulRestart",
- "advertisedAndReceived");
- else if (CHECK_FLAG(p->cap,
- PEER_CAP_LLGR_ADV))
- json_object_string_add(
- json_cap,
- "longLivedGracefulRestart",
- "advertised");
- else if (CHECK_FLAG(p->cap,
- PEER_CAP_LLGR_RCV))
- json_object_string_add(
- json_cap,
- "longLivedGracefulRestart",
- "received");
+ if (CHECK_FLAG(p->cap, PEER_CAP_LLGR_ADV) &&
+ CHECK_FLAG(p->cap, PEER_CAP_LLGR_RCV))
+ json_object_string_add(
+ json_cap,
+ "longLivedGracefulRestart",
+ "advertisedAndReceived");
+ else if (CHECK_FLAG(p->cap, PEER_CAP_LLGR_ADV))
+ json_object_string_add(
+ json_cap,
+ "longLivedGracefulRestart",
+ "advertised");
+ else if (CHECK_FLAG(p->cap, PEER_CAP_LLGR_RCV))
+ json_object_string_add(
+ json_cap,
+ "longLivedGracefulRestart",
+ "received");
- if (CHECK_FLAG(p->cap,
- PEER_CAP_LLGR_RCV)) {
- json_llgr =
- json_object_new_object();
+ if (CHECK_FLAG(p->cap, PEER_CAP_LLGR_RCV)) {
+ json_llgr = json_object_new_object();
- FOREACH_AFI_SAFI (afi, safi) {
- if (CHECK_FLAG(
- p->af_cap
- [afi]
- [safi],
- PEER_CAP_ENHE_AF_RCV)) {
- afi_safi_str = get_afi_safi_str(
+ FOREACH_AFI_SAFI (afi, safi) {
+ if (CHECK_FLAG(
+ p->af_cap[afi]
+ [safi],
+ PEER_CAP_ENHE_AF_RCV)) {
+ afi_safi_str =
+ get_afi_safi_str(
afi,
safi,
true);
- json_object_string_add(
- json_llgr,
- afi_safi_str,
- "received");
- }
+ json_object_string_add(
+ json_llgr,
+ afi_safi_str,
+ "received");
}
- json_object_object_add(
- json_cap,
- "longLivedGracefulRestartByPeer",
- json_llgr);
}
+ json_object_object_add(
+ json_cap,
+ "longLivedGracefulRestartByPeer",
+ json_llgr);
}
+ }
- /* Route Refresh */
- if (CHECK_FLAG(p->cap, PEER_CAP_REFRESH_ADV)
- || CHECK_FLAG(p->cap,
- PEER_CAP_REFRESH_NEW_RCV)
- || CHECK_FLAG(p->cap,
- PEER_CAP_REFRESH_OLD_RCV)) {
- if (CHECK_FLAG(p->cap,
- PEER_CAP_REFRESH_ADV)
- && (CHECK_FLAG(
- p->cap,
- PEER_CAP_REFRESH_NEW_RCV)
- || CHECK_FLAG(
- p->cap,
- PEER_CAP_REFRESH_OLD_RCV))) {
+ /* Route Refresh */
+ if (CHECK_FLAG(p->cap, PEER_CAP_REFRESH_ADV) ||
+ CHECK_FLAG(p->cap, PEER_CAP_REFRESH_NEW_RCV) ||
+ CHECK_FLAG(p->cap, PEER_CAP_REFRESH_OLD_RCV)) {
+ if (CHECK_FLAG(p->cap, PEER_CAP_REFRESH_ADV) &&
+ (CHECK_FLAG(p->cap,
+ PEER_CAP_REFRESH_NEW_RCV) ||
+ CHECK_FLAG(p->cap,
+ PEER_CAP_REFRESH_OLD_RCV))) {
+ if (CHECK_FLAG(
+ p->cap,
+ PEER_CAP_REFRESH_OLD_RCV) &&
+ CHECK_FLAG(
+ p->cap,
+ PEER_CAP_REFRESH_NEW_RCV))
+ json_object_string_add(
+ json_cap,
+ "routeRefresh",
+ "advertisedAndReceivedOldNew");
+ else {
if (CHECK_FLAG(
p->cap,
- PEER_CAP_REFRESH_OLD_RCV)
- && CHECK_FLAG(
- p->cap,
- PEER_CAP_REFRESH_NEW_RCV))
+ PEER_CAP_REFRESH_OLD_RCV))
json_object_string_add(
json_cap,
"routeRefresh",
- "advertisedAndReceivedOldNew");
- else {
- if (CHECK_FLAG(
- p->cap,
- PEER_CAP_REFRESH_OLD_RCV))
- json_object_string_add(
- json_cap,
- "routeRefresh",
- "advertisedAndReceivedOld");
- else
- json_object_string_add(
- json_cap,
- "routeRefresh",
- "advertisedAndReceivedNew");
- }
- } else if (
- CHECK_FLAG(
- p->cap,
- PEER_CAP_REFRESH_ADV))
- json_object_string_add(
- json_cap,
- "routeRefresh",
- "advertised");
- else if (
- CHECK_FLAG(
- p->cap,
- PEER_CAP_REFRESH_NEW_RCV)
- || CHECK_FLAG(
- p->cap,
- PEER_CAP_REFRESH_OLD_RCV))
- json_object_string_add(
- json_cap,
- "routeRefresh",
- "received");
- }
+ "advertisedAndReceivedOld");
+ else
+ json_object_string_add(
+ json_cap,
+ "routeRefresh",
+ "advertisedAndReceivedNew");
+ }
+ } else if (CHECK_FLAG(p->cap,
+ PEER_CAP_REFRESH_ADV))
+ json_object_string_add(json_cap,
+ "routeRefresh",
+ "advertised");
+ else if (CHECK_FLAG(p->cap,
+ PEER_CAP_REFRESH_NEW_RCV) ||
+ CHECK_FLAG(p->cap,
+ PEER_CAP_REFRESH_OLD_RCV))
+ json_object_string_add(json_cap,
+ "routeRefresh",
+ "received");
+ }
- /* Enhanced Route Refresh */
- if (CHECK_FLAG(p->cap, PEER_CAP_ENHANCED_RR_ADV)
- || CHECK_FLAG(p->cap,
- PEER_CAP_ENHANCED_RR_RCV)) {
- if (CHECK_FLAG(p->cap,
- PEER_CAP_ENHANCED_RR_ADV)
- && CHECK_FLAG(
- p->cap,
+ /* Enhanced Route Refresh */
+ if (CHECK_FLAG(p->cap, PEER_CAP_ENHANCED_RR_ADV) ||
+ CHECK_FLAG(p->cap, PEER_CAP_ENHANCED_RR_RCV)) {
+ if (CHECK_FLAG(p->cap,
+ PEER_CAP_ENHANCED_RR_ADV) &&
+ CHECK_FLAG(p->cap,
+ PEER_CAP_ENHANCED_RR_RCV))
+ json_object_string_add(
+ json_cap,
+ "enhancedRouteRefresh",
+ "advertisedAndReceived");
+ else if (CHECK_FLAG(p->cap,
+ PEER_CAP_ENHANCED_RR_ADV))
+ json_object_string_add(
+ json_cap,
+ "enhancedRouteRefresh",
+ "advertised");
+ else if (CHECK_FLAG(p->cap,
PEER_CAP_ENHANCED_RR_RCV))
- json_object_string_add(
- json_cap,
- "enhancedRouteRefresh",
+ json_object_string_add(
+ json_cap,
+ "enhancedRouteRefresh",
+ "received");
+ }
+
+ /* Multiprotocol Extensions */
+ json_object *json_multi = NULL;
+
+ json_multi = json_object_new_object();
+
+ FOREACH_AFI_SAFI (afi, safi) {
+ if (p->afc_adv[afi][safi] ||
+ p->afc_recv[afi][safi]) {
+ json_object *json_exten = NULL;
+ json_exten = json_object_new_object();
+
+ if (p->afc_adv[afi][safi] &&
+ p->afc_recv[afi][safi])
+ json_object_boolean_true_add(
+ json_exten,
"advertisedAndReceived");
- else if (
- CHECK_FLAG(
- p->cap,
- PEER_CAP_ENHANCED_RR_ADV))
- json_object_string_add(
- json_cap,
- "enhancedRouteRefresh",
+ else if (p->afc_adv[afi][safi])
+ json_object_boolean_true_add(
+ json_exten,
"advertised");
- else if (
- CHECK_FLAG(
- p->cap,
- PEER_CAP_ENHANCED_RR_RCV))
- json_object_string_add(
- json_cap,
- "enhancedRouteRefresh",
- "received");
+ else if (p->afc_recv[afi][safi])
+ json_object_boolean_true_add(
+ json_exten, "received");
+
+ json_object_object_add(
+ json_multi,
+ get_afi_safi_str(afi, safi,
+ true),
+ json_exten);
}
+ }
+ json_object_object_add(json_cap,
+ "multiprotocolExtensions",
+ json_multi);
- /* Multiprotocol Extensions */
- json_object *json_multi = NULL;
- json_multi = json_object_new_object();
+ /* Hostname capabilities */
+ json_object *json_hname = NULL;
- FOREACH_AFI_SAFI (afi, safi) {
- if (p->afc_adv[afi][safi]
- || p->afc_recv[afi][safi]) {
- json_object *json_exten = NULL;
- json_exten =
- json_object_new_object();
-
- if (p->afc_adv[afi][safi]
- && p->afc_recv[afi][safi])
- json_object_boolean_true_add(
- json_exten,
- "advertisedAndReceived");
- else if (p->afc_adv[afi][safi])
- json_object_boolean_true_add(
- json_exten,
- "advertised");
- else if (p->afc_recv[afi][safi])
- json_object_boolean_true_add(
- json_exten,
- "received");
+ json_hname = json_object_new_object();
- json_object_object_add(
- json_multi,
- get_afi_safi_str(afi,
- safi,
- true),
- json_exten);
- }
- }
- json_object_object_add(
- json_cap, "multiprotocolExtensions",
- json_multi);
-
- /* Hostname capabilities */
- json_object *json_hname = NULL;
+ if (CHECK_FLAG(p->cap, PEER_CAP_HOSTNAME_ADV)) {
+ json_object_string_add(
+ json_hname, "advHostName",
+ bgp->peer_self->hostname
+ ? bgp->peer_self->hostname
+ : "n/a");
+ json_object_string_add(
+ json_hname, "advDomainName",
+ bgp->peer_self->domainname
+ ? bgp->peer_self->domainname
+ : "n/a");
+ }
- json_hname = json_object_new_object();
- if (CHECK_FLAG(p->cap, PEER_CAP_HOSTNAME_ADV)) {
- json_object_string_add(
- json_hname, "advHostName",
- bgp->peer_self->hostname
- ? bgp->peer_self
- ->hostname
- : "n/a");
- json_object_string_add(
- json_hname, "advDomainName",
- bgp->peer_self->domainname
- ? bgp->peer_self
- ->domainname
- : "n/a");
- }
+ if (CHECK_FLAG(p->cap, PEER_CAP_HOSTNAME_RCV)) {
+ json_object_string_add(
+ json_hname, "rcvHostName",
+ p->hostname ? p->hostname : "n/a");
+ json_object_string_add(
+ json_hname, "rcvDomainName",
+ p->domainname ? p->domainname : "n/a");
+ }
+ json_object_object_add(json_cap, "hostName",
+ json_hname);
- if (CHECK_FLAG(p->cap, PEER_CAP_HOSTNAME_RCV)) {
+ /* Gracefull Restart */
+ if (CHECK_FLAG(p->cap, PEER_CAP_RESTART_RCV) ||
+ CHECK_FLAG(p->cap, PEER_CAP_RESTART_ADV)) {
+ if (CHECK_FLAG(p->cap, PEER_CAP_RESTART_ADV) &&
+ CHECK_FLAG(p->cap, PEER_CAP_RESTART_RCV))
+ json_object_string_add(
+ json_cap, "gracefulRestart",
+ "advertisedAndReceived");
+ else if (CHECK_FLAG(p->cap,
+ PEER_CAP_RESTART_ADV))
json_object_string_add(
- json_hname, "rcvHostName",
- p->hostname ? p->hostname
- : "n/a");
+ json_cap,
+ "gracefulRestartCapability",
+ "advertised");
+ else if (CHECK_FLAG(p->cap,
+ PEER_CAP_RESTART_RCV))
json_object_string_add(
- json_hname, "rcvDomainName",
- p->domainname ? p->domainname
- : "n/a");
- }
+ json_cap,
+ "gracefulRestartCapability",
+ "received");
- json_object_object_add(json_cap, "hostName",
- json_hname);
-
- /* Gracefull Restart */
- if (CHECK_FLAG(p->cap, PEER_CAP_RESTART_RCV)
- || CHECK_FLAG(p->cap,
- PEER_CAP_RESTART_ADV)) {
- if (CHECK_FLAG(p->cap,
- PEER_CAP_RESTART_ADV)
- && CHECK_FLAG(p->cap,
- PEER_CAP_RESTART_RCV))
- json_object_string_add(
- json_cap,
- "gracefulRestart",
- "advertisedAndReceived");
- else if (CHECK_FLAG(
- p->cap,
- PEER_CAP_RESTART_ADV))
- json_object_string_add(
- json_cap,
- "gracefulRestartCapability",
- "advertised");
- else if (CHECK_FLAG(
- p->cap,
- PEER_CAP_RESTART_RCV))
- json_object_string_add(
- json_cap,
- "gracefulRestartCapability",
- "received");
+ if (CHECK_FLAG(p->cap, PEER_CAP_RESTART_RCV)) {
+ int restart_af_count = 0;
+ json_object *json_restart = NULL;
+ json_restart = json_object_new_object();
- if (CHECK_FLAG(p->cap,
- PEER_CAP_RESTART_RCV)) {
- int restart_af_count = 0;
- json_object *json_restart =
- NULL;
- json_restart =
- json_object_new_object();
+ json_object_int_add(
+ json_cap,
+ "gracefulRestartRemoteTimerMsecs",
+ p->v_gr_restart * 1000);
- json_object_int_add(
- json_cap,
- "gracefulRestartRemoteTimerMsecs",
- p->v_gr_restart * 1000);
+ FOREACH_AFI_SAFI (afi, safi) {
+ if (CHECK_FLAG(
+ p->af_cap[afi]
+ [safi],
+ PEER_CAP_RESTART_AF_RCV)) {
+ json_object *json_sub =
+ NULL;
+ json_sub =
+ json_object_new_object();
- FOREACH_AFI_SAFI (afi, safi) {
if (CHECK_FLAG(
p->af_cap
[afi]
[safi],
- PEER_CAP_RESTART_AF_RCV)) {
- json_object *
- json_sub =
- NULL;
- json_sub =
- json_object_new_object();
-
- if (CHECK_FLAG(
- p->af_cap
- [afi]
- [safi],
- PEER_CAP_RESTART_AF_PRESERVE_RCV))
- json_object_boolean_true_add(
- json_sub,
- "preserved");
- restart_af_count++;
- json_object_object_add(
- json_restart,
- get_afi_safi_str(
- afi,
- safi,
- true),
- json_sub);
- }
- }
- if (!restart_af_count) {
- json_object_string_add(
- json_cap,
- "addressFamiliesByPeer",
- "none");
- json_object_free(
- json_restart);
- } else
+ PEER_CAP_RESTART_AF_PRESERVE_RCV))
+ json_object_boolean_true_add(
+ json_sub,
+ "preserved");
+ restart_af_count++;
json_object_object_add(
- json_cap,
- "addressFamiliesByPeer",
- json_restart);
+ json_restart,
+ get_afi_safi_str(
+ afi,
+ safi,
+ true),
+ json_sub);
+ }
}
+ if (!restart_af_count) {
+ json_object_string_add(
+ json_cap,
+ "addressFamiliesByPeer",
+ "none");
+ json_object_free(json_restart);
+ } else
+ json_object_object_add(
+ json_cap,
+ "addressFamiliesByPeer",
+ json_restart);
}
- json_object_object_add(json_neigh,
- "neighborCapabilities",
- json_cap);
- } else {
- vty_out(vty, " Neighbor capabilities:\n");
-
- /* AS4 */
- if (CHECK_FLAG(p->cap, PEER_CAP_AS4_RCV)
- || CHECK_FLAG(p->cap, PEER_CAP_AS4_ADV)) {
- vty_out(vty, " 4 Byte AS:");
- if (CHECK_FLAG(p->cap,
- PEER_CAP_AS4_ADV))
- vty_out(vty, " advertised");
- if (CHECK_FLAG(p->cap,
- PEER_CAP_AS4_RCV))
- vty_out(vty, " %sreceived",
- CHECK_FLAG(
- p->cap,
- PEER_CAP_AS4_ADV)
- ? "and "
- : "");
- vty_out(vty, "\n");
- }
+ }
+ json_object_object_add(
+ json_neigh, "neighborCapabilities", json_cap);
+ } else {
+ vty_out(vty, " Neighbor capabilities:\n");
+
+ /* AS4 */
+ if (CHECK_FLAG(p->cap, PEER_CAP_AS4_RCV) ||
+ CHECK_FLAG(p->cap, PEER_CAP_AS4_ADV)) {
+ vty_out(vty, " 4 Byte AS:");
+ if (CHECK_FLAG(p->cap, PEER_CAP_AS4_ADV))
+ vty_out(vty, " advertised");
+ if (CHECK_FLAG(p->cap, PEER_CAP_AS4_RCV))
+ vty_out(vty, " %sreceived",
+ CHECK_FLAG(p->cap,
+ PEER_CAP_AS4_ADV)
+ ? "and "
+ : "");
+ vty_out(vty, "\n");
+ }
- /* Extended Message Support */
+ /* Extended Message Support */
+ if (CHECK_FLAG(p->cap, PEER_CAP_EXTENDED_MESSAGE_RCV) ||
+ CHECK_FLAG(p->cap, PEER_CAP_EXTENDED_MESSAGE_ADV)) {
+ vty_out(vty, " Extended Message:");
if (CHECK_FLAG(p->cap,
- PEER_CAP_EXTENDED_MESSAGE_RCV)
- || CHECK_FLAG(
- p->cap,
- PEER_CAP_EXTENDED_MESSAGE_ADV)) {
- vty_out(vty, " Extended Message:");
- if (CHECK_FLAG(
- p->cap,
- PEER_CAP_EXTENDED_MESSAGE_ADV))
- vty_out(vty, " advertised");
+ PEER_CAP_EXTENDED_MESSAGE_ADV))
+ vty_out(vty, " advertised");
+ if (CHECK_FLAG(p->cap,
+ PEER_CAP_EXTENDED_MESSAGE_RCV))
+ vty_out(vty, " %sreceived",
+ CHECK_FLAG(
+ p->cap,
+ PEER_CAP_EXTENDED_MESSAGE_ADV)
+ ? "and "
+ : "");
+ vty_out(vty, "\n");
+ }
+
+ /* AddPath */
+ if (CHECK_FLAG(p->cap, PEER_CAP_ADDPATH_RCV) ||
+ CHECK_FLAG(p->cap, PEER_CAP_ADDPATH_ADV)) {
+ vty_out(vty, " AddPath:\n");
+
+ FOREACH_AFI_SAFI (afi, safi) {
if (CHECK_FLAG(
- p->cap,
- PEER_CAP_EXTENDED_MESSAGE_RCV))
- vty_out(vty, " %sreceived",
- CHECK_FLAG(
- p->cap,
- PEER_CAP_EXTENDED_MESSAGE_ADV)
- ? "and "
- : "");
- vty_out(vty, "\n");
- }
+ p->af_cap[afi][safi],
+ PEER_CAP_ADDPATH_AF_TX_ADV) ||
+ CHECK_FLAG(
+ p->af_cap[afi][safi],
+ PEER_CAP_ADDPATH_AF_TX_RCV)) {
+ vty_out(vty, " %s: TX ",
+ get_afi_safi_str(
+ afi, safi,
+ false));
- /* AddPath */
- if (CHECK_FLAG(p->cap, PEER_CAP_ADDPATH_RCV)
- || CHECK_FLAG(p->cap,
- PEER_CAP_ADDPATH_ADV)) {
- vty_out(vty, " AddPath:\n");
+ if (CHECK_FLAG(
+ p->af_cap[afi]
+ [safi],
+ PEER_CAP_ADDPATH_AF_TX_ADV))
+ vty_out(vty,
+ "advertised");
- FOREACH_AFI_SAFI (afi, safi) {
if (CHECK_FLAG(
p->af_cap[afi]
[safi],
- PEER_CAP_ADDPATH_AF_TX_ADV)
- || CHECK_FLAG(
- p->af_cap[afi]
- [safi],
- PEER_CAP_ADDPATH_AF_TX_RCV)) {
+ PEER_CAP_ADDPATH_AF_TX_RCV))
vty_out(vty,
- " %s: TX ",
- get_afi_safi_str(
- afi,
- safi,
- false));
+ "%sreceived",
+ CHECK_FLAG(
+ p->af_cap
+ [afi]
+ [safi],
+ PEER_CAP_ADDPATH_AF_TX_ADV)
+ ? " and "
+ : "");
- if (CHECK_FLAG(
- p->af_cap
- [afi]
- [safi],
- PEER_CAP_ADDPATH_AF_TX_ADV))
- vty_out(vty,
- "advertised");
+ vty_out(vty, "\n");
+ }
- if (CHECK_FLAG(
- p->af_cap
- [afi]
- [safi],
- PEER_CAP_ADDPATH_AF_TX_RCV))
- vty_out(vty,
- "%sreceived",
- CHECK_FLAG(
- p->af_cap
- [afi]
- [safi],
- PEER_CAP_ADDPATH_AF_TX_ADV)
- ? " and "
- : "");
-
- vty_out(vty, "\n");
- }
+ if (CHECK_FLAG(
+ p->af_cap[afi][safi],
+ PEER_CAP_ADDPATH_AF_RX_ADV) ||
+ CHECK_FLAG(
+ p->af_cap[afi][safi],
+ PEER_CAP_ADDPATH_AF_RX_RCV)) {
+ vty_out(vty, " %s: RX ",
+ get_afi_safi_str(
+ afi, safi,
+ false));
if (CHECK_FLAG(
p->af_cap[afi]
[safi],
- PEER_CAP_ADDPATH_AF_RX_ADV)
- || CHECK_FLAG(
- p->af_cap[afi]
- [safi],
- PEER_CAP_ADDPATH_AF_RX_RCV)) {
+ PEER_CAP_ADDPATH_AF_RX_ADV))
vty_out(vty,
- " %s: RX ",
- get_afi_safi_str(
- afi,
- safi,
- false));
+ "advertised");
- if (CHECK_FLAG(
- p->af_cap
- [afi]
- [safi],
- PEER_CAP_ADDPATH_AF_RX_ADV))
- vty_out(vty,
- "advertised");
+ if (CHECK_FLAG(
+ p->af_cap[afi]
+ [safi],
+ PEER_CAP_ADDPATH_AF_RX_RCV))
+ vty_out(vty,
+ "%sreceived",
+ CHECK_FLAG(
+ p->af_cap
+ [afi]
+ [safi],
+ PEER_CAP_ADDPATH_AF_RX_ADV)
+ ? " and "
+ : "");
- if (CHECK_FLAG(
- p->af_cap
- [afi]
- [safi],
- PEER_CAP_ADDPATH_AF_RX_RCV))
- vty_out(vty,
- "%sreceived",
- CHECK_FLAG(
- p->af_cap
- [afi]
- [safi],
- PEER_CAP_ADDPATH_AF_RX_ADV)
- ? " and "
- : "");
-
- vty_out(vty, "\n");
- }
+ vty_out(vty, "\n");
}
}
+ }
- /* Dynamic */
- if (CHECK_FLAG(p->cap, PEER_CAP_DYNAMIC_RCV)
- || CHECK_FLAG(p->cap,
- PEER_CAP_DYNAMIC_ADV)) {
- vty_out(vty, " Dynamic:");
- if (CHECK_FLAG(p->cap,
- PEER_CAP_DYNAMIC_ADV))
- vty_out(vty, " advertised");
- if (CHECK_FLAG(p->cap,
- PEER_CAP_DYNAMIC_RCV))
- vty_out(vty, " %sreceived",
- CHECK_FLAG(
- p->cap,
- PEER_CAP_DYNAMIC_ADV)
- ? "and "
- : "");
- vty_out(vty, "\n");
- }
+ /* Dynamic */
+ if (CHECK_FLAG(p->cap, PEER_CAP_DYNAMIC_RCV) ||
+ CHECK_FLAG(p->cap, PEER_CAP_DYNAMIC_ADV)) {
+ vty_out(vty, " Dynamic:");
+ if (CHECK_FLAG(p->cap, PEER_CAP_DYNAMIC_ADV))
+ vty_out(vty, " advertised");
+ if (CHECK_FLAG(p->cap, PEER_CAP_DYNAMIC_RCV))
+ vty_out(vty, " %sreceived",
+ CHECK_FLAG(p->cap,
+ PEER_CAP_DYNAMIC_ADV)
+ ? "and "
+ : "");
+ vty_out(vty, "\n");
+ }
- /* Extended nexthop */
- if (CHECK_FLAG(p->cap, PEER_CAP_ENHE_RCV)
- || CHECK_FLAG(p->cap, PEER_CAP_ENHE_ADV)) {
- vty_out(vty, " Extended nexthop:");
- if (CHECK_FLAG(p->cap,
- PEER_CAP_ENHE_ADV))
- vty_out(vty, " advertised");
- if (CHECK_FLAG(p->cap,
- PEER_CAP_ENHE_RCV))
- vty_out(vty, " %sreceived",
- CHECK_FLAG(
- p->cap,
- PEER_CAP_ENHE_ADV)
- ? "and "
- : "");
- vty_out(vty, "\n");
+ /* Extended nexthop */
+ if (CHECK_FLAG(p->cap, PEER_CAP_ENHE_RCV) ||
+ CHECK_FLAG(p->cap, PEER_CAP_ENHE_ADV)) {
+ vty_out(vty, " Extended nexthop:");
+ if (CHECK_FLAG(p->cap, PEER_CAP_ENHE_ADV))
+ vty_out(vty, " advertised");
+ if (CHECK_FLAG(p->cap, PEER_CAP_ENHE_RCV))
+ vty_out(vty, " %sreceived",
+ CHECK_FLAG(p->cap,
+ PEER_CAP_ENHE_ADV)
+ ? "and "
+ : "");
+ vty_out(vty, "\n");
- if (CHECK_FLAG(p->cap,
- PEER_CAP_ENHE_RCV)) {
- vty_out(vty,
- " Address families by peer:\n ");
- for (safi = SAFI_UNICAST;
- safi < SAFI_MAX; safi++)
- if (CHECK_FLAG(
- p->af_cap
- [AFI_IP]
- [safi],
- PEER_CAP_ENHE_AF_RCV))
- vty_out(vty,
- " %s\n",
- get_afi_safi_str(
- AFI_IP,
- safi,
- false));
- }
+ if (CHECK_FLAG(p->cap, PEER_CAP_ENHE_RCV)) {
+ vty_out(vty,
+ " Address families by peer:\n ");
+ for (safi = SAFI_UNICAST;
+ safi < SAFI_MAX; safi++)
+ if (CHECK_FLAG(
+ p->af_cap[AFI_IP]
+ [safi],
+ PEER_CAP_ENHE_AF_RCV))
+ vty_out(vty,
+ " %s\n",
+ get_afi_safi_str(
+ AFI_IP,
+ safi,
+ false));
}
+ }
- /* Long-lived Graceful Restart */
- if (CHECK_FLAG(p->cap, PEER_CAP_LLGR_RCV)
- || CHECK_FLAG(p->cap, PEER_CAP_LLGR_ADV)) {
- vty_out(vty,
- " Long-lived Graceful Restart:");
- if (CHECK_FLAG(p->cap,
- PEER_CAP_LLGR_ADV))
- vty_out(vty, " advertised");
- if (CHECK_FLAG(p->cap,
- PEER_CAP_LLGR_RCV))
- vty_out(vty, " %sreceived",
- CHECK_FLAG(
- p->cap,
- PEER_CAP_LLGR_ADV)
- ? "and "
- : "");
- vty_out(vty, "\n");
+ /* Long-lived Graceful Restart */
+ if (CHECK_FLAG(p->cap, PEER_CAP_LLGR_RCV) ||
+ CHECK_FLAG(p->cap, PEER_CAP_LLGR_ADV)) {
+ vty_out(vty,
+ " Long-lived Graceful Restart:");
+ if (CHECK_FLAG(p->cap, PEER_CAP_LLGR_ADV))
+ vty_out(vty, " advertised");
+ if (CHECK_FLAG(p->cap, PEER_CAP_LLGR_RCV))
+ vty_out(vty, " %sreceived",
+ CHECK_FLAG(p->cap,
+ PEER_CAP_LLGR_ADV)
+ ? "and "
+ : "");
+ vty_out(vty, "\n");
- if (CHECK_FLAG(p->cap,
- PEER_CAP_LLGR_RCV)) {
- vty_out(vty,
- " Address families by peer:\n");
- FOREACH_AFI_SAFI (afi, safi)
- if (CHECK_FLAG(
- p->af_cap
- [afi]
- [safi],
- PEER_CAP_LLGR_AF_RCV))
- vty_out(vty,
- " %s\n",
- get_afi_safi_str(
- afi,
- safi,
- false));
- }
+ if (CHECK_FLAG(p->cap, PEER_CAP_LLGR_RCV)) {
+ vty_out(vty,
+ " Address families by peer:\n");
+ FOREACH_AFI_SAFI (afi, safi)
+ if (CHECK_FLAG(
+ p->af_cap[afi]
+ [safi],
+ PEER_CAP_LLGR_AF_RCV))
+ vty_out(vty,
+ " %s\n",
+ get_afi_safi_str(
+ afi,
+ safi,
+ false));
}
+ }
- /* Route Refresh */
- if (CHECK_FLAG(p->cap, PEER_CAP_REFRESH_ADV)
- || CHECK_FLAG(p->cap,
- PEER_CAP_REFRESH_NEW_RCV)
- || CHECK_FLAG(p->cap,
- PEER_CAP_REFRESH_OLD_RCV)) {
- vty_out(vty, " Route refresh:");
- if (CHECK_FLAG(p->cap,
- PEER_CAP_REFRESH_ADV))
- vty_out(vty, " advertised");
- if (CHECK_FLAG(p->cap,
- PEER_CAP_REFRESH_NEW_RCV)
- || CHECK_FLAG(
- p->cap,
- PEER_CAP_REFRESH_OLD_RCV))
- vty_out(vty, " %sreceived(%s)",
- CHECK_FLAG(
- p->cap,
- PEER_CAP_REFRESH_ADV)
- ? "and "
- : "",
- (CHECK_FLAG(
- p->cap,
- PEER_CAP_REFRESH_OLD_RCV)
- && CHECK_FLAG(
- p->cap,
- PEER_CAP_REFRESH_NEW_RCV))
- ? "old & new"
- : CHECK_FLAG(
- p->cap,
- PEER_CAP_REFRESH_OLD_RCV)
- ? "old"
- : "new");
+ /* Route Refresh */
+ if (CHECK_FLAG(p->cap, PEER_CAP_REFRESH_ADV) ||
+ CHECK_FLAG(p->cap, PEER_CAP_REFRESH_NEW_RCV) ||
+ CHECK_FLAG(p->cap, PEER_CAP_REFRESH_OLD_RCV)) {
+ vty_out(vty, " Route refresh:");
+ if (CHECK_FLAG(p->cap, PEER_CAP_REFRESH_ADV))
+ vty_out(vty, " advertised");
+ if (CHECK_FLAG(p->cap,
+ PEER_CAP_REFRESH_NEW_RCV) ||
+ CHECK_FLAG(p->cap,
+ PEER_CAP_REFRESH_OLD_RCV))
+ vty_out(vty, " %sreceived(%s)",
+ CHECK_FLAG(p->cap,
+ PEER_CAP_REFRESH_ADV)
+ ? "and "
+ : "",
+ (CHECK_FLAG(
+ p->cap,
+ PEER_CAP_REFRESH_OLD_RCV) &&
+ CHECK_FLAG(
+ p->cap,
+ PEER_CAP_REFRESH_NEW_RCV))
+ ? "old & new"
+ : CHECK_FLAG(
+ p->cap,
+ PEER_CAP_REFRESH_OLD_RCV)
+ ? "old"
+ : "new");
- vty_out(vty, "\n");
- }
+ vty_out(vty, "\n");
+ }
- /* Enhanced Route Refresh */
- if (CHECK_FLAG(p->cap, PEER_CAP_ENHANCED_RR_ADV)
- || CHECK_FLAG(p->cap,
- PEER_CAP_ENHANCED_RR_RCV)) {
- vty_out(vty,
- " Enhanced Route Refresh:");
- if (CHECK_FLAG(
- p->cap,
- PEER_CAP_ENHANCED_RR_ADV))
+ /* Enhanced Route Refresh */
+ if (CHECK_FLAG(p->cap, PEER_CAP_ENHANCED_RR_ADV) ||
+ CHECK_FLAG(p->cap, PEER_CAP_ENHANCED_RR_RCV)) {
+ vty_out(vty, " Enhanced Route Refresh:");
+ if (CHECK_FLAG(p->cap,
+ PEER_CAP_ENHANCED_RR_ADV))
+ vty_out(vty, " advertised");
+ if (CHECK_FLAG(p->cap,
+ PEER_CAP_ENHANCED_RR_RCV))
+ vty_out(vty, " %sreceived",
+ CHECK_FLAG(p->cap,
+ PEER_CAP_REFRESH_ADV)
+ ? "and "
+ : "");
+ vty_out(vty, "\n");
+ }
+
+ /* Multiprotocol Extensions */
+ FOREACH_AFI_SAFI (afi, safi)
+ if (p->afc_adv[afi][safi] ||
+ p->afc_recv[afi][safi]) {
+ vty_out(vty, " Address Family %s:",
+ get_afi_safi_str(afi, safi,
+ false));
+ if (p->afc_adv[afi][safi])
vty_out(vty, " advertised");
- if (CHECK_FLAG(
- p->cap,
- PEER_CAP_ENHANCED_RR_RCV))
+ if (p->afc_recv[afi][safi])
vty_out(vty, " %sreceived",
- CHECK_FLAG(
- p->cap,
- PEER_CAP_REFRESH_ADV)
+ p->afc_adv[afi][safi]
? "and "
: "");
vty_out(vty, "\n");
}
- /* Multiprotocol Extensions */
- FOREACH_AFI_SAFI (afi, safi)
- if (p->afc_adv[afi][safi]
- || p->afc_recv[afi][safi]) {
- vty_out(vty,
- " Address Family %s:",
- get_afi_safi_str(
- afi,
- safi,
- false));
- if (p->afc_adv[afi][safi])
- vty_out(vty,
- " advertised");
- if (p->afc_recv[afi][safi])
- vty_out(vty,
- " %sreceived",
- p->afc_adv[afi]
- [safi]
- ? "and "
- : "");
- vty_out(vty, "\n");
- }
+ /* Hostname capability */
+ vty_out(vty, " Hostname Capability:");
- /* Hostname capability */
- vty_out(vty, " Hostname Capability:");
+ if (CHECK_FLAG(p->cap, PEER_CAP_HOSTNAME_ADV)) {
+ vty_out(vty,
+ " advertised (name: %s,domain name: %s)",
+ bgp->peer_self->hostname
+ ? bgp->peer_self->hostname
+ : "n/a",
+ bgp->peer_self->domainname
+ ? bgp->peer_self->domainname
+ : "n/a");
+ } else {
+ vty_out(vty, " not advertised");
+ }
- if (CHECK_FLAG(p->cap, PEER_CAP_HOSTNAME_ADV)) {
- vty_out(vty,
- " advertised (name: %s,domain name: %s)",
- bgp->peer_self->hostname
- ? bgp->peer_self
- ->hostname
- : "n/a",
- bgp->peer_self->domainname
- ? bgp->peer_self
- ->domainname
- : "n/a");
- } else {
- vty_out(vty, " not advertised");
- }
+ if (CHECK_FLAG(p->cap, PEER_CAP_HOSTNAME_RCV)) {
+ vty_out(vty,
+ " received (name: %s,domain name: %s)",
+ p->hostname ? p->hostname : "n/a",
+ p->domainname ? p->domainname : "n/a");
+ } else {
+ vty_out(vty, " not received");
+ }
- if (CHECK_FLAG(p->cap, PEER_CAP_HOSTNAME_RCV)) {
- vty_out(vty,
- " received (name: %s,domain name: %s)",
- p->hostname ? p->hostname
- : "n/a",
- p->domainname ? p->domainname
- : "n/a");
- } else {
- vty_out(vty, " not received");
- }
+ vty_out(vty, "\n");
+ /* Graceful Restart */
+ if (CHECK_FLAG(p->cap, PEER_CAP_RESTART_RCV) ||
+ CHECK_FLAG(p->cap, PEER_CAP_RESTART_ADV)) {
+ vty_out(vty,
+ " Graceful Restart Capability:");
+ if (CHECK_FLAG(p->cap, PEER_CAP_RESTART_ADV))
+ vty_out(vty, " advertised");
+ if (CHECK_FLAG(p->cap, PEER_CAP_RESTART_RCV))
+ vty_out(vty, " %sreceived",
+ CHECK_FLAG(p->cap,
+ PEER_CAP_RESTART_ADV)
+ ? "and "
+ : "");
vty_out(vty, "\n");
- /* Graceful Restart */
- if (CHECK_FLAG(p->cap, PEER_CAP_RESTART_RCV)
- || CHECK_FLAG(p->cap,
- PEER_CAP_RESTART_ADV)) {
- vty_out(vty,
- " Graceful Restart Capability:");
- if (CHECK_FLAG(p->cap,
- PEER_CAP_RESTART_ADV))
- vty_out(vty, " advertised");
- if (CHECK_FLAG(p->cap,
- PEER_CAP_RESTART_RCV))
- vty_out(vty, " %sreceived",
- CHECK_FLAG(
- p->cap,
- PEER_CAP_RESTART_ADV)
- ? "and "
- : "");
- vty_out(vty, "\n");
-
- if (CHECK_FLAG(p->cap,
- PEER_CAP_RESTART_RCV)) {
- int restart_af_count = 0;
+ if (CHECK_FLAG(p->cap, PEER_CAP_RESTART_RCV)) {
+ int restart_af_count = 0;
- vty_out(vty,
- " Remote Restart timer is %d seconds\n",
- p->v_gr_restart);
- vty_out(vty,
- " Address families by peer:\n ");
+ vty_out(vty,
+ " Remote Restart timer is %d seconds\n",
+ p->v_gr_restart);
+ vty_out(vty,
+ " Address families by peer:\n ");
- FOREACH_AFI_SAFI (afi, safi)
- if (CHECK_FLAG(
- p->af_cap
- [afi]
- [safi],
- PEER_CAP_RESTART_AF_RCV)) {
- vty_out(vty,
- "%s%s(%s)",
- restart_af_count
- ? ", "
- : "",
- get_afi_safi_str(
- afi,
- safi,
- false),
- CHECK_FLAG(
- p->af_cap
- [afi]
- [safi],
- PEER_CAP_RESTART_AF_PRESERVE_RCV)
- ? "preserved"
- : "not preserved");
- restart_af_count++;
- }
- if (!restart_af_count)
- vty_out(vty, "none");
- vty_out(vty, "\n");
- }
- } /* Gracefull Restart */
- }
+ FOREACH_AFI_SAFI (afi, safi)
+ if (CHECK_FLAG(
+ p->af_cap[afi]
+ [safi],
+ PEER_CAP_RESTART_AF_RCV)) {
+ vty_out(vty, "%s%s(%s)",
+ restart_af_count
+ ? ", "
+ : "",
+ get_afi_safi_str(
+ afi,
+ safi,
+ false),
+ CHECK_FLAG(
+ p->af_cap
+ [afi]
+ [safi],
+ PEER_CAP_RESTART_AF_PRESERVE_RCV)
+ ? "preserved"
+ : "not preserved");
+ restart_af_count++;
+ }
+ if (!restart_af_count)
+ vty_out(vty, "none");
+ vty_out(vty, "\n");
+ }
+ } /* Gracefull Restart */
}
}
/* graceful restart information */
- json_object *json_grace = NULL;
- json_object *json_grace_send = NULL;
- json_object *json_grace_recv = NULL;
- int eor_send_af_count = 0;
- int eor_receive_af_count = 0;
+ json_object *json_grace = NULL;
+ json_object *json_grace_send = NULL;
+ json_object *json_grace_recv = NULL;
+ int eor_send_af_count = 0;
+ int eor_receive_af_count = 0;
- if (use_json) {
- json_grace = json_object_new_object();
- json_grace_send = json_object_new_object();
- json_grace_recv = json_object_new_object();
-
- if ((peer_established(p))
- && CHECK_FLAG(p->cap, PEER_CAP_RESTART_RCV)) {
- FOREACH_AFI_SAFI (afi, safi) {
- if (CHECK_FLAG(p->af_sflags[afi][safi],
- PEER_STATUS_EOR_SEND)) {
- json_object_boolean_true_add(
- json_grace_send,
- get_afi_safi_str(afi,
- safi,
- true));
- eor_send_af_count++;
- }
+ if (use_json) {
+ json_grace = json_object_new_object();
+ json_grace_send = json_object_new_object();
+ json_grace_recv = json_object_new_object();
+
+ if ((peer_established(p)) &&
+ CHECK_FLAG(p->cap, PEER_CAP_RESTART_RCV)) {
+ FOREACH_AFI_SAFI (afi, safi) {
+ if (CHECK_FLAG(p->af_sflags[afi][safi],
+ PEER_STATUS_EOR_SEND)) {
+ json_object_boolean_true_add(
+ json_grace_send,
+ get_afi_safi_str(afi, safi,
+ true));
+ eor_send_af_count++;
}
- FOREACH_AFI_SAFI (afi, safi) {
- if (CHECK_FLAG(
- p->af_sflags[afi][safi],
- PEER_STATUS_EOR_RECEIVED)) {
- json_object_boolean_true_add(
- json_grace_recv,
- get_afi_safi_str(afi,
- safi,
- true));
- eor_receive_af_count++;
- }
+ }
+ FOREACH_AFI_SAFI (afi, safi) {
+ if (CHECK_FLAG(p->af_sflags[afi][safi],
+ PEER_STATUS_EOR_RECEIVED)) {
+ json_object_boolean_true_add(
+ json_grace_recv,
+ get_afi_safi_str(afi, safi,
+ true));
+ eor_receive_af_count++;
}
}
- json_object_object_add(json_grace, "endOfRibSend",
- json_grace_send);
- json_object_object_add(json_grace, "endOfRibRecv",
- json_grace_recv);
+ }
+ json_object_object_add(json_grace, "endOfRibSend",
+ json_grace_send);
+ json_object_object_add(json_grace, "endOfRibRecv",
+ json_grace_recv);
- if (p->t_gr_restart)
- json_object_int_add(json_grace,
- "gracefulRestartTimerMsecs",
- thread_timer_remain_second(
- p->t_gr_restart)
- * 1000);
-
- if (p->t_gr_stale)
- json_object_int_add(
- json_grace,
- "gracefulStalepathTimerMsecs",
- thread_timer_remain_second(
- p->t_gr_stale)
- * 1000);
- /* more gr info in new format */
- BGP_SHOW_PEER_GR_CAPABILITY(vty, p, use_json,
- json_grace);
- json_object_object_add(
- json_neigh, "gracefulRestartInfo", json_grace);
- } else {
- vty_out(vty, " Graceful restart information:\n");
- if ((peer_established(p))
- && CHECK_FLAG(p->cap, PEER_CAP_RESTART_RCV)) {
+ if (p->t_gr_restart)
+ json_object_int_add(
+ json_grace, "gracefulRestartTimerMsecs",
+ thread_timer_remain_second(p->t_gr_restart) *
+ 1000);
- vty_out(vty, " End-of-RIB send: ");
- FOREACH_AFI_SAFI (afi, safi) {
- if (CHECK_FLAG(p->af_sflags[afi][safi],
- PEER_STATUS_EOR_SEND)) {
- vty_out(vty, "%s%s",
- eor_send_af_count ? ", "
- : "",
- get_afi_safi_str(
- afi, safi,
- false));
- eor_send_af_count++;
- }
+ if (p->t_gr_stale)
+ json_object_int_add(
+ json_grace, "gracefulStalepathTimerMsecs",
+ thread_timer_remain_second(p->t_gr_stale) *
+ 1000);
+ /* more gr info in new format */
+ BGP_SHOW_PEER_GR_CAPABILITY(vty, p, use_json, json_grace);
+ json_object_object_add(json_neigh, "gracefulRestartInfo",
+ json_grace);
+ } else {
+ vty_out(vty, " Graceful restart information:\n");
+ if ((peer_established(p)) &&
+ CHECK_FLAG(p->cap, PEER_CAP_RESTART_RCV)) {
+
+ vty_out(vty, " End-of-RIB send: ");
+ FOREACH_AFI_SAFI (afi, safi) {
+ if (CHECK_FLAG(p->af_sflags[afi][safi],
+ PEER_STATUS_EOR_SEND)) {
+ vty_out(vty, "%s%s",
+ eor_send_af_count ? ", " : "",
+ get_afi_safi_str(afi, safi,
+ false));
+ eor_send_af_count++;
}
- vty_out(vty, "\n");
- vty_out(vty, " End-of-RIB received: ");
- FOREACH_AFI_SAFI (afi, safi) {
- if (CHECK_FLAG(
- p->af_sflags[afi][safi],
- PEER_STATUS_EOR_RECEIVED)) {
- vty_out(vty, "%s%s",
- eor_receive_af_count
- ? ", "
- : "",
- get_afi_safi_str(afi,
- safi,
- false));
- eor_receive_af_count++;
- }
+ }
+ vty_out(vty, "\n");
+ vty_out(vty, " End-of-RIB received: ");
+ FOREACH_AFI_SAFI (afi, safi) {
+ if (CHECK_FLAG(p->af_sflags[afi][safi],
+ PEER_STATUS_EOR_RECEIVED)) {
+ vty_out(vty, "%s%s",
+ eor_receive_af_count ? ", "
+ : "",
+ get_afi_safi_str(afi, safi,
+ false));
+ eor_receive_af_count++;
}
- vty_out(vty, "\n");
}
+ vty_out(vty, "\n");
+ }
- if (p->t_gr_restart)
- vty_out(vty,
- " The remaining time of restart timer is %ld\n",
- thread_timer_remain_second(
- p->t_gr_restart));
+ if (p->t_gr_restart)
+ vty_out(vty,
+ " The remaining time of restart timer is %ld\n",
+ thread_timer_remain_second(p->t_gr_restart));
- if (p->t_gr_stale)
- vty_out(vty,
- " The remaining time of stalepath timer is %ld\n",
- thread_timer_remain_second(
- p->t_gr_stale));
+ if (p->t_gr_stale)
+ vty_out(vty,
+ " The remaining time of stalepath timer is %ld\n",
+ thread_timer_remain_second(p->t_gr_stale));
- /* more gr info in new format */
- BGP_SHOW_PEER_GR_CAPABILITY(vty, p, use_json, NULL);
- }
+ /* more gr info in new format */
+ BGP_SHOW_PEER_GR_CAPABILITY(vty, p, use_json, NULL);
+ }
if (use_json) {
json_object *json_stat = NULL;
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index 8dc6a09cbd..b592724d27 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -4090,6 +4090,32 @@ bool peer_active_nego(struct peer *peer)
return false;
}
+/* If peer received at least one address family MP, return true */
+bool peer_afc_received(struct peer *peer)
+{
+ afi_t afi;
+ safi_t safi;
+
+ FOREACH_AFI_SAFI (afi, safi)
+ if (peer->afc_recv[afi][safi])
+ return true;
+
+ return false;
+}
+
+/* If peer advertised at least one address family MP, return true */
+bool peer_afc_advertised(struct peer *peer)
+{
+ afi_t afi;
+ safi_t safi;
+
+ FOREACH_AFI_SAFI (afi, safi)
+ if (peer->afc_adv[afi][safi])
+ return true;
+
+ return false;
+}
+
void peer_change_action(struct peer *peer, afi_t afi, safi_t safi,
enum peer_change_type type)
{
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index 865a50757f..747c185e39 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -2021,6 +2021,8 @@ extern bgp_peer_sort_t peer_sort_lookup(struct peer *peer);
extern bool peer_active(struct peer *);
extern bool peer_active_nego(struct peer *);
+extern bool peer_afc_received(struct peer *peer);
+extern bool peer_afc_advertised(struct peer *peer);
extern void bgp_recalculate_all_bestpaths(struct bgp *bgp);
extern struct peer *peer_create(union sockunion *, const char *, struct bgp *,
as_t, as_t, int, struct peer_group *);
diff --git a/doc/developer/logging.rst b/doc/developer/logging.rst
index e608046820..4e6fc04206 100644
--- a/doc/developer/logging.rst
+++ b/doc/developer/logging.rst
@@ -123,10 +123,14 @@ Networking data types
:frrfmtout:`1.2.3.4`
+ ``%pI4s``: :frrfmtout:`*` — print star instead of ``0.0.0.0`` (for multicast)
+
.. frrfmt:: %pI6 (struct in6_addr *)
:frrfmtout:`fe80::1234`
+ ``%pI6s``: :frrfmtout:`*` — print star instead of ``::`` (for multicast)
+
.. frrfmt:: %pEA (struct ethaddr *)
:frrfmtout:`01:23:45:67:89:ab`
@@ -135,6 +139,8 @@ Networking data types
:frrfmtout:`1.2.3.4` / :frrfmtout:`fe80::1234`
+ ``%pIAs``: — print star instead of zero address (for multicast)
+
.. frrfmt:: %pFX (struct prefix *)
:frrfmtout:`1.2.3.0/24` / :frrfmtout:`fe80::1234/64`
@@ -213,6 +219,144 @@ Networking data types
:frrfmtout:`SOCK_STREAM`
+Time/interval formats
+^^^^^^^^^^^^^^^^^^^^^
+
+.. frrfmt:: %pTS (struct timespec *)
+
+.. frrfmt:: %pTV (struct timeval *)
+
+.. frrfmt:: %pTT (time_t *)
+
+ Above 3 options internally result in the same code being called, support
+ the same flags and produce equal output with one exception: ``%pTT``
+ has no sub-second precision and the formatter will never print a
+ (nonsensical) ``.000``.
+
+ Exactly one of ``I``, ``M`` or ``R`` must immediately follow after
+ ``TS``/``TV``/``TT`` to specify whether the input is an interval, monotonic
+ timestamp or realtime timestamp:
+
+ ``%pTVI``: input is an interval, not a timestamp. Print interval.
+
+ ``%pTVIs``: input is an interval, convert to wallclock by subtracting it
+ from current time (i.e. interval has passed **s**\ ince.)
+
+ ``%pTVIu``: input is an interval, convert to wallclock by adding it to
+ current time (i.e. **u**\ ntil interval has passed.)
+
+ ``%pTVM`` - input is a timestamp on CLOCK_MONOTONIC, convert to wallclock
+ time (by grabbing current CLOCK_MONOTONIC and CLOCK_REALTIME and doing the
+ math) and print calendaric date.
+
+ ``%pTVMs`` - input is a timestamp on CLOCK_MONOTONIC, print interval
+ **s**\ ince that timestamp (elapsed.)
+
+ ``%pTVMu`` - input is a timestamp on CLOCK_MONOTONIC, print interval
+ **u**\ ntil that timestamp (deadline.)
+
+ ``%pTVR`` - input is a timestamp on CLOCK_REALTIME, print calendaric date.
+
+ ``%pTVRs`` - input is a timestamp on CLOCK_REALTIME, print interval
+ **s**\ ince that timestamp.
+
+ ``%pTVRu`` - input is a timestamp on CLOCK_REALTIME, print interval
+ **u**\ ntil that timestamp.
+
+ ``%pTVA`` - reserved for CLOCK_TAI in case a PTP implementation is
+ interfaced to FRR. Not currently implemented.
+
+ .. note::
+
+ If ``%pTVRs`` or ``%pTVRu`` are used, this is generally an indication
+ that a CLOCK_MONOTONIC timestamp should be used instead (or added in
+ parallel.) CLOCK_REALTIME might be adjusted by NTP, PTP or similar
+ procedures, causing bogus intervals to be printed.
+
+ ``%pTVM`` on first look might be assumed to have the same problem, but
+ on closer thought the assumption is always that current system time is
+ correct. And since a CLOCK_MONOTONIC interval is also quite safe to
+ assume to be correct, the (past) absolute timestamp to be printed from
+ this can likely be correct even if it doesn't match what CLOCK_REALTIME
+ would have indicated at that point in the past. This logic does,
+ however, not quite work for *future* times.
+
+ Generally speaking, almost all use cases in FRR should (and do) use
+ CLOCK_MONOTONIC (through :c:func:`monotime()`.)
+
+ Flags common to printing calendar times and intervals:
+
+ ``p``: include spaces in appropriate places (depends on selected format.)
+
+ ``%p.3TV...``: specify sub-second resolution (use with ``FMT_NSTD`` to
+ suppress gcc warning.) As noted above, ``%pTT`` will never print sub-second
+ digits since there are none. Only some formats support printing sub-second
+ digits and the default may vary.
+
+ The following flags are available for printing calendar times/dates:
+
+ (no flag): :frrfmtout:`Sat Jan 1 00:00:00 2022` - print output from
+ ``ctime()``, in local time zone. Since FRR does not currently use/enable
+ locale support, this is always the C locale. (Locale support getting added
+ is unlikely for the time being and would likely break other things worse
+ than this.)
+
+ ``i``: :frrfmtout:`2022-01-01T00:00:00.123` - ISO8601 timestamp in local
+ time zone (note there is no ``Z`` or ``+00:00`` suffix.) Defaults to
+ millisecond precision.
+
+ ``ip``: :frrfmtout:`2022-01-01 00:00:00.123` - use readable form of ISO8601
+ with space instead of ``T`` separator.
+
+ The following flags are available for printing intervals:
+
+ (no flag): :frrfmtout:`9w9d09:09:09.123` - does not match any
+ preexisting format; added because it does not lose precision (like ``t``)
+ for longer intervals without printing huge numbers (like ``h``/``m``).
+ Defaults to millisecond precision. The week/day fields are left off if
+ they're zero, ``p`` adds a space after the respective letter.
+
+ ``t``: :frrfmtout:`9w9d09h`, :frrfmtout:`9d09h09m`, :frrfmtout:`09:09:09` -
+ this replaces :c:func:`frrtime_to_interval()`. ``p`` adds spaces after
+ week/day/hour letters.
+
+ ``d``: print decimal number of seconds. Defaults to millisecond precision.
+
+ ``x`` / ``tx`` / ``dx``: Like no flag / ``t`` / ``d``, but print
+ :frrfmtout:`-` for zero or negative intervals (for use with unset timers.)
+
+ ``h``: :frrfmtout:`09:09:09`
+
+ ``hx``: :frrfmtout:`09:09:09`, :frrfmtout:`--:--:--` - this replaces
+ :c:func:`pim_time_timer_to_hhmmss()`.
+
+ ``m``: :frrfmtout:`09:09`
+
+ ``mx``: :frrfmtout:`09:09`, :frrfmtout:`--:--` - this replaces
+ :c:func:`pim_time_timer_to_mmss()`.
+
+FRR library helper formats
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. frrfmt:: %pTH (struct thread *)
+
+ Print remaining time on timer thread. Interval-printing flag characters
+ listed above for ``%pTV`` can be added, e.g. ``%pTHtx``.
+
+ ``NULL`` pointers are printed as ``-``.
+
+.. frrfmt:: %pTHD (struct thread *)
+
+ Print debugging information for given thread. Sample output:
+
+ .. code-block:: none
+
+ {(thread *)NULL}
+ {(thread *)0x55a3b5818910 arg=0x55a3b5827c50 timer r=7.824 mld_t_query() &mld_ifp->t_query from pimd/pim6_mld.c:1369}
+ {(thread *)0x55a3b5827230 arg=0x55a3b5827c50 read fd=16 mld_t_recv() &mld_ifp->t_recv from pimd/pim6_mld.c:1186}
+
+ (The output is aligned to some degree.)
+
General utility formats
^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst
index ada14b4fa1..0fb5fa8482 100644
--- a/doc/user/bgp.rst
+++ b/doc/user/bgp.rst
@@ -2832,9 +2832,8 @@ at the same time.
EVPN Overlay Index Gateway IP
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-Draft https://tools.ietf.org/html/draft-ietf-bess-evpn-prefix-advertisement-11
-explains the use of overlay indexes for recursive route resolution for EVPN
-type-5 route.
+RFC https://datatracker.ietf.org/doc/html/rfc9136 explains the use of overlay
+indexes for recursive route resolution for EVPN type-5 route.
We support gateway IP overlay index.
A gateway IP, advertised with EVPN prefix route, is used to find an EVPN MAC/IP
diff --git a/lib/monotime.h b/lib/monotime.h
index dda763784f..15b6933955 100644
--- a/lib/monotime.h
+++ b/lib/monotime.h
@@ -25,6 +25,9 @@
extern "C" {
#endif
+struct fbuf;
+struct printfrr_eargs;
+
#ifndef TIMESPEC_TO_TIMEVAL
/* should be in sys/time.h on BSD & Linux libcs */
#define TIMESPEC_TO_TIMEVAL(tv, ts) \
@@ -42,6 +45,31 @@ extern "C" {
} while (0)
#endif
+/* Linux/glibc is sadly missing these timespec helpers */
+#ifndef timespecadd
+#define timespecadd(tsp, usp, vsp) \
+ do { \
+ (vsp)->tv_sec = (tsp)->tv_sec + (usp)->tv_sec; \
+ (vsp)->tv_nsec = (tsp)->tv_nsec + (usp)->tv_nsec; \
+ if ((vsp)->tv_nsec >= 1000000000L) { \
+ (vsp)->tv_sec++; \
+ (vsp)->tv_nsec -= 1000000000L; \
+ } \
+ } while (0)
+#endif
+
+#ifndef timespecsub
+#define timespecsub(tsp, usp, vsp) \
+ do { \
+ (vsp)->tv_sec = (tsp)->tv_sec - (usp)->tv_sec; \
+ (vsp)->tv_nsec = (tsp)->tv_nsec - (usp)->tv_nsec; \
+ if ((vsp)->tv_nsec < 0) { \
+ (vsp)->tv_sec--; \
+ (vsp)->tv_nsec += 1000000000L; \
+ } \
+ } while (0)
+#endif
+
static inline time_t monotime(struct timeval *tvo)
{
struct timespec ts;
@@ -132,6 +160,53 @@ static inline const char *frrtime_to_interval(time_t t, char *buf,
return buf;
}
+enum {
+ /* n/a - input was seconds precision, don't print any fractional */
+ TIMEFMT_SECONDS = (1 << 0),
+ /* caller is directly invoking printfrr_time and has pre-specified
+ * I/Iu/Is/M/Mu/Ms/R/Ru/Rs (for printing timers)
+ */
+ TIMEFMT_PRESELECT = (1 << 1),
+ /* don't print any output - this is needed for invoking printfrr_time
+ * from another printfrr extensions to skip over flag characters
+ */
+ TIMEFMT_SKIP = (1 << 2),
+ /* use spaces in appropriate places */
+ TIMEFMT_SPACE = (1 << 3),
+
+ /* input interpretations: */
+ TIMEFMT_REALTIME = (1 << 8),
+ TIMEFMT_MONOTONIC = (1 << 9),
+ TIMEFMT_SINCE = (1 << 10),
+ TIMEFMT_UNTIL = (1 << 11),
+
+ TIMEFMT_ABSOLUTE = TIMEFMT_REALTIME | TIMEFMT_MONOTONIC,
+ TIMEFMT_ANCHORS = TIMEFMT_SINCE | TIMEFMT_UNTIL,
+
+ /* calendaric formats: */
+ TIMEFMT_ISO8601 = (1 << 16),
+
+ /* interval formats: */
+ /* 't' - use [t]raditional 3-block format */
+ TIMEFMT_BASIC = (1 << 24),
+ /* 'm' - select mm:ss */
+ TIMEFMT_MMSS = (1 << 25),
+ /* 'h' - select hh:mm:ss */
+ TIMEFMT_HHMMSS = (1 << 26),
+ /* 'd' - print as decimal number of seconds */
+ TIMEFMT_DECIMAL = (1 << 27),
+ /* 'mx'/'hx' - replace zero value with "--:--" or "--:--:--" */
+ TIMEFMT_DASHES = (1 << 31),
+
+ /* helpers for reference */
+ TIMEFMT_TIMER_DEADLINE =
+ TIMEFMT_PRESELECT | TIMEFMT_MONOTONIC | TIMEFMT_UNTIL,
+ TIMEFMT_TIMER_INTERVAL = TIMEFMT_PRESELECT,
+};
+
+extern ssize_t printfrr_time(struct fbuf *buf, struct printfrr_eargs *ea,
+ const struct timespec *ts, unsigned int flags);
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/nexthop.c b/lib/nexthop.c
index 2e09cb4bcc..e17eeb8303 100644
--- a/lib/nexthop.c
+++ b/lib/nexthop.c
@@ -943,7 +943,7 @@ int nexthop_str2backups(const char *str, int *num_backups,
* eth0
* (0-length if no interface present)
*/
-printfrr_ext_autoreg_p("NH", printfrr_nh)
+printfrr_ext_autoreg_p("NH", printfrr_nh);
static ssize_t printfrr_nh(struct fbuf *buf, struct printfrr_eargs *ea,
const void *ptr)
{
diff --git a/lib/prefix.c b/lib/prefix.c
index d3e8a612eb..90ab48a13b 100644
--- a/lib/prefix.c
+++ b/lib/prefix.c
@@ -1353,7 +1353,7 @@ char *evpn_es_df_alg2str(uint8_t df_alg, char *buf, int buf_len)
return buf;
}
-printfrr_ext_autoreg_p("EA", printfrr_ea)
+printfrr_ext_autoreg_p("EA", printfrr_ea);
static ssize_t printfrr_ea(struct fbuf *buf, struct printfrr_eargs *ea,
const void *ptr)
{
@@ -1368,47 +1368,93 @@ static ssize_t printfrr_ea(struct fbuf *buf, struct printfrr_eargs *ea,
return bputs(buf, cbuf);
}
-printfrr_ext_autoreg_p("IA", printfrr_ia)
+printfrr_ext_autoreg_p("IA", printfrr_ia);
static ssize_t printfrr_ia(struct fbuf *buf, struct printfrr_eargs *ea,
const void *ptr)
{
const struct ipaddr *ipa = ptr;
char cbuf[INET6_ADDRSTRLEN];
+ bool use_star = false;
+
+ if (ea->fmt[0] == 's') {
+ use_star = true;
+ ea->fmt++;
+ }
if (!ipa)
return bputs(buf, "(null)");
+ if (use_star) {
+ struct in_addr zero4 = {};
+ struct in6_addr zero6 = {};
+
+ switch (ipa->ipa_type) {
+ case IPADDR_V4:
+ if (!memcmp(&ipa->ip.addr, &zero4, sizeof(zero4)))
+ return bputch(buf, '*');
+ break;
+
+ case IPADDR_V6:
+ if (!memcmp(&ipa->ip.addr, &zero6, sizeof(zero6)))
+ return bputch(buf, '*');
+ break;
+
+ default:
+ break;
+ }
+ }
+
ipaddr2str(ipa, cbuf, sizeof(cbuf));
return bputs(buf, cbuf);
}
-printfrr_ext_autoreg_p("I4", printfrr_i4)
+printfrr_ext_autoreg_p("I4", printfrr_i4);
static ssize_t printfrr_i4(struct fbuf *buf, struct printfrr_eargs *ea,
const void *ptr)
{
char cbuf[INET_ADDRSTRLEN];
+ bool use_star = false;
+ struct in_addr zero = {};
+
+ if (ea->fmt[0] == 's') {
+ use_star = true;
+ ea->fmt++;
+ }
if (!ptr)
return bputs(buf, "(null)");
+ if (use_star && !memcmp(ptr, &zero, sizeof(zero)))
+ return bputch(buf, '*');
+
inet_ntop(AF_INET, ptr, cbuf, sizeof(cbuf));
return bputs(buf, cbuf);
}
-printfrr_ext_autoreg_p("I6", printfrr_i6)
+printfrr_ext_autoreg_p("I6", printfrr_i6);
static ssize_t printfrr_i6(struct fbuf *buf, struct printfrr_eargs *ea,
const void *ptr)
{
char cbuf[INET6_ADDRSTRLEN];
+ bool use_star = false;
+ struct in6_addr zero = {};
+
+ if (ea->fmt[0] == 's') {
+ use_star = true;
+ ea->fmt++;
+ }
if (!ptr)
return bputs(buf, "(null)");
+ if (use_star && !memcmp(ptr, &zero, sizeof(zero)))
+ return bputch(buf, '*');
+
inet_ntop(AF_INET6, ptr, cbuf, sizeof(cbuf));
return bputs(buf, cbuf);
}
-printfrr_ext_autoreg_p("FX", printfrr_pfx)
+printfrr_ext_autoreg_p("FX", printfrr_pfx);
static ssize_t printfrr_pfx(struct fbuf *buf, struct printfrr_eargs *ea,
const void *ptr)
{
@@ -1421,7 +1467,7 @@ static ssize_t printfrr_pfx(struct fbuf *buf, struct printfrr_eargs *ea,
return bputs(buf, cbuf);
}
-printfrr_ext_autoreg_p("PSG4", printfrr_psg)
+printfrr_ext_autoreg_p("PSG4", printfrr_psg);
static ssize_t printfrr_psg(struct fbuf *buf, struct printfrr_eargs *ea,
const void *ptr)
{
diff --git a/lib/printf/glue.c b/lib/printf/glue.c
index 1147901236..6e39c2d9cf 100644
--- a/lib/printf/glue.c
+++ b/lib/printf/glue.c
@@ -256,7 +256,7 @@ ssize_t printfrr_exti(struct fbuf *buf, struct printfrr_eargs *ea,
return -1;
}
-printfrr_ext_autoreg_p("FB", printfrr_fb)
+printfrr_ext_autoreg_p("FB", printfrr_fb);
static ssize_t printfrr_fb(struct fbuf *out, struct printfrr_eargs *ea,
const void *ptr)
{
@@ -278,7 +278,7 @@ static ssize_t printfrr_fb(struct fbuf *out, struct printfrr_eargs *ea,
return in->pos - in->buf;
}
-printfrr_ext_autoreg_p("VA", printfrr_va)
+printfrr_ext_autoreg_p("VA", printfrr_va);
static ssize_t printfrr_va(struct fbuf *buf, struct printfrr_eargs *ea,
const void *ptr)
{
diff --git a/lib/printfrr.h b/lib/printfrr.h
index 37f1f9c8cd..a2d113ba1e 100644
--- a/lib/printfrr.h
+++ b/lib/printfrr.h
@@ -209,10 +209,11 @@ void printfrr_ext_reg(const struct printfrr_ext *);
.print_ptr = print_fn, \
}; \
static void _printreg_##print_fn(void) __attribute__((constructor)); \
- static void _printreg_##print_fn(void) { \
+ static void _printreg_##print_fn(void) \
+ { \
printfrr_ext_reg(&_printext_##print_fn); \
} \
- /* end */
+ MACRO_REQUIRE_SEMICOLON()
#define printfrr_ext_autoreg_i(matchs, print_fn) \
static ssize_t print_fn(struct fbuf *, struct printfrr_eargs *, \
@@ -222,10 +223,11 @@ void printfrr_ext_reg(const struct printfrr_ext *);
.print_int = print_fn, \
}; \
static void _printreg_##print_fn(void) __attribute__((constructor)); \
- static void _printreg_##print_fn(void) { \
+ static void _printreg_##print_fn(void) \
+ { \
printfrr_ext_reg(&_printext_##print_fn); \
} \
- /* end */
+ MACRO_REQUIRE_SEMICOLON()
/* fbuf helper functions - note all 3 of these return the length that would
* be written regardless of how much space was available in the buffer, as
@@ -286,6 +288,10 @@ struct va_format {
#pragma FRR printfrr_ext "%pSE" (char *)
#pragma FRR printfrr_ext "%pSQ" (char *)
+
+#pragma FRR printfrr_ext "%pTS" (struct timespec *)
+#pragma FRR printfrr_ext "%pTV" (struct timeval *)
+#pragma FRR printfrr_ext "%pTT" (time_t *)
#endif
/* when using non-ISO-C compatible extension specifiers... */
diff --git a/lib/sockunion.c b/lib/sockunion.c
index c7af458e9e..006ac142aa 100644
--- a/lib/sockunion.c
+++ b/lib/sockunion.c
@@ -662,7 +662,7 @@ void sockunion_init(union sockunion *su)
memset(su, 0, sizeof(union sockunion));
}
-printfrr_ext_autoreg_p("SU", printfrr_psu)
+printfrr_ext_autoreg_p("SU", printfrr_psu);
static ssize_t printfrr_psu(struct fbuf *buf, struct printfrr_eargs *ea,
const void *ptr)
{
@@ -752,7 +752,7 @@ int sockunion_is_null(const union sockunion *su)
}
}
-printfrr_ext_autoreg_i("PF", printfrr_pf)
+printfrr_ext_autoreg_i("PF", printfrr_pf);
static ssize_t printfrr_pf(struct fbuf *buf, struct printfrr_eargs *ea,
uintmax_t val)
{
@@ -775,7 +775,7 @@ static ssize_t printfrr_pf(struct fbuf *buf, struct printfrr_eargs *ea,
return bprintfrr(buf, "AF_(%ju)", val);
}
-printfrr_ext_autoreg_i("SO", printfrr_so)
+printfrr_ext_autoreg_i("SO", printfrr_so);
static ssize_t printfrr_so(struct fbuf *buf, struct printfrr_eargs *ea,
uintmax_t val)
{
diff --git a/lib/srcdest_table.c b/lib/srcdest_table.c
index d2e0682e95..828cf2cce0 100644
--- a/lib/srcdest_table.c
+++ b/lib/srcdest_table.c
@@ -306,7 +306,7 @@ const char *srcdest_rnode2str(const struct route_node *rn, char *str, int size)
return srcdest2str(dst_p, (const struct prefix_ipv6 *)src_p, str, size);
}
-printfrr_ext_autoreg_p("RN", printfrr_rn)
+printfrr_ext_autoreg_p("RN", printfrr_rn);
static ssize_t printfrr_rn(struct fbuf *buf, struct printfrr_eargs *ea,
const void *ptr)
{
diff --git a/lib/strformat.c b/lib/strformat.c
index 431e573a0c..a420ba553a 100644
--- a/lib/strformat.c
+++ b/lib/strformat.c
@@ -22,10 +22,12 @@
#include <string.h>
#include <ctype.h>
+#include <time.h>
#include "printfrr.h"
+#include "monotime.h"
-printfrr_ext_autoreg_p("HX", printfrr_hexdump)
+printfrr_ext_autoreg_p("HX", printfrr_hexdump);
static ssize_t printfrr_hexdump(struct fbuf *buf, struct printfrr_eargs *ea,
const void *ptr)
{
@@ -56,7 +58,7 @@ static ssize_t printfrr_hexdump(struct fbuf *buf, struct printfrr_eargs *ea,
/* string analog for hexdumps / the "this." in ("74 68 69 73 0a |this.|") */
-printfrr_ext_autoreg_p("HS", printfrr_hexdstr)
+printfrr_ext_autoreg_p("HS", printfrr_hexdstr);
static ssize_t printfrr_hexdstr(struct fbuf *buf, struct printfrr_eargs *ea,
const void *ptr)
{
@@ -199,7 +201,7 @@ static ssize_t bquote(struct fbuf *buf, const uint8_t *pos, size_t len,
return ret;
}
-printfrr_ext_autoreg_p("SE", printfrr_escape)
+printfrr_ext_autoreg_p("SE", printfrr_escape);
static ssize_t printfrr_escape(struct fbuf *buf, struct printfrr_eargs *ea,
const void *vptr)
{
@@ -224,7 +226,7 @@ static ssize_t printfrr_escape(struct fbuf *buf, struct printfrr_eargs *ea,
return bquote(buf, ptr, len, ESC_ALL);
}
-printfrr_ext_autoreg_p("SQ", printfrr_quote)
+printfrr_ext_autoreg_p("SQ", printfrr_quote);
static ssize_t printfrr_quote(struct fbuf *buf, struct printfrr_eargs *ea,
const void *vptr)
{
@@ -270,3 +272,326 @@ static ssize_t printfrr_quote(struct fbuf *buf, struct printfrr_eargs *ea,
ret += bputch(buf, '"');
return ret;
}
+
+static ssize_t printfrr_abstime(struct fbuf *buf, struct printfrr_eargs *ea,
+ const struct timespec *ts, unsigned int flags);
+static ssize_t printfrr_reltime(struct fbuf *buf, struct printfrr_eargs *ea,
+ const struct timespec *ts, unsigned int flags);
+
+ssize_t printfrr_time(struct fbuf *buf, struct printfrr_eargs *ea,
+ const struct timespec *ts, unsigned int flags)
+{
+ bool have_abs, have_anchor;
+
+ if (!(flags & TIMEFMT_PRESELECT)) {
+ switch (ea->fmt[0]) {
+ case 'I':
+ /* no bit set */
+ break;
+ case 'M':
+ flags |= TIMEFMT_MONOTONIC;
+ break;
+ case 'R':
+ flags |= TIMEFMT_REALTIME;
+ break;
+ default:
+ return bputs(buf,
+ "{invalid time format input specifier}");
+ }
+ ea->fmt++;
+
+ if (ea->fmt[0] == 's') {
+ flags |= TIMEFMT_SINCE;
+ ea->fmt++;
+ } else if (ea->fmt[0] == 'u') {
+ flags |= TIMEFMT_UNTIL;
+ ea->fmt++;
+ }
+ }
+
+ have_abs = !!(flags & TIMEFMT_ABSOLUTE);
+ have_anchor = !!(flags & TIMEFMT_ANCHORS);
+
+ if (have_abs ^ have_anchor)
+ return printfrr_abstime(buf, ea, ts, flags);
+ else
+ return printfrr_reltime(buf, ea, ts, flags);
+}
+
+static ssize_t do_subsec(struct fbuf *buf, const struct timespec *ts,
+ int precision, unsigned int flags)
+{
+ unsigned long long frac;
+
+ if (precision <= 0 || (flags & TIMEFMT_SECONDS))
+ return 0;
+
+ frac = ts->tv_nsec;
+ if (precision > 9)
+ precision = 9;
+ for (int i = precision; i < 9; i++)
+ frac /= 10;
+ return bprintfrr(buf, ".%0*llu", precision, frac);
+}
+
+static ssize_t printfrr_abstime(struct fbuf *buf, struct printfrr_eargs *ea,
+ const struct timespec *ts, unsigned int flags)
+{
+ struct timespec real_ts[1];
+ struct tm tm;
+ char cbuf[32] = ""; /* manpage says 26 for ctime_r */
+ ssize_t ret = 0;
+ int precision = ea->precision;
+
+ while (ea->fmt[0]) {
+ char ch = *ea->fmt++;
+
+ switch (ch) {
+ case 'p':
+ flags |= TIMEFMT_SPACE;
+ continue;
+ case 'i':
+ flags |= TIMEFMT_ISO8601;
+ continue;
+ }
+
+ ea->fmt--;
+ break;
+ }
+
+ if (flags & TIMEFMT_SKIP)
+ return 0;
+
+ if (flags & TIMEFMT_REALTIME)
+ *real_ts = *ts;
+ else if (flags & TIMEFMT_MONOTONIC) {
+ struct timespec mono_now[1];
+
+ clock_gettime(CLOCK_REALTIME, real_ts);
+ clock_gettime(CLOCK_MONOTONIC, mono_now);
+
+ timespecsub(real_ts, mono_now, real_ts);
+ timespecadd(real_ts, ts, real_ts);
+ } else {
+ clock_gettime(CLOCK_REALTIME, real_ts);
+
+ if (flags & TIMEFMT_SINCE)
+ timespecsub(real_ts, ts, real_ts);
+ else /* flags & TIMEFMT_UNTIL */
+ timespecadd(real_ts, ts, real_ts);
+ }
+
+ localtime_r(&real_ts->tv_sec, &tm);
+
+ if (flags & TIMEFMT_ISO8601) {
+ if (flags & TIMEFMT_SPACE)
+ strftime(cbuf, sizeof(cbuf), "%Y-%m-%d %H:%M:%S", &tm);
+ else
+ strftime(cbuf, sizeof(cbuf), "%Y-%m-%dT%H:%M:%S", &tm);
+ ret += bputs(buf, cbuf);
+
+ if (precision == -1)
+ precision = 3;
+ ret += do_subsec(buf, real_ts, precision, flags);
+ } else {
+ size_t len;
+
+ asctime_r(&tm, cbuf);
+
+ len = strlen(cbuf);
+ if (!len)
+ /* WTF. */
+ return 0;
+ if (cbuf[len - 1] == '\n')
+ cbuf[len - 1] = '\0';
+
+ ret += bputs(buf, cbuf);
+ }
+ return ret;
+}
+
+static ssize_t printfrr_reltime(struct fbuf *buf, struct printfrr_eargs *ea,
+ const struct timespec *ts, unsigned int flags)
+{
+ struct timespec real_ts[1];
+ ssize_t ret = 0;
+ const char *space = "";
+ const char *dashes = "-";
+ int precision = ea->precision;
+
+ while (ea->fmt[0]) {
+ char ch = *ea->fmt++;
+
+ switch (ch) {
+ case 'p':
+ flags |= TIMEFMT_SPACE;
+ space = " ";
+ continue;
+ case 't':
+ flags |= TIMEFMT_BASIC;
+ continue;
+ case 'd':
+ flags |= TIMEFMT_DECIMAL;
+ continue;
+ case 'm':
+ flags |= TIMEFMT_MMSS;
+ dashes = "--:--";
+ continue;
+ case 'h':
+ flags |= TIMEFMT_HHMMSS;
+ dashes = "--:--:--";
+ continue;
+ case 'x':
+ flags |= TIMEFMT_DASHES;
+ continue;
+ }
+
+ ea->fmt--;
+ break;
+ }
+
+ if (flags & TIMEFMT_SKIP)
+ return 0;
+
+ if (flags & TIMEFMT_ABSOLUTE) {
+ struct timespec anchor[1];
+
+ if (flags & TIMEFMT_REALTIME)
+ clock_gettime(CLOCK_REALTIME, anchor);
+ else
+ clock_gettime(CLOCK_MONOTONIC, anchor);
+ if (flags & TIMEFMT_UNTIL)
+ timespecsub(ts, anchor, real_ts);
+ else /* flags & TIMEFMT_SINCE */
+ timespecsub(anchor, ts, real_ts);
+ } else
+ *real_ts = *ts;
+
+ if (real_ts->tv_sec == 0 && real_ts->tv_nsec == 0 &&
+ (flags & TIMEFMT_DASHES))
+ return bputs(buf, dashes);
+
+ if (real_ts->tv_sec < 0) {
+ if (flags & TIMEFMT_DASHES)
+ return bputs(buf, dashes);
+
+ /* -0.3s is { -1s + 700ms } */
+ real_ts->tv_sec = -real_ts->tv_sec - 1;
+ real_ts->tv_nsec = 1000000000L - real_ts->tv_nsec;
+ if (real_ts->tv_nsec >= 1000000000L) {
+ real_ts->tv_sec++;
+ real_ts->tv_nsec -= 1000000000L;
+ }
+
+ /* all formats have a - make sense in front */
+ ret += bputch(buf, '-');
+ }
+
+ if (flags & TIMEFMT_DECIMAL) {
+ ret += bprintfrr(buf, "%lld", (long long)real_ts->tv_sec);
+ if (precision == -1)
+ precision = 3;
+ ret += do_subsec(buf, real_ts, precision, flags);
+ return ret;
+ }
+
+ /* these divisions may be slow on embedded boxes, hence only do the
+ * ones we need, plus the ?: zero check to hopefully skip zeros fast
+ */
+ lldiv_t min_sec = lldiv(real_ts->tv_sec, 60);
+
+ if (flags & TIMEFMT_MMSS) {
+ ret += bprintfrr(buf, "%02lld:%02lld", min_sec.quot,
+ min_sec.rem);
+ ret += do_subsec(buf, real_ts, precision, flags);
+ return ret;
+ }
+
+ lldiv_t hour_min = min_sec.quot ? lldiv(min_sec.quot, 60) : (lldiv_t){};
+
+ if (flags & TIMEFMT_HHMMSS) {
+ ret += bprintfrr(buf, "%02lld:%02lld:%02lld", hour_min.quot,
+ hour_min.rem, min_sec.rem);
+ ret += do_subsec(buf, real_ts, precision, flags);
+ return ret;
+ }
+
+ lldiv_t day_hour =
+ hour_min.quot ? lldiv(hour_min.quot, 24) : (lldiv_t){};
+ lldiv_t week_day =
+ day_hour.quot ? lldiv(day_hour.quot, 7) : (lldiv_t){};
+
+ /* if sub-second precision is not supported, return */
+ if (flags & TIMEFMT_BASIC) {
+ /* match frrtime_to_interval (without space flag) */
+ if (week_day.quot)
+ ret += bprintfrr(buf, "%lldw%s%lldd%s%02lldh",
+ week_day.quot, space, week_day.rem,
+ space, day_hour.rem);
+ else if (day_hour.quot)
+ ret += bprintfrr(buf, "%lldd%s%02lldh%s%02lldm",
+ day_hour.quot, space, day_hour.rem,
+ space, hour_min.rem);
+ else
+ ret += bprintfrr(buf, "%02lld:%02lld:%02lld",
+ hour_min.quot, hour_min.rem,
+ min_sec.rem);
+ /* no sub-seconds here */
+ return ret;
+ }
+
+ /* default format */
+ if (week_day.quot)
+ ret += bprintfrr(buf, "%lldw%s", week_day.quot, space);
+ if (week_day.rem || week_day.quot)
+ ret += bprintfrr(buf, "%lldd%s", week_day.rem, space);
+
+ ret += bprintfrr(buf, "%02lld:%02lld:%02lld", day_hour.rem,
+ hour_min.rem, min_sec.rem);
+
+ if (precision == -1)
+ precision = 3;
+ ret += do_subsec(buf, real_ts, precision, flags);
+ return ret;
+}
+
+printfrr_ext_autoreg_p("TS", printfrr_ts);
+static ssize_t printfrr_ts(struct fbuf *buf, struct printfrr_eargs *ea,
+ const void *vptr)
+{
+ const struct timespec *ts = vptr;
+
+ if (!ts)
+ return bputs(buf, "(null)");
+ return printfrr_time(buf, ea, ts, 0);
+}
+
+printfrr_ext_autoreg_p("TV", printfrr_tv);
+static ssize_t printfrr_tv(struct fbuf *buf, struct printfrr_eargs *ea,
+ const void *vptr)
+{
+ const struct timeval *tv = vptr;
+ struct timespec ts;
+
+ if (!tv)
+ return bputs(buf, "(null)");
+
+ ts.tv_sec = tv->tv_sec;
+ ts.tv_nsec = tv->tv_usec * 1000;
+ return printfrr_time(buf, ea, &ts, 0);
+}
+
+printfrr_ext_autoreg_p("TT", printfrr_tt);
+static ssize_t printfrr_tt(struct fbuf *buf, struct printfrr_eargs *ea,
+ const void *vptr)
+{
+ const time_t *tt = vptr;
+ struct timespec ts;
+
+ if (!tt)
+ return bputs(buf, "(null)");
+
+ ts.tv_sec = *tt;
+ ts.tv_nsec = 0;
+ return printfrr_time(buf, ea, &ts, TIMEFMT_SECONDS);
+}
diff --git a/lib/thread.c b/lib/thread.c
index 7b223ed6de..77e34f48f3 100644
--- a/lib/thread.c
+++ b/lib/thread.c
@@ -2056,3 +2056,70 @@ bool thread_is_scheduled(struct thread *thread)
return true;
}
+
+static ssize_t printfrr_thread_dbg(struct fbuf *buf, struct printfrr_eargs *ea,
+ const struct thread *thread)
+{
+ static const char * const types[] = {
+ [THREAD_READ] = "read",
+ [THREAD_WRITE] = "write",
+ [THREAD_TIMER] = "timer",
+ [THREAD_EVENT] = "event",
+ [THREAD_READY] = "ready",
+ [THREAD_UNUSED] = "unused",
+ [THREAD_EXECUTE] = "exec",
+ };
+ ssize_t rv = 0;
+ char info[16] = "";
+
+ if (!thread)
+ return bputs(buf, "{(thread *)NULL}");
+
+ rv += bprintfrr(buf, "{(thread *)%p arg=%p", thread, thread->arg);
+
+ if (thread->type < array_size(types) && types[thread->type])
+ rv += bprintfrr(buf, " %-6s", types[thread->type]);
+ else
+ rv += bprintfrr(buf, " INVALID(%u)", thread->type);
+
+ switch (thread->type) {
+ case THREAD_READ:
+ case THREAD_WRITE:
+ snprintfrr(info, sizeof(info), "fd=%d", thread->u.fd);
+ break;
+
+ case THREAD_TIMER:
+ snprintfrr(info, sizeof(info), "r=%pTVMud", &thread->u.sands);
+ break;
+ }
+
+ rv += bprintfrr(buf, " %-12s %s() %s from %s:%d}", info,
+ thread->xref->funcname, thread->xref->dest,
+ thread->xref->xref.file, thread->xref->xref.line);
+ return rv;
+}
+
+printfrr_ext_autoreg_p("TH", printfrr_thread);
+static ssize_t printfrr_thread(struct fbuf *buf, struct printfrr_eargs *ea,
+ const void *ptr)
+{
+ const struct thread *thread = ptr;
+ struct timespec remain = {};
+
+ if (ea->fmt[0] == 'D') {
+ ea->fmt++;
+ return printfrr_thread_dbg(buf, ea, thread);
+ }
+
+ if (!thread) {
+ /* need to jump over time formatting flag characters in the
+ * input format string, i.e. adjust ea->fmt!
+ */
+ printfrr_time(buf, ea, &remain,
+ TIMEFMT_TIMER_DEADLINE | TIMEFMT_SKIP);
+ return bputch(buf, '-');
+ }
+
+ TIMEVAL_TO_TIMESPEC(&thread->u.sands, &remain);
+ return printfrr_time(buf, ea, &remain, TIMEFMT_TIMER_DEADLINE);
+}
diff --git a/lib/thread.h b/lib/thread.h
index 39f21da11d..49a70696d0 100644
--- a/lib/thread.h
+++ b/lib/thread.h
@@ -128,6 +128,10 @@ struct thread {
pthread_mutex_t mtx; /* mutex for thread.c functions */
};
+#ifdef _FRR_ATTRIBUTE_PRINTFRR
+#pragma FRR printfrr_ext "%pTH" (struct thread *)
+#endif
+
struct cpu_thread_history {
int (*func)(struct thread *);
atomic_size_t total_cpu_warn;
diff --git a/pimd/pim_addr.c b/pimd/pim_addr.c
index 825f38274a..8d89b57141 100644
--- a/pimd/pim_addr.c
+++ b/pimd/pim_addr.c
@@ -24,7 +24,7 @@
#include "prefix.h"
-printfrr_ext_autoreg_p("PA", printfrr_pimaddr)
+printfrr_ext_autoreg_p("PA", printfrr_pimaddr);
static ssize_t printfrr_pimaddr(struct fbuf *buf, struct printfrr_eargs *ea,
const void *vptr)
{
@@ -56,7 +56,7 @@ static ssize_t printfrr_pimaddr(struct fbuf *buf, struct printfrr_eargs *ea,
#endif
}
-printfrr_ext_autoreg_p("SG", printfrr_sgaddr)
+printfrr_ext_autoreg_p("SG", printfrr_sgaddr);
static ssize_t printfrr_sgaddr(struct fbuf *buf, struct printfrr_eargs *ea,
const void *vptr)
{
diff --git a/tests/lib/test_printfrr.c b/tests/lib/test_printfrr.c
index 7694077574..8f9d637afd 100644
--- a/tests/lib/test_printfrr.c
+++ b/tests/lib/test_printfrr.c
@@ -186,6 +186,10 @@ int main(int argc, char **argv)
test_va("VA [192.168.1.2 1234] --", "%pI4 %u", &ip, 1234);
+ inet_aton("0.0.0.0", &ip);
+ printchk("0.0.0.0", "%pI4", &ip);
+ printchk("*", "%pI4s", &ip);
+
snprintfrr(buf, sizeof(buf), "test%s", "#1");
csnprintfrr(buf, sizeof(buf), "test%s", "#2");
assert(strcmp(buf, "test#1test#2") == 0);
@@ -274,5 +278,115 @@ int main(int argc, char **argv)
inet_pton(AF_INET6, "fe2c::34", &nh.gate.ipv6);
printchk("fe2c::34", "%pNHcg", &nh);
+ /* time printing */
+
+ /* need a non-UTC timezone for testing */
+ setenv("TZ", "TEST-01:00", 1);
+ tzset();
+
+ struct timespec ts;
+ struct timeval tv;
+ time_t tt;
+
+ ts.tv_sec = tv.tv_sec = tt = 1642015880;
+ ts.tv_nsec = 123456789;
+ tv.tv_usec = 234567;
+
+ printchk("Wed Jan 12 20:31:20 2022", "%pTSR", &ts);
+ printchk("Wed Jan 12 20:31:20 2022", "%pTVR", &tv);
+ printchk("Wed Jan 12 20:31:20 2022", "%pTTR", &tt);
+
+ FMT_NSTD(printchk("Wed Jan 12 20:31:20 2022", "%.3pTSR", &ts));
+
+ printchk("2022-01-12T20:31:20.123", "%pTSRi", &ts);
+ printchk("2022-01-12 20:31:20.123", "%pTSRip", &ts);
+ printchk("2022-01-12 20:31:20.123", "%pTSRpi", &ts);
+ FMT_NSTD(printchk("2022-01-12T20:31:20", "%.0pTSRi", &ts));
+ FMT_NSTD(printchk("2022-01-12T20:31:20.123456789", "%.9pTSRi", &ts));
+ FMT_NSTD(printchk("2022-01-12T20:31:20", "%.3pTTRi", &tt));
+
+ ts.tv_sec = tv.tv_sec = tt = 9 * 86400 + 12345;
+
+ printchk("1w 2d 03:25:45.123", "%pTSIp", &ts);
+ printchk("1w2d03:25:45.123", "%pTSI", &ts);
+ printchk("1w2d03:25:45.234", "%pTVI", &tv);
+ printchk("1w2d03:25:45", "%pTTI", &tt);
+
+ printchk("1w 2d 03h", "%pTVItp", &tv);
+ printchk("1w2d03h", "%pTSIt", &ts);
+
+ printchk("219:25:45", "%pTVIh", &tv);
+ printchk("13165:45", "%pTVIm", &tv);
+
+ ts.tv_sec = tv.tv_sec = tt = 1 * 86400 + 12345;
+
+ printchk("1d 03:25:45.123", "%pTSIp", &ts);
+ printchk("1d03:25:45.234", "%pTVI", &tv);
+
+ printchk("1d 03h 25m", "%pTVItp", &tv);
+ printchk("1d03h25m", "%pTSIt", &ts);
+
+ printchk("98745.234", "%pTVId", &tv);
+
+ printchk("27:25:45", "%pTVIh", &tv);
+ printchk("1645:45", "%pTVIm", &tv);
+
+ ts.tv_sec = tv.tv_sec = tt = 12345;
+
+ printchk("03:25:45.123", "%pTSIp", &ts);
+ printchk("03:25:45.123", "%pTSI", &ts);
+ printchk("03:25:45.234", "%pTVI", &tv);
+ printchk("03:25:45", "%pTTI", &tt);
+
+ printchk("03:25:45", "%pTSItp", &ts);
+ printchk("03:25:45", "%pTVIt", &tv);
+
+ printchk("12345.234", "%pTVId", &tv);
+
+ printchk("03:25:45", "%pTVIh", &tv);
+ printchk("205:45", "%pTVIm", &tv);
+
+ ts.tv_sec = tv.tv_sec = tt = 0;
+
+ printchk("00:00:00.123", "%pTSIp", &ts);
+ printchk("00:00:00.123", "%pTSI", &ts);
+ printchk("00:00:00.234", "%pTVI", &tv);
+ printchk("00:00:00", "%pTTI", &tt);
+
+ printchk("00:00:00", "%pTVItp", &tv);
+ printchk("00:00:00", "%pTSIt", &ts);
+
+ printchk("0.234", "%pTVId", &tv);
+ printchk("0.234", "%pTVIdx", &tv);
+ printchk("-", "%pTTIdx", &tt);
+
+ printchk("00:00:00", "%pTVIhx", &tv);
+ printchk("--:--:--", "%pTTIhx", &tt);
+ printchk("00:00", "%pTVImx", &tv);
+ printchk("--:--", "%pTTImx", &tt);
+
+ ts.tv_sec = tv.tv_sec = tt = -10;
+
+ printchk("-00:00:09.876", "%pTSIp", &ts);
+ printchk("-00:00:09.876", "%pTSI", &ts);
+ printchk("-00:00:09.765", "%pTVI", &tv);
+ printchk("-00:00:10", "%pTTI", &tt);
+
+ printchk("-00:00:09", "%pTSItp", &ts);
+ printchk("-00:00:09", "%pTSIt", &ts);
+ printchk("-00:00:09", "%pTVIt", &tv);
+ printchk("-00:00:10", "%pTTIt", &tt);
+
+ printchk("-9.765", "%pTVId", &tv);
+ printchk("-", "%pTVIdx", &tv);
+
+ printchk("-00:00:09", "%pTSIh", &ts);
+ printchk("--:--:--", "%pTVIhx", &tv);
+ printchk("--:--:--", "%pTTIhx", &tt);
+
+ printchk("-00:09", "%pTSIm", &ts);
+ printchk("--:--", "%pTVImx", &tv);
+ printchk("--:--", "%pTTImx", &tt);
+
return !!errors;
}
diff --git a/tools/checkpatch.pl b/tools/checkpatch.pl
index d2eb20ce5b..db6460f343 100755
--- a/tools/checkpatch.pl
+++ b/tools/checkpatch.pl
@@ -5789,7 +5789,7 @@ sub process {
}
# check for vsprintf extension %p<foo> misuses
- if ($^V && $^V ge 5.10.0 &&
+ if (0 && $^V && $^V ge 5.10.0 &&
defined $stat &&
$stat =~ /^\+(?![^\{]*\{\s*).*\b(\w+)\s*\(.*$String\s*,/s &&
$1 !~ /^_*volatile_*$/) {