diff options
355 files changed, 18233 insertions, 3579 deletions
diff --git a/alpine/APKBUILD.in b/alpine/APKBUILD.in index f740a34583..d4657dfe55 100644 --- a/alpine/APKBUILD.in +++ b/alpine/APKBUILD.in @@ -2,7 +2,7 @@ pkgname=frr pkgver=@VERSION@ pkgrel=0 -pkgdesc="Free Range Routing is a fork of quagga" +pkgdesc="FRRouting is a fork of quagga" url="https://frrouting.org/" arch="x86_64" license="GPL-2.0" diff --git a/bfdd/bfd_packet.c b/bfdd/bfd_packet.c index 1ec761e3b8..12e508c601 100644 --- a/bfdd/bfd_packet.c +++ b/bfdd/bfd_packet.c @@ -779,7 +779,7 @@ int bp_udp_send(int sd, uint8_t ttl, uint8_t *data, size_t datalen, cmsg->cmsg_level = IPPROTO_IPV6; cmsg->cmsg_type = IPV6_HOPLIMIT; } else { -#if BFD_LINUX +#ifdef BFD_LINUX cmsg->cmsg_level = IPPROTO_IP; cmsg->cmsg_type = IP_TTL; #else diff --git a/bfdd/config.c b/bfdd/config.c index dd4a192694..4ae7bfdc08 100644 --- a/bfdd/config.c +++ b/bfdd/config.c @@ -178,7 +178,7 @@ static int parse_peer_config(struct json_object *jo, struct bfd_peer_cfg *bpc) int family_type = (bpc->bpc_ipv4) ? AF_INET : AF_INET6; int error = 0; - log_debug("\tpeer: %s", bpc->bpc_ipv4 ? "ipv4" : "ipv6"); + log_debug(" peer: %s", bpc->bpc_ipv4 ? "ipv4" : "ipv6"); JSON_FOREACH (jo, joi, join) { key = json_object_iter_peek_name(&joi); @@ -186,7 +186,7 @@ static int parse_peer_config(struct json_object *jo, struct bfd_peer_cfg *bpc) if (strcmp(key, "multihop") == 0) { bpc->bpc_mhop = json_object_get_boolean(jo_val); - log_debug("\tmultihop: %s", + log_debug(" multihop: %s", bpc->bpc_mhop ? "true" : "false"); } else if (strcmp(key, "peer-address") == 0) { sval = json_object_get_string(jo_val); @@ -197,7 +197,7 @@ static int parse_peer_config(struct json_object *jo, struct bfd_peer_cfg *bpc) __func__, __LINE__, sval); error++; } - log_debug("\tpeer-address: %s", sval); + log_debug(" peer-address: %s", sval); } else if (strcmp(key, "local-address") == 0) { sval = json_object_get_string(jo_val); if (strtosa(sval, &bpc->bpc_local) != 0 @@ -208,18 +208,19 @@ static int parse_peer_config(struct json_object *jo, struct bfd_peer_cfg *bpc) __func__, __LINE__, sval); error++; } - log_debug("\tlocal-address: %s", sval); + log_debug(" local-address: %s", sval); } else if (strcmp(key, "local-interface") == 0) { bpc->bpc_has_localif = true; sval = json_object_get_string(jo_val); if (strlcpy(bpc->bpc_localif, sval, sizeof(bpc->bpc_localif)) > sizeof(bpc->bpc_localif)) { - log_debug("\tlocal-interface: %s (truncated)", - sval); + log_debug( + " local-interface: %s (truncated)", + sval); error++; } else { - log_debug("\tlocal-interface: %s", sval); + log_debug(" local-interface: %s", sval); } } else if (strcmp(key, "vrf-name") == 0) { bpc->bpc_has_vrfname = true; @@ -227,43 +228,44 @@ static int parse_peer_config(struct json_object *jo, struct bfd_peer_cfg *bpc) if (strlcpy(bpc->bpc_vrfname, sval, sizeof(bpc->bpc_vrfname)) > sizeof(bpc->bpc_vrfname)) { - log_debug("\tvrf-name: %s (truncated)", sval); + log_debug(" vrf-name: %s (truncated)", + sval); error++; } else { - log_debug("\tvrf-name: %s", sval); + log_debug(" vrf-name: %s", sval); } } else if (strcmp(key, "detect-multiplier") == 0) { bpc->bpc_detectmultiplier = json_object_get_int64(jo_val); bpc->bpc_has_detectmultiplier = true; - log_debug("\tdetect-multiplier: %u", + log_debug(" detect-multiplier: %u", bpc->bpc_detectmultiplier); } else if (strcmp(key, "receive-interval") == 0) { bpc->bpc_recvinterval = json_object_get_int64(jo_val); bpc->bpc_has_recvinterval = true; - log_debug("\treceive-interval: %llu", + log_debug(" receive-interval: %" PRIu64, bpc->bpc_recvinterval); } else if (strcmp(key, "transmit-interval") == 0) { bpc->bpc_txinterval = json_object_get_int64(jo_val); bpc->bpc_has_txinterval = true; - log_debug("\ttransmit-interval: %llu", + log_debug(" transmit-interval: %" PRIu64, bpc->bpc_txinterval); } else if (strcmp(key, "echo-interval") == 0) { bpc->bpc_echointerval = json_object_get_int64(jo_val); bpc->bpc_has_echointerval = true; - log_debug("\techo-interval: %llu", + log_debug(" echo-interval: %" PRIu64, bpc->bpc_echointerval); } else if (strcmp(key, "create-only") == 0) { bpc->bpc_createonly = json_object_get_boolean(jo_val); - log_debug("\tcreate-only: %s", + log_debug(" create-only: %s", bpc->bpc_createonly ? "true" : "false"); } else if (strcmp(key, "shutdown") == 0) { bpc->bpc_shutdown = json_object_get_boolean(jo_val); - log_debug("\tshutdown: %s", + log_debug(" shutdown: %s", bpc->bpc_shutdown ? "true" : "false"); } else if (strcmp(key, "echo-mode") == 0) { bpc->bpc_echo = json_object_get_boolean(jo_val); - log_debug("\techo-mode: %s", + log_debug(" echo-mode: %s", bpc->bpc_echo ? "true" : "false"); } else if (strcmp(key, "label") == 0) { bpc->bpc_has_label = true; @@ -271,10 +273,11 @@ static int parse_peer_config(struct json_object *jo, struct bfd_peer_cfg *bpc) if (strlcpy(bpc->bpc_label, sval, sizeof(bpc->bpc_label)) > sizeof(bpc->bpc_label)) { - log_debug("\tlabel: %s (truncated)", sval); + log_debug(" label: %s (truncated)", + sval); error++; } else { - log_debug("\tlabel: %s", sval); + log_debug(" label: %s", sval); } } else { sval = json_object_get_string(jo_val); @@ -309,7 +312,7 @@ static int parse_peer_label_config(struct json_object *jo, if (pl == NULL) return 1; - log_debug("\tpeer-label: %s", sval); + log_debug(" peer-label: %s", sval); /* Translate the label into BFD address keys. */ bs_to_bpc(pl->pl_bs, bpc); diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 0d170e5a30..221386e38d 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -898,14 +898,11 @@ struct attr *bgp_attr_default_set(struct attr *attr, uint8_t origin) } /* Create the attributes for an aggregate */ -struct attr *bgp_attr_aggregate_intern(struct bgp *bgp, uint8_t origin, - struct aspath *aspath, - struct community *community, - struct ecommunity *ecommunity, - struct lcommunity *lcommunity, - struct bgp_aggregate *aggregate, - uint8_t atomic_aggregate, - struct prefix *p) +struct attr *bgp_attr_aggregate_intern( + struct bgp *bgp, uint8_t origin, struct aspath *aspath, + struct community *community, struct ecommunity *ecommunity, + struct lcommunity *lcommunity, struct bgp_aggregate *aggregate, + uint8_t atomic_aggregate, const struct prefix *p) { struct attr attr; struct attr *new; @@ -1655,20 +1652,21 @@ static int bgp_attr_aggregator(struct bgp_attr_parser_args *args) else aggregator_as = stream_getw(peer->curr); + attr->aggregator_as = aggregator_as; + attr->aggregator_addr.s_addr = stream_get_ipv4(peer->curr); + + /* Set atomic aggregate flag. */ + attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR); + /* Codification of AS 0 Processing */ if (aggregator_as == BGP_AS_ZERO) { flog_err(EC_BGP_ATTR_LEN, - "AGGREGATOR attribute is BGP_AS_ZERO(0)"); + "AGGREGATOR AS number is 0 for aspath: %s", + aspath_print(attr->aspath)); return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_MAL_AS_PATH, args->total); } - attr->aggregator_as = aggregator_as; - attr->aggregator_addr.s_addr = stream_get_ipv4(peer->curr); - - /* Set atomic aggregate flag. */ - attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR); - return BGP_ATTR_PARSE_PROCEED; } @@ -1690,20 +1688,21 @@ bgp_attr_as4_aggregator(struct bgp_attr_parser_args *args, 0); } - /* Codification of AS 0 Processing */ aggregator_as = stream_getl(peer->curr); + *as4_aggregator_as = aggregator_as; + as4_aggregator_addr->s_addr = stream_get_ipv4(peer->curr); + + attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR); + + /* Codification of AS 0 Processing */ if (aggregator_as == BGP_AS_ZERO) { flog_err(EC_BGP_ATTR_LEN, - "AS4_AGGREGATOR attribute is BGP_AS_ZERO(0)"); + "AS4_AGGREGATOR AS number is 0 for aspath: %s", + aspath_print(attr->aspath)); return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_MAL_AS_PATH, 0); } - *as4_aggregator_as = aggregator_as; - as4_aggregator_addr->s_addr = stream_get_ipv4(peer->curr); - - attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR); - return BGP_ATTR_PARSE_PROCEED; } @@ -3416,10 +3415,10 @@ size_t bgp_packet_mpattr_start(struct stream *s, struct peer *peer, afi_t afi, } void bgp_packet_mpattr_prefix(struct stream *s, afi_t afi, safi_t safi, - struct prefix *p, struct prefix_rd *prd, - mpls_label_t *label, uint32_t num_labels, - int addpath_encode, uint32_t addpath_tx_id, - struct attr *attr) + const struct prefix *p, + const struct prefix_rd *prd, mpls_label_t *label, + uint32_t num_labels, int addpath_encode, + uint32_t addpath_tx_id, struct attr *attr) { if (safi == SAFI_MPLS_VPN) { if (addpath_encode) @@ -3445,7 +3444,8 @@ void bgp_packet_mpattr_prefix(struct stream *s, afi_t afi, safi_t safi, stream_put_prefix_addpath(s, p, addpath_encode, addpath_tx_id); } -size_t bgp_packet_mpattr_prefix_size(afi_t afi, safi_t safi, struct prefix *p) +size_t bgp_packet_mpattr_prefix_size(afi_t afi, safi_t safi, + const struct prefix *p) { int size = PSIZE(p->prefixlen); if (safi == SAFI_MPLS_VPN) @@ -4079,8 +4079,9 @@ size_t bgp_packet_mpunreach_start(struct stream *s, afi_t afi, safi_t safi) return attrlen_pnt; } -void bgp_packet_mpunreach_prefix(struct stream *s, struct prefix *p, afi_t afi, - safi_t safi, struct prefix_rd *prd, +void bgp_packet_mpunreach_prefix(struct stream *s, const struct prefix *p, + afi_t afi, safi_t safi, + const struct prefix_rd *prd, mpls_label_t *label, uint32_t num_labels, int addpath_encode, uint32_t addpath_tx_id, struct attr *attr) @@ -4130,7 +4131,7 @@ void bgp_attr_finish(void) /* Make attribute packet. */ void bgp_dump_routes_attr(struct stream *s, struct attr *attr, - struct prefix *prefix) + const struct prefix *prefix) { unsigned long cp; unsigned long len; diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index f90631c5b9..8a9902bb9f 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -87,7 +87,7 @@ struct bgp_attr_encap_subtlv { uint8_t value[0]; /* will be extended */ }; -#if ENABLE_BGP_VNC +#ifdef ENABLE_BGP_VNC /* * old rfp<->rfapi representation */ @@ -233,7 +233,7 @@ struct attr { uint16_t encap_tunneltype; /* grr */ struct bgp_attr_encap_subtlv *encap_subtlvs; /* rfc5512 */ -#if ENABLE_BGP_VNC +#ifdef ENABLE_BGP_VNC struct bgp_attr_encap_subtlv *vnc_subtlvs; /* VNC-specific */ #endif /* EVPN */ @@ -310,22 +310,19 @@ extern void bgp_attr_unintern_sub(struct attr *); extern void bgp_attr_unintern(struct attr **); extern void bgp_attr_flush(struct attr *); extern struct attr *bgp_attr_default_set(struct attr *attr, uint8_t); -extern struct attr *bgp_attr_aggregate_intern(struct bgp *bgp, uint8_t origin, - struct aspath *aspath, - struct community *community, - struct ecommunity *ecommunity, - struct lcommunity *lcommunity, - struct bgp_aggregate *aggregate, - uint8_t atomic_aggregate, - struct prefix *p); +extern struct attr *bgp_attr_aggregate_intern( + struct bgp *bgp, uint8_t origin, struct aspath *aspath, + struct community *community, struct ecommunity *ecommunity, + struct lcommunity *lcommunity, struct bgp_aggregate *aggregate, + uint8_t atomic_aggregate, const struct prefix *p); extern bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *, struct stream *, struct attr *, struct bpacket_attr_vec_arr *vecarr, struct prefix *, afi_t, safi_t, struct peer *, struct prefix_rd *, mpls_label_t *, uint32_t, int, uint32_t); -extern void bgp_dump_routes_attr(struct stream *, struct attr *, - struct prefix *); +extern void bgp_dump_routes_attr(struct stream *s, struct attr *attr, + const struct prefix *p); extern bool attrhash_cmp(const void *arg1, const void *arg2); extern unsigned int attrhash_key_make(const void *); extern void attr_show_all(struct vty *); @@ -372,20 +369,21 @@ extern size_t bgp_packet_mpattr_start(struct stream *s, struct peer *peer, struct bpacket_attr_vec_arr *vecarr, struct attr *attr); extern void bgp_packet_mpattr_prefix(struct stream *s, afi_t afi, safi_t safi, - struct prefix *p, struct prefix_rd *prd, + const struct prefix *p, + const struct prefix_rd *prd, mpls_label_t *label, uint32_t num_labels, int addpath_encode, uint32_t addpath_tx_id, struct attr *); extern size_t bgp_packet_mpattr_prefix_size(afi_t afi, safi_t safi, - struct prefix *p); + const struct prefix *p); extern void bgp_packet_mpattr_end(struct stream *s, size_t sizep); extern size_t bgp_packet_mpunreach_start(struct stream *s, afi_t afi, safi_t safi); -extern void bgp_packet_mpunreach_prefix(struct stream *s, struct prefix *p, - afi_t afi, safi_t safi, - struct prefix_rd *prd, mpls_label_t *, - uint32_t, int, uint32_t, struct attr *); +extern void bgp_packet_mpunreach_prefix( + struct stream *s, const struct prefix *p, afi_t afi, safi_t safi, + const struct prefix_rd *prd, mpls_label_t *label, uint32_t num_labels, + int addpath_encode, uint32_t addpath_tx_id, struct attr *attr); extern void bgp_packet_mpunreach_end(struct stream *s, size_t attrlen_pnt); extern bgp_attr_parse_ret_t bgp_attr_nexthop_valid(struct peer *peer, diff --git a/bgpd/bgp_attr_evpn.c b/bgpd/bgp_attr_evpn.c index 6941e1f9b5..7239ddef93 100644 --- a/bgpd/bgp_attr_evpn.c +++ b/bgpd/bgp_attr_evpn.c @@ -186,7 +186,7 @@ uint32_t bgp_attr_mac_mobility_seqnum(struct attr *attr, uint8_t *sticky) * one. */ for (i = 0; i < ecom->size; i++) { - uint8_t *pnt; + const uint8_t *pnt; uint8_t type, sub_type; uint32_t seq_num; diff --git a/bgpd/bgp_bmp.c b/bgpd/bgp_bmp.c index 32865da376..a6fc4ebd03 100644 --- a/bgpd/bgp_bmp.c +++ b/bgpd/bgp_bmp.c @@ -385,15 +385,15 @@ static struct stream *bmp_peerstate(struct peer *peer, bool down) stream_put(s, bbpeer->open_tx, bbpeer->open_tx_len); else { stream_put(s, dummy_open, sizeof(dummy_open)); - zlog_warn("bmp: missing TX OPEN message for peer %s\n", - peer->host); + zlog_warn("bmp: missing TX OPEN message for peer %s", + peer->host); } if (bbpeer && bbpeer->open_rx) stream_put(s, bbpeer->open_rx, bbpeer->open_rx_len); else { stream_put(s, dummy_open, sizeof(dummy_open)); - zlog_warn("bmp: missing RX OPEN message for peer %s\n", - peer->host); + zlog_warn("bmp: missing RX OPEN message for peer %s", + peer->host); } if (peer->desc) @@ -765,8 +765,8 @@ static void bmp_eor(struct bmp *bmp, afi_t afi, safi_t safi, uint8_t flags) stream_free(s); } -static struct stream *bmp_update(struct prefix *p, struct peer *peer, - struct attr *attr, afi_t afi, safi_t safi) +static struct stream *bmp_update(const struct prefix *p, struct peer *peer, + struct attr *attr, afi_t afi, safi_t safi) { struct bpacket_attr_vec_arr vecarr; struct stream *s; @@ -813,7 +813,8 @@ static struct stream *bmp_update(struct prefix *p, struct peer *peer, return s; } -static struct stream *bmp_withdraw(struct prefix *p, afi_t afi, safi_t safi) +static struct stream *bmp_withdraw(const struct prefix *p, afi_t afi, + safi_t safi) { struct stream *s; size_t attrlen_pos = 0, mp_start, mplen_pos; @@ -853,7 +854,7 @@ static struct stream *bmp_withdraw(struct prefix *p, afi_t afi, safi_t safi) } static void bmp_monitor(struct bmp *bmp, struct peer *peer, uint8_t flags, - struct prefix *p, struct attr *attr, afi_t afi, + const struct prefix *p, struct attr *attr, afi_t afi, safi_t safi, time_t uptime) { struct stream *hdr, *msg; @@ -940,7 +941,7 @@ afibreak: return true; } bmp->syncpeerid = 0; - prefix_copy(&bmp->syncpos, &bn->p); + prefix_copy(&bmp->syncpos, bgp_node_get_prefix(bn)); } if (bmp->targets->afimon[afi][safi] & BMP_MON_POSTPOLICY) { @@ -988,12 +989,14 @@ afibreak: bmp->syncpeerid = adjin->peer->qobj_node.nid; } + const struct prefix *bn_p = bgp_node_get_prefix(bn); + if (bpi) - bmp_monitor(bmp, bpi->peer, BMP_PEER_FLAG_L, &bn->p, bpi->attr, + bmp_monitor(bmp, bpi->peer, BMP_PEER_FLAG_L, bn_p, bpi->attr, afi, safi, bpi->uptime); if (adjin) - bmp_monitor(bmp, adjin->peer, 0, &bn->p, adjin->attr, - afi, safi, adjin->uptime); + bmp_monitor(bmp, adjin->peer, 0, bn_p, adjin->attr, afi, safi, + adjin->uptime); return true; } @@ -1130,16 +1133,13 @@ static void bmp_process_one(struct bmp_targets *bt, struct bgp *bgp, struct bmp *bmp; struct bmp_queue_entry *bqe, bqeref; size_t refcount; - char buf[256]; - - prefix2str(&bn->p, buf, sizeof(buf)); refcount = bmp_session_count(&bt->sessions); if (refcount == 0) return; memset(&bqeref, 0, sizeof(bqeref)); - prefix_copy(&bqeref.p, &bn->p); + prefix_copy(&bqeref.p, bgp_node_get_prefix(bn)); bqeref.peerid = peer->qobj_node.nid; bqeref.afi = afi; bqeref.safi = safi; @@ -1342,8 +1342,7 @@ static int bmp_accept(struct thread *thread) /* We can handle IPv4 or IPv6 socket. */ bmp_sock = sockunion_accept(bl->sock, &su); if (bmp_sock < 0) { - zlog_info("bmp: accept_sock failed: %s\n", - safe_strerror (errno)); + zlog_info("bmp: accept_sock failed: %s", safe_strerror(errno)); return -1; } bmp_open(bl->targets, bmp_sock); diff --git a/bgpd/bgp_clist.c b/bgpd/bgp_clist.c index 5c461dbe77..cf4d44ea22 100644 --- a/bgpd/bgp_clist.c +++ b/bgpd/bgp_clist.c @@ -311,9 +311,9 @@ static void community_list_delete(struct community_list_master *cm, community_list_free(list); } -static int community_list_empty_p(struct community_list *list) +static bool community_list_empty_p(struct community_list *list) { - return (list->head == NULL && list->tail == NULL) ? 1 : 0; + return list->head == NULL && list->tail == NULL; } /* Delete community-list entry from the list. */ @@ -497,7 +497,7 @@ static char *community_str_get(struct community *com, int i) /* Internal function to perform regular expression match for * a single community. */ -static int community_regexp_include(regex_t *reg, struct community *com, int i) +static bool community_regexp_include(regex_t *reg, struct community *com, int i) { char *str; int rv; @@ -514,16 +514,12 @@ static int community_regexp_include(regex_t *reg, struct community *com, int i) XFREE(MTYPE_COMMUNITY_STR, str); - if (rv == 0) - return 1; - - /* No match. */ - return 0; + return rv == 0; } /* Internal function to perform regular expression match for community attribute. */ -static int community_regexp_match(struct community *com, regex_t *reg) +static bool community_regexp_match(struct community *com, regex_t *reg) { const char *str; @@ -536,10 +532,10 @@ static int community_regexp_match(struct community *com, regex_t *reg) /* Regular expression match. */ if (regexec(reg, str, 0, NULL, 0) == 0) - return 1; + return true; /* No match. */ - return 0; + return false; } static char *lcommunity_str_get(struct lcommunity *lcom, int i) @@ -549,7 +545,7 @@ static char *lcommunity_str_get(struct lcommunity *lcom, int i) uint32_t localdata1; uint32_t localdata2; char *str; - uint8_t *ptr; + const uint8_t *ptr; char *pnt; ptr = lcom->val + (i * LCOMMUNITY_SIZE); @@ -574,8 +570,8 @@ static char *lcommunity_str_get(struct lcommunity *lcom, int i) /* Internal function to perform regular expression match for * a single community. */ -static int lcommunity_regexp_include(regex_t *reg, struct lcommunity *lcom, - int i) +static bool lcommunity_regexp_include(regex_t *reg, struct lcommunity *lcom, + int i) { char *str; @@ -589,15 +585,15 @@ static int lcommunity_regexp_include(regex_t *reg, struct lcommunity *lcom, /* Regular expression match. */ if (regexec(reg, str, 0, NULL, 0) == 0) { XFREE(MTYPE_LCOMMUNITY_STR, str); - return 1; + return true; } XFREE(MTYPE_LCOMMUNITY_STR, str); /* No match. */ - return 0; + return false; } -static int lcommunity_regexp_match(struct lcommunity *com, regex_t *reg) +static bool lcommunity_regexp_match(struct lcommunity *com, regex_t *reg) { const char *str; @@ -610,14 +606,14 @@ static int lcommunity_regexp_match(struct lcommunity *com, regex_t *reg) /* Regular expression match. */ if (regexec(reg, str, 0, NULL, 0) == 0) - return 1; + return true; /* No match. */ - return 0; + return false; } -static int ecommunity_regexp_match(struct ecommunity *ecom, regex_t *reg) +static bool ecommunity_regexp_match(struct ecommunity *ecom, regex_t *reg) { const char *str; @@ -630,10 +626,10 @@ static int ecommunity_regexp_match(struct ecommunity *ecom, regex_t *reg) /* Regular expression match. */ if (regexec(reg, str, 0, NULL, 0) == 0) - return 1; + return true; /* No match. */ - return 0; + return false; } #if 0 @@ -718,125 +714,113 @@ community_regexp_delete (struct community *com, regex_t * reg) /* When given community attribute matches to the community-list return 1 else return 0. */ -int community_list_match(struct community *com, struct community_list *list) +bool community_list_match(struct community *com, struct community_list *list) { struct community_entry *entry; for (entry = list->head; entry; entry = entry->next) { if (entry->any) - return entry->direct == COMMUNITY_PERMIT ? 1 : 0; + return entry->direct == COMMUNITY_PERMIT; if (entry->style == COMMUNITY_LIST_STANDARD) { if (community_include(entry->u.com, COMMUNITY_INTERNET)) - return entry->direct == COMMUNITY_PERMIT ? 1 - : 0; + return entry->direct == COMMUNITY_PERMIT; if (community_match(com, entry->u.com)) - return entry->direct == COMMUNITY_PERMIT ? 1 - : 0; + return entry->direct == COMMUNITY_PERMIT; } else if (entry->style == COMMUNITY_LIST_EXPANDED) { if (community_regexp_match(com, entry->reg)) - return entry->direct == COMMUNITY_PERMIT ? 1 - : 0; + return entry->direct == COMMUNITY_PERMIT; } } - return 0; + return false; } -int lcommunity_list_match(struct lcommunity *lcom, struct community_list *list) +bool lcommunity_list_match(struct lcommunity *lcom, struct community_list *list) { struct community_entry *entry; for (entry = list->head; entry; entry = entry->next) { if (entry->any) - return entry->direct == COMMUNITY_PERMIT ? 1 : 0; + return entry->direct == COMMUNITY_PERMIT; if (entry->style == LARGE_COMMUNITY_LIST_STANDARD) { if (lcommunity_match(lcom, entry->u.lcom)) - return entry->direct == COMMUNITY_PERMIT ? 1 - : 0; + return entry->direct == COMMUNITY_PERMIT; } else if (entry->style == LARGE_COMMUNITY_LIST_EXPANDED) { if (lcommunity_regexp_match(lcom, entry->reg)) - return entry->direct == COMMUNITY_PERMIT ? 1 - : 0; + return entry->direct == COMMUNITY_PERMIT; } } - return 0; + return false; } /* Perform exact matching. In case of expanded large-community-list, do * same thing as lcommunity_list_match(). */ -int lcommunity_list_exact_match(struct lcommunity *lcom, - struct community_list *list) +bool lcommunity_list_exact_match(struct lcommunity *lcom, + struct community_list *list) { struct community_entry *entry; for (entry = list->head; entry; entry = entry->next) { if (entry->any) - return entry->direct == COMMUNITY_PERMIT ? 1 : 0; + return entry->direct == COMMUNITY_PERMIT; if (entry->style == LARGE_COMMUNITY_LIST_STANDARD) { if (lcommunity_cmp(lcom, entry->u.com)) - return entry->direct == COMMUNITY_PERMIT ? 1 - : 0; + return entry->direct == COMMUNITY_PERMIT; } else if (entry->style == LARGE_COMMUNITY_LIST_EXPANDED) { if (lcommunity_regexp_match(lcom, entry->reg)) - return entry->direct == COMMUNITY_PERMIT ? 1 - : 0; + return entry->direct == COMMUNITY_PERMIT; } } - return 0; + return false; } -int ecommunity_list_match(struct ecommunity *ecom, struct community_list *list) +bool ecommunity_list_match(struct ecommunity *ecom, struct community_list *list) { struct community_entry *entry; for (entry = list->head; entry; entry = entry->next) { if (entry->any) - return entry->direct == COMMUNITY_PERMIT ? 1 : 0; + return entry->direct == COMMUNITY_PERMIT; if (entry->style == EXTCOMMUNITY_LIST_STANDARD) { if (ecommunity_match(ecom, entry->u.ecom)) - return entry->direct == COMMUNITY_PERMIT ? 1 - : 0; + return entry->direct == COMMUNITY_PERMIT; } else if (entry->style == EXTCOMMUNITY_LIST_EXPANDED) { if (ecommunity_regexp_match(ecom, entry->reg)) - return entry->direct == COMMUNITY_PERMIT ? 1 - : 0; + return entry->direct == COMMUNITY_PERMIT; } } - return 0; + return false; } /* Perform exact matching. In case of expanded community-list, do same thing as community_list_match(). */ -int community_list_exact_match(struct community *com, - struct community_list *list) +bool community_list_exact_match(struct community *com, + struct community_list *list) { struct community_entry *entry; for (entry = list->head; entry; entry = entry->next) { if (entry->any) - return entry->direct == COMMUNITY_PERMIT ? 1 : 0; + return entry->direct == COMMUNITY_PERMIT; if (entry->style == COMMUNITY_LIST_STANDARD) { if (community_include(entry->u.com, COMMUNITY_INTERNET)) - return entry->direct == COMMUNITY_PERMIT ? 1 - : 0; + return entry->direct == COMMUNITY_PERMIT; if (community_cmp(com, entry->u.com)) - return entry->direct == COMMUNITY_PERMIT ? 1 - : 0; + return entry->direct == COMMUNITY_PERMIT; } else if (entry->style == COMMUNITY_LIST_EXPANDED) { if (community_regexp_match(com, entry->reg)) - return entry->direct == COMMUNITY_PERMIT ? 1 - : 0; + return entry->direct == COMMUNITY_PERMIT; } } - return 0; + return false; } /* Delete all permitted communities in the list from com. */ @@ -900,8 +884,8 @@ struct community *community_list_match_delete(struct community *com, /* To avoid duplicated entry in the community-list, this function compares specified entry to existing entry. */ -static int community_list_dup_check(struct community_list *list, - struct community_entry *new) +static bool community_list_dup_check(struct community_list *list, + struct community_entry *new) { struct community_entry *entry; @@ -916,32 +900,32 @@ static int community_list_dup_check(struct community_list *list, continue; if (entry->any) - return 1; + return true; switch (entry->style) { case COMMUNITY_LIST_STANDARD: if (community_cmp(entry->u.com, new->u.com)) - return 1; + return true; break; case LARGE_COMMUNITY_LIST_STANDARD: if (lcommunity_cmp(entry->u.lcom, new->u.lcom)) - return 1; + return true; break; case EXTCOMMUNITY_LIST_STANDARD: if (ecommunity_cmp(entry->u.ecom, new->u.ecom)) - return 1; + return true; break; case COMMUNITY_LIST_EXPANDED: case EXTCOMMUNITY_LIST_EXPANDED: case LARGE_COMMUNITY_LIST_EXPANDED: if (strcmp(entry->config, new->config) == 0) - return 1; + return true; break; default: break; } } - return 0; + return false; } /* Set community-list. */ @@ -1104,7 +1088,7 @@ struct lcommunity *lcommunity_list_match_delete(struct lcommunity *lcom, } /* Helper to check if every octet do not exceed UINT_MAX */ -static int lcommunity_list_valid(const char *community) +static bool lcommunity_list_valid(const char *community) { int octets = 0; char **splits; @@ -1114,10 +1098,10 @@ static int lcommunity_list_valid(const char *community) for (int i = 0; i < num; i++) { if (strtoul(splits[i], NULL, 10) > UINT_MAX) - return 0; + return false; if (strlen(splits[i]) == 0) - return 0; + return false; octets++; XFREE(MTYPE_TMP, splits[i]); @@ -1125,9 +1109,9 @@ static int lcommunity_list_valid(const char *community) XFREE(MTYPE_TMP, splits); if (octets < 3) - return 0; + return false; - return 1; + return true; } /* Set lcommunity-list. */ diff --git a/bgpd/bgp_clist.h b/bgpd/bgp_clist.h index c5718aecac..4cb5d7c593 100644 --- a/bgpd/bgp_clist.h +++ b/bgpd/bgp_clist.h @@ -165,13 +165,13 @@ extern struct community_list * community_list_lookup(struct community_list_handler *c, const char *name, uint32_t name_hash, int master); -extern int community_list_match(struct community *, struct community_list *); -extern int ecommunity_list_match(struct ecommunity *, struct community_list *); -extern int lcommunity_list_match(struct lcommunity *, struct community_list *); -extern int community_list_exact_match(struct community *, - struct community_list *); -extern int lcommunity_list_exact_match(struct lcommunity *lcom, - struct community_list *list); +extern bool community_list_match(struct community *, struct community_list *); +extern bool ecommunity_list_match(struct ecommunity *, struct community_list *); +extern bool lcommunity_list_match(struct lcommunity *, struct community_list *); +extern bool community_list_exact_match(struct community *, + struct community_list *); +extern bool lcommunity_list_exact_match(struct lcommunity *lcom, + struct community_list *list); extern struct community *community_list_match_delete(struct community *, struct community_list *); extern struct lcommunity * diff --git a/bgpd/bgp_damp.c b/bgpd/bgp_damp.c index 792f3cea70..538610f6d7 100644 --- a/bgpd/bgp_damp.c +++ b/bgpd/bgp_damp.c @@ -155,9 +155,9 @@ static int bgp_reuse_timer(struct thread *t) if (bdi->lastrecord == BGP_RECORD_UPDATE) { bgp_path_info_unset_flag(bdi->rn, bdi->path, BGP_PATH_HISTORY); - bgp_aggregate_increment(bgp, &bdi->rn->p, - bdi->path, bdi->afi, - bdi->safi); + bgp_aggregate_increment( + bgp, bgp_node_get_prefix(bdi->rn), + bdi->path, bdi->afi, bdi->safi); bgp_process(bgp, bdi->rn, bdi->afi, bdi->safi); } diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c index b552b8811c..5104e23515 100644 --- a/bgpd/bgp_debug.c +++ b/bgpd/bgp_debug.c @@ -2404,7 +2404,7 @@ void bgp_debug_init(void) /* Return true if this prefix is on the per_prefix_list of prefixes to debug * for BGP_DEBUG_TYPE */ -static int bgp_debug_per_prefix(struct prefix *p, +static int bgp_debug_per_prefix(const struct prefix *p, unsigned long term_bgp_debug_type, unsigned int BGP_DEBUG_TYPE, struct list *per_prefix_list) @@ -2489,7 +2489,7 @@ int bgp_debug_keepalive(struct peer *peer) bgp_debug_keepalive_peers); } -bool bgp_debug_update(struct peer *peer, struct prefix *p, +bool bgp_debug_update(struct peer *peer, const struct prefix *p, struct update_group *updgrp, unsigned int inbound) { char *host = NULL; @@ -2528,19 +2528,19 @@ bool bgp_debug_update(struct peer *peer, struct prefix *p, return false; } -bool bgp_debug_bestpath(struct prefix *p) +bool bgp_debug_bestpath(struct bgp_node *rn) { if (BGP_DEBUG(bestpath, BESTPATH)) { - if (bgp_debug_per_prefix(p, term_bgp_debug_bestpath, - BGP_DEBUG_BESTPATH, - bgp_debug_bestpath_prefixes)) + if (bgp_debug_per_prefix( + bgp_node_get_prefix(rn), term_bgp_debug_bestpath, + BGP_DEBUG_BESTPATH, bgp_debug_bestpath_prefixes)) return true; } return false; } -bool bgp_debug_zebra(struct prefix *p) +bool bgp_debug_zebra(const struct prefix *p) { if (BGP_DEBUG(zebra, ZEBRA)) { if (bgp_debug_per_prefix(p, term_bgp_debug_zebra, @@ -2553,7 +2553,7 @@ bool bgp_debug_zebra(struct prefix *p) } const char *bgp_debug_rdpfxpath2str(afi_t afi, safi_t safi, - struct prefix_rd *prd, + const struct prefix_rd *prd, union prefixconstptr pu, mpls_label_t *label, uint32_t num_labels, int addpath_valid, uint32_t addpath_id, diff --git a/bgpd/bgp_debug.h b/bgpd/bgp_debug.h index 73007fe819..7352b7917a 100644 --- a/bgpd/bgp_debug.h +++ b/bgpd/bgp_debug.h @@ -166,15 +166,16 @@ extern void bgp_notify_print(struct peer *, struct bgp_notify *, const char *); extern const struct message bgp_status_msg[]; extern int bgp_debug_neighbor_events(struct peer *peer); extern int bgp_debug_keepalive(struct peer *peer); -extern bool bgp_debug_update(struct peer *peer, struct prefix *p, +extern bool bgp_debug_update(struct peer *peer, const struct prefix *p, struct update_group *updgrp, unsigned int inbound); -extern bool bgp_debug_bestpath(struct prefix *p); -extern bool bgp_debug_zebra(struct prefix *p); - -extern const char *bgp_debug_rdpfxpath2str(afi_t, safi_t, struct prefix_rd *, - union prefixconstptr, mpls_label_t *, - uint32_t, int, uint32_t, char *, - int); +extern bool bgp_debug_bestpath(struct bgp_node *rn); +extern bool bgp_debug_zebra(const struct prefix *p); + +extern const char * +bgp_debug_rdpfxpath2str(afi_t afi, safi_t safi, const struct prefix_rd *prd, + union prefixconstptr pu, mpls_label_t *label, + uint32_t num_labels, int addpath_valid, + uint32_t addpath_id, char *str, int size); const char *bgp_notify_admin_message(char *buf, size_t bufsz, uint8_t *data, size_t datalen); diff --git a/bgpd/bgp_dump.c b/bgpd/bgp_dump.c index c448b9894a..cd1722ccca 100644 --- a/bgpd/bgp_dump.c +++ b/bgpd/bgp_dump.c @@ -307,6 +307,7 @@ bgp_dump_route_node_record(int afi, struct bgp_node *rn, struct stream *obuf; size_t sizep; size_t endp; + const struct prefix *p = bgp_node_get_prefix(rn); obuf = bgp_dump_obuf; stream_reset(obuf); @@ -325,19 +326,19 @@ bgp_dump_route_node_record(int afi, struct bgp_node *rn, stream_putl(obuf, seq); /* Prefix length */ - stream_putc(obuf, rn->p.prefixlen); + stream_putc(obuf, p->prefixlen); /* Prefix */ if (afi == AFI_IP) { /* We'll dump only the useful bits (those not 0), but have to * align on 8 bits */ - stream_write(obuf, (uint8_t *)&rn->p.u.prefix4, - (rn->p.prefixlen + 7) / 8); + stream_write(obuf, (uint8_t *)&p->u.prefix4, + (p->prefixlen + 7) / 8); } else if (afi == AFI_IP6) { /* We'll dump only the useful bits (those not 0), but have to * align on 8 bits */ - stream_write(obuf, (uint8_t *)&rn->p.u.prefix6, - (rn->p.prefixlen + 7) / 8); + stream_write(obuf, (uint8_t *)&p->u.prefix6, + (p->prefixlen + 7) / 8); } /* Save where we are now, so we can overwride the entry count later */ @@ -361,7 +362,7 @@ bgp_dump_route_node_record(int afi, struct bgp_node *rn, /* Dump attribute. */ /* Skip prefix & AFI/SAFI for MP_NLRI */ - bgp_dump_routes_attr(obuf, path->attr, &rn->p); + bgp_dump_routes_attr(obuf, path->attr, p); cur_endp = stream_get_endp(obuf); if (cur_endp > BGP_MAX_PACKET_SIZE + BGP_DUMP_MSG_HEADER diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c index 21bfe3f126..fc66494742 100644 --- a/bgpd/bgp_ecommunity.c +++ b/bgpd/bgp_ecommunity.c @@ -555,7 +555,7 @@ struct ecommunity *ecommunity_str2com(const char *str, int type, return ecom; } -static int ecommunity_rt_soo_str(char *buf, size_t bufsz, uint8_t *pnt, +static int ecommunity_rt_soo_str(char *buf, size_t bufsz, const uint8_t *pnt, int type, int sub_type, int format) { int len = 0; diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index c3a9527b66..a77a1e912e 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -496,7 +496,7 @@ static void unmap_vni_from_rt(struct bgp *bgp, struct bgpevpn *vpn, } static void bgp_evpn_get_rmac_nexthop(struct bgpevpn *vpn, - struct prefix_evpn *p, + const struct prefix_evpn *p, struct attr *attr, uint8_t flags) { struct bgp *bgp_vrf = vpn->bgp_vrf; @@ -583,7 +583,7 @@ static void evpn_convert_nexthop_to_ipv6(struct attr *attr) * Add (update) or delete MACIP from zebra. */ static int bgp_zebra_send_remote_macip(struct bgp *bgp, struct bgpevpn *vpn, - struct prefix_evpn *p, + const struct prefix_evpn *p, struct in_addr remote_vtep_ip, int add, uint8_t flags, uint32_t seq) { @@ -651,8 +651,8 @@ static int bgp_zebra_send_remote_macip(struct bgp *bgp, struct bgpevpn *vpn, * Add (update) or delete remote VTEP from zebra. */ static int bgp_zebra_send_remote_vtep(struct bgp *bgp, struct bgpevpn *vpn, - struct prefix_evpn *p, - int flood_control, int add) + const struct prefix_evpn *p, + int flood_control, int add) { struct stream *s; @@ -930,7 +930,8 @@ static void add_mac_mobility_to_attr(uint32_t seq_num, struct attr *attr) /* Install EVPN route into zebra. */ static int evpn_zebra_install(struct bgp *bgp, struct bgpevpn *vpn, - struct prefix_evpn *p, struct bgp_path_info *pi) + const struct prefix_evpn *p, + struct bgp_path_info *pi) { int ret; uint8_t flags; @@ -970,7 +971,7 @@ static int evpn_zebra_install(struct bgp *bgp, struct bgpevpn *vpn, /* Uninstall EVPN route from zebra. */ static int evpn_zebra_uninstall(struct bgp *bgp, struct bgpevpn *vpn, - struct prefix_evpn *p, + const struct prefix_evpn *p, struct in_addr remote_vtep_ip) { int ret; @@ -1004,7 +1005,7 @@ static void evpn_delete_old_local_route(struct bgp *bgp, struct bgpevpn *vpn, * L3VPN routes. */ global_rn = bgp_afi_node_lookup(bgp->rib[afi][safi], afi, safi, - (struct prefix *)&rn->p, &vpn->prd); + bgp_node_get_prefix(rn), &vpn->prd); if (global_rn) { /* Delete route entry in the global EVPN table. */ delete_evpn_route_entry(bgp, afi, safi, global_rn, &pi); @@ -1054,9 +1055,8 @@ static int is_vtep_present_in_list(struct list *list, * Best path for ES route was changed, * update the list of VTEPs for this ES */ -static int evpn_es_install_vtep(struct bgp *bgp, - struct evpnes *es, - struct prefix_evpn *p, +static int evpn_es_install_vtep(struct bgp *bgp, struct evpnes *es, + const struct prefix_evpn *p, struct in_addr rvtep) { struct in_addr *vtep_ip; @@ -1128,7 +1128,7 @@ static int evpn_es_route_select_install(struct bgp *bgp, && !bgp_addpath_is_addpath_used(&bgp->tx_addpath, afi, safi)) { if (bgp_zebra_has_route_changed(rn, old_select)) { ret = evpn_es_install_vtep(bgp, es, - (struct prefix_evpn *)&rn->p, + (const struct prefix_evpn *)bgp_node_get_prefix(rn), old_select->attr->nexthop); } UNSET_FLAG(old_select->flags, BGP_PATH_MULTIPATH_CHG); @@ -1157,13 +1157,13 @@ static int evpn_es_route_select_install(struct bgp *bgp, if (new_select && new_select->type == ZEBRA_ROUTE_BGP && new_select->sub_type == BGP_ROUTE_IMPORTED) { ret = evpn_es_install_vtep(bgp, es, - (struct prefix_evpn *)&rn->p, + (const struct prefix_evpn *)bgp_node_get_prefix(rn), new_select->attr->nexthop); } else { if (old_select && old_select->type == ZEBRA_ROUTE_BGP && old_select->sub_type == BGP_ROUTE_IMPORTED) ret = evpn_es_uninstall_vtep( - bgp, es, (struct prefix_evpn *)&rn->p, + bgp, es, (struct prefix_evpn *)bgp_node_get_prefix(rn), old_select->attr->nexthop); } @@ -1208,7 +1208,7 @@ static int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn, && !bgp_addpath_is_addpath_used(&bgp->tx_addpath, afi, safi)) { if (bgp_zebra_has_route_changed(rn, old_select)) ret = evpn_zebra_install( - bgp, vpn, (struct prefix_evpn *)&rn->p, + bgp, vpn, (const struct prefix_evpn *)bgp_node_get_prefix(rn), old_select); UNSET_FLAG(old_select->flags, BGP_PATH_MULTIPATH_CHG); bgp_zebra_clear_route_change_flags(rn); @@ -1234,8 +1234,9 @@ static int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn, if (new_select && new_select->type == ZEBRA_ROUTE_BGP && new_select->sub_type == BGP_ROUTE_IMPORTED) { - ret = evpn_zebra_install(bgp, vpn, (struct prefix_evpn *)&rn->p, - new_select); + ret = evpn_zebra_install( + bgp, vpn, (struct prefix_evpn *)bgp_node_get_prefix(rn), + new_select); /* If an old best existed and it was a "local" route, the only * reason @@ -1251,9 +1252,11 @@ static int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn, } else { if (old_select && old_select->type == ZEBRA_ROUTE_BGP && old_select->sub_type == BGP_ROUTE_IMPORTED) - ret = evpn_zebra_uninstall(bgp, vpn, - (struct prefix_evpn *)&rn->p, - old_select->attr->nexthop); + ret = evpn_zebra_uninstall( + bgp, vpn, + (const struct prefix_evpn *)bgp_node_get_prefix( + rn), + old_select->attr->nexthop); } /* Clear any route change flags. */ @@ -1330,11 +1333,11 @@ static int update_evpn_type4_route_entry(struct bgp *bgp, struct evpnes *es, struct bgp_path_info *local_pi = NULL; /* local route entry if any */ struct bgp_path_info *remote_pi = NULL; /* remote route entry if any */ struct attr *attr_new = NULL; - struct prefix_evpn *evp = NULL; + const struct prefix_evpn *evp = NULL; *ri = NULL; *route_changed = 1; - evp = (struct prefix_evpn *)&rn->p; + evp = (const struct prefix_evpn *)bgp_node_get_prefix(rn); /* locate the local and remote entries if any */ for (tmp_pi = bgp_node_get_bgp_path_info(rn); tmp_pi; @@ -1662,10 +1665,10 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, uint32_t num_labels = 1; int route_change = 1; uint8_t sticky = 0; - struct prefix_evpn *evp; + const struct prefix_evpn *evp; *pi = NULL; - evp = (struct prefix_evpn *)&rn->p; + evp = (const struct prefix_evpn *)bgp_node_get_prefix(rn); memset(&label, 0, sizeof(label)); /* See if this is an update of an existing route, or a new add. */ @@ -1797,8 +1800,8 @@ static void evpn_zebra_reinstall_best_route(struct bgp *bgp, if (curr_select && curr_select->type == ZEBRA_ROUTE_BGP && curr_select->sub_type == BGP_ROUTE_IMPORTED) evpn_zebra_install(bgp, vpn, - (struct prefix_evpn *)&rn->p, - curr_select); + (const struct prefix_evpn *)bgp_node_get_prefix(rn), + curr_select); } /* @@ -1820,13 +1823,10 @@ static void evpn_cleanup_local_non_best_route(struct bgp *bgp, struct bgp_node *rn, struct bgp_path_info *local_pi) { - char buf[PREFIX_STRLEN]; - /* local path was not picked as the winner; kick it out */ - if (bgp_debug_zebra(NULL)) { - zlog_debug("evicting local evpn prefix %s as remote won", - prefix2str(&rn->p, buf, sizeof(buf))); - } + if (bgp_debug_zebra(NULL)) + zlog_debug("evicting local evpn prefix %pRN as remote won", rn); + evpn_delete_old_local_route(bgp, vpn, rn, local_pi); bgp_path_info_reap(rn, local_pi); @@ -2145,7 +2145,7 @@ static int update_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn) */ for (rn = bgp_table_top(vpn->route_table); rn; rn = bgp_route_next(rn)) { - struct prefix_evpn *evp = (struct prefix_evpn *)&rn->p; + const struct prefix_evpn *evp = (const struct prefix_evpn *)bgp_node_get_prefix(rn); struct bgp_node *rd_rn; struct bgp_path_info *global_pi; @@ -2278,7 +2278,7 @@ static int delete_global_type2_routes(struct bgp *bgp, struct bgpevpn *vpn) if (rdrn && bgp_node_has_bgp_path_info_data(rdrn)) { table = bgp_node_get_bgp_table_info(rdrn); for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) { - struct prefix_evpn *evp = (struct prefix_evpn *)&rn->p; + const struct prefix_evpn *evp = (const struct prefix_evpn *)bgp_node_get_prefix(rn); if (evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE) continue; @@ -2319,7 +2319,7 @@ static int delete_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn) /* Next, walk this VNI's route table and delete local type-2 routes. */ for (rn = bgp_table_top(vpn->route_table); rn; rn = bgp_route_next(rn)) { - struct prefix_evpn *evp = (struct prefix_evpn *)&rn->p; + const struct prefix_evpn *evp = (const struct prefix_evpn *)bgp_node_get_prefix(rn); if (evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE) continue; @@ -2555,7 +2555,7 @@ bgp_create_evpn_bgp_path_info(struct bgp_path_info *parent_pi, /* Install EVPN route entry in ES */ static int install_evpn_route_entry_in_es(struct bgp *bgp, struct evpnes *es, - struct prefix_evpn *p, + const struct prefix_evpn *p, struct bgp_path_info *parent_pi) { int ret = 0; @@ -2619,7 +2619,7 @@ static int install_evpn_route_entry_in_es(struct bgp *bgp, struct evpnes *es, * Install route entry into the VRF routing table and invoke route selection. */ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf, - struct prefix_evpn *evp, + const struct prefix_evpn *evp, struct bgp_path_info *parent_pi) { struct bgp_node *rn; @@ -2709,7 +2709,8 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf, /* as it is an importation, change nexthop */ bgp_path_info_set_flag(rn, pi, BGP_PATH_ANNC_NH_SELF); - bgp_aggregate_increment(bgp_vrf, &rn->p, pi, afi, safi); + bgp_aggregate_increment(bgp_vrf, bgp_node_get_prefix(rn), pi, afi, + safi); /* Perform route selection and update zebra, if required. */ bgp_process(bgp_vrf, rn, afi, safi); @@ -2726,7 +2727,7 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf, * Install route entry into the VNI routing table and invoke route selection. */ static int install_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, - struct prefix_evpn *p, + const struct prefix_evpn *p, struct bgp_path_info *parent_pi) { struct bgp_node *rn; @@ -2782,7 +2783,7 @@ static int install_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, /* Uninstall EVPN route entry from ES route table */ static int uninstall_evpn_route_entry_in_es(struct bgp *bgp, struct evpnes *es, - struct prefix_evpn *p, + const struct prefix_evpn *p, struct bgp_path_info *parent_pi) { int ret; @@ -2825,7 +2826,7 @@ static int uninstall_evpn_route_entry_in_es(struct bgp *bgp, struct evpnes *es, * to zebra, if appropriate. */ static int uninstall_evpn_route_entry_in_vrf(struct bgp *bgp_vrf, - struct prefix_evpn *evp, + const struct prefix_evpn *evp, struct bgp_path_info *parent_pi) { struct bgp_node *rn; @@ -2876,7 +2877,8 @@ static int uninstall_evpn_route_entry_in_vrf(struct bgp *bgp_vrf, /* Process for route leaking. */ vpn_leak_from_vrf_withdraw(bgp_get_default(), bgp_vrf, pi); - bgp_aggregate_decrement(bgp_vrf, &rn->p, pi, afi, safi); + bgp_aggregate_decrement(bgp_vrf, bgp_node_get_prefix(rn), pi, afi, + safi); /* Mark entry for deletion */ bgp_path_info_delete(rn, pi); @@ -2895,7 +2897,7 @@ static int uninstall_evpn_route_entry_in_vrf(struct bgp *bgp_vrf, * to zebra, if appropriate. */ static int uninstall_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, - struct prefix_evpn *p, + const struct prefix_evpn *p, struct bgp_path_info *parent_pi) { struct bgp_node *rn; @@ -2932,7 +2934,7 @@ static int uninstall_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, /* * Given a prefix, see if it belongs to ES. */ -static int is_prefix_matching_for_es(struct prefix_evpn *p, +static int is_prefix_matching_for_es(const struct prefix_evpn *p, struct evpnes *es) { /* if not an ES route return false */ @@ -3107,7 +3109,9 @@ static int install_uninstall_routes_for_es(struct bgp *bgp, continue; for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) { - struct prefix_evpn *evp = (struct prefix_evpn *)&rn->p; + const struct prefix_evpn *evp = + (const struct prefix_evpn *)bgp_node_get_prefix( + rn); for (pi = bgp_node_get_bgp_path_info(rn); pi; pi = pi->next) { @@ -3153,7 +3157,7 @@ static int install_uninstall_routes_for_es(struct bgp *bgp, * route into bgp vrf table and remote rmac in bridge table. */ static int bgp_evpn_route_rmac_self_check(struct bgp *bgp_vrf, - struct prefix_evpn *evp, + const struct prefix_evpn *evp, struct bgp_path_info *pi) { /* evpn route could have learnt prior to L3vni has come up, @@ -3214,7 +3218,7 @@ static int install_uninstall_routes_for_vrf(struct bgp *bgp_vrf, int install) continue; for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) { - struct prefix_evpn *evp = (struct prefix_evpn *)&rn->p; + const struct prefix_evpn *evp = (const struct prefix_evpn *)bgp_node_get_prefix(rn); /* if not mac-ip route skip this route */ if (!(evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE @@ -3302,7 +3306,9 @@ static int install_uninstall_routes_for_vni(struct bgp *bgp, continue; for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) { - struct prefix_evpn *evp = (struct prefix_evpn *)&rn->p; + const struct prefix_evpn *evp = + (const struct prefix_evpn *)bgp_node_get_prefix( + rn); if (evp->prefix.route_type != rtype) continue; @@ -3524,7 +3530,7 @@ static int install_uninstall_route_in_vnis(struct bgp *bgp, afi_t afi, * Install or uninstall route for appropriate VNIs/ESIs. */ static int install_uninstall_evpn_route(struct bgp *bgp, afi_t afi, safi_t safi, - struct prefix *p, + const struct prefix *p, struct bgp_path_info *pi, int import) { struct prefix_evpn *evp = (struct prefix_evpn *)p; @@ -3774,7 +3780,8 @@ static int update_advertise_vni_routes(struct bgp *bgp, struct bgpevpn *vpn) */ for (rn = bgp_table_top(vpn->route_table); rn; rn = bgp_route_next(rn)) { - struct prefix_evpn *evp = (struct prefix_evpn *)&rn->p; + const struct prefix_evpn *evp = + (const struct prefix_evpn *)bgp_node_get_prefix(rn); /* Identify MAC-IP local routes. */ if (evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE) @@ -4297,13 +4304,14 @@ static int process_type5_route(struct peer *peer, afi_t afi, safi_t safi, return ret; } -static void evpn_mpattr_encode_type5(struct stream *s, struct prefix *p, - struct prefix_rd *prd, mpls_label_t *label, - uint32_t num_labels, struct attr *attr) +static void evpn_mpattr_encode_type5(struct stream *s, const struct prefix *p, + const struct prefix_rd *prd, + mpls_label_t *label, uint32_t num_labels, + struct attr *attr) { int len; char temp[16]; - struct evpn_addr *p_evpn_p; + const struct evpn_addr *p_evpn_p; memset(&temp, 0, 16); if (p->family != AF_EVPN) @@ -4465,7 +4473,7 @@ static void update_autort_vni(struct hash_bucket *bucket, struct bgp *bgp) */ /* withdraw type-5 route corresponding to ip prefix */ -void bgp_evpn_withdraw_type5_route(struct bgp *bgp_vrf, struct prefix *p, +void bgp_evpn_withdraw_type5_route(struct bgp *bgp_vrf, const struct prefix *p, afi_t afi, safi_t safi) { int ret = 0; @@ -4499,8 +4507,9 @@ void bgp_evpn_withdraw_type5_routes(struct bgp *bgp_vrf, afi_t afi, safi_t safi) for (pi = bgp_node_get_bgp_path_info(rn); pi; pi = pi->next) { if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED) && is_route_injectable_into_evpn(pi)) { - bgp_evpn_withdraw_type5_route(bgp_vrf, &rn->p, - afi, safi); + bgp_evpn_withdraw_type5_route( + bgp_vrf, bgp_node_get_prefix(rn), afi, + safi); break; } } @@ -4535,7 +4544,7 @@ void bgp_evpn_install_uninstall_default_route(struct bgp *bgp_vrf, afi_t afi, * path in the case of the attr. In the case of a local prefix (when we * are advertising local subnets), the src_attr will be NULL. */ -void bgp_evpn_advertise_type5_route(struct bgp *bgp_vrf, struct prefix *p, +void bgp_evpn_advertise_type5_route(struct bgp *bgp_vrf, const struct prefix *p, struct attr *src_attr, afi_t afi, safi_t safi) { @@ -4592,18 +4601,21 @@ void bgp_evpn_advertise_type5_routes(struct bgp *bgp_vrf, afi_t afi, ret = route_map_apply( bgp_vrf->adv_cmd_rmap[afi][safi] .map, - &rn->p, RMAP_BGP, &tmp_pi); + bgp_node_get_prefix(rn), + RMAP_BGP, &tmp_pi); if (ret == RMAP_DENYMATCH) { bgp_attr_flush(&tmp_attr); continue; } bgp_evpn_advertise_type5_route( - bgp_vrf, &rn->p, &tmp_attr, - afi, safi); + bgp_vrf, + bgp_node_get_prefix(rn), + &tmp_attr, afi, safi); } else bgp_evpn_advertise_type5_route( - bgp_vrf, &rn->p, pi->attr, - afi, safi); + bgp_vrf, + bgp_node_get_prefix(rn), + pi->attr, afi, safi); break; } } @@ -4900,7 +4912,7 @@ char *bgp_evpn_label2str(mpls_label_t *label, uint32_t num_labels, char *buf, * Function to convert evpn route to json format. * NOTE: We don't use prefix2str as the output here is a bit different. */ -void bgp_evpn_route2json(struct prefix_evpn *p, json_object *json) +void bgp_evpn_route2json(const struct prefix_evpn *p, json_object *json) { char buf1[ETHER_ADDR_STRLEN]; char buf2[PREFIX2STR_BUFFER]; @@ -4965,7 +4977,7 @@ void bgp_evpn_route2json(struct prefix_evpn *p, json_object *json) * Function to convert evpn route to string. * NOTE: We don't use prefix2str as the output here is a bit different. */ -char *bgp_evpn_route2str(struct prefix_evpn *p, char *buf, int len) +char *bgp_evpn_route2str(const struct prefix_evpn *p, char *buf, int len) { char buf1[ETHER_ADDR_STRLEN]; char buf2[PREFIX2STR_BUFFER]; @@ -5030,8 +5042,8 @@ char *bgp_evpn_route2str(struct prefix_evpn *p, char *buf, int len) /* * Encode EVPN prefix in Update (MP_REACH) */ -void bgp_evpn_encode_prefix(struct stream *s, struct prefix *p, - struct prefix_rd *prd, mpls_label_t *label, +void bgp_evpn_encode_prefix(struct stream *s, const struct prefix *p, + const struct prefix_rd *prd, mpls_label_t *label, uint32_t num_labels, struct attr *attr, int addpath_encode, uint32_t addpath_tx_id) { @@ -5550,7 +5562,7 @@ void bgp_evpn_es_free(struct bgp *bgp, struct evpnes *es) * Import evpn route from global table to VNI/VRF/ESI. */ int bgp_evpn_import_route(struct bgp *bgp, afi_t afi, safi_t safi, - struct prefix *p, struct bgp_path_info *pi) + const struct prefix *p, struct bgp_path_info *pi) { return install_uninstall_evpn_route(bgp, afi, safi, p, pi, 1); } @@ -5559,7 +5571,7 @@ int bgp_evpn_import_route(struct bgp *bgp, afi_t afi, safi_t safi, * Unimport evpn route from VNI/VRF/ESI. */ int bgp_evpn_unimport_route(struct bgp *bgp, afi_t afi, safi_t safi, - struct prefix *p, struct bgp_path_info *pi) + const struct prefix *p, struct bgp_path_info *pi) { return install_uninstall_evpn_route(bgp, afi, safi, p, pi, 0); } @@ -5601,25 +5613,23 @@ int bgp_filter_evpn_routes_upon_martian_nh_change(struct bgp *bgp) if (bgp_nexthop_self(bgp, afi, pi->type, pi->sub_type, pi->attr, rn)) { + const struct prefix *p = + bgp_node_get_prefix(rn); - char attr_str[BUFSIZ] = {0}; - char pbuf[PREFIX_STRLEN]; + if (bgp_debug_update(pi->peer, p, NULL, + 1)) { + char attr_str[BUFSIZ] = {0}; - bgp_dump_attr(pi->attr, attr_str, - BUFSIZ); + bgp_dump_attr(pi->attr, + attr_str, BUFSIZ); - if (bgp_debug_update(pi->peer, &rn->p, - NULL, 1)) zlog_debug( - "%u: prefix %s with attr %s - DENIED due to martian or self nexthop", - bgp->vrf_id, - prefix2str( - &rn->p, pbuf, - sizeof(pbuf)), + "%u: prefix %pRN with attr %s - DENIED due to martian or self nexthop", + bgp->vrf_id, rn, attr_str); - + } bgp_evpn_unimport_route(bgp, afi, safi, - &rn->p, pi); + p, pi); bgp_rib_remove(rn, pi, pi->peer, afi, safi); @@ -6264,7 +6274,7 @@ void bgp_evpn_vrf_delete(struct bgp *bgp_vrf) /* * Get the prefixlen of the ip prefix carried within the type5 evpn route. */ -int bgp_evpn_get_type5_prefixlen(struct prefix *pfx) +int bgp_evpn_get_type5_prefixlen(const struct prefix *pfx) { struct prefix_evpn *evp = (struct prefix_evpn *)pfx; @@ -6280,7 +6290,7 @@ int bgp_evpn_get_type5_prefixlen(struct prefix *pfx) /* * Should we register nexthop for this EVPN prefix for nexthop tracking? */ -bool bgp_evpn_is_prefix_nht_supported(struct prefix *pfx) +bool bgp_evpn_is_prefix_nht_supported(const struct prefix *pfx) { struct prefix_evpn *evp = (struct prefix_evpn *)pfx; diff --git a/bgpd/bgp_evpn.h b/bgpd/bgp_evpn.h index b030f0a33e..a48a707b94 100644 --- a/bgpd/bgp_evpn.h +++ b/bgpd/bgp_evpn.h @@ -140,11 +140,12 @@ static inline bool is_route_injectable_into_evpn(struct bgp_path_info *pi) } extern void bgp_evpn_advertise_type5_route(struct bgp *bgp_vrf, - struct prefix *p, + const struct prefix *p, struct attr *src_attr, afi_t afi, safi_t safi); -extern void bgp_evpn_withdraw_type5_route(struct bgp *bgp_vrf, struct prefix *p, - afi_t afi, safi_t safi); +extern void bgp_evpn_withdraw_type5_route(struct bgp *bgp_vrf, + const struct prefix *p, afi_t afi, + safi_t safi); extern void bgp_evpn_withdraw_type5_routes(struct bgp *bgp_vrf, afi_t afi, safi_t safi); extern void bgp_evpn_advertise_type5_routes(struct bgp *bgp_vrf, afi_t afi, @@ -153,18 +154,22 @@ extern void bgp_evpn_vrf_delete(struct bgp *bgp_vrf); extern void bgp_evpn_handle_router_id_update(struct bgp *bgp, int withdraw); extern char *bgp_evpn_label2str(mpls_label_t *label, uint32_t num_labels, char *buf, int len); -extern char *bgp_evpn_route2str(struct prefix_evpn *p, char *buf, int len); -extern void bgp_evpn_route2json(struct prefix_evpn *p, json_object *json); -extern void bgp_evpn_encode_prefix(struct stream *s, struct prefix *p, - struct prefix_rd *prd, mpls_label_t *label, - uint32_t num_labels, struct attr *attr, - int addpath_encode, uint32_t addpath_tx_id); +extern char *bgp_evpn_route2str(const struct prefix_evpn *p, char *buf, + int len); +extern void bgp_evpn_route2json(const struct prefix_evpn *p, json_object *json); +extern void bgp_evpn_encode_prefix(struct stream *s, const struct prefix *p, + const struct prefix_rd *prd, + mpls_label_t *label, uint32_t num_labels, + struct attr *attr, int addpath_encode, + uint32_t addpath_tx_id); extern int bgp_nlri_parse_evpn(struct peer *peer, struct attr *attr, struct bgp_nlri *packet, int withdraw); extern int bgp_evpn_import_route(struct bgp *bgp, afi_t afi, safi_t safi, - struct prefix *p, struct bgp_path_info *ri); + const struct prefix *p, + struct bgp_path_info *ri); extern int bgp_evpn_unimport_route(struct bgp *bgp, afi_t afi, safi_t safi, - struct prefix *p, struct bgp_path_info *ri); + const struct prefix *p, + struct bgp_path_info *ri); extern int bgp_filter_evpn_routes_upon_martian_nh_change(struct bgp *bgp); extern int bgp_evpn_local_macip_del(struct bgp *bgp, vni_t vni, struct ethaddr *mac, struct ipaddr *ip, @@ -191,8 +196,8 @@ extern void bgp_evpn_flood_control_change(struct bgp *bgp); extern void bgp_evpn_cleanup_on_disable(struct bgp *bgp); extern void bgp_evpn_cleanup(struct bgp *bgp); extern void bgp_evpn_init(struct bgp *bgp); -extern int bgp_evpn_get_type5_prefixlen(struct prefix *pfx); -extern bool bgp_evpn_is_prefix_nht_supported(struct prefix *pfx); +extern int bgp_evpn_get_type5_prefixlen(const struct prefix *pfx); +extern bool bgp_evpn_is_prefix_nht_supported(const struct prefix *pfx); extern void update_advertise_vrf_routes(struct bgp *bgp_vrf); #endif /* _QUAGGA_BGP_EVPN_H */ diff --git a/bgpd/bgp_evpn_private.h b/bgpd/bgp_evpn_private.h index 76cf8b2cd6..ea1ae087f1 100644 --- a/bgpd/bgp_evpn_private.h +++ b/bgpd/bgp_evpn_private.h @@ -366,7 +366,7 @@ static inline void encode_na_flag_extcomm(struct ecommunity_val *eval, eval->val[2] |= ECOMMUNITY_EVPN_SUBTYPE_ND_ROUTER_FLAG; } -static inline void ip_prefix_from_type5_prefix(struct prefix_evpn *evp, +static inline void ip_prefix_from_type5_prefix(const struct prefix_evpn *evp, struct prefix *ip) { memset(ip, 0, sizeof(struct prefix)); @@ -392,7 +392,7 @@ static inline int is_evpn_prefix_default(const struct prefix *evp) 1 : 0); } -static inline void ip_prefix_from_type2_prefix(struct prefix_evpn *evp, +static inline void ip_prefix_from_type2_prefix(const struct prefix_evpn *evp, struct prefix *ip) { memset(ip, 0, sizeof(struct prefix)); @@ -409,7 +409,7 @@ static inline void ip_prefix_from_type2_prefix(struct prefix_evpn *evp, } } -static inline void ip_prefix_from_evpn_prefix(struct prefix_evpn *evp, +static inline void ip_prefix_from_evpn_prefix(const struct prefix_evpn *evp, struct prefix *ip) { if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) @@ -432,8 +432,9 @@ static inline void build_evpn_type2_prefix(struct prefix_evpn *p, memcpy(&p->prefix.macip_addr.ip, ip, sizeof(*ip)); } -static inline void build_type5_prefix_from_ip_prefix(struct prefix_evpn *evp, - struct prefix *ip_prefix) +static inline void +build_type5_prefix_from_ip_prefix(struct prefix_evpn *evp, + const struct prefix *ip_prefix) { struct ipaddr ip; diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index 4f9d2a7b53..fddb00b6e2 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -59,7 +59,7 @@ struct vni_walk_ctx { static void display_vrf_import_rt(struct vty *vty, struct vrf_irt_node *irt, json_object *json) { - uint8_t *pnt; + const uint8_t *pnt; uint8_t type, sub_type; struct ecommunity_as eas; struct ecommunity_ip eip; @@ -167,7 +167,7 @@ static void show_vrf_import_rt_entry(struct hash_bucket *bucket, void *args[]) static void display_import_rt(struct vty *vty, struct irt_node *irt, json_object *json) { - uint8_t *pnt; + const uint8_t *pnt; uint8_t type, sub_type; struct ecommunity_as eas; struct ecommunity_ip eip; @@ -281,9 +281,10 @@ static void bgp_evpn_show_route_rd_header(struct vty *vty, uint16_t type; struct rd_as rd_as; struct rd_ip rd_ip; - uint8_t *pnt; + const uint8_t *pnt; + const struct prefix *p = bgp_node_get_prefix(rd_rn); - pnt = rd_rn->p.u.val; + pnt = p->u.val; /* Decode RD type. */ type = decode_rd_type(pnt); @@ -647,8 +648,9 @@ static void show_esi_routes(struct bgp *bgp, char prefix_str[BUFSIZ]; json_object *json_paths = NULL; json_object *json_prefix = NULL; + const struct prefix *p = bgp_node_get_prefix(rn); - bgp_evpn_route2str((struct prefix_evpn *)&rn->p, prefix_str, + bgp_evpn_route2str((struct prefix_evpn *)p, prefix_str, sizeof(prefix_str)); if (json) @@ -678,7 +680,7 @@ static void show_esi_routes(struct bgp *bgp, if (json) json_path = json_object_new_array(); - route_vty_out(vty, &rn->p, pi, 0, SAFI_EVPN, json_path); + route_vty_out(vty, p, pi, 0, SAFI_EVPN, json_path); if (json) json_object_array_add(json_paths, json_path); @@ -692,7 +694,7 @@ static void show_esi_routes(struct bgp *bgp, json_object_string_add(json_prefix, "prefix", prefix_str); json_object_int_add(json_prefix, "prefixLen", - rn->p.prefixlen); + p->prefixlen); json_object_object_add(json_prefix, "paths", json_paths); json_object_object_add(json, prefix_str, @@ -735,13 +737,15 @@ static void show_vni_routes(struct bgp *bgp, struct bgpevpn *vpn, int type, tbl_ver = table->version; for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) { - struct prefix_evpn *evp = (struct prefix_evpn *)&rn->p; + const struct prefix_evpn *evp = + (const struct prefix_evpn *)bgp_node_get_prefix(rn); int add_prefix_to_json = 0; char prefix_str[BUFSIZ]; json_object *json_paths = NULL; json_object *json_prefix = NULL; + const struct prefix *p = bgp_node_get_prefix(rn); - bgp_evpn_route2str((struct prefix_evpn *)&rn->p, prefix_str, + bgp_evpn_route2str((const struct prefix_evpn *)p, prefix_str, sizeof(prefix_str)); if (type && evp->prefix.route_type != type) @@ -784,7 +788,7 @@ static void show_vni_routes(struct bgp *bgp, struct bgpevpn *vpn, int type, AFI_L2VPN, SAFI_EVPN, json_path); else - route_vty_out(vty, &rn->p, pi, 0, SAFI_EVPN, + route_vty_out(vty, p, pi, 0, SAFI_EVPN, json_path); if (json) @@ -799,7 +803,7 @@ static void show_vni_routes(struct bgp *bgp, struct bgpevpn *vpn, int type, json_object_string_add(json_prefix, "prefix", prefix_str); json_object_int_add(json_prefix, "prefixLen", - rn->p.prefixlen); + p->prefixlen); json_object_object_add(json_prefix, "paths", json_paths); json_object_object_add(json, prefix_str, @@ -1188,8 +1192,9 @@ static int bgp_show_ethernet_vpn(struct vty *vty, struct prefix_rd *prd, rn = bgp_route_next(rn)) { uint64_t tbl_ver; json_object *json_nroute = NULL; + const struct prefix *p = bgp_node_get_prefix(rn); - if (prd && memcmp(rn->p.u.val, prd->val, 8) != 0) + if (prd && memcmp(p->u.val, prd->val, 8) != 0) continue; table = bgp_node_get_bgp_table_info(rn); @@ -1290,16 +1295,18 @@ static int bgp_show_ethernet_vpn(struct vty *vty, struct prefix_rd *prd, json_array = json_object_new_array(); if (option == SHOW_DISPLAY_TAGS) - route_vty_out_tag(vty, &rm->p, pi, - no_display, SAFI_EVPN, - json_array); + route_vty_out_tag( + vty, bgp_node_get_prefix(rm), + pi, no_display, SAFI_EVPN, + json_array); else if (option == SHOW_DISPLAY_OVERLAY) - route_vty_out_overlay(vty, &rm->p, pi, - no_display, - json_array); + route_vty_out_overlay( + vty, bgp_node_get_prefix(rm), + pi, no_display, json_array); else - route_vty_out(vty, &rm->p, pi, - no_display, SAFI_EVPN, + route_vty_out(vty, + bgp_node_get_prefix(rm), + pi, no_display, SAFI_EVPN, json_array); no_display = 1; } @@ -1308,15 +1315,19 @@ static int bgp_show_ethernet_vpn(struct vty *vty, struct prefix_rd *prd, output_count++; if (use_json && json_array) { + const struct prefix *p = + bgp_node_get_prefix(rm); + json_prefix_info = json_object_new_object(); - json_object_string_add(json_prefix_info, - "prefix", bgp_evpn_route2str( - (struct prefix_evpn *)&rm->p, buf, - BUFSIZ)); + json_object_string_add( + json_prefix_info, "prefix", + bgp_evpn_route2str( + (struct prefix_evpn *)p, buf, + BUFSIZ)); json_object_int_add(json_prefix_info, - "prefixLen", rm->p.prefixlen); + "prefixLen", p->prefixlen); json_object_object_add(json_prefix_info, "paths", json_array); @@ -2580,13 +2591,14 @@ static void evpn_show_route_rd(struct vty *vty, struct bgp *bgp, /* Display all prefixes with this RD. */ for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) { - struct prefix_evpn *evp = (struct prefix_evpn *)&rn->p; + const struct prefix_evpn *evp = + (const struct prefix_evpn *)bgp_node_get_prefix(rn); json_object *json_prefix = NULL; json_object *json_paths = NULL; char prefix_str[BUFSIZ]; int add_prefix_to_json = 0; - bgp_evpn_route2str((struct prefix_evpn *)&rn->p, prefix_str, + bgp_evpn_route2str((struct prefix_evpn *)evp, prefix_str, sizeof(prefix_str)); if (type && evp->prefix.route_type != type) @@ -2703,13 +2715,14 @@ static void evpn_show_all_routes(struct vty *vty, struct bgp *bgp, int type, json_object *json_rd = NULL; /* contains routes for an RD */ int add_rd_to_json = 0; uint64_t tbl_ver; + const struct prefix *rd_rnp = bgp_node_get_prefix(rd_rn); table = bgp_node_get_bgp_table_info(rd_rn); if (table == NULL) continue; tbl_ver = table->version; - prefix_rd2str((struct prefix_rd *)&rd_rn->p, rd_str, + prefix_rd2str((struct prefix_rd *)rd_rnp, rd_str, sizeof(rd_str)); if (json) @@ -2723,12 +2736,15 @@ static void evpn_show_all_routes(struct vty *vty, struct bgp *bgp, int type, NULL; /* contains prefix under a RD */ json_object *json_paths = NULL; /* array of paths under a prefix*/ - struct prefix_evpn *evp = (struct prefix_evpn *)&rn->p; + const struct prefix_evpn *evp = + (const struct prefix_evpn *)bgp_node_get_prefix( + rn); char prefix_str[BUFSIZ]; int add_prefix_to_json = 0; + const struct prefix *p = bgp_node_get_prefix(rn); - bgp_evpn_route2str((struct prefix_evpn *)&rn->p, - prefix_str, sizeof(prefix_str)); + bgp_evpn_route2str((struct prefix_evpn *)p, prefix_str, + sizeof(prefix_str)); if (type && evp->prefix.route_type != type) continue; @@ -2764,15 +2780,15 @@ static void evpn_show_all_routes(struct vty *vty, struct bgp *bgp, int type, json_object_string_add(json_prefix, "prefix", prefix_str); json_object_int_add(json_prefix, "prefixLen", - rn->p.prefixlen); + p->prefixlen); } /* Prefix and num paths displayed once per prefix. */ if (detail) route_vty_out_detail_header( vty, bgp, rn, - (struct prefix_rd *)&rd_rn->p, - AFI_L2VPN, SAFI_EVPN, json_prefix); + (struct prefix_rd *)rd_rnp, AFI_L2VPN, + SAFI_EVPN, json_prefix); /* For EVPN, the prefix is displayed for each path (to * fit in @@ -2792,8 +2808,8 @@ static void evpn_show_all_routes(struct vty *vty, struct bgp *bgp, int type, vty, bgp, rn, pi, AFI_L2VPN, SAFI_EVPN, json_path); } else - route_vty_out(vty, &rn->p, pi, 0, - SAFI_EVPN, json_path); + route_vty_out(vty, p, pi, 0, SAFI_EVPN, + json_path); if (json) json_object_array_add(json_paths, diff --git a/bgpd/bgp_flowspec.h b/bgpd/bgp_flowspec.h index bc201b739f..94c571f2fc 100644 --- a/bgpd/bgp_flowspec.h +++ b/bgpd/bgp_flowspec.h @@ -43,7 +43,7 @@ extern void bgp_fs_nlri_get_string(unsigned char *nlri_content, size_t len, char *return_string, int format, json_object *json_path); -extern void route_vty_out_flowspec(struct vty *vty, struct prefix *p, +extern void route_vty_out_flowspec(struct vty *vty, const struct prefix *p, struct bgp_path_info *path, int display, json_object *json_paths); extern int bgp_fs_config_write_pbr(struct vty *vty, struct bgp *bgp, diff --git a/bgpd/bgp_flowspec_util.c b/bgpd/bgp_flowspec_util.c index c117d08bfb..9d824a8641 100644 --- a/bgpd/bgp_flowspec_util.c +++ b/bgpd/bgp_flowspec_util.c @@ -76,9 +76,8 @@ static int bgp_flowspec_call_non_opaque_decode(uint8_t *nlri_content, int len, return ret; } -bool bgp_flowspec_contains_prefix(struct prefix *pfs, - struct prefix *input, - int prefix_check) +bool bgp_flowspec_contains_prefix(const struct prefix *pfs, + struct prefix *input, int prefix_check) { uint32_t offset = 0; int type; @@ -608,7 +607,8 @@ bool bgp_flowspec_get_first_nh(struct bgp *bgp, struct bgp_path_info *pi, struct bgp_pbr_entry_action *api_action; memset(&api, 0, sizeof(struct bgp_pbr_entry_main)); - if (bgp_pbr_build_and_validate_entry(&rn->p, pi, &api) < 0) + if (bgp_pbr_build_and_validate_entry(bgp_node_get_prefix(rn), pi, &api) + < 0) return true; for (i = 0; i < api.action_num; i++) { api_action = &api.actions[i]; diff --git a/bgpd/bgp_flowspec_util.h b/bgpd/bgp_flowspec_util.h index bd89176bec..0e78c7a53c 100644 --- a/bgpd/bgp_flowspec_util.h +++ b/bgpd/bgp_flowspec_util.h @@ -50,7 +50,7 @@ struct bgp_pbr_entry_main; extern int bgp_flowspec_match_rules_fill(uint8_t *nlri_content, int len, struct bgp_pbr_entry_main *bpem); -extern bool bgp_flowspec_contains_prefix(struct prefix *pfs, +extern bool bgp_flowspec_contains_prefix(const struct prefix *pfs, struct prefix *input, int prefix_check); diff --git a/bgpd/bgp_flowspec_vty.c b/bgpd/bgp_flowspec_vty.c index 80384c12c6..c852e18c46 100644 --- a/bgpd/bgp_flowspec_vty.c +++ b/bgpd/bgp_flowspec_vty.c @@ -252,7 +252,7 @@ void bgp_fs_nlri_get_string(unsigned char *nlri_content, size_t len, } } -void route_vty_out_flowspec(struct vty *vty, struct prefix *p, +void route_vty_out_flowspec(struct vty *vty, const struct prefix *p, struct bgp_path_info *path, int display, json_object *json_paths) { @@ -409,8 +409,8 @@ int bgp_show_table_flowspec(struct vty *vty, struct bgp *bgp, afi_t afi, } for (; pi; pi = pi->next) { total_count++; - route_vty_out_flowspec(vty, &rn->p, pi, display, - json_paths); + route_vty_out_flowspec(vty, bgp_node_get_prefix(rn), pi, + display, json_paths); } if (use_json) { vty_out(vty, "%s\n", @@ -554,18 +554,18 @@ extern int bgp_flowspec_display_match_per_ip(afi_t afi, struct bgp_table *rib, json_object *json_paths) { struct bgp_node *rn; - struct prefix *prefix; + const struct prefix *prefix; int display = 0; for (rn = bgp_table_top(rib); rn; rn = bgp_route_next(rn)) { - prefix = &rn->p; + prefix = bgp_node_get_prefix(rn); if (prefix->family != AF_FLOWSPEC) continue; if (bgp_flowspec_contains_prefix(prefix, match, prefix_check)) { route_vty_out_flowspec( - vty, &rn->p, bgp_node_get_bgp_path_info(rn), + vty, prefix, bgp_node_get_bgp_path_info(rn), use_json ? NLRI_STRING_FORMAT_JSON : NLRI_STRING_FORMAT_LARGE, json_paths); diff --git a/bgpd/bgp_label.c b/bgpd/bgp_label.c index ff1ab1a37d..ec44037bf7 100644 --- a/bgpd/bgp_label.c +++ b/bgpd/bgp_label.c @@ -132,7 +132,6 @@ int bgp_reg_for_label_callback(mpls_label_t new_label, void *labelid, { struct bgp_path_info *pi; struct bgp_node *rn; - char addr[PREFIX_STRLEN]; pi = labelid; /* Is this path still valid? */ @@ -145,10 +144,9 @@ int bgp_reg_for_label_callback(mpls_label_t new_label, void *labelid, } rn = pi->net; - prefix2str(&rn->p, addr, PREFIX_STRLEN); if (BGP_DEBUG(labelpool, LABELPOOL)) - zlog_debug("%s: FEC %s label=%u, allocated=%d", __func__, addr, + zlog_debug("%s: FEC %pRN label=%u, allocated=%d", __func__, rn, new_label, allocated); if (!allocated) { @@ -174,8 +172,8 @@ int bgp_reg_for_label_callback(mpls_label_t new_label, void *labelid, if (pi->attr->label_index != MPLS_INVALID_LABEL_INDEX) { flog_err( EC_BGP_LABEL, - "%s: FEC %s Rejecting allocated label %u as Label Index is %u", - __func__, addr, new_label, pi->attr->label_index); + "%s: FEC %pRN Rejecting allocated label %u as Label Index is %u", + __func__, rn, new_label, pi->attr->label_index); bgp_register_for_label(pi->net, pi); @@ -189,8 +187,8 @@ int bgp_reg_for_label_callback(mpls_label_t new_label, void *labelid, } /* Shouldn't happen: different label allocation */ flog_err(EC_BGP_LABEL, - "%s: %s had label %u but got new assignment %u", - __func__, addr, pi->attr->label, new_label); + "%s: %pRN had label %u but got new assignment %u", + __func__, rn, pi->attr->label, new_label); /* continue means use new one */ } @@ -210,14 +208,14 @@ void bgp_reg_dereg_for_label(struct bgp_node *rn, struct bgp_path_info *pi, { bool with_label_index = false; struct stream *s; - struct prefix *p; + const struct prefix *p; mpls_label_t *local_label; int command; uint16_t flags = 0; size_t flags_pos = 0; char addr[PREFIX_STRLEN]; - p = &(rn->p); + p = bgp_node_get_prefix(rn); local_label = &(rn->local_label); /* this prevents the loop when we're called by * bgp_reg_for_label_callback() @@ -473,7 +471,7 @@ int bgp_nlri_parse_label(struct peer *peer, struct attr *attr, if (pnt != lim) { flog_err( EC_BGP_UPDATE_RCV, - "%s [Error] Update packet error / L-U (%zu data remaining after parsing)", + "%s [Error] Update packet error / L-U (%td data remaining after parsing)", peer->host, lim - pnt); return BGP_NLRI_PARSE_ERROR_PACKET_LENGTH; } diff --git a/bgpd/bgp_lcommunity.c b/bgpd/bgp_lcommunity.c index 324505418c..ec7d07fe73 100644 --- a/bgpd/bgp_lcommunity.c +++ b/bgpd/bgp_lcommunity.c @@ -2,7 +2,7 @@ * * Copyright (C) 2016 Keyur Patel <keyur@arrcus.com> * - * This file is part of FreeRangeRouting (FRR). + * This file is part of FRRouting (FRR). * * FRR is free software; you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software @@ -178,7 +178,7 @@ static void set_lcommunity_string(struct lcommunity *lcom, bool make_json) int i; int len; char *str_buf; - uint8_t *pnt; + const uint8_t *pnt; uint32_t global, local1, local2; json_object *json_lcommunity_list = NULL; json_object *json_string = NULL; diff --git a/bgpd/bgp_lcommunity.h b/bgpd/bgp_lcommunity.h index e10ab0eef1..c96df8482d 100644 --- a/bgpd/bgp_lcommunity.h +++ b/bgpd/bgp_lcommunity.h @@ -2,7 +2,7 @@ * * Copyright (C) 2016 Keyur Patel <keyur@arrcus.com> * - * This file is part of FreeRangeRouting (FRR). + * This file is part of FRRouting (FRR). * * FRR is free software; you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software diff --git a/bgpd/bgp_mac.c b/bgpd/bgp_mac.c index 537bb45455..af20e5fdd7 100644 --- a/bgpd/bgp_mac.c +++ b/bgpd/bgp_mac.c @@ -142,13 +142,15 @@ static void bgp_process_mac_rescan_table(struct bgp *bgp, struct peer *peer, for (prn = bgp_table_top(table); prn; prn = bgp_route_next(prn)) { struct bgp_table *sub = prn->info; + const struct prefix *prn_p = bgp_node_get_prefix(prn); if (!sub) continue; for (rn = bgp_table_top(sub); rn; rn = bgp_route_next(rn)) { bool rn_affected; - struct prefix_evpn *pevpn = (struct prefix_evpn *)&rn->p; + const struct prefix *p = bgp_node_get_prefix(rn); + const struct prefix_evpn *pevpn = (const struct prefix_evpn *)p; struct prefix_rd prd; uint32_t num_labels = 0; mpls_label_t *label_pnt = NULL; @@ -156,7 +158,7 @@ static void bgp_process_mac_rescan_table(struct bgp *bgp, struct peer *peer, if (pevpn->family == AF_EVPN && pevpn->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE && - memcmp(&rn->p.u.prefix_evpn.macip_addr.mac, + memcmp(&p->u.prefix_evpn.macip_addr.mac, macaddr, ETH_ALEN) == 0) rn_affected = true; else @@ -185,15 +187,15 @@ static void bgp_process_mac_rescan_table(struct bgp *bgp, struct peer *peer, prd.family = AF_UNSPEC; prd.prefixlen = 64; - memcpy(&prd.val, &prn->p.u.val, 8); + memcpy(&prd.val, prn_p->u.val, 8); if (CHECK_FLAG(pi->flags, BGP_PATH_REMOVED)) { - if (bgp_debug_update(peer, &rn->p, NULL, 1)) { + if (bgp_debug_update(peer, p, NULL, 1)) { char pfx_buf[BGP_PRD_PATH_STRLEN]; bgp_debug_rdpfxpath2str( AFI_L2VPN, SAFI_EVPN, &prd, - &rn->p, label_pnt, num_labels, + p, label_pnt, num_labels, pi->addpath_rx_id ? 1 : 0, pi->addpath_rx_id, pfx_buf, sizeof(pfx_buf)); @@ -205,7 +207,7 @@ static void bgp_process_mac_rescan_table(struct bgp *bgp, struct peer *peer, } memcpy(&evpn, &pi->attr->evpn_overlay, sizeof(evpn)); - int32_t ret = bgp_update(peer, &rn->p, + int32_t ret = bgp_update(peer, p, pi->addpath_rx_id, pi->attr, AFI_L2VPN, SAFI_EVPN, ZEBRA_ROUTE_BGP, @@ -358,7 +360,7 @@ void bgp_mac_del_mac_entry(struct interface *ifp) * An example: router-mac attribute in any of evpn update * requires to compare against local mac. */ -bool bgp_mac_exist(struct ethaddr *mac) +bool bgp_mac_exist(const struct ethaddr *mac) { struct bgp_self_mac lookup; struct bgp_self_mac *bsm; @@ -379,9 +381,9 @@ bool bgp_mac_exist(struct ethaddr *mac) * mac against any of local assigned (SVIs) MAC * address. */ -bool bgp_mac_entry_exists(struct prefix *p) +bool bgp_mac_entry_exists(const struct prefix *p) { - struct prefix_evpn *pevpn = (struct prefix_evpn *)p; + const struct prefix_evpn *pevpn = (const struct prefix_evpn *)p; if (pevpn->family != AF_EVPN) return false; diff --git a/bgpd/bgp_mac.h b/bgpd/bgp_mac.h index 68449b574a..4b94d80d1a 100644 --- a/bgpd/bgp_mac.h +++ b/bgpd/bgp_mac.h @@ -36,7 +36,7 @@ void bgp_mac_dump_table(struct vty *vty); /* * Function to lookup the prefix and see if we have a matching mac */ -bool bgp_mac_entry_exists(struct prefix *p); -bool bgp_mac_exist(struct ethaddr *mac); +bool bgp_mac_entry_exists(const struct prefix *p); +bool bgp_mac_exist(const struct ethaddr *mac); #endif diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c index c4ece2f082..c14a1a05ac 100644 --- a/bgpd/bgp_main.c +++ b/bgpd/bgp_main.c @@ -228,7 +228,7 @@ static __attribute__((__noreturn__)) void bgp_exit(int status) community_list_terminate(bgp_clist); bgp_vrf_terminate(); -#if ENABLE_BGP_VNC +#ifdef ENABLE_BGP_VNC vnc_zebra_destroy(); #endif bgp_zebra_destroy(); @@ -275,7 +275,7 @@ static int bgp_vrf_enable(struct vrf *vrf) XFREE(MTYPE_BGP, bgp->name_pretty); bgp->name_pretty = XSTRDUP(MTYPE_BGP, "VRF default"); bgp->inst_type = BGP_INSTANCE_TYPE_DEFAULT; -#if ENABLE_BGP_VNC +#ifdef ENABLE_BGP_VNC if (!bgp->rfapi) { bgp->rfapi = bgp_rfapi_new(bgp); assert(bgp->rfapi); diff --git a/bgpd/bgp_mpath.c b/bgpd/bgp_mpath.c index 9e73acdc01..cbef41bafd 100644 --- a/bgpd/bgp_mpath.c +++ b/bgpd/bgp_mpath.c @@ -447,7 +447,7 @@ void bgp_path_info_mpath_update(struct bgp_node *rn, struct listnode *mp_node, *mp_next_node; struct bgp_path_info *cur_mpath, *new_mpath, *next_mpath, *prev_mpath; int mpath_changed, debug; - char pfx_buf[PREFIX2STR_BUFFER], nh_buf[2][INET6_ADDRSTRLEN]; + char nh_buf[2][INET6_ADDRSTRLEN]; char path_buf[PATH_ADDPATH_STR_BUFFER]; mpath_changed = 0; @@ -457,10 +457,7 @@ void bgp_path_info_mpath_update(struct bgp_node *rn, old_mpath_count = 0; prev_mpath = new_best; mp_node = listhead(mp_list); - debug = bgp_debug_bestpath(&rn->p); - - if (debug) - prefix2str(&rn->p, pfx_buf, sizeof(pfx_buf)); + debug = bgp_debug_bestpath(rn); if (new_best) { mpath_count++; @@ -480,8 +477,8 @@ void bgp_path_info_mpath_update(struct bgp_node *rn, if (debug) zlog_debug( - "%s: starting mpath update, newbest %s num candidates %d old-mpath-count %d", - pfx_buf, new_best ? new_best->peer->host : "NONE", + "%pRN: starting mpath update, newbest %s num candidates %d old-mpath-count %d", + rn, new_best ? new_best->peer->host : "NONE", mp_list ? listcount(mp_list) : 0, old_mpath_count); /* @@ -513,8 +510,8 @@ void bgp_path_info_mpath_update(struct bgp_node *rn, if (debug) zlog_debug( - "%s: comparing candidate %s with existing mpath %s", - pfx_buf, + "%pRN: comparing candidate %s with existing mpath %s", + rn, tmp_info ? tmp_info->peer->host : "NONE", cur_mpath ? cur_mpath->peer->host : "NONE"); @@ -537,8 +534,8 @@ void bgp_path_info_mpath_update(struct bgp_node *rn, bgp_path_info_path_with_addpath_rx_str( cur_mpath, path_buf); zlog_debug( - "%s: %s is still multipath, cur count %d", - pfx_buf, path_buf, mpath_count); + "%pRN: %s is still multipath, cur count %d", + rn, path_buf, mpath_count); } } else { mpath_changed = 1; @@ -546,8 +543,8 @@ void bgp_path_info_mpath_update(struct bgp_node *rn, bgp_path_info_path_with_addpath_rx_str( cur_mpath, path_buf); zlog_debug( - "%s: remove mpath %s nexthop %s, cur count %d", - pfx_buf, path_buf, + "%pRN: remove mpath %s nexthop %s, cur count %d", + rn, path_buf, inet_ntop(AF_INET, &cur_mpath->attr ->nexthop, @@ -579,8 +576,8 @@ void bgp_path_info_mpath_update(struct bgp_node *rn, bgp_path_info_path_with_addpath_rx_str( cur_mpath, path_buf); zlog_debug( - "%s: remove mpath %s nexthop %s, cur count %d", - pfx_buf, path_buf, + "%pRN: remove mpath %s nexthop %s, cur count %d", + rn, path_buf, inet_ntop(AF_INET, &cur_mpath->attr->nexthop, nh_buf[0], sizeof(nh_buf[0])), @@ -624,8 +621,8 @@ void bgp_path_info_mpath_update(struct bgp_node *rn, bgp_path_info_path_with_addpath_rx_str( new_mpath, path_buf); zlog_debug( - "%s: add mpath %s nexthop %s, cur count %d", - pfx_buf, path_buf, + "%pRN: add mpath %s nexthop %s, cur count %d", + rn, path_buf, inet_ntop(AF_INET, &new_mpath->attr ->nexthop, @@ -641,8 +638,8 @@ void bgp_path_info_mpath_update(struct bgp_node *rn, if (new_best) { if (debug) zlog_debug( - "%s: New mpath count (incl newbest) %d mpath-change %s", - pfx_buf, mpath_count, + "%pRN: New mpath count (incl newbest) %d mpath-change %s", + rn, mpath_count, mpath_changed ? "YES" : "NO"); bgp_path_info_mpath_count_set(new_best, mpath_count - 1); diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index 3e2ba9802a..46dcd2864e 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -48,7 +48,7 @@ #include "bgpd/bgp_nht.h" #include "bgpd/bgp_evpn.h" -#if ENABLE_BGP_VNC +#ifdef ENABLE_BGP_VNC #include "bgpd/rfapi/rfapi_backend.h" #endif @@ -214,7 +214,7 @@ int bgp_nlri_parse_vpn(struct peer *peer, struct attr *attr, decode_rd_ip(pnt + 5, &rd_ip); break; -#if ENABLE_BGP_VNC +#ifdef ENABLE_BGP_VNC case RD_TYPE_VNC_ETH: break; #endif @@ -244,7 +244,7 @@ int bgp_nlri_parse_vpn(struct peer *peer, struct attr *attr, if (pnt != lim) { flog_err( EC_BGP_UPDATE_RCV, - "%s [Error] Update packet error / VPN (%zu data remaining after parsing)", + "%s [Error] Update packet error / VPN (%td data remaining after parsing)", peer->host, lim - pnt); return BGP_NLRI_PARSE_ERROR_PACKET_LENGTH; } @@ -468,18 +468,16 @@ leak_update(struct bgp *bgp, /* destination bgp instance */ struct bgp *bgp_orig, struct prefix *nexthop_orig, int nexthop_self_flag, int debug) { - struct prefix *p = &bn->p; + const struct prefix *p = bgp_node_get_prefix(bn); struct bgp_path_info *bpi; struct bgp_path_info *bpi_ultimate; struct bgp_path_info *new; - char buf_prefix[PREFIX_STRLEN]; - if (debug) { - prefix2str(&bn->p, buf_prefix, sizeof(buf_prefix)); - zlog_debug("%s: entry: leak-to=%s, p=%s, type=%d, sub_type=%d", - __func__, bgp->name_pretty, buf_prefix, - source_bpi->type, source_bpi->sub_type); - } + if (debug) + zlog_debug( + "%s: entry: leak-to=%s, p=%pRN, type=%d, sub_type=%d", + __func__, bgp->name_pretty, bn, source_bpi->type, + source_bpi->sub_type); /* * Routes that are redistributed into BGP from zebra do not get @@ -518,9 +516,8 @@ leak_update(struct bgp *bgp, /* destination bgp instance */ bgp_attr_unintern(&new_attr); if (debug) zlog_debug( - "%s: ->%s: %s: Found route, no change", - __func__, bgp->name_pretty, - buf_prefix); + "%s: ->%s: %pRN: Found route, no change", + __func__, bgp->name_pretty, bn); return NULL; } @@ -580,8 +577,8 @@ leak_update(struct bgp *bgp, /* destination bgp instance */ bgp_unlock_node(bn); if (debug) - zlog_debug("%s: ->%s: %s Found route, changed attr", - __func__, bgp->name_pretty, buf_prefix); + zlog_debug("%s: ->%s: %pRN Found route, changed attr", + __func__, bgp->name_pretty, bn); return bpi; } @@ -645,8 +642,8 @@ leak_update(struct bgp *bgp, /* destination bgp instance */ bgp_process(bgp, bn, afi, safi); if (debug) - zlog_debug("%s: ->%s: %s: Added new route", __func__, - bgp->name_pretty, buf_prefix); + zlog_debug("%s: ->%s: %pRN: Added new route", __func__, + bgp->name_pretty, bn); return new; } @@ -657,7 +654,7 @@ void vpn_leak_from_vrf_update(struct bgp *bgp_vpn, /* to */ struct bgp_path_info *path_vrf) /* route */ { int debug = BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF); - struct prefix *p = &path_vrf->net->p; + const struct prefix *p = bgp_node_get_prefix(path_vrf->net); afi_t afi = family2afi(p->family); struct attr static_attr = {0}; struct attr *new_attr = NULL; @@ -891,19 +888,17 @@ void vpn_leak_from_vrf_withdraw(struct bgp *bgp_vpn, /* to */ struct bgp_path_info *path_vrf) /* route */ { int debug = BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF); - struct prefix *p = &path_vrf->net->p; + const struct prefix *p = bgp_node_get_prefix(path_vrf->net); afi_t afi = family2afi(p->family); safi_t safi = SAFI_MPLS_VPN; struct bgp_path_info *bpi; struct bgp_node *bn; const char *debugmsg; - char buf_prefix[PREFIX_STRLEN]; if (debug) { - prefix2str(p, buf_prefix, sizeof(buf_prefix)); zlog_debug( - "%s: entry: leak-from=%s, p=%s, type=%d, sub_type=%d", - __func__, bgp_vrf->name_pretty, buf_prefix, + "%s: entry: leak-from=%s, p=%pRN, type=%d, sub_type=%d", + __func__, bgp_vrf->name_pretty, path_vrf->net, path_vrf->type, path_vrf->sub_type); } @@ -980,14 +975,10 @@ void vpn_leak_from_vrf_withdraw_all(struct bgp *bgp_vpn, /* to */ continue; for (bn = bgp_table_top(table); bn; bn = bgp_route_next(bn)) { - - char buf[PREFIX2STR_BUFFER]; - bpi = bgp_node_get_bgp_path_info(bn); if (debug && bpi) { - zlog_debug( - "%s: looking at prefix %s", __func__, - prefix2str(&bn->p, buf, sizeof(buf))); + zlog_debug("%s: looking at prefix %pRN", + __func__, bn); } for (; bpi; bpi = bpi->next) { @@ -1005,8 +996,10 @@ void vpn_leak_from_vrf_withdraw_all(struct bgp *bgp_vpn, /* to */ if (debug) zlog_debug("%s: deleting it", __func__); - bgp_aggregate_decrement(bgp_vpn, &bn->p, - bpi, afi, safi); + bgp_aggregate_decrement( + bgp_vpn, + bgp_node_get_prefix(bn), bpi, + afi, safi); bgp_path_info_delete(bn, bpi); bgp_process(bgp_vpn, bn, afi, safi); } @@ -1049,7 +1042,7 @@ vpn_leak_to_vrf_update_onevrf(struct bgp *bgp_vrf, /* to */ struct bgp *bgp_vpn, /* from */ struct bgp_path_info *path_vpn) /* route */ { - struct prefix *p = &path_vpn->net->p; + const struct prefix *p = bgp_node_get_prefix(path_vpn->net); afi_t afi = family2afi(p->family); struct attr static_attr = {0}; @@ -1228,12 +1221,9 @@ vpn_leak_to_vrf_update_onevrf(struct bgp *bgp_vrf, /* to */ } } - if (debug) { - char buf_prefix[PREFIX_STRLEN]; - prefix2str(p, buf_prefix, sizeof(buf_prefix)); - zlog_debug("%s: pfx %s: num_labels %d", __func__, buf_prefix, - num_labels); - } + if (debug) + zlog_debug("%s: pfx %pRN: num_labels %d", __func__, + path_vpn->net, num_labels); /* * For VRF-2-VRF route-leaking, @@ -1273,7 +1263,7 @@ void vpn_leak_to_vrf_update(struct bgp *bgp_vpn, /* from */ void vpn_leak_to_vrf_withdraw(struct bgp *bgp_vpn, /* from */ struct bgp_path_info *path_vpn) /* route */ { - struct prefix *p; + const struct prefix *p; afi_t afi; safi_t safi = SAFI_UNICAST; struct bgp *bgp; @@ -1281,21 +1271,18 @@ void vpn_leak_to_vrf_withdraw(struct bgp *bgp_vpn, /* from */ struct bgp_node *bn; struct bgp_path_info *bpi; const char *debugmsg; - char buf_prefix[PREFIX_STRLEN]; int debug = BGP_DEBUG(vpn, VPN_LEAK_TO_VRF); - if (debug) { - prefix2str(&path_vpn->net->p, buf_prefix, sizeof(buf_prefix)); - zlog_debug("%s: entry: p=%s, type=%d, sub_type=%d", __func__, - buf_prefix, path_vpn->type, path_vpn->sub_type); - } + if (debug) + zlog_debug("%s: entry: p=%pRN, type=%d, sub_type=%d", __func__, + path_vpn->net, path_vpn->type, path_vpn->sub_type); if (debug) zlog_debug("%s: start (path_vpn=%p)", __func__, path_vpn); if (!path_vpn->net) { -#if ENABLE_BGP_VNC +#ifdef ENABLE_BGP_VNC /* BGP_ROUTE_RFP routes do not have path_vpn->net set (yet) */ if (path_vpn->type == ZEBRA_ROUTE_BGP && path_vpn->sub_type == BGP_ROUTE_RFP) { @@ -1310,7 +1297,7 @@ void vpn_leak_to_vrf_withdraw(struct bgp *bgp_vpn, /* from */ return; } - p = &path_vpn->net->p; + p = bgp_node_get_prefix(path_vpn->net); afi = family2afi(p->family); /* Loop over VRFs */ @@ -1381,8 +1368,9 @@ void vpn_leak_to_vrf_withdraw_all(struct bgp *bgp_vrf, /* to */ && is_pi_family_vpn(bpi->extra->parent)) { /* delete route */ - bgp_aggregate_decrement(bgp_vrf, &bn->p, bpi, - afi, safi); + bgp_aggregate_decrement(bgp_vrf, + bgp_node_get_prefix(bn), + bpi, afi, safi); bgp_path_info_delete(bn, bpi); bgp_process(bgp_vrf, bn, afi, safi); } @@ -1405,7 +1393,7 @@ void vpn_leak_to_vrf_update_all(struct bgp *bgp_vrf, /* to */ */ for (prn = bgp_table_top(bgp_vpn->rib[afi][safi]); prn; prn = bgp_route_next(prn)) { - + const struct prefix *p = bgp_node_get_prefix(prn); struct bgp_table *table; struct bgp_node *bn; struct bgp_path_info *bpi; @@ -1413,7 +1401,7 @@ void vpn_leak_to_vrf_update_all(struct bgp *bgp_vrf, /* to */ memset(&prd, 0, sizeof(prd)); prd.family = AF_UNSPEC; prd.prefixlen = 64; - memcpy(prd.val, prn->p.u.val, 8); + memcpy(prd.val, &p->u.val, 8); /* This is the per-RD table of prefixes */ table = bgp_node_get_bgp_table_info(prn); @@ -1805,8 +1793,9 @@ void vrf_unimport_from_vrf(struct bgp *to_bgp, struct bgp *from_bgp, vpn_leak_prechange(idir, afi, bgp_get_default(), to_bgp); if (to_bgp->vpn_policy[afi].import_vrf->count == 0) { - UNSET_FLAG(to_bgp->af_flags[afi][safi], - BGP_CONFIG_VRF_TO_VRF_IMPORT); + if (!to_bgp->vpn_policy[afi].rmap[idir]) + UNSET_FLAG(to_bgp->af_flags[afi][safi], + BGP_CONFIG_VRF_TO_VRF_IMPORT); if (to_bgp->vpn_policy[afi].rtlist[idir]) ecommunity_free(&to_bgp->vpn_policy[afi].rtlist[idir]); } else { diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c index 23c5adbf28..c77238aa33 100644 --- a/bgpd/bgp_nexthop.c +++ b/bgpd/bgp_nexthop.c @@ -49,7 +49,7 @@ DEFINE_MTYPE_STATIC(BGPD, MARTIAN_STRING, "BGP Martian Address Intf String"); char *bnc_str(struct bgp_nexthop_cache *bnc, char *buf, int size) { - prefix2str(&(bnc->node->p), buf, size); + prefix2str(bgp_node_get_prefix(bnc->node), buf, size); return buf; } @@ -476,7 +476,7 @@ bool bgp_nexthop_self(struct bgp *bgp, afi_t afi, uint8_t type, uint8_t new_afi = afi == AFI_IP ? AF_INET : AF_INET6; struct bgp_addr tmp_addr = {{0}}, *addr = NULL; struct tip_addr tmp_tip, *tip = NULL; - + const struct prefix *p = bgp_node_get_prefix(rn); bool is_bgp_static_route = ((type == ZEBRA_ROUTE_BGP) && (sub_type == BGP_ROUTE_STATIC)) ? true @@ -489,8 +489,8 @@ bool bgp_nexthop_self(struct bgp *bgp, afi_t afi, uint8_t type, switch (new_afi) { case AF_INET: if (is_bgp_static_route) { - tmp_addr.p.u.prefix4 = rn->p.u.prefix4; - tmp_addr.p.prefixlen = rn->p.prefixlen; + tmp_addr.p.u.prefix4 = p->u.prefix4; + tmp_addr.p.prefixlen = p->prefixlen; } else { /* Here we need to find out which nexthop to be used*/ if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP)) { @@ -510,8 +510,8 @@ bool bgp_nexthop_self(struct bgp *bgp, afi_t afi, uint8_t type, break; case AF_INET6: if (is_bgp_static_route) { - tmp_addr.p.u.prefix6 = rn->p.u.prefix6; - tmp_addr.p.prefixlen = rn->p.prefixlen; + tmp_addr.p.u.prefix6 = p->u.prefix6; + tmp_addr.p.prefixlen = p->prefixlen; } else { tmp_addr.p.u.prefix6 = attr->mp_nexthop_global; tmp_addr.p.prefixlen = IPV6_MAX_BITLEN; @@ -763,6 +763,7 @@ static void bgp_show_nexthops(struct vty *vty, struct bgp *bgp, int detail, for (rn = bgp_table_top(table[afi]); rn; rn = bgp_route_next(rn)) { struct peer *peer; + const struct prefix *p = bgp_node_get_prefix(rn); bnc = bgp_node_get_bgp_nexthop_info(rn); if (!bnc) @@ -772,8 +773,7 @@ static void bgp_show_nexthops(struct vty *vty, struct bgp *bgp, int detail, if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID)) { vty_out(vty, " %s valid [IGP metric %d], #paths %d", - inet_ntop(rn->p.family, - &rn->p.u.prefix, buf, + inet_ntop(p->family, &p->u.prefix, buf, sizeof(buf)), bnc->metric, bnc->path_count); if (peer) @@ -787,8 +787,7 @@ static void bgp_show_nexthops(struct vty *vty, struct bgp *bgp, int detail, } else { vty_out(vty, " %s invalid", - inet_ntop(rn->p.family, - &rn->p.u.prefix, buf, + inet_ntop(p->family, &p->u.prefix, buf, sizeof(buf))); if (peer) vty_out(vty, ", peer %s", peer->host); diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c index dfa9ac9398..0531542a38 100644 --- a/bgpd/bgp_nht.c +++ b/bgpd/bgp_nht.c @@ -130,6 +130,7 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop, struct bgp_nexthop_cache *bnc; struct prefix p; int is_bgp_static_route = 0; + const struct prefix *bnc_p; if (pi) { is_bgp_static_route = ((pi->type == ZEBRA_ROUTE_BGP) @@ -181,6 +182,8 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop, } } + bnc_p = bgp_node_get_prefix(bnc->node); + bgp_unlock_node(rn); if (is_bgp_static_route) { SET_FLAG(bnc->flags, BGP_STATIC_ROUTE); @@ -226,8 +229,8 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop, if (bgp_route->inst_type == BGP_INSTANCE_TYPE_VIEW) { SET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED); SET_FLAG(bnc->flags, BGP_NEXTHOP_VALID); - } else if (!CHECK_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED) && - !is_default_host_route(&bnc->node->p)) + } else if (!CHECK_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED) + && !is_default_host_route(bnc_p)) register_zebra_rnh(bnc, is_bgp_static_route); if (pi && pi->nexthop != bnc) { @@ -528,7 +531,7 @@ static int make_prefix(int afi, struct bgp_path_info *pi, struct prefix *p) ? 1 : 0; struct bgp_node *net = pi->net; - struct prefix *p_orig = &net->p; + const struct prefix *p_orig = bgp_node_get_prefix(net); if (p_orig->family == AF_FLOWSPEC) { if (!pi->peer) @@ -541,8 +544,8 @@ static int make_prefix(int afi, struct bgp_path_info *pi, struct prefix *p) case AFI_IP: p->family = AF_INET; if (is_bgp_static) { - p->u.prefix4 = pi->net->p.u.prefix4; - p->prefixlen = pi->net->p.prefixlen; + p->u.prefix4 = p_orig->u.prefix4; + p->prefixlen = p_orig->prefixlen; } else { p->u.prefix4 = pi->attr->nexthop; p->prefixlen = IPV4_MAX_BITLEN; @@ -552,8 +555,8 @@ static int make_prefix(int afi, struct bgp_path_info *pi, struct prefix *p) p->family = AF_INET6; if (is_bgp_static) { - p->u.prefix6 = pi->net->p.u.prefix6; - p->prefixlen = pi->net->p.prefixlen; + p->u.prefix6 = p_orig->u.prefix6; + p->prefixlen = p_orig->prefixlen; } else { p->u.prefix6 = pi->attr->mp_nexthop_global; p->prefixlen = IPV6_MAX_BITLEN; @@ -581,7 +584,7 @@ static int make_prefix(int afi, struct bgp_path_info *pi, struct prefix *p) */ static void sendmsg_zebra_rnh(struct bgp_nexthop_cache *bnc, int command) { - struct prefix *p; + const struct prefix *p; bool exact_match = false; int ret; @@ -603,7 +606,7 @@ static void sendmsg_zebra_rnh(struct bgp_nexthop_cache *bnc, int command) "%s: We have not connected yet, cannot send nexthops", __func__); } - p = &(bnc->node->p); + p = bgp_node_get_prefix(bnc->node); if ((command == ZEBRA_NEXTHOP_REGISTER || command == ZEBRA_IMPORT_ROUTE_REGISTER) && (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED) @@ -691,6 +694,7 @@ static void evaluate_paths(struct bgp_nexthop_cache *bnc) struct bgp_table *table; safi_t safi; struct bgp *bgp_path; + const struct prefix *p; if (BGP_DEBUG(nht, NHT)) { char buf[PREFIX2STR_BUFFER]; @@ -710,7 +714,8 @@ static void evaluate_paths(struct bgp_nexthop_cache *bnc) rn = path->net; assert(rn && bgp_node_table(rn)); - afi = family2afi(rn->p.family); + p = bgp_node_get_prefix(rn); + afi = family2afi(p->family); table = bgp_node_table(rn); safi = table->safi; @@ -744,27 +749,23 @@ static void evaluate_paths(struct bgp_nexthop_cache *bnc) bgp_isvalid_nexthop(bnc) ? 1 : 0; } - if (BGP_DEBUG(nht, NHT)) { - char buf[PREFIX_STRLEN]; - - prefix2str(&rn->p, buf, PREFIX_STRLEN); - zlog_debug("%s: prefix %s (vrf %s) %svalid", - __func__, buf, bgp_path->name, - (bnc_is_valid_nexthop ? "" : "not ")); - } + if (BGP_DEBUG(nht, NHT)) + zlog_debug("%s: prefix %pRN (vrf %s) %svalid", __func__, + rn, bgp_path->name, + (bnc_is_valid_nexthop ? "" : "not ")); if ((CHECK_FLAG(path->flags, BGP_PATH_VALID) ? 1 : 0) != bnc_is_valid_nexthop) { if (CHECK_FLAG(path->flags, BGP_PATH_VALID)) { - bgp_aggregate_decrement(bgp_path, &rn->p, - path, afi, safi); + bgp_aggregate_decrement(bgp_path, p, path, afi, + safi); bgp_path_info_unset_flag(rn, path, BGP_PATH_VALID); } else { bgp_path_info_set_flag(rn, path, BGP_PATH_VALID); - bgp_aggregate_increment(bgp_path, &rn->p, - path, afi, safi); + bgp_aggregate_increment(bgp_path, p, path, afi, + safi); } } @@ -780,14 +781,13 @@ static void evaluate_paths(struct bgp_nexthop_cache *bnc) || CHECK_FLAG(bnc->change_flags, BGP_NEXTHOP_CHANGED)) SET_FLAG(path->flags, BGP_PATH_IGP_CHANGED); - if (safi == SAFI_EVPN && - bgp_evpn_is_prefix_nht_supported(&rn->p)) { + if (safi == SAFI_EVPN && bgp_evpn_is_prefix_nht_supported(p)) { if (CHECK_FLAG(path->flags, BGP_PATH_VALID)) - bgp_evpn_import_route(bgp_path, afi, safi, - &rn->p, path); + bgp_evpn_import_route(bgp_path, afi, safi, p, + path); else - bgp_evpn_unimport_route(bgp_path, afi, safi, - &rn->p, path); + bgp_evpn_unimport_route(bgp_path, afi, safi, p, + path); } bgp_process(bgp_path, rn, afi, safi); diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index ae4f521b9c..7137c1a784 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -1362,8 +1362,9 @@ static int bgp_open_receive(struct peer *peer, bgp_size_t size) peer->afc[AFI_IP6][SAFI_FLOWSPEC]; } - /* When collision is detected and this peer is closed. Retrun - immidiately. */ + /* When collision is detected and this peer is closed. + * Return immediately. + */ ret = bgp_collision_detect(peer, remote_id); if (ret < 0) return BGP_Stop; diff --git a/bgpd/bgp_pbr.c b/bgpd/bgp_pbr.c index 172ec8b42e..fd3fad63f5 100644 --- a/bgpd/bgp_pbr.c +++ b/bgpd/bgp_pbr.c @@ -685,9 +685,9 @@ static int bgp_pbr_validate_policy_route(struct bgp_pbr_entry_main *api) } /* return -1 if build or validation failed */ -int bgp_pbr_build_and_validate_entry(struct prefix *p, - struct bgp_path_info *path, - struct bgp_pbr_entry_main *api) +int bgp_pbr_build_and_validate_entry(const struct prefix *p, + struct bgp_path_info *path, + struct bgp_pbr_entry_main *api) { int ret; int i, action_count = 0; @@ -2610,7 +2610,7 @@ static void bgp_pbr_handle_entry(struct bgp *bgp, struct bgp_path_info *path, } } -void bgp_pbr_update_entry(struct bgp *bgp, struct prefix *p, +void bgp_pbr_update_entry(struct bgp *bgp, const struct prefix *p, struct bgp_path_info *info, afi_t afi, safi_t safi, bool nlri_update) { diff --git a/bgpd/bgp_pbr.h b/bgpd/bgp_pbr.h index 393b08da48..47d5e21692 100644 --- a/bgpd/bgp_pbr.h +++ b/bgpd/bgp_pbr.h @@ -291,7 +291,7 @@ void bgp_pbr_print_policy_route(struct bgp_pbr_entry_main *api); struct bgp_node; struct bgp_path_info; -extern void bgp_pbr_update_entry(struct bgp *bgp, struct prefix *p, +extern void bgp_pbr_update_entry(struct bgp *bgp, const struct prefix *p, struct bgp_path_info *new_select, afi_t afi, safi_t safi, bool nlri_update); @@ -301,7 +301,7 @@ extern void bgp_pbr_reset(struct bgp *bgp, afi_t afi); extern struct bgp_pbr_interface *bgp_pbr_interface_lookup(const char *name, struct bgp_pbr_interface_head *head); -extern int bgp_pbr_build_and_validate_entry(struct prefix *p, +extern int bgp_pbr_build_and_validate_entry(const struct prefix *p, struct bgp_path_info *path, struct bgp_pbr_entry_main *api); #endif /* __BGP_PBR_H__ */ diff --git a/bgpd/bgp_rd.c b/bgpd/bgp_rd.c index be950dfa51..66d64066c4 100644 --- a/bgpd/bgp_rd.c +++ b/bgpd/bgp_rd.c @@ -33,16 +33,16 @@ #include "bgpd/bgp_rd.h" #include "bgpd/bgp_attr.h" -#if ENABLE_BGP_VNC +#ifdef ENABLE_BGP_VNC #include "bgpd/rfapi/rfapi_backend.h" #endif -uint16_t decode_rd_type(uint8_t *pnt) +uint16_t decode_rd_type(const uint8_t *pnt) { uint16_t v; v = ((uint16_t)*pnt++ << 8); -#if ENABLE_BGP_VNC +#ifdef ENABLE_BGP_VNC /* * VNC L2 stores LHI in lower byte, so omit it */ @@ -60,7 +60,7 @@ void encode_rd_type(uint16_t v, uint8_t *pnt) } /* type == RD_TYPE_AS */ -void decode_rd_as(uint8_t *pnt, struct rd_as *rd_as) +void decode_rd_as(const uint8_t *pnt, struct rd_as *rd_as) { rd_as->as = (uint16_t)*pnt++ << 8; rd_as->as |= (uint16_t)*pnt++; @@ -68,7 +68,7 @@ void decode_rd_as(uint8_t *pnt, struct rd_as *rd_as) } /* type == RD_TYPE_AS4 */ -void decode_rd_as4(uint8_t *pnt, struct rd_as *rd_as) +void decode_rd_as4(const uint8_t *pnt, struct rd_as *rd_as) { pnt = ptr_get_be32(pnt, &rd_as->as); rd_as->val = ((uint16_t)*pnt++ << 8); @@ -76,7 +76,7 @@ void decode_rd_as4(uint8_t *pnt, struct rd_as *rd_as) } /* type == RD_TYPE_IP */ -void decode_rd_ip(uint8_t *pnt, struct rd_ip *rd_ip) +void decode_rd_ip(const uint8_t *pnt, struct rd_ip *rd_ip) { memcpy(&rd_ip->ip, pnt, 4); pnt += 4; @@ -85,9 +85,9 @@ void decode_rd_ip(uint8_t *pnt, struct rd_ip *rd_ip) rd_ip->val |= (uint16_t)*pnt; } -#if ENABLE_BGP_VNC +#ifdef ENABLE_BGP_VNC /* type == RD_TYPE_VNC_ETH */ -void decode_rd_vnc_eth(uint8_t *pnt, struct rd_vnc_eth *rd_vnc_eth) +void decode_rd_vnc_eth(const uint8_t *pnt, struct rd_vnc_eth *rd_vnc_eth) { rd_vnc_eth->type = RD_TYPE_VNC_ETH; rd_vnc_eth->local_nve_id = pnt[1]; @@ -159,9 +159,9 @@ out: return lret; } -char *prefix_rd2str(struct prefix_rd *prd, char *buf, size_t size) +char *prefix_rd2str(const struct prefix_rd *prd, char *buf, size_t size) { - uint8_t *pnt; + const uint8_t *pnt; uint16_t type; struct rd_as rd_as; struct rd_ip rd_ip; @@ -186,7 +186,7 @@ char *prefix_rd2str(struct prefix_rd *prd, char *buf, size_t size) rd_ip.val); return buf; } -#if ENABLE_BGP_VNC +#ifdef ENABLE_BGP_VNC else if (type == RD_TYPE_VNC_ETH) { snprintf(buf, size, "LHI:%d, %02x:%02x:%02x:%02x:%02x:%02x", *(pnt + 1), /* LHI */ diff --git a/bgpd/bgp_rd.h b/bgpd/bgp_rd.h index c5ea34103f..b5ad9d624d 100644 --- a/bgpd/bgp_rd.h +++ b/bgpd/bgp_rd.h @@ -28,7 +28,7 @@ #define RD_TYPE_IP 1 #define RD_TYPE_AS4 2 -#if ENABLE_BGP_VNC +#ifdef ENABLE_BGP_VNC #define RD_TYPE_VNC_ETH 0xff00 /* VNC L2VPN */ #endif @@ -46,7 +46,7 @@ struct rd_ip { uint16_t val; }; -#if ENABLE_BGP_VNC +#ifdef ENABLE_BGP_VNC struct rd_vnc_eth { uint16_t type; uint8_t local_nve_id; @@ -54,18 +54,19 @@ struct rd_vnc_eth { }; #endif -extern uint16_t decode_rd_type(uint8_t *pnt); +extern uint16_t decode_rd_type(const uint8_t *pnt); extern void encode_rd_type(uint16_t, uint8_t *); -extern void decode_rd_as(uint8_t *pnt, struct rd_as *rd_as); -extern void decode_rd_as4(uint8_t *pnt, struct rd_as *rd_as); -extern void decode_rd_ip(uint8_t *pnt, struct rd_ip *rd_ip); -#if ENABLE_BGP_VNC -extern void decode_rd_vnc_eth(uint8_t *pnt, struct rd_vnc_eth *rd_vnc_eth); +extern void decode_rd_as(const uint8_t *pnt, struct rd_as *rd_as); +extern void decode_rd_as4(const uint8_t *pnt, struct rd_as *rd_as); +extern void decode_rd_ip(const uint8_t *pnt, struct rd_ip *rd_ip); +#ifdef ENABLE_BGP_VNC +extern void decode_rd_vnc_eth(const uint8_t *pnt, + struct rd_vnc_eth *rd_vnc_eth); #endif extern int str2prefix_rd(const char *, struct prefix_rd *); -extern char *prefix_rd2str(struct prefix_rd *, char *, size_t); +extern char *prefix_rd2str(const struct prefix_rd *, char *, size_t); extern void form_auto_rd(struct in_addr router_id, uint16_t rd_id, struct prefix_rd *prd); diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 265f122c23..7aea1fec14 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -71,7 +71,7 @@ #include "bgpd/bgp_mac.h" #include "bgpd/bgp_network.h" -#if ENABLE_BGP_VNC +#ifdef ENABLE_BGP_VNC #include "bgpd/rfapi/rfapi_backend.h" #include "bgpd/rfapi/vnc_import_bgp.h" #include "bgpd/rfapi/vnc_export_bgp.h" @@ -116,7 +116,7 @@ DEFINE_HOOK(bgp_process, struct bgp_node *bgp_afi_node_get(struct bgp_table *table, afi_t afi, - safi_t safi, struct prefix *p, + safi_t safi, const struct prefix *p, struct prefix_rd *prd) { struct bgp_node *rn; @@ -146,7 +146,7 @@ struct bgp_node *bgp_afi_node_get(struct bgp_table *table, afi_t afi, } struct bgp_node *bgp_afi_node_lookup(struct bgp_table *table, afi_t afi, - safi_t safi, struct prefix *p, + safi_t safi, const struct prefix *p, struct prefix_rd *prd) { struct bgp_node *rn; @@ -303,7 +303,6 @@ static int bgp_node_set_defer_flag(struct bgp_node *rn, bool delete) struct bgp_table *table = NULL; afi_t afi = 0; safi_t safi = 0; - char buf[PREFIX2STR_BUFFER]; /* If the flag BGP_NODE_SELECT_DEFER is set and new path is added * then the route selection is deferred @@ -312,12 +311,11 @@ static int bgp_node_set_defer_flag(struct bgp_node *rn, bool delete) return 0; if (CHECK_FLAG(rn->flags, BGP_NODE_PROCESS_SCHEDULED)) { - if (BGP_DEBUG(update, UPDATE_OUT)) { - prefix2str(&rn->p, buf, PREFIX2STR_BUFFER); + if (BGP_DEBUG(update, UPDATE_OUT)) zlog_debug( - "Route %s is in workqueue and being processed, not deferred.", - buf); - } + "Route %pRN is in workqueue and being processed, not deferred.", + rn); + return 0; } @@ -361,13 +359,12 @@ static int bgp_node_set_defer_flag(struct bgp_node *rn, bool delete) if (set_flag && table) { if (bgp && (bgp->gr_info[afi][safi].t_select_deferral)) { SET_FLAG(rn->flags, BGP_NODE_SELECT_DEFER); - prefix2str(&rn->p, buf, PREFIX2STR_BUFFER); if (rn->rt_node == NULL) rn->rt_node = listnode_add( bgp->gr_info[afi][safi].route_list, rn); if (BGP_DEBUG(update, UPDATE_OUT)) - zlog_debug("DEFER route %s, rn %p, node %p", - buf, rn, rn->rt_node); + zlog_debug("DEFER route %pRN, rn %p, node %p", + rn, rn, rn->rt_node); return 0; } } @@ -594,7 +591,8 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, */ if (newattr->sticky != existattr->sticky) { if (!debug) { - prefix2str(&new->net->p, pfx_buf, + prefix2str(bgp_node_get_prefix(new->net), + pfx_buf, sizeof(*pfx_buf) * PREFIX2STR_BUFFER); bgp_path_info_path_with_addpath_rx_str(new, @@ -1202,7 +1200,8 @@ int bgp_path_info_cmp_compatible(struct bgp *bgp, struct bgp_path_info *new, return ret; } -static enum filter_type bgp_input_filter(struct peer *peer, struct prefix *p, +static enum filter_type bgp_input_filter(struct peer *peer, + const struct prefix *p, struct attr *attr, afi_t afi, safi_t safi) { @@ -1241,7 +1240,8 @@ static enum filter_type bgp_input_filter(struct peer *peer, struct prefix *p, #undef FILTER_EXIST_WARN } -static enum filter_type bgp_output_filter(struct peer *peer, struct prefix *p, +static enum filter_type bgp_output_filter(struct peer *peer, + const struct prefix *p, struct attr *attr, afi_t afi, safi_t safi) { @@ -1321,7 +1321,7 @@ static bool bgp_cluster_filter(struct peer *peer, struct attr *attr) return false; } -static int bgp_input_modifier(struct peer *peer, struct prefix *p, +static int bgp_input_modifier(struct peer *peer, const struct prefix *p, struct attr *attr, afi_t afi, safi_t safi, const char *rmap_name, mpls_label_t *label, uint32_t num_labels, struct bgp_node *rn) @@ -1379,7 +1379,7 @@ static int bgp_input_modifier(struct peer *peer, struct prefix *p, return RMAP_PERMIT; } -static int bgp_output_modifier(struct peer *peer, struct prefix *p, +static int bgp_output_modifier(struct peer *peer, const struct prefix *p, struct attr *attr, afi_t afi, safi_t safi, const char *rmap_name) { @@ -1544,8 +1544,8 @@ static void subgroup_announce_reset_nhop(uint8_t family, struct attr *attr) } bool subgroup_announce_check(struct bgp_node *rn, struct bgp_path_info *pi, - struct update_subgroup *subgrp, struct prefix *p, - struct attr *attr) + struct update_subgroup *subgrp, + const struct prefix *p, struct attr *attr) { struct bgp_filter *filter; struct peer *from; @@ -1577,7 +1577,7 @@ bool subgroup_announce_check(struct bgp_node *rn, struct bgp_path_info *pi, piattr = bgp_path_info_mpath_count(pi) ? bgp_path_info_mpath_attr(pi) : pi->attr; -#if ENABLE_BGP_VNC +#ifdef ENABLE_BGP_VNC if (((afi == AFI_IP) || (afi == AFI_IP6)) && (safi == SAFI_MPLS_VPN) && ((pi->type == ZEBRA_ROUTE_BGP_DIRECT) || (pi->type == ZEBRA_ROUTE_BGP_DIRECT_EXT))) { @@ -2095,10 +2095,10 @@ void bgp_best_selection(struct bgp *bgp, struct bgp_node *rn, do_mpath = (mpath_cfg->maxpaths_ebgp > 1 || mpath_cfg->maxpaths_ibgp > 1); - debug = bgp_debug_bestpath(&rn->p); + debug = bgp_debug_bestpath(rn); if (debug) - prefix2str(&rn->p, pfx_buf, sizeof(pfx_buf)); + prefix2str(bgp_node_get_prefix(rn), pfx_buf, sizeof(pfx_buf)); rn->reason = bgp_path_selection_none; /* bgp deterministic-med */ @@ -2318,13 +2318,13 @@ void subgroup_process_announce_selected(struct update_subgroup *subgrp, struct bgp_node *rn, uint32_t addpath_tx_id) { - struct prefix *p; + const struct prefix *p; struct peer *onlypeer; struct attr attr; afi_t afi; safi_t safi; - p = &rn->p; + p = bgp_node_get_prefix(rn); afi = SUBGRP_AFI(subgrp); safi = SUBGRP_SAFI(subgrp); onlypeer = ((SUBGRP_PCOUNT(subgrp) == 1) ? (SUBGRP_PFIRST(subgrp))->peer @@ -2444,18 +2444,15 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn, struct bgp_path_info *new_select; struct bgp_path_info *old_select; struct bgp_path_info_pair old_and_new; - char pfx_buf[PREFIX2STR_BUFFER]; int debug = 0; if (CHECK_FLAG(bgp->flags, BGP_FLAG_DELETE_IN_PROGRESS)) { if (rn) - debug = bgp_debug_bestpath(&rn->p); - if (debug) { - prefix2str(&rn->p, pfx_buf, sizeof(pfx_buf)); + debug = bgp_debug_bestpath(rn); + if (debug) zlog_debug( - "%s: bgp delete in progress, ignoring event, p=%s", - __func__, pfx_buf); - } + "%s: bgp delete in progress, ignoring event, p=%pRN", + __func__, rn); return; } /* Is it end of initial update? (after startup) */ @@ -2474,14 +2471,12 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn, return; } - struct prefix *p = &rn->p; + const struct prefix *p = bgp_node_get_prefix(rn); - debug = bgp_debug_bestpath(&rn->p); - if (debug) { - prefix2str(&rn->p, pfx_buf, sizeof(pfx_buf)); - zlog_debug("%s: p=%s afi=%s, safi=%s start", __func__, pfx_buf, + debug = bgp_debug_bestpath(rn); + if (debug) + zlog_debug("%s: p=%pRN afi=%s, safi=%s start", __func__, rn, afi2str(afi), safi2str(safi)); - } /* The best path calculation for the route is deferred if * BGP_NODE_SELECT_DEFER is set @@ -2538,13 +2533,11 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn, bgp_unregister_for_label(rn); } - if (debug) { - prefix2str(&rn->p, pfx_buf, sizeof(pfx_buf)); + if (debug) zlog_debug( - "%s: p=%s afi=%s, safi=%s, old_select=%p, new_select=%p", - __func__, pfx_buf, afi2str(afi), safi2str(safi), + "%s: p=%pRN afi=%s, safi=%s, old_select=%p, new_select=%p", + __func__, rn, afi2str(afi), safi2str(safi), old_select, new_select); - } /* If best route remains the same and this is not due to user-initiated * clear, see exactly what needs to be done. @@ -2554,7 +2547,7 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn, && !CHECK_FLAG(old_select->flags, BGP_PATH_ATTR_CHANGED) && !bgp_addpath_is_addpath_used(&bgp->tx_addpath, afi, safi)) { if (bgp_zebra_has_route_changed(rn, old_select)) { -#if ENABLE_BGP_VNC +#ifdef ENABLE_BGP_VNC vnc_import_bgp_add_route(bgp, p, old_select); vnc_import_bgp_exterior_add_route(bgp, p, old_select); #endif @@ -2622,7 +2615,7 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn, UNSET_FLAG(new_select->flags, BGP_PATH_MULTIPATH_CHG); } -#if ENABLE_BGP_VNC +#ifdef ENABLE_BGP_VNC if ((afi == AFI_IP || afi == AFI_IP6) && (safi == SAFI_UNICAST)) { if (old_select != new_select) { if (old_select) { @@ -2677,6 +2670,8 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn, /* advertise/withdraw type-5 routes */ if ((afi == AFI_IP || afi == AFI_IP6) && (safi == SAFI_UNICAST)) { + const struct prefix *p = bgp_node_get_prefix(rn); + if (advertise_type5_routes(bgp, afi) && new_select && is_route_injectable_into_evpn(new_select)) { @@ -2700,18 +2695,17 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn, ret = route_map_apply( bgp->adv_cmd_rmap[afi][safi].map, - &rn->p, RMAP_BGP, &rmap_path); + p, RMAP_BGP, &rmap_path); if (ret == RMAP_DENYMATCH) { bgp_attr_flush(&dummy_attr); bgp_evpn_withdraw_type5_route( - bgp, &rn->p, afi, safi); + bgp, p, afi, safi); } else bgp_evpn_advertise_type5_route( - bgp, &rn->p, &dummy_attr, + bgp, p, &dummy_attr, afi, safi); } else { - bgp_evpn_advertise_type5_route(bgp, - &rn->p, + bgp_evpn_advertise_type5_route(bgp, p, new_select->attr, afi, safi); @@ -2719,7 +2713,7 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn, } else if (advertise_type5_routes(bgp, afi) && old_select && is_route_injectable_into_evpn(old_select)) - bgp_evpn_withdraw_type5_route(bgp, &rn->p, afi, safi); + bgp_evpn_withdraw_type5_route(bgp, p, afi, safi); } /* Clear any route change flags. */ @@ -3046,7 +3040,8 @@ void bgp_rib_remove(struct bgp_node *rn, struct bgp_path_info *pi, struct bgp *bgp = NULL; bool delete_route = false; - bgp_aggregate_decrement(peer->bgp, &rn->p, pi, afi, safi); + bgp_aggregate_decrement(peer->bgp, bgp_node_get_prefix(rn), + pi, afi, safi); if (!CHECK_FLAG(pi->flags, BGP_PATH_HISTORY)) { bgp_path_info_delete(rn, pi); /* keep historical info */ @@ -3081,6 +3076,8 @@ static void bgp_rib_withdraw(struct bgp_node *rn, struct bgp_path_info *pi, struct peer *peer, afi_t afi, safi_t safi, struct prefix_rd *prd) { + const struct prefix *p = bgp_node_get_prefix(rn); + /* apply dampening, if result is suppressed, we'll be retaining * the bgp_path_info in the RIB for historical reference. */ @@ -3088,12 +3085,12 @@ static void bgp_rib_withdraw(struct bgp_node *rn, struct bgp_path_info *pi, && peer->sort == BGP_PEER_EBGP) if ((bgp_damp_withdraw(pi, rn, afi, safi, 0)) == BGP_DAMP_SUPPRESSED) { - bgp_aggregate_decrement(peer->bgp, &rn->p, pi, afi, + bgp_aggregate_decrement(peer->bgp, p, pi, afi, safi); return; } -#if ENABLE_BGP_VNC +#ifdef ENABLE_BGP_VNC if (safi == SAFI_MPLS_VPN) { struct bgp_node *prn = NULL; struct bgp_table *table = NULL; @@ -3104,23 +3101,22 @@ static void bgp_rib_withdraw(struct bgp_node *rn, struct bgp_path_info *pi, table = bgp_node_get_bgp_table_info(prn); vnc_import_bgp_del_vnc_host_route_mode_resolve_nve( - peer->bgp, prd, table, &rn->p, pi); + peer->bgp, prd, table, p, pi); } bgp_unlock_node(prn); } if ((afi == AFI_IP || afi == AFI_IP6) && (safi == SAFI_UNICAST)) { if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED)) { - vnc_import_bgp_del_route(peer->bgp, &rn->p, pi); - vnc_import_bgp_exterior_del_route(peer->bgp, &rn->p, - pi); + vnc_import_bgp_del_route(peer->bgp, p, pi); + vnc_import_bgp_exterior_del_route(peer->bgp, p, pi); } } #endif /* If this is an EVPN route, process for un-import. */ if (safi == SAFI_EVPN) - bgp_evpn_unimport_route(peer->bgp, afi, safi, &rn->p, pi); + bgp_evpn_unimport_route(peer->bgp, afi, safi, p, pi); bgp_rib_remove(rn, pi, peer, afi, safi); } @@ -3257,7 +3253,7 @@ static bool bgp_update_martian_nexthop(struct bgp *bgp, afi_t afi, safi_t safi, return ret; } -int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id, +int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, struct attr *attr, afi_t afi, safi_t safi, int type, int sub_type, struct prefix_rd *prd, mpls_label_t *label, uint32_t num_labels, int soft_reconfig, @@ -3281,7 +3277,7 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id, uint8_t pi_type = 0; uint8_t pi_sub_type = 0; -#if ENABLE_BGP_VNC +#ifdef ENABLE_BGP_VNC int vnc_implicit_withdraw = 0; #endif int same_attr = 0; @@ -3581,7 +3577,7 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id, if (!CHECK_FLAG(pi->flags, BGP_PATH_HISTORY)) bgp_damp_withdraw(pi, rn, afi, safi, 1); } -#if ENABLE_BGP_VNC +#ifdef ENABLE_BGP_VNC if (safi == SAFI_MPLS_VPN) { struct bgp_node *prn = NULL; struct bgp_table *table = NULL; @@ -3671,7 +3667,7 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id, } } -#if ENABLE_BGP_VNC +#ifdef ENABLE_BGP_VNC if ((afi == AFI_IP || afi == AFI_IP6) && (safi == SAFI_UNICAST)) { if (vnc_implicit_withdraw) { @@ -3754,7 +3750,7 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id, } else bgp_path_info_set_flag(rn, pi, BGP_PATH_VALID); -#if ENABLE_BGP_VNC +#ifdef ENABLE_BGP_VNC if (safi == SAFI_MPLS_VPN) { struct bgp_node *prn = NULL; struct bgp_table *table = NULL; @@ -3805,7 +3801,7 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id, vpn_leak_to_vrf_update(bgp, pi); } -#if ENABLE_BGP_VNC +#ifdef ENABLE_BGP_VNC if (SAFI_MPLS_VPN == safi) { mpls_label_t label_decoded = decode_label(label); @@ -3914,7 +3910,7 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id, /* route_node_get lock */ bgp_unlock_node(rn); -#if ENABLE_BGP_VNC +#ifdef ENABLE_BGP_VNC if (safi == SAFI_MPLS_VPN) { struct bgp_node *prn = NULL; struct bgp_table *table = NULL; @@ -3954,7 +3950,7 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id, vpn_leak_to_vrf_update(bgp, new); } -#if ENABLE_BGP_VNC +#ifdef ENABLE_BGP_VNC if (SAFI_MPLS_VPN == safi) { mpls_label_t label_decoded = decode_label(label); @@ -4011,7 +4007,7 @@ filtered: bgp_unlock_node(rn); -#if ENABLE_BGP_VNC +#ifdef ENABLE_BGP_VNC /* * Filtered update is treated as an implicit withdrawal (see * bgp_rib_remove() @@ -4026,7 +4022,7 @@ filtered: return 0; } -int bgp_withdraw(struct peer *peer, struct prefix *p, uint32_t addpath_id, +int bgp_withdraw(struct peer *peer, const struct prefix *p, uint32_t addpath_id, struct attr *attr, afi_t afi, safi_t safi, int type, int sub_type, struct prefix_rd *prd, mpls_label_t *label, uint32_t num_labels, struct bgp_route_evpn *evpn) @@ -4036,7 +4032,7 @@ int bgp_withdraw(struct peer *peer, struct prefix *p, uint32_t addpath_id, struct bgp_node *rn; struct bgp_path_info *pi; -#if ENABLE_BGP_VNC +#ifdef ENABLE_BGP_VNC if ((SAFI_MPLS_VPN == safi) || (SAFI_ENCAP == safi)) { rfapiProcessWithdraw(peer, NULL, p, prd, NULL, afi, safi, type, 0); @@ -4252,8 +4248,9 @@ static void bgp_soft_reconfig_table(struct peer *peer, afi_t afi, safi_t safi, else memset(&evpn, 0, sizeof(evpn)); - ret = bgp_update(peer, &rn->p, ain->addpath_rx_id, - ain->attr, afi, safi, ZEBRA_ROUTE_BGP, + ret = bgp_update(peer, bgp_node_get_prefix(rn), + ain->addpath_rx_id, ain->attr, + afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, prd, label_pnt, num_labels, 1, &evpn); @@ -4279,16 +4276,18 @@ void bgp_soft_reconfig_in(struct peer *peer, afi_t afi, safi_t safi) for (rn = bgp_table_top(peer->bgp->rib[afi][safi]); rn; rn = bgp_route_next(rn)) { table = bgp_node_get_bgp_table_info(rn); - if (table != NULL) { - struct prefix_rd prd; - prd.family = AF_UNSPEC; - prd.prefixlen = 64; - memcpy(&prd.val, rn->p.u.val, 8); + if (table == NULL) + continue; - bgp_soft_reconfig_table(peer, afi, safi, table, - &prd); - } + const struct prefix *p = bgp_node_get_prefix(rn); + struct prefix_rd prd; + + prd.family = AF_UNSPEC; + prd.prefixlen = 64; + memcpy(&prd.val, p->u.val, 8); + + bgp_soft_reconfig_table(peer, afi, safi, table, &prd); } } @@ -4327,7 +4326,8 @@ static wq_item_status bgp_clear_route_node(struct work_queue *wq, void *data) /* If this is an EVPN route, process for * un-import. */ if (safi == SAFI_EVPN) - bgp_evpn_unimport_route(bgp, afi, safi, &rn->p, + bgp_evpn_unimport_route(bgp, afi, safi, + bgp_node_get_prefix(rn), pi); /* Handle withdraw for VRF route-leaking and L3VPN */ if (SAFI_UNICAST == safi @@ -4530,7 +4530,7 @@ void bgp_clear_route_all(struct peer *peer) FOREACH_AFI_SAFI (afi, safi) bgp_clear_route(peer, afi, safi); -#if ENABLE_BGP_VNC +#ifdef ENABLE_BGP_VNC rfapiProcessPeerDown(peer); #endif } @@ -4643,13 +4643,14 @@ static void bgp_cleanup_table(struct bgp *bgp, struct bgp_table *table, for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) for (pi = bgp_node_get_bgp_path_info(rn); pi; pi = next) { + const struct prefix *p = bgp_node_get_prefix(rn); + next = pi->next; /* Unimport EVPN routes from VRFs */ if (safi == SAFI_EVPN) bgp_evpn_unimport_route(bgp, AFI_L2VPN, - SAFI_EVPN, - &rn->p, pi); + SAFI_EVPN, p, pi); if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED) && pi->type == ZEBRA_ROUTE_BGP @@ -4658,8 +4659,7 @@ static void bgp_cleanup_table(struct bgp *bgp, struct bgp_table *table, || pi->sub_type == BGP_ROUTE_IMPORTED)) { if (bgp_fibupd_safi(safi)) - bgp_zebra_withdraw(&rn->p, pi, bgp, - safi); + bgp_zebra_withdraw(p, pi, bgp, safi); bgp_path_info_reap(rn, pi); } } @@ -4908,7 +4908,7 @@ static void bgp_static_free(struct bgp_static *bgp_static) XFREE(MTYPE_BGP_STATIC, bgp_static); } -void bgp_static_update(struct bgp *bgp, struct prefix *p, +void bgp_static_update(struct bgp *bgp, const struct prefix *p, struct bgp_static *bgp_static, afi_t afi, safi_t safi) { struct bgp_node *rn; @@ -4918,7 +4918,7 @@ void bgp_static_update(struct bgp *bgp, struct prefix *p, struct attr attr; struct attr *attr_new; route_map_result_t ret; -#if ENABLE_BGP_VNC +#ifdef ENABLE_BGP_VNC int vnc_implicit_withdraw = 0; #endif @@ -5000,7 +5000,7 @@ void bgp_static_update(struct bgp *bgp, struct prefix *p, bgp_path_info_restore(rn, pi); else bgp_aggregate_decrement(bgp, p, pi, afi, safi); -#if ENABLE_BGP_VNC +#ifdef ENABLE_BGP_VNC if ((afi == AFI_IP || afi == AFI_IP6) && (safi == SAFI_UNICAST)) { if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED)) { @@ -5019,7 +5019,7 @@ void bgp_static_update(struct bgp *bgp, struct prefix *p, bgp_attr_unintern(&pi->attr); pi->attr = attr_new; pi->uptime = bgp_clock(); -#if ENABLE_BGP_VNC +#ifdef ENABLE_BGP_VNC if ((afi == AFI_IP || afi == AFI_IP6) && (safi == SAFI_UNICAST)) { if (vnc_implicit_withdraw) { @@ -5137,7 +5137,7 @@ void bgp_static_update(struct bgp *bgp, struct prefix *p, aspath_unintern(&attr.aspath); } -void bgp_static_withdraw(struct bgp *bgp, struct prefix *p, afi_t afi, +void bgp_static_withdraw(struct bgp *bgp, const struct prefix *p, afi_t afi, safi_t safi) { struct bgp_node *rn; @@ -5171,7 +5171,7 @@ void bgp_static_withdraw(struct bgp *bgp, struct prefix *p, afi_t afi, /* * Used for SAFI_MPLS_VPN and SAFI_ENCAP */ -static void bgp_static_withdraw_safi(struct bgp *bgp, struct prefix *p, +static void bgp_static_withdraw_safi(struct bgp *bgp, const struct prefix *p, afi_t afi, safi_t safi, struct prefix_rd *prd) { @@ -5188,7 +5188,7 @@ static void bgp_static_withdraw_safi(struct bgp *bgp, struct prefix *p, /* Withdraw static BGP route from routing table. */ if (pi) { -#if ENABLE_BGP_VNC +#ifdef ENABLE_BGP_VNC rfapiProcessWithdraw( pi->peer, NULL, p, prd, pi->attr, afi, safi, pi->type, 1); /* Kill, since it is an administrative change */ @@ -5206,7 +5206,7 @@ static void bgp_static_withdraw_safi(struct bgp *bgp, struct prefix *p, bgp_unlock_node(rn); } -static void bgp_static_update_safi(struct bgp *bgp, struct prefix *p, +static void bgp_static_update_safi(struct bgp *bgp, const struct prefix *p, struct bgp_static *bgp_static, afi_t afi, safi_t safi) { @@ -5215,7 +5215,7 @@ static void bgp_static_update_safi(struct bgp *bgp, struct prefix *p, struct attr *attr_new; struct attr attr = {0}; struct bgp_path_info *pi; -#if ENABLE_BGP_VNC +#ifdef ENABLE_BGP_VNC mpls_label_t label = 0; #endif uint32_t num_labels = 0; @@ -5317,7 +5317,7 @@ static void bgp_static_update_safi(struct bgp *bgp, struct prefix *p, bgp_attr_unintern(&pi->attr); pi->attr = attr_new; pi->uptime = bgp_clock(); -#if ENABLE_BGP_VNC +#ifdef ENABLE_BGP_VNC if (pi->extra) label = decode_label(&pi->extra->label[0]); #endif @@ -5330,7 +5330,7 @@ static void bgp_static_update_safi(struct bgp *bgp, struct prefix *p, && bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT) { vpn_leak_to_vrf_update(bgp, pi); } -#if ENABLE_BGP_VNC +#ifdef ENABLE_BGP_VNC rfapiProcessUpdate(pi->peer, NULL, p, &bgp_static->prd, pi->attr, afi, safi, pi->type, pi->sub_type, &label); @@ -5351,7 +5351,7 @@ static void bgp_static_update_safi(struct bgp *bgp, struct prefix *p, new->extra->label[0] = bgp_static->label; new->extra->num_labels = num_labels; } -#if ENABLE_BGP_VNC +#ifdef ENABLE_BGP_VNC label = decode_label(&bgp_static->label); #endif @@ -5370,7 +5370,7 @@ static void bgp_static_update_safi(struct bgp *bgp, struct prefix *p, && bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT) { vpn_leak_to_vrf_update(bgp, new); } -#if ENABLE_BGP_VNC +#ifdef ENABLE_BGP_VNC rfapiProcessUpdate(new->peer, NULL, p, &bgp_static->prd, new->attr, afi, safi, new->type, new->sub_type, &label); #endif @@ -5540,13 +5540,14 @@ void bgp_static_add(struct bgp *bgp) bgp_static = bgp_node_get_bgp_static_info( rm); - bgp_static_update_safi(bgp, &rm->p, + bgp_static_update_safi(bgp, + bgp_node_get_prefix(rm), bgp_static, afi, safi); } } else { bgp_static_update( - bgp, &rn->p, + bgp, bgp_node_get_prefix(rn), bgp_node_get_bgp_static_info(rn), afi, safi); } @@ -5583,15 +5584,20 @@ void bgp_static_delete(struct bgp *bgp) continue; bgp_static_withdraw_safi( - bgp, &rm->p, AFI_IP, safi, - (struct prefix_rd *)&rn->p); + bgp, bgp_node_get_prefix(rm), + AFI_IP, safi, + (struct prefix_rd *) + bgp_node_get_prefix( + rn)); bgp_static_free(bgp_static); bgp_node_set_bgp_static_info(rn, NULL); bgp_unlock_node(rn); } } else { bgp_static = bgp_node_get_bgp_static_info(rn); - bgp_static_withdraw(bgp, &rn->p, afi, safi); + bgp_static_withdraw(bgp, + bgp_node_get_prefix(rn), + afi, safi); bgp_static_free(bgp_static); bgp_node_set_bgp_static_info(rn, NULL); bgp_unlock_node(rn); @@ -5625,13 +5631,15 @@ void bgp_static_redo_import_check(struct bgp *bgp) bgp_static = bgp_node_get_bgp_static_info( rm); - bgp_static_update_safi(bgp, &rm->p, + bgp_static_update_safi(bgp, + bgp_node_get_prefix(rm), bgp_static, afi, safi); } } else { bgp_static = bgp_node_get_bgp_static_info(rn); - bgp_static_update(bgp, &rn->p, bgp_static, afi, + bgp_static_update(bgp, bgp_node_get_prefix(rn), + bgp_static, afi, safi); } } @@ -5662,8 +5670,9 @@ static void bgp_purge_af_static_redist_routes(struct bgp *bgp, afi_t afi, || (pi->type != ZEBRA_ROUTE_BGP && pi->sub_type == BGP_ROUTE_REDISTRIBUTE))) { - bgp_aggregate_decrement(bgp, &rn->p, pi, afi, - safi); + bgp_aggregate_decrement(bgp, + bgp_node_get_prefix(rn), + pi, afi, safi); bgp_unlink_nexthop(pi); bgp_path_info_delete(rn, pi); bgp_process(bgp, rn, afi, safi); @@ -6056,14 +6065,11 @@ static bool bgp_aggregate_info_same(struct bgp_path_info *pi, uint8_t origin, return true; } -static void bgp_aggregate_install(struct bgp *bgp, afi_t afi, safi_t safi, - struct prefix *p, uint8_t origin, - struct aspath *aspath, - struct community *community, - struct ecommunity *ecommunity, - struct lcommunity *lcommunity, - uint8_t atomic_aggregate, - struct bgp_aggregate *aggregate) +static void bgp_aggregate_install( + struct bgp *bgp, afi_t afi, safi_t safi, const struct prefix *p, + uint8_t origin, struct aspath *aspath, struct community *community, + struct ecommunity *ecommunity, struct lcommunity *lcommunity, + uint8_t atomic_aggregate, struct bgp_aggregate *aggregate) { struct bgp_node *rn; struct bgp_table *table; @@ -6140,9 +6146,8 @@ static void bgp_aggregate_install(struct bgp *bgp, afi_t afi, safi_t safi, } /* Update an aggregate as routes are added/removed from the BGP table */ -void bgp_aggregate_route(struct bgp *bgp, struct prefix *p, - afi_t afi, safi_t safi, - struct bgp_aggregate *aggregate) +void bgp_aggregate_route(struct bgp *bgp, const struct prefix *p, afi_t afi, + safi_t safi, struct bgp_aggregate *aggregate) { struct bgp_table *table; struct bgp_node *top; @@ -6178,7 +6183,9 @@ void bgp_aggregate_route(struct bgp *bgp, struct prefix *p, top = bgp_node_get(table, p); for (rn = bgp_node_get(table, p); rn; rn = bgp_route_next_until(rn, top)) { - if (rn->p.prefixlen <= p->prefixlen) + const struct prefix *rn_p = bgp_node_get_prefix(rn); + + if (rn_p->prefixlen <= p->prefixlen) continue; match = 0; @@ -6312,8 +6319,8 @@ void bgp_aggregate_route(struct bgp *bgp, struct prefix *p, aggregate); } -void bgp_aggregate_delete(struct bgp *bgp, struct prefix *p, afi_t afi, - safi_t safi, struct bgp_aggregate *aggregate) +void bgp_aggregate_delete(struct bgp *bgp, const struct prefix *p, afi_t afi, + safi_t safi, struct bgp_aggregate *aggregate) { struct bgp_table *table; struct bgp_node *top; @@ -6327,7 +6334,9 @@ void bgp_aggregate_delete(struct bgp *bgp, struct prefix *p, afi_t afi, top = bgp_node_get(table, p); for (rn = bgp_node_get(table, p); rn; rn = bgp_route_next_until(rn, top)) { - if (rn->p.prefixlen <= p->prefixlen) + const struct prefix *rn_p = bgp_node_get_prefix(rn); + + if (rn_p->prefixlen <= p->prefixlen) continue; match = 0; @@ -6403,7 +6412,8 @@ void bgp_aggregate_delete(struct bgp *bgp, struct prefix *p, afi_t afi, bgp_unlock_node(top); } -static void bgp_add_route_to_aggregate(struct bgp *bgp, struct prefix *aggr_p, +static void bgp_add_route_to_aggregate(struct bgp *bgp, + const struct prefix *aggr_p, struct bgp_path_info *pinew, afi_t afi, safi_t safi, struct bgp_aggregate *aggregate) @@ -6509,7 +6519,7 @@ static void bgp_remove_route_from_aggregate(struct bgp *bgp, afi_t afi, safi_t safi, struct bgp_path_info *pi, struct bgp_aggregate *aggregate, - struct prefix *aggr_p) + const struct prefix *aggr_p) { uint8_t origin; struct aspath *aspath = NULL; @@ -6613,7 +6623,7 @@ static void bgp_remove_route_from_aggregate(struct bgp *bgp, afi_t afi, lcommunity, atomic_aggregate, aggregate); } -void bgp_aggregate_increment(struct bgp *bgp, struct prefix *p, +void bgp_aggregate_increment(struct bgp *bgp, const struct prefix *p, struct bgp_path_info *pi, afi_t afi, safi_t safi) { struct bgp_node *child; @@ -6637,16 +6647,18 @@ void bgp_aggregate_increment(struct bgp *bgp, struct prefix *p, /* Aggregate address configuration check. */ for (rn = child; rn; rn = bgp_node_parent_nolock(rn)) { + const struct prefix *rn_p = bgp_node_get_prefix(rn); + aggregate = bgp_node_get_bgp_aggregate_info(rn); - if (aggregate != NULL && rn->p.prefixlen < p->prefixlen) { - bgp_add_route_to_aggregate(bgp, &rn->p, pi, afi, - safi, aggregate); + if (aggregate != NULL && rn_p->prefixlen < p->prefixlen) { + bgp_add_route_to_aggregate(bgp, rn_p, pi, afi, safi, + aggregate); } } bgp_unlock_node(child); } -void bgp_aggregate_decrement(struct bgp *bgp, struct prefix *p, +void bgp_aggregate_decrement(struct bgp *bgp, const struct prefix *p, struct bgp_path_info *del, afi_t afi, safi_t safi) { struct bgp_node *child; @@ -6667,10 +6679,12 @@ void bgp_aggregate_decrement(struct bgp *bgp, struct prefix *p, /* Aggregate address configuration check. */ for (rn = child; rn; rn = bgp_node_parent_nolock(rn)) { + const struct prefix *rn_p = bgp_node_get_prefix(rn); + aggregate = bgp_node_get_bgp_aggregate_info(rn); - if (aggregate != NULL && rn->p.prefixlen < p->prefixlen) { - bgp_remove_route_from_aggregate(bgp, afi, safi, - del, aggregate, &rn->p); + if (aggregate != NULL && rn_p->prefixlen < p->prefixlen) { + bgp_remove_route_from_aggregate(bgp, afi, safi, del, + aggregate, rn_p); } } bgp_unlock_node(child); @@ -6844,7 +6858,7 @@ static int bgp_aggregate_set(struct vty *vty, const char *prefix_str, afi_t afi, if (as_set == AGGREGATE_AS_SET) { as_set_new = AGGREGATE_AS_UNSET; zlog_warn( - "%s: Ignoring as-set because `bgp reject-as-sets` is enabled.\n", + "%s: Ignoring as-set because `bgp reject-as-sets` is enabled.", __func__); vty_out(vty, "Ignoring as-set because `bgp reject-as-sets` is enabled.\n"); @@ -7333,8 +7347,8 @@ void bgp_redistribute_withdraw(struct bgp *bgp, afi_t afi, int type, vpn_leak_from_vrf_withdraw(bgp_get_default(), bgp, pi); } - bgp_aggregate_decrement(bgp, &rn->p, pi, afi, - SAFI_UNICAST); + bgp_aggregate_decrement(bgp, bgp_node_get_prefix(rn), + pi, afi, SAFI_UNICAST); bgp_path_info_delete(rn, pi); bgp_process(bgp, rn, afi, SAFI_UNICAST); } @@ -7342,7 +7356,7 @@ void bgp_redistribute_withdraw(struct bgp *bgp, afi_t afi, int type, } /* Static function to display route. */ -static void route_vty_out_route(struct prefix *p, struct vty *vty, +static void route_vty_out_route(const struct prefix *p, struct vty *vty, json_object *json) { int len = 0; @@ -7499,7 +7513,7 @@ static char *bgp_nexthop_hostname(struct peer *peer, struct attr *attr) } /* called from terminal list command */ -void route_vty_out(struct vty *vty, struct prefix *p, +void route_vty_out(struct vty *vty, const struct prefix *p, struct bgp_path_info *path, int display, safi_t safi, json_object *json_paths) { @@ -7805,32 +7819,19 @@ void route_vty_out(struct vty *vty, struct prefix *p, /* MED/Metric */ if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC)) - if (json_paths) { - - /* - * Adding "metric" field to match with corresponding - * CLI. "med" will be deprecated in future. - */ - json_object_int_add(json_path, "med", attr->med); + if (json_paths) json_object_int_add(json_path, "metric", attr->med); - } else + else vty_out(vty, "%10u", attr->med); else if (!json_paths) vty_out(vty, " "); /* Local Pref */ if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF)) - if (json_paths) { - - /* - * Adding "locPrf" field to match with corresponding - * CLI. "localPref" will be deprecated in future. - */ - json_object_int_add(json_path, "localpref", - attr->local_pref); + if (json_paths) json_object_int_add(json_path, "locPrf", - attr->local_pref); - } else + attr->local_pref); + else vty_out(vty, "%7u", attr->local_pref); else if (!json_paths) vty_out(vty, " "); @@ -7849,17 +7850,10 @@ void route_vty_out(struct vty *vty, struct prefix *p, /* Print aspath */ if (attr->aspath) { - if (json_paths) { - - /* - * Adding "path" field to match with corresponding - * CLI. "aspath" will be deprecated in future. - */ - json_object_string_add(json_path, "aspath", - attr->aspath->str); + if (json_paths) json_object_string_add(json_path, "path", - attr->aspath->str); - } else + attr->aspath->str); + else aspath_print_vty(vty, "%s", attr->aspath, " "); } @@ -7922,7 +7916,7 @@ void route_vty_out(struct vty *vty, struct prefix *p, vty_out(vty, "%s\n", attr->ecommunity->str); } -#if ENABLE_BGP_VNC +#ifdef ENABLE_BGP_VNC /* prints an additional line, indented, with VNC info, if * present */ if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP)) @@ -7932,8 +7926,9 @@ void route_vty_out(struct vty *vty, struct prefix *p, } /* called from terminal list command */ -void route_vty_out_tmp(struct vty *vty, struct prefix *p, struct attr *attr, - safi_t safi, bool use_json, json_object *json_ar) +void route_vty_out_tmp(struct vty *vty, const struct prefix *p, + struct attr *attr, safi_t safi, bool use_json, + json_object *json_ar) { json_object *json_status = NULL; json_object *json_net = NULL; @@ -8001,34 +7996,16 @@ void route_vty_out_tmp(struct vty *vty, struct prefix *p, struct attr *attr, json_object_int_add(json_net, "metric", attr->med); - if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF)) { - - /* - * Adding "locPrf" field to match with - * corresponding CLI. "localPref" will be - * deprecated in future. - */ - json_object_int_add(json_net, "localPref", - attr->local_pref); + if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF)) json_object_int_add(json_net, "locPrf", - attr->local_pref); - } + attr->local_pref); json_object_int_add(json_net, "weight", attr->weight); /* Print aspath */ - if (attr->aspath) { - - /* - * Adding "path" field to match with - * corresponding CLI. "localPref" will be - * deprecated in future. - */ - json_object_string_add(json_net, "asPath", - attr->aspath->str); + if (attr->aspath) json_object_string_add(json_net, "path", - attr->aspath->str); - } + attr->aspath->str); /* Print origin */ json_object_string_add(json_net, "bgpOriginCode", @@ -8095,7 +8072,7 @@ void route_vty_out_tmp(struct vty *vty, struct prefix *p, struct attr *attr, vty_out(vty, "\n"); } -void route_vty_out_tag(struct vty *vty, struct prefix *p, +void route_vty_out_tag(struct vty *vty, const struct prefix *p, struct bgp_path_info *path, int display, safi_t safi, json_object *json) { @@ -8188,7 +8165,7 @@ void route_vty_out_tag(struct vty *vty, struct prefix *p, } } -void route_vty_out_overlay(struct vty *vty, struct prefix *p, +void route_vty_out_overlay(struct vty *vty, const struct prefix *p, struct bgp_path_info *path, int display, json_object *json_paths) { @@ -8312,9 +8289,10 @@ void route_vty_out_overlay(struct vty *vty, struct prefix *p, } /* dampening route */ -static void damp_route_vty_out(struct vty *vty, struct prefix *p, - struct bgp_path_info *path, int display, afi_t afi, - safi_t safi, bool use_json, json_object *json) +static void damp_route_vty_out(struct vty *vty, const struct prefix *p, + struct bgp_path_info *path, int display, + afi_t afi, safi_t safi, bool use_json, + json_object *json) { struct attr *attr; int len; @@ -8376,9 +8354,10 @@ static void damp_route_vty_out(struct vty *vty, struct prefix *p, } /* flap route */ -static void flap_route_vty_out(struct vty *vty, struct prefix *p, - struct bgp_path_info *path, int display, afi_t afi, - safi_t safi, bool use_json, json_object *json) +static void flap_route_vty_out(struct vty *vty, const struct prefix *p, + struct bgp_path_info *path, int display, + afi_t afi, safi_t safi, bool use_json, + json_object *json) { struct attr *attr; struct bgp_damp_info *bdi; @@ -8641,8 +8620,10 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, } if (safi == SAFI_EVPN) { if (!json_paths) { - bgp_evpn_route2str((struct prefix_evpn *)&bn->p, - buf2, sizeof(buf2)); + bgp_evpn_route2str( + (struct prefix_evpn *) + bgp_node_get_prefix(bn), + buf2, sizeof(buf2)); vty_out(vty, " Route %s", buf2); if (tag_buf[0] != '\0') vty_out(vty, " VNI %s", tag_buf); @@ -8662,11 +8643,14 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, rn = parent_ri->net; if (rn && rn->prn) { prn = rn->prn; - prefix_rd2str((struct prefix_rd *)&prn->p, + prefix_rd2str((struct prefix_rd *) + bgp_node_get_prefix(prn), buf1, sizeof(buf1)); if (is_pi_family_evpn(parent_ri)) { - bgp_evpn_route2str((struct prefix_evpn *)&rn->p, - buf2, sizeof(buf2)); + bgp_evpn_route2str( + (struct prefix_evpn *) + bgp_node_get_prefix(rn), + buf2, sizeof(buf2)); vty_out(vty, " Imported from %s:%s, VNI %s\n", buf1, buf2, tag_buf); } else vty_out(vty, " Imported from %s:%s\n", buf1, buf2); @@ -8711,10 +8695,22 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, json_object_string_add( json_path, "aggregatorId", inet_ntoa(attr->aggregator_addr)); + if (attr->aggregator_as == BGP_AS_ZERO) + json_object_boolean_true_add( + json_path, "aggregatorAsMalformed"); + else + json_object_boolean_false_add( + json_path, "aggregatorAsMalformed"); } else { - vty_out(vty, ", (aggregated by %u %s)", - attr->aggregator_as, - inet_ntoa(attr->aggregator_addr)); + if (attr->aggregator_as == BGP_AS_ZERO) + vty_out(vty, + ", (aggregated by %u(malformed) %s)", + attr->aggregator_as, + inet_ntoa(attr->aggregator_addr)); + else + vty_out(vty, ", (aggregated by %u %s)", + attr->aggregator_as, + inet_ntoa(attr->aggregator_addr)); } } @@ -8755,8 +8751,10 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, /* Line2 display Next-hop, Neighbor, Router-id */ /* Display the nexthop */ - if ((bn->p.family == AF_INET || bn->p.family == AF_ETHERNET - || bn->p.family == AF_EVPN) + const struct prefix *bn_p = bgp_node_get_prefix(bn); + + if ((bn_p->family == AF_INET || bn_p->family == AF_ETHERNET + || bn_p->family == AF_EVPN) && (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP || safi == SAFI_EVPN || !BGP_ATTR_NEXTHOP_AFI_IP6(attr))) { if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP @@ -8857,7 +8855,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, if (path->peer == bgp->peer_self) { if (safi == SAFI_EVPN - || (bn->p.family == AF_INET + || (bn_p->family == AF_INET && !BGP_ATTR_NEXTHOP_AFI_IP6(attr))) { if (json_paths) json_object_string_add(json_peer, "peerId", @@ -9041,21 +9039,15 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, bgp_origin_long_str[attr->origin]); if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC)) { - if (json_paths) { - /* - * Adding "metric" field to match with - * corresponding CLI. "med" will be - * deprecated in future. - */ - json_object_int_add(json_path, "med", attr->med); + if (json_paths) json_object_int_add(json_path, "metric", attr->med); - } else + else vty_out(vty, ", metric %u", attr->med); } if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF)) { if (json_paths) - json_object_int_add(json_path, "localpref", + json_object_int_add(json_path, "locPrf", attr->local_pref); else vty_out(vty, ", localpref %u", attr->local_pref); @@ -9527,6 +9519,8 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi, /* Start processing of routes. */ for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) { + const struct prefix *rn_p = bgp_node_get_prefix(rn); + pi = bgp_node_get_bgp_path_info(rn); if (pi == NULL) continue; @@ -9556,7 +9550,7 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi, if (type == bgp_show_type_prefix_list) { struct prefix_list *plist = output_arg; - if (prefix_list_apply(plist, &rn->p) + if (prefix_list_apply(plist, rn_p) != PREFIX_PERMIT) continue; } @@ -9578,7 +9572,7 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi, path.peer = pi->peer; path.attr = &dummy_attr; - ret = route_map_apply(rmap, &rn->p, RMAP_BGP, + ret = route_map_apply(rmap, rn_p, RMAP_BGP, &path); if (ret == RMAP_DENYMATCH) continue; @@ -9596,20 +9590,20 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi, if (type == bgp_show_type_cidr_only) { uint32_t destination; - destination = ntohl(rn->p.u.prefix4.s_addr); + destination = ntohl(rn_p->u.prefix4.s_addr); if (IN_CLASSC(destination) - && rn->p.prefixlen == 24) + && rn_p->prefixlen == 24) continue; if (IN_CLASSB(destination) - && rn->p.prefixlen == 16) + && rn_p->prefixlen == 16) continue; if (IN_CLASSA(destination) - && rn->p.prefixlen == 8) + && rn_p->prefixlen == 8) continue; } if (type == bgp_show_type_prefix_longer) { p = output_arg; - if (!prefix_match(p, &rn->p)) + if (!prefix_match(p, rn_p)) continue; } if (type == bgp_show_type_community_all) { @@ -9722,14 +9716,16 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi, } if (type == bgp_show_type_dampend_paths || type == bgp_show_type_damp_neighbor) - damp_route_vty_out(vty, &rn->p, pi, display, AFI_IP, - safi, use_json, json_paths); + damp_route_vty_out(vty, rn_p, pi, display, + AFI_IP, safi, use_json, + json_paths); else if (type == bgp_show_type_flap_statistics || type == bgp_show_type_flap_neighbor) - flap_route_vty_out(vty, &rn->p, pi, display, AFI_IP, - safi, use_json, json_paths); + flap_route_vty_out(vty, rn_p, pi, display, + AFI_IP, safi, use_json, + json_paths); else - route_vty_out(vty, &rn->p, pi, display, safi, + route_vty_out(vty, rn_p, pi, display, safi, json_paths); display++; } @@ -9739,28 +9735,25 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi, if (!use_json) continue; - p = &rn->p; /* encode prefix */ - if (p->family == AF_FLOWSPEC) { + if (rn_p->family == AF_FLOWSPEC) { char retstr[BGP_FLOWSPEC_STRING_DISPLAY_MAX]; - bgp_fs_nlri_get_string((unsigned char *) - p->u.prefix_flowspec.ptr, - p->u.prefix_flowspec - .prefixlen, - retstr, - NLRI_STRING_FORMAT_MIN, - NULL); + bgp_fs_nlri_get_string( + (unsigned char *) + rn_p->u.prefix_flowspec.ptr, + rn_p->u.prefix_flowspec.prefixlen, + retstr, NLRI_STRING_FORMAT_MIN, NULL); if (first) - vty_out(vty, "\"%s/%d\": ", - retstr, - p->u.prefix_flowspec.prefixlen); + vty_out(vty, "\"%s/%d\": ", retstr, + rn_p->u.prefix_flowspec + .prefixlen); else - vty_out(vty, ",\"%s/%d\": ", - retstr, - p->u.prefix_flowspec.prefixlen); + vty_out(vty, ",\"%s/%d\": ", retstr, + rn_p->u.prefix_flowspec + .prefixlen); } else { - prefix2str(p, buf2, sizeof(buf2)); + prefix2str(rn_p, buf2, sizeof(buf2)); if (first) vty_out(vty, "\"%s\": ", buf2); else @@ -9826,8 +9819,10 @@ int bgp_show_table_rd(struct vty *vty, struct bgp *bgp, safi_t safi, show_msg = (!use_json && type == bgp_show_type_normal); for (rn = bgp_table_top(table); rn; rn = next) { + const struct prefix *rn_p = bgp_node_get_prefix(rn); + next = bgp_route_next(rn); - if (prd_match && memcmp(rn->p.u.val, prd_match->val, 8) != 0) + if (prd_match && memcmp(rn_p->u.val, prd_match->val, 8) != 0) continue; itable = bgp_node_get_bgp_table_info(rn); @@ -9835,7 +9830,7 @@ int bgp_show_table_rd(struct vty *vty, struct bgp *bgp, safi_t safi, struct prefix_rd prd; char rd[RD_ADDRSTRLEN]; - memcpy(&prd, &(rn->p), sizeof(struct prefix_rd)); + memcpy(&prd, rn_p, sizeof(struct prefix_rd)); prefix_rd2str(&prd, rd, sizeof(rd)); bgp_show_table(vty, bgp, safi, itable, type, output_arg, use_json, rd, next == NULL, &output_cum, @@ -9938,7 +9933,7 @@ void route_vty_out_detail_header(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi, json_object *json) { struct bgp_path_info *pi; - struct prefix *p; + const struct prefix *p; struct peer *peer; struct listnode *node, *nnode; char buf1[RD_ADDRSTRLEN]; @@ -9966,7 +9961,7 @@ void route_vty_out_detail_header(struct vty *vty, struct bgp *bgp, mpls_label_t label = 0; json_object *json_adv_to = NULL; - p = &rn->p; + p = bgp_node_get_prefix(rn); has_valid_label = bgp_is_valid_label(&rn->local_label); if (has_valid_label) @@ -10226,7 +10221,9 @@ static int bgp_show_route_in_table(struct vty *vty, struct bgp *bgp, if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP) { for (rn = bgp_table_top(rib); rn; rn = bgp_route_next(rn)) { - if (prd && memcmp(rn->p.u.val, prd->val, 8) != 0) + const struct prefix *rn_p = bgp_node_get_prefix(rn); + + if (prd && memcmp(rn_p->u.val, prd->val, 8) != 0) continue; table = bgp_node_get_bgp_table_info(rn); if (!table) @@ -10235,15 +10232,16 @@ static int bgp_show_route_in_table(struct vty *vty, struct bgp *bgp, if ((rm = bgp_node_match(table, &match)) == NULL) continue; + const struct prefix *rm_p = bgp_node_get_prefix(rm); if (prefix_check - && rm->p.prefixlen != match.prefixlen) { + && rm_p->prefixlen != match.prefixlen) { bgp_unlock_node(rm); continue; } - bgp_show_path_info((struct prefix_rd *)&rn->p, rm, - vty, bgp, afi, safi, json, - pathtype, &display); + bgp_show_path_info((struct prefix_rd *)rn_p, rm, vty, + bgp, afi, safi, json, pathtype, + &display); bgp_unlock_node(rm); } @@ -10252,7 +10250,9 @@ static int bgp_show_route_in_table(struct vty *vty, struct bgp *bgp, bool is_exact_pfxlen_match = FALSE; for (rn = bgp_table_top(rib); rn; rn = bgp_route_next(rn)) { - if (prd && memcmp(rn->p.u.val, prd->val, 8) != 0) + const struct prefix *rn_p = bgp_node_get_prefix(rn); + + if (prd && memcmp(&rn_p->u.val, prd->val, 8) != 0) continue; table = bgp_node_get_bgp_table_info(rn); if (!table) @@ -10268,15 +10268,18 @@ static int bgp_show_route_in_table(struct vty *vty, struct bgp *bgp, */ for (rm = bgp_table_top(table); rm; rm = bgp_route_next(rm)) { + const struct prefix *rm_p = + bgp_node_get_prefix(rm); /* * Get prefixlen of the ip-prefix within type5 * evpn route */ - if (evpn_type5_prefix_match(&rm->p, - &match) && rm->info) { + if (evpn_type5_prefix_match(rm_p, &match) + && rm->info) { longest_pfx = rm; int type5_pfxlen = - bgp_evpn_get_type5_prefixlen(&rm->p); + bgp_evpn_get_type5_prefixlen( + rm_p); if (type5_pfxlen == match.prefixlen) { is_exact_pfxlen_match = TRUE; bgp_unlock_node(rm); @@ -10294,9 +10297,9 @@ static int bgp_show_route_in_table(struct vty *vty, struct bgp *bgp, rm = longest_pfx; bgp_lock_node(rm); - bgp_show_path_info((struct prefix_rd *)&rn->p, rm, - vty, bgp, afi, safi, json, - pathtype, &display); + bgp_show_path_info((struct prefix_rd *)rn_p, rm, vty, + bgp, afi, safi, json, pathtype, + &display); bgp_unlock_node(rm); } @@ -10313,8 +10316,9 @@ static int bgp_show_route_in_table(struct vty *vty, struct bgp *bgp, json_object_object_add(json, "paths", json_paths); } else { if ((rn = bgp_node_match(rib, &match)) != NULL) { + const struct prefix *rn_p = bgp_node_get_prefix(rn); if (!prefix_check - || rn->p.prefixlen == match.prefixlen) { + || rn_p->prefixlen == match.prefixlen) { bgp_show_path_info(NULL, rn, vty, bgp, afi, safi, json, pathtype, &display); @@ -11025,6 +11029,7 @@ static void bgp_table_stats_rn(struct bgp_node *rn, struct bgp_node *top, { struct bgp_node *prn = bgp_node_parent_nolock(rn); struct bgp_path_info *pi; + const struct prefix *rn_p; if (rn == top) return; @@ -11032,14 +11037,15 @@ static void bgp_table_stats_rn(struct bgp_node *rn, struct bgp_node *top, if (!bgp_node_has_bgp_path_info_data(rn)) return; + rn_p = bgp_node_get_prefix(rn); ts->counts[BGP_STATS_PREFIXES]++; - ts->counts[BGP_STATS_TOTPLEN] += rn->p.prefixlen; + ts->counts[BGP_STATS_TOTPLEN] += rn_p->prefixlen; #if 0 ts->counts[BGP_STATS_AVGPLEN] = ravg_tally (ts->counts[BGP_STATS_PREFIXES], ts->counts[BGP_STATS_AVGPLEN], - rn->p.prefixlen); + rn_p->prefixlen); #endif /* check if the prefix is included by any other announcements */ @@ -11050,7 +11056,7 @@ static void bgp_table_stats_rn(struct bgp_node *rn, struct bgp_node *top, ts->counts[BGP_STATS_UNAGGREGATEABLE]++; /* announced address space */ if (space) - ts->total_space += pow(2.0, space - rn->p.prefixlen); + ts->total_space += pow(2.0, space - rn_p->prefixlen); } else if (bgp_node_has_bgp_path_info_data(prn)) ts->counts[BGP_STATS_MAX_AGGREGATEABLE]++; @@ -11722,14 +11728,17 @@ static void show_adj_route(struct vty *vty, struct peer *peer, afi_t afi, /* Filter prefix using distribute list, * filter list or prefix list */ - if ((bgp_input_filter(peer, &rn->p, &attr, afi, - safi)) == FILTER_DENY) + const struct prefix *rn_p = + bgp_node_get_prefix(rn); + if ((bgp_input_filter(peer, rn_p, &attr, afi, + safi)) + == FILTER_DENY) route_filtered = true; /* Filter prefix using route-map */ - ret = bgp_input_modifier(peer, &rn->p, &attr, - afi, safi, rmap_name, NULL, 0, - NULL); + ret = bgp_input_modifier(peer, rn_p, &attr, afi, + safi, rmap_name, NULL, + 0, NULL); if (type == bgp_show_adj_route_filtered && !route_filtered && ret != RMAP_DENY) { @@ -11741,7 +11750,7 @@ static void show_adj_route(struct vty *vty, struct peer *peer, afi_t afi, (route_filtered || ret == RMAP_DENY)) filtered_count++; - route_vty_out_tmp(vty, &rn->p, &attr, safi, + route_vty_out_tmp(vty, rn_p, &attr, safi, use_json, json_ar); bgp_attr_undup(&attr, ain->attr); output_count++; @@ -11818,16 +11827,18 @@ static void show_adj_route(struct vty *vty, struct peer *peer, afi_t afi, header2 = 0; } + const struct prefix *rn_p = + bgp_node_get_prefix(rn); + attr = *adj->attr; ret = bgp_output_modifier( - peer, &rn->p, &attr, afi, safi, + peer, rn_p, &attr, afi, safi, rmap_name); if (ret != RMAP_DENY) { - route_vty_out_tmp(vty, &rn->p, - &attr, safi, - use_json, - json_ar); + route_vty_out_tmp( + vty, rn_p, &attr, safi, + use_json, json_ar); output_count++; } else { filtered_count++; @@ -12296,7 +12307,7 @@ static int bgp_distance_unset(struct vty *vty, const char *distance_str, } /* Apply BGP information to distance method. */ -uint8_t bgp_distance_apply(struct prefix *p, struct bgp_path_info *pinfo, +uint8_t bgp_distance_apply(const struct prefix *p, struct bgp_path_info *pinfo, afi_t afi, safi_t safi, struct bgp *bgp) { struct bgp_node *rn; @@ -12657,7 +12668,9 @@ static int bgp_clear_damp_route(struct vty *vty, const char *view_name, || (safi == SAFI_EVPN)) { for (rn = bgp_table_top(bgp->rib[AFI_IP][safi]); rn; rn = bgp_route_next(rn)) { - if (prd && memcmp(rn->p.u.val, prd->val, 8) != 0) + const struct prefix *rn_p = bgp_node_get_prefix(rn); + + if (prd && memcmp(rn_p->u.val, prd->val, 8) != 0) continue; table = bgp_node_get_bgp_table_info(rn); if (!table) @@ -12665,8 +12678,10 @@ static int bgp_clear_damp_route(struct vty *vty, const char *view_name, if ((rm = bgp_node_match(table, &match)) == NULL) continue; + const struct prefix *rm_p = bgp_node_get_prefix(rn); + if (!prefix_check - || rm->p.prefixlen == match.prefixlen) { + || rm_p->prefixlen == match.prefixlen) { pi = bgp_node_get_bgp_path_info(rm); while (pi) { if (pi->extra && pi->extra->damp_info) { @@ -12685,8 +12700,10 @@ static int bgp_clear_damp_route(struct vty *vty, const char *view_name, } else { if ((rn = bgp_node_match(bgp->rib[afi][safi], &match)) != NULL) { + const struct prefix *rn_p = bgp_node_get_prefix(rn); + if (!prefix_check - || rn->p.prefixlen == match.prefixlen) { + || rn_p->prefixlen == match.prefixlen) { pi = bgp_node_get_bgp_path_info(rn); while (pi) { if (pi->extra && pi->extra->damp_info) { @@ -12822,8 +12839,8 @@ static void bgp_config_write_network_vpn(struct vty *vty, struct bgp *bgp, struct bgp_node *prn; struct bgp_node *rn; struct bgp_table *table; - struct prefix *p; - struct prefix_rd *prd; + const struct prefix *p; + const struct prefix_rd *prd; struct bgp_static *bgp_static; mpls_label_t label; char buf[SU_ADDRSTRLEN]; @@ -12841,8 +12858,9 @@ static void bgp_config_write_network_vpn(struct vty *vty, struct bgp *bgp, if (bgp_static == NULL) continue; - p = &rn->p; - prd = (struct prefix_rd *)&prn->p; + p = bgp_node_get_prefix(rn); + prd = (const struct prefix_rd *)bgp_node_get_prefix( + prn); /* "network" configuration display. */ prefix_rd2str(prd, rdbuf, sizeof(rdbuf)); @@ -12873,8 +12891,8 @@ static void bgp_config_write_network_evpn(struct vty *vty, struct bgp *bgp, struct bgp_node *prn; struct bgp_node *rn; struct bgp_table *table; - struct prefix *p; - struct prefix_rd *prd; + const struct prefix *p; + const struct prefix_rd *prd; struct bgp_static *bgp_static; char buf[PREFIX_STRLEN * 2]; char buf2[SU_ADDRSTRLEN]; @@ -12900,8 +12918,8 @@ static void bgp_config_write_network_evpn(struct vty *vty, struct bgp *bgp, bgp_static->router_mac, NULL, 0); if (bgp_static->eth_s_id) esi = esi2str(bgp_static->eth_s_id); - p = &rn->p; - prd = (struct prefix_rd *)&prn->p; + p = bgp_node_get_prefix(rn); + prd = (struct prefix_rd *)bgp_node_get_prefix(prn); /* "network" configuration display. */ prefix_rd2str(prd, rdbuf, sizeof(rdbuf)); @@ -12944,7 +12962,7 @@ void bgp_config_write_network(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi) { struct bgp_node *rn; - struct prefix *p; + const struct prefix *p; struct bgp_static *bgp_static; struct bgp_aggregate *bgp_aggregate; char buf[SU_ADDRSTRLEN]; @@ -12966,7 +12984,7 @@ void bgp_config_write_network(struct vty *vty, struct bgp *bgp, afi_t afi, if (bgp_static == NULL) continue; - p = &rn->p; + p = bgp_node_get_prefix(rn); vty_out(vty, " network %s/%d", inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), @@ -12992,7 +13010,7 @@ void bgp_config_write_network(struct vty *vty, struct bgp *bgp, afi_t afi, if (bgp_aggregate == NULL) continue; - p = &rn->p; + p = bgp_node_get_prefix(rn); vty_out(vty, " aggregate-address %s/%d", inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), @@ -13037,15 +13055,11 @@ void bgp_config_write_distance(struct vty *vty, struct bgp *bgp, afi_t afi, for (rn = bgp_table_top(bgp_distance_table[afi][safi]); rn; rn = bgp_route_next(rn)) { bdistance = bgp_node_get_bgp_distance_info(rn); - if (bdistance != NULL) { - char buf[PREFIX_STRLEN]; - - vty_out(vty, " distance %d %s %s\n", - bdistance->distance, - prefix2str(&rn->p, buf, sizeof(buf)), + if (bdistance != NULL) + vty_out(vty, " distance %d %pRN %s\n", + bdistance->distance, rn, bdistance->access_list ? bdistance->access_list : ""); - } } } diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index 628c933c07..e1998633d7 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -125,7 +125,7 @@ struct bgp_path_info_extra { struct in6_addr sid[BGP_MAX_SIDS]; uint32_t num_sids; -#if ENABLE_BGP_VNC +#ifdef ENABLE_BGP_VNC union { struct { @@ -510,7 +510,7 @@ extern bool bgp_outbound_policy_exists(struct peer *, struct bgp_filter *); extern bool bgp_inbound_policy_exists(struct peer *, struct bgp_filter *); extern struct bgp_node *bgp_afi_node_get(struct bgp_table *table, afi_t afi, - safi_t safi, struct prefix *p, + safi_t safi, const struct prefix *p, struct prefix_rd *prd); extern struct bgp_path_info *bgp_path_info_lock(struct bgp_path_info *path); extern struct bgp_path_info *bgp_path_info_unlock(struct bgp_path_info *path); @@ -544,9 +544,10 @@ extern void bgp_static_add(struct bgp *); extern void bgp_static_delete(struct bgp *); extern void bgp_static_redo_import_check(struct bgp *); extern void bgp_purge_static_redist_routes(struct bgp *bgp); -extern void bgp_static_update(struct bgp *, struct prefix *, - struct bgp_static *, afi_t, safi_t); -extern void bgp_static_withdraw(struct bgp *, struct prefix *, afi_t, safi_t); +extern void bgp_static_update(struct bgp *bgp, const struct prefix *p, + struct bgp_static *s, afi_t afi, safi_t safi); +extern void bgp_static_withdraw(struct bgp *bgp, const struct prefix *p, + afi_t afi, safi_t safi); extern int bgp_static_set_safi(afi_t afi, safi_t safi, struct vty *vty, const char *, const char *, const char *, @@ -558,12 +559,17 @@ extern int bgp_static_unset_safi(afi_t afi, safi_t safi, struct vty *, const char *, const char *, const char *); /* this is primarily for MPLS-VPN */ -extern int bgp_update(struct peer *, struct prefix *, uint32_t, struct attr *, - afi_t, safi_t, int, int, struct prefix_rd *, - mpls_label_t *, uint32_t, int, struct bgp_route_evpn *); -extern int bgp_withdraw(struct peer *, struct prefix *, uint32_t, struct attr *, - afi_t, safi_t, int, int, struct prefix_rd *, - mpls_label_t *, uint32_t, struct bgp_route_evpn *); +extern int bgp_update(struct peer *peer, const struct prefix *p, + uint32_t addpath_id, struct attr *attr, + afi_t afi, safi_t safi, int type, int sub_type, + struct prefix_rd *prd, mpls_label_t *label, + uint32_t num_labels, int soft_reconfig, + struct bgp_route_evpn *evpn); +extern int bgp_withdraw(struct peer *peer, const struct prefix *p, + uint32_t addpath_id, struct attr *attr, afi_t afi, + safi_t safi, int type, int sub_type, + struct prefix_rd *prd, mpls_label_t *label, + uint32_t num_labels, struct bgp_route_evpn *evpn); /* for bgp_nexthop and bgp_damp */ extern void bgp_process(struct bgp *, struct bgp_node *, afi_t, safi_t); @@ -579,19 +585,22 @@ extern void bgp_config_write_network(struct vty *, struct bgp *, afi_t, safi_t); extern void bgp_config_write_distance(struct vty *, struct bgp *, afi_t, safi_t); -extern void bgp_aggregate_delete(struct bgp *bgp, struct prefix *p, afi_t afi, - safi_t safi, struct bgp_aggregate *aggregate); -extern void bgp_aggregate_route(struct bgp *bgp, struct prefix *p, afi_t afi, - safi_t safi, struct bgp_aggregate *aggregate); -extern void bgp_aggregate_increment(struct bgp *bgp, struct prefix *p, +extern void bgp_aggregate_delete(struct bgp *bgp, const struct prefix *p, + afi_t afi, safi_t safi, + struct bgp_aggregate *aggregate); +extern void bgp_aggregate_route(struct bgp *bgp, const struct prefix *p, + afi_t afi, safi_t safi, + struct bgp_aggregate *aggregate); +extern void bgp_aggregate_increment(struct bgp *bgp, const struct prefix *p, struct bgp_path_info *path, afi_t afi, safi_t safi); -extern void bgp_aggregate_decrement(struct bgp *bgp, struct prefix *p, +extern void bgp_aggregate_decrement(struct bgp *bgp, const struct prefix *p, struct bgp_path_info *path, afi_t afi, safi_t safi); -extern uint8_t bgp_distance_apply(struct prefix *p, struct bgp_path_info *path, - afi_t afi, safi_t safi, struct bgp *bgp); +extern uint8_t bgp_distance_apply(const struct prefix *p, + struct bgp_path_info *path, afi_t afi, + safi_t safi, struct bgp *bgp); extern afi_t bgp_node_afi(struct vty *); extern safi_t bgp_node_safi(struct vty *); @@ -601,16 +610,16 @@ extern struct bgp_path_info *info_make(int type, int sub_type, struct peer *peer, struct attr *attr, struct bgp_node *rn); -extern void route_vty_out(struct vty *vty, struct prefix *p, +extern void route_vty_out(struct vty *vty, const struct prefix *p, struct bgp_path_info *path, int display, safi_t safi, json_object *json_paths); -extern void route_vty_out_tag(struct vty *vty, struct prefix *p, +extern void route_vty_out_tag(struct vty *vty, const struct prefix *p, struct bgp_path_info *path, int display, safi_t safi, json_object *json); -extern void route_vty_out_tmp(struct vty *vty, struct prefix *p, +extern void route_vty_out_tmp(struct vty *vty, const struct prefix *p, struct attr *attr, safi_t safi, bool use_json, json_object *json_ar); -extern void route_vty_out_overlay(struct vty *vty, struct prefix *p, +extern void route_vty_out_overlay(struct vty *vty, const struct prefix *p, struct bgp_path_info *path, int display, json_object *json); @@ -622,14 +631,14 @@ extern void subgroup_process_announce_selected(struct update_subgroup *subgrp, extern bool subgroup_announce_check(struct bgp_node *rn, struct bgp_path_info *pi, struct update_subgroup *subgrp, - struct prefix *p, struct attr *attr); + const struct prefix *p, struct attr *attr); extern void bgp_peer_clear_node_queue_drain_immediate(struct peer *peer); extern void bgp_process_queues_drain_immediate(void); /* for encap/vpn */ extern struct bgp_node *bgp_afi_node_lookup(struct bgp_table *table, afi_t afi, - safi_t safi, struct prefix *p, + safi_t safi, const struct prefix *p, struct prefix_rd *prd); extern void bgp_path_info_restore(struct bgp_node *rn, struct bgp_path_info *path); diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 029570df35..8bc4ef6893 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -64,7 +64,7 @@ #include "bgpd/bgp_flowspec_util.h" #include "bgpd/bgp_encap_types.h" -#if ENABLE_BGP_VNC +#ifdef ENABLE_BGP_VNC #include "bgpd/rfapi/bgp_rfapi_cfg.h" #endif @@ -1015,7 +1015,7 @@ route_match_rd(void *rule, const struct prefix *prefix, route_map_object_t type, void *object) { struct prefix_rd *prd_rule = NULL; - struct prefix_rd *prd_route = NULL; + const struct prefix_rd *prd_route = NULL; struct bgp_path_info *path = NULL; if (type == RMAP_BGP) { @@ -1028,7 +1028,8 @@ route_match_rd(void *rule, const struct prefix *prefix, if (path->net == NULL || path->net->prn == NULL) return RMAP_NOMATCH; - prd_route = (struct prefix_rd *)&path->net->prn->p; + prd_route = + (struct prefix_rd *)bgp_node_get_prefix(path->net->prn); if (memcmp(prd_route->val, prd_rule->val, ECOMMUNITY_SIZE) == 0) return RMAP_MATCH; } @@ -3637,14 +3638,17 @@ static void bgp_route_map_process_update(struct bgp *bgp, const char *rmap_name, bgp_static->rmap.map = map; if (route_update && !bgp_static->backdoor) { - if (bgp_debug_zebra(&bn->p)) + const struct prefix *bn_p = + bgp_node_get_prefix(bn); + + if (bgp_debug_zebra(bn_p)) zlog_debug( "Processing route_map %s update on static route %s", rmap_name, - inet_ntop(bn->p.family, - &bn->p.u.prefix, buf, + inet_ntop(bn_p->family, + &bn_p->u.prefix, buf, INET6_ADDRSTRLEN)); - bgp_static_update(bgp, &bn->p, bgp_static, afi, + bgp_static_update(bgp, bn_p, bgp_static, afi, safi); } } @@ -3666,14 +3670,17 @@ static void bgp_route_map_process_update(struct bgp *bgp, const char *rmap_name, aggregate->rmap.map = map; if (route_update) { - if (bgp_debug_zebra(&bn->p)) + const struct prefix *bn_p = + bgp_node_get_prefix(bn); + + if (bgp_debug_zebra(bn_p)) zlog_debug( "Processing route_map %s update on aggregate-address route %s", rmap_name, - inet_ntop(bn->p.family, - &bn->p.u.prefix, buf, + inet_ntop(bn_p->family, + &bn_p->u.prefix, buf, INET6_ADDRSTRLEN)); - bgp_aggregate_route(bgp, &bn->p, afi, safi, + bgp_aggregate_route(bgp, bn_p, afi, safi, aggregate); } } @@ -3742,7 +3749,7 @@ static void bgp_route_map_process_update_cb(char *rmap_name) for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) { bgp_route_map_process_update(bgp, rmap_name, 1); -#if ENABLE_BGP_VNC +#ifdef ENABLE_BGP_VNC /* zlog_debug("%s: calling vnc_routemap_update", __func__); */ vnc_routemap_update(bgp, __func__); #endif @@ -3786,7 +3793,7 @@ static void bgp_route_map_mark_update(const char *rmap_name) } else { for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) bgp_route_map_process_update(bgp, rmap_name, 0); -#if ENABLE_BGP_VNC +#ifdef ENABLE_BGP_VNC zlog_debug("%s: calling vnc_routemap_update", __func__); vnc_routemap_update(bgp, __func__); #endif diff --git a/bgpd/bgp_rpki.c b/bgpd/bgp_rpki.c index ee1c49666b..e40c7231a7 100644 --- a/bgpd/bgp_rpki.c +++ b/bgpd/bgp_rpki.c @@ -438,10 +438,10 @@ static void revalidate_bgp_node(struct bgp_node *bgp_node, afi_t afi, label = path->extra->label; num_labels = path->extra->num_labels; } - ret = bgp_update(ain->peer, &bgp_node->p, ain->addpath_rx_id, - ain->attr, afi, safi, ZEBRA_ROUTE_BGP, - BGP_ROUTE_NORMAL, NULL, label, num_labels, 1, - NULL); + ret = bgp_update(ain->peer, bgp_node_get_prefix(bgp_node), + ain->addpath_rx_id, ain->attr, afi, safi, + ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL, label, + num_labels, 1, NULL); if (ret < 0) return; diff --git a/bgpd/bgp_snmp.c b/bgpd/bgp_snmp.c index 5cf0b73984..28eea46a5a 100644 --- a/bgpd/bgp_snmp.c +++ b/bgpd/bgp_snmp.c @@ -761,20 +761,23 @@ static struct bgp_path_info *bgp4PathAttrLookup(struct variable *v, oid name[], } if (min) { + const struct prefix *rn_p = + bgp_node_get_prefix(rn); + *length = v->namelen + BGP_PATHATTR_ENTRY_OFFSET; offset = name + v->namelen; - oid_copy_addr(offset, &rn->p.u.prefix4, + oid_copy_addr(offset, &rn_p->u.prefix4, IN_ADDR_SIZE); offset += IN_ADDR_SIZE; - *offset = rn->p.prefixlen; + *offset = rn_p->prefixlen; offset++; oid_copy_addr(offset, &min->peer->su.sin.sin_addr, IN_ADDR_SIZE); - addr->prefix = rn->p.u.prefix4; - addr->prefixlen = rn->p.prefixlen; + addr->prefix = rn_p->u.prefix4; + addr->prefixlen = rn_p->prefixlen; bgp_unlock_node(rn); diff --git a/bgpd/bgp_table.c b/bgpd/bgp_table.c index 3d74128da4..dcf9852a67 100644 --- a/bgpd/bgp_table.c +++ b/bgpd/bgp_table.c @@ -168,13 +168,22 @@ static struct bgp_node * bgp_route_next_until_maxlen(struct bgp_node *node, const struct bgp_node *limit, const uint8_t maxlen) { - if (node->l_left && node->p.prefixlen < maxlen - && node->l_left->p.prefixlen <= maxlen) { - return bgp_node_from_rnode(node->l_left); + const struct prefix *p = bgp_node_get_prefix(node); + + if (node->l_left) { + const struct prefix *left_p = + bgp_node_get_prefix(bgp_node_from_rnode(node->l_left)); + + if (p->prefixlen < maxlen && left_p->prefixlen <= maxlen) + return bgp_node_from_rnode(node->l_left); } - if (node->l_right && node->p.prefixlen < maxlen - && node->l_right->p.prefixlen <= maxlen) { - return bgp_node_from_rnode(node->l_right); + + if (node->l_right) { + const struct prefix *right_p = + bgp_node_get_prefix(bgp_node_from_rnode(node->l_right)); + + if (p->prefixlen < maxlen && right_p->prefixlen <= maxlen) + return bgp_node_from_rnode(node->l_right); } while (node->parent && node != limit) { @@ -197,24 +206,29 @@ void bgp_table_range_lookup(const struct bgp_table *table, if (node == NULL) return; - while (node && - node->p.prefixlen <= p->prefixlen && prefix_match(&node->p, p)) { + const struct prefix *node_p = bgp_node_get_prefix(node); + + while (node && node_p->prefixlen <= p->prefixlen + && prefix_match(node_p, p)) { if (bgp_node_has_bgp_path_info_data(node) - && node->p.prefixlen == p->prefixlen) { + && node_p->prefixlen == p->prefixlen) { matched = node; break; } node = bgp_node_from_rnode(node->link[prefix_bit( - &p->u.prefix, node->p.prefixlen)]); + &p->u.prefix, node_p->prefixlen)]); + node_p = bgp_node_get_prefix(node); } if (!node) return; - if (matched == NULL && node->p.prefixlen <= maxlen - && prefix_match(p, &node->p) && node->parent == NULL) + node_p = bgp_node_get_prefix(node); + if (matched == NULL && node_p->prefixlen <= maxlen + && prefix_match(p, node_p) && node->parent == NULL) matched = node; - else if ((matched == NULL && node->p.prefixlen > maxlen) || !node->parent) + else if ((matched == NULL && node_p->prefixlen > maxlen) + || !node->parent) return; else if (matched == NULL && node->parent) matched = node = bgp_node_from_rnode(node->parent); @@ -228,7 +242,8 @@ void bgp_table_range_lookup(const struct bgp_table *table, } while ((node = bgp_route_next_until_maxlen(node, matched, maxlen))) { - if (prefix_match(p, &node->p)) { + node_p = bgp_node_get_prefix(node); + if (prefix_match(p, node_p)) { if (bgp_node_has_bgp_path_info_data(node)) { bgp_lock_node(node); listnode_add(matches, node); diff --git a/bgpd/bgp_table.h b/bgpd/bgp_table.h index 7b468cc036..da2ca3181a 100644 --- a/bgpd/bgp_table.h +++ b/bgpd/bgp_table.h @@ -443,4 +443,13 @@ static inline bool bgp_node_has_bgp_path_info_data(struct bgp_node *node) return !!node->info; } +static inline const struct prefix *bgp_node_get_prefix(struct bgp_node *node) +{ + return &node->p; +} + +#ifdef _FRR_ATTRIBUTE_PRINTFRR +#pragma FRR printfrr_ext "%pRN" (struct bgp_node *) +#endif + #endif /* _QUAGGA_BGP_TABLE_H */ diff --git a/bgpd/bgp_updgrp_adv.c b/bgpd/bgp_updgrp_adv.c index 34f80def8c..e40b3320ea 100644 --- a/bgpd/bgp_updgrp_adv.c +++ b/bgpd/bgp_updgrp_adv.c @@ -148,12 +148,9 @@ static int group_announce_route_walkcb(struct update_group *updgrp, void *arg) peer = UPDGRP_PEER(updgrp); addpath_capable = bgp_addpath_encode_tx(peer, afi, safi); - if (BGP_DEBUG(update, UPDATE_OUT)) { - char buf_prefix[PREFIX_STRLEN]; - prefix2str(&ctx->rn->p, buf_prefix, sizeof(buf_prefix)); - zlog_debug("%s: afi=%s, safi=%s, p=%s", __func__, afi2str(afi), - safi2str(safi), buf_prefix); - } + if (BGP_DEBUG(update, UPDATE_OUT)) + zlog_debug("%s: afi=%s, safi=%s, p=%pRN", __func__, + afi2str(afi), safi2str(safi), ctx->rn); UPDGRP_FOREACH_SUBGRP (updgrp, subgrp) { @@ -242,7 +239,9 @@ static void subgrp_show_adjq_vty(struct update_subgroup *subgrp, output_count = 0; - for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) + for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) { + const struct prefix *rn_p = bgp_node_get_prefix(rn); + RB_FOREACH (adj, bgp_adj_out_rb, &rn->adj_out) if (adj->subgroup == subgrp) { if (header1) { @@ -261,20 +260,20 @@ static void subgrp_show_adjq_vty(struct update_subgroup *subgrp, } if ((flags & UPDWALK_FLAGS_ADVQUEUE) && adj->adv && adj->adv->baa) { - route_vty_out_tmp(vty, &rn->p, - adj->adv->baa->attr, - SUBGRP_SAFI(subgrp), - 0, NULL); + route_vty_out_tmp( + vty, rn_p, adj->adv->baa->attr, + SUBGRP_SAFI(subgrp), 0, NULL); output_count++; } if ((flags & UPDWALK_FLAGS_ADVERTISED) && adj->attr) { - route_vty_out_tmp( - vty, &rn->p, adj->attr, - SUBGRP_SAFI(subgrp), 0, NULL); + route_vty_out_tmp(vty, rn_p, adj->attr, + SUBGRP_SAFI(subgrp), + 0, NULL); output_count++; } } + } if (output_count != 0) vty_out(vty, "\nTotal number of prefixes %ld\n", output_count); } @@ -623,7 +622,9 @@ void subgroup_announce_table(struct update_subgroup *subgrp, PEER_FLAG_DEFAULT_ORIGINATE)) subgroup_default_originate(subgrp, 0); - for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) + for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) { + const struct prefix *rn_p = bgp_node_get_prefix(rn); + for (ri = bgp_node_get_bgp_path_info(rn); ri; ri = ri->next) if (CHECK_FLAG(ri->flags, BGP_PATH_SELECTED) @@ -632,7 +633,7 @@ void subgroup_announce_table(struct update_subgroup *subgrp, peer->addpath_type[afi][safi], ri))) { if (subgroup_announce_check(rn, ri, subgrp, - &rn->p, &attr)) + rn_p, &attr)) bgp_adj_out_set_subgroup(rn, subgrp, &attr, ri); else @@ -642,6 +643,7 @@ void subgroup_announce_table(struct update_subgroup *subgrp, peer, afi, safi, &ri->tx_addpath)); } + } /* * We walked through the whole table -- make sure our version number @@ -761,7 +763,8 @@ void subgroup_default_originate(struct update_subgroup *subgrp, int withdraw) for (rn = bgp_table_top(bgp->rib[afi][safi]); rn; rn = bgp_route_next(rn)) { ret = route_map_apply(peer->default_rmap[afi][safi].map, - &rn->p, RMAP_BGP, &bpi_rmap); + bgp_node_get_prefix(rn), RMAP_BGP, + &bpi_rmap); if (ret != RMAP_DENYMATCH) break; diff --git a/bgpd/bgp_updgrp_packet.c b/bgpd/bgp_updgrp_packet.c index 6553211b0f..8d6fc1f6a2 100644 --- a/bgpd/bgp_updgrp_packet.c +++ b/bgpd/bgp_updgrp_packet.c @@ -726,8 +726,11 @@ struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp) adv = bgp_adv_fifo_first(&subgrp->sync->update); while (adv) { + const struct prefix *rn_p; + assert(adv->rn); rn = adv->rn; + rn_p = bgp_node_get_prefix(rn); adj = adv->adj; addpath_tx_id = adj->addpath_tx_id; path = adv->pathi; @@ -750,9 +753,8 @@ struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp) space_remaining = STREAM_CONCAT_REMAIN(s, snlri, STREAM_SIZE(s)) - BGP_MAX_PACKET_SIZE_OVERFLOW; - space_needed = - BGP_NLRI_LENGTH + addpath_overhead - + bgp_packet_mpattr_prefix_size(afi, safi, &rn->p); + space_needed = BGP_NLRI_LENGTH + addpath_overhead + + bgp_packet_mpattr_prefix_size(afi, safi, rn_p); /* When remaining space can't include NLRI and it's length. */ if (space_remaining < space_needed) @@ -798,7 +800,7 @@ struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp) - BGP_MAX_PACKET_SIZE_OVERFLOW; space_needed = BGP_NLRI_LENGTH + addpath_overhead + bgp_packet_mpattr_prefix_size( - afi, safi, &rn->p); + afi, safi, rn_p); /* If the attributes alone do not leave any room for * NLRI then @@ -828,12 +830,13 @@ struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp) if ((afi == AFI_IP && safi == SAFI_UNICAST) && !peer_cap_enhe(peer, afi, safi)) - stream_put_prefix_addpath(s, &rn->p, addpath_encode, + stream_put_prefix_addpath(s, rn_p, addpath_encode, addpath_tx_id); else { /* Encode the prefix in MP_REACH_NLRI attribute */ if (rn->prn) - prd = (struct prefix_rd *)&rn->prn->p; + prd = (struct prefix_rd *)bgp_node_get_prefix( + rn->prn); if (safi == SAFI_LABELED_UNICAST) { label = bgp_adv_label(rn, path, peer, afi, @@ -850,7 +853,7 @@ struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp) snlri, peer, afi, safi, &vecarr, adv->baa->attr); - bgp_packet_mpattr_prefix(snlri, afi, safi, &rn->p, prd, + bgp_packet_mpattr_prefix(snlri, afi, safi, rn_p, prd, label_pnt, num_labels, addpath_encode, addpath_tx_id, adv->baa->attr); @@ -858,7 +861,7 @@ struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp) num_pfx++; - if (bgp_debug_update(NULL, &rn->p, subgrp->update_group, 0)) { + if (bgp_debug_update(NULL, rn_p, subgrp->update_group, 0)) { char pfx_buf[BGP_PRD_PATH_STRLEN]; if (!send_attr_printed) { @@ -882,10 +885,10 @@ struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp) send_attr_printed = 1; } - bgp_debug_rdpfxpath2str(afi, safi, prd, &rn->p, - label_pnt, num_labels, - addpath_encode, addpath_tx_id, - pfx_buf, sizeof(pfx_buf)); + bgp_debug_rdpfxpath2str(afi, safi, prd, rn_p, label_pnt, + num_labels, addpath_encode, + addpath_tx_id, pfx_buf, + sizeof(pfx_buf)); zlog_debug("u%" PRIu64 ":s%" PRIu64 " send UPDATE %s", subgrp->update_group->id, subgrp->id, pfx_buf); @@ -964,7 +967,7 @@ struct bpacket *subgroup_withdraw_packet(struct update_subgroup *subgrp) int addpath_encode = 0; int addpath_overhead = 0; uint32_t addpath_tx_id = 0; - struct prefix_rd *prd = NULL; + const struct prefix_rd *prd = NULL; if (!subgrp) @@ -982,16 +985,19 @@ struct bpacket *subgroup_withdraw_packet(struct update_subgroup *subgrp) addpath_overhead = addpath_encode ? BGP_ADDPATH_ID_LEN : 0; while ((adv = bgp_adv_fifo_first(&subgrp->sync->withdraw)) != NULL) { + const struct prefix *rn_p; + assert(adv->rn); adj = adv->adj; rn = adv->rn; + rn_p = bgp_node_get_prefix(rn); addpath_tx_id = adj->addpath_tx_id; space_remaining = STREAM_WRITEABLE(s) - BGP_MAX_PACKET_SIZE_OVERFLOW; - space_needed = - BGP_NLRI_LENGTH + addpath_overhead + BGP_TOTAL_ATTR_LEN - + bgp_packet_mpattr_prefix_size(afi, safi, &rn->p); + space_needed = BGP_NLRI_LENGTH + addpath_overhead + + BGP_TOTAL_ATTR_LEN + + bgp_packet_mpattr_prefix_size(afi, safi, rn_p); if (space_remaining < space_needed) break; @@ -1004,13 +1010,15 @@ struct bpacket *subgroup_withdraw_packet(struct update_subgroup *subgrp) if (afi == AFI_IP && safi == SAFI_UNICAST && !peer_cap_enhe(peer, afi, safi)) - stream_put_prefix_addpath(s, &rn->p, addpath_encode, + stream_put_prefix_addpath(s, rn_p, addpath_encode, addpath_tx_id); else { if (rn->prn) - prd = (struct prefix_rd *)&rn->prn->p; + prd = (struct prefix_rd *)bgp_node_get_prefix( + rn->prn); - /* If first time, format the MP_UNREACH header */ + /* If first time, format the MP_UNREACH header + */ if (first_time) { iana_afi_t pkt_afi; iana_safi_t pkt_safi; @@ -1019,8 +1027,8 @@ struct bpacket *subgroup_withdraw_packet(struct update_subgroup *subgrp) pkt_safi = safi_int2iana(safi); attrlen_pos = stream_get_endp(s); - /* total attr length = 0 for now. reevaluate - * later */ + /* total attr length = 0 for now. + * reevaluate later */ stream_putw(s, 0); mp_start = stream_get_endp(s); mplen_pos = bgp_packet_mpunreach_start(s, afi, @@ -1034,17 +1042,17 @@ struct bpacket *subgroup_withdraw_packet(struct update_subgroup *subgrp) subgrp->id, pkt_afi, pkt_safi); } - bgp_packet_mpunreach_prefix(s, &rn->p, afi, safi, prd, + bgp_packet_mpunreach_prefix(s, rn_p, afi, safi, prd, NULL, 0, addpath_encode, addpath_tx_id, NULL); } num_pfx++; - if (bgp_debug_update(NULL, &rn->p, subgrp->update_group, 0)) { + if (bgp_debug_update(NULL, rn_p, subgrp->update_group, 0)) { char pfx_buf[BGP_PRD_PATH_STRLEN]; - bgp_debug_rdpfxpath2str(afi, safi, prd, &rn->p, NULL, 0, + bgp_debug_rdpfxpath2str(afi, safi, prd, rn_p, NULL, 0, addpath_encode, addpath_tx_id, pfx_buf, sizeof(pfx_buf)); zlog_debug("u%" PRIu64 ":s%" PRIu64 diff --git a/bgpd/bgp_vnc_types.h b/bgpd/bgp_vnc_types.h index f4202ff75e..04847ce6c9 100644 --- a/bgpd/bgp_vnc_types.h +++ b/bgpd/bgp_vnc_types.h @@ -19,7 +19,7 @@ #ifndef _QUAGGA_BGP_VNC_TYPES_H #define _QUAGGA_BGP_VNC_TYPES_H -#if ENABLE_BGP_VNC +#ifdef ENABLE_BGP_VNC typedef enum { BGP_VNC_SUBTLV_TYPE_LIFETIME = 1, BGP_VNC_SUBTLV_TYPE_RFPOPTION = 2, /* deprecated */ diff --git a/bgpd/bgp_vpn.c b/bgpd/bgp_vpn.c index b67b0c322e..af632a1340 100644 --- a/bgpd/bgp_vpn.c +++ b/bgpd/bgp_vpn.c @@ -78,7 +78,9 @@ int show_adj_route_vpn(struct vty *vty, struct peer *peer, for (rn = bgp_table_top(bgp->rib[afi][safi]); rn; rn = bgp_route_next(rn)) { - if (prd && memcmp(rn->p.u.val, prd->val, 8) != 0) + const struct prefix *rn_p = bgp_node_get_prefix(rn); + + if (prd && memcmp(rn_p->u.val, prd->val, 8) != 0) continue; table = bgp_node_get_bgp_table_info(rn); @@ -153,12 +155,12 @@ int show_adj_route_vpn(struct vty *vty, struct peer *peer, uint16_t type; struct rd_as rd_as = {0}; struct rd_ip rd_ip = {0}; -#if ENABLE_BGP_VNC +#ifdef ENABLE_BGP_VNC struct rd_vnc_eth rd_vnc_eth = {0}; #endif - uint8_t *pnt; + const uint8_t *pnt; - pnt = rn->p.u.val; + pnt = rn_p->u.val; /* Decode RD type. */ type = decode_rd_type(pnt); @@ -169,7 +171,7 @@ int show_adj_route_vpn(struct vty *vty, struct peer *peer, decode_rd_as4(pnt + 2, &rd_as); else if (type == RD_TYPE_IP) decode_rd_ip(pnt + 2, &rd_ip); -#if ENABLE_BGP_VNC +#ifdef ENABLE_BGP_VNC else if (type == RD_TYPE_VNC_ETH) decode_rd_vnc_eth(pnt, &rd_vnc_eth); #endif @@ -198,7 +200,7 @@ int show_adj_route_vpn(struct vty *vty, struct peer *peer, vty_out(vty, "%s:%d", inet_ntoa(rd_ip.ip), rd_ip.val); -#if ENABLE_BGP_VNC +#ifdef ENABLE_BGP_VNC else if (type == RD_TYPE_VNC_ETH) vty_out(vty, "%u:%02x:%02x:%02x:%02x:%02x:%02x", @@ -221,9 +223,8 @@ int show_adj_route_vpn(struct vty *vty, struct peer *peer, } rd_header = 0; } - route_vty_out_tmp(vty, &rm->p, attr, - safi, use_json, - json_routes); + route_vty_out_tmp(vty, bgp_node_get_prefix(rm), attr, + safi, use_json, json_routes); output_count++; } diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 3db9866a99..9f4347e736 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -68,25 +68,25 @@ #include "bgpd/bgp_addpath.h" #include "bgpd/bgp_mac.h" #include "bgpd/bgp_flowspec.h" -#if ENABLE_BGP_VNC +#ifdef ENABLE_BGP_VNC #include "bgpd/rfapi/bgp_rfapi_cfg.h" #endif FRR_CFG_DEFAULT_BOOL(BGP_IMPORT_CHECK, - { .val_long = true, .match_profile = "datacenter", }, - { .val_long = false }, + { .val_bool = true, .match_profile = "datacenter", }, + { .val_bool = false }, ) FRR_CFG_DEFAULT_BOOL(BGP_SHOW_HOSTNAME, - { .val_long = true, .match_profile = "datacenter", }, - { .val_long = false }, + { .val_bool = true, .match_profile = "datacenter", }, + { .val_bool = false }, ) FRR_CFG_DEFAULT_BOOL(BGP_LOG_NEIGHBOR_CHANGES, - { .val_long = true, .match_profile = "datacenter", }, - { .val_long = false }, + { .val_bool = true, .match_profile = "datacenter", }, + { .val_bool = false }, ) FRR_CFG_DEFAULT_BOOL(BGP_DETERMINISTIC_MED, - { .val_long = true, .match_profile = "datacenter", }, - { .val_long = false }, + { .val_bool = true, .match_profile = "datacenter", }, + { .val_bool = false }, ) FRR_CFG_DEFAULT_ULONG(BGP_CONNECT_RETRY, { .val_ulong = 10, .match_profile = "datacenter", }, @@ -6590,6 +6590,7 @@ DEFUN(no_neighbor_maximum_prefix_out, if (!peer) return CMD_WARNING_CONFIG_FAILED; + UNSET_FLAG(peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_OUT); peer->pmax_out[afi][safi] = 0; return CMD_SUCCESS; @@ -7520,8 +7521,7 @@ ALIAS (af_route_map_vpn_imexport, "For routes leaked from current address-family to vpn\n") DEFPY(af_import_vrf_route_map, af_import_vrf_route_map_cmd, - "[no] import vrf route-map RMAP$rmap_str", - NO_STR + "import vrf route-map RMAP$rmap_str", "Import routes from another VRF\n" "Vrf routes being filtered\n" "Specify route map\n" @@ -7530,13 +7530,8 @@ DEFPY(af_import_vrf_route_map, af_import_vrf_route_map_cmd, VTY_DECLVAR_CONTEXT(bgp, bgp); vpn_policy_direction_t dir = BGP_VPN_POLICY_DIR_FROMVPN; afi_t afi; - int idx = 0; - int yes = 1; struct bgp *bgp_default; - if (argv_find(argv, argc, "no", &idx)) - yes = 0; - afi = vpn_policy_getafi(vty, bgp, true); if (afi == AFI_MAX) return CMD_WARNING_CONFIG_FAILED; @@ -7559,35 +7554,56 @@ DEFPY(af_import_vrf_route_map, af_import_vrf_route_map_cmd, vpn_leak_prechange(dir, afi, bgp_get_default(), bgp); - if (yes) { - if (bgp->vpn_policy[afi].rmap_name[dir]) - XFREE(MTYPE_ROUTE_MAP_NAME, - bgp->vpn_policy[afi].rmap_name[dir]); - bgp->vpn_policy[afi].rmap_name[dir] = - XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap_str); - bgp->vpn_policy[afi].rmap[dir] = - route_map_lookup_warn_noexist(vty, rmap_str); - if (!bgp->vpn_policy[afi].rmap[dir]) - return CMD_SUCCESS; - } else { - if (bgp->vpn_policy[afi].rmap_name[dir]) - XFREE(MTYPE_ROUTE_MAP_NAME, - bgp->vpn_policy[afi].rmap_name[dir]); - bgp->vpn_policy[afi].rmap_name[dir] = NULL; - bgp->vpn_policy[afi].rmap[dir] = NULL; - } + if (bgp->vpn_policy[afi].rmap_name[dir]) + XFREE(MTYPE_ROUTE_MAP_NAME, + bgp->vpn_policy[afi].rmap_name[dir]); + bgp->vpn_policy[afi].rmap_name[dir] = + XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap_str); + bgp->vpn_policy[afi].rmap[dir] = + route_map_lookup_warn_noexist(vty, rmap_str); + if (!bgp->vpn_policy[afi].rmap[dir]) + return CMD_SUCCESS; + + SET_FLAG(bgp->af_flags[afi][SAFI_UNICAST], + BGP_CONFIG_VRF_TO_VRF_IMPORT); vpn_leak_postchange(dir, afi, bgp_get_default(), bgp); return CMD_SUCCESS; } -ALIAS(af_import_vrf_route_map, af_no_import_vrf_route_map_cmd, - "no import vrf route-map", +DEFPY(af_no_import_vrf_route_map, af_no_import_vrf_route_map_cmd, + "no import vrf route-map [RMAP$rmap_str]", NO_STR "Import routes from another VRF\n" "Vrf routes being filtered\n" - "Specify route map\n") + "Specify route map\n" + "name of route-map\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + vpn_policy_direction_t dir = BGP_VPN_POLICY_DIR_FROMVPN; + afi_t afi; + + afi = vpn_policy_getafi(vty, bgp, true); + if (afi == AFI_MAX) + return CMD_WARNING_CONFIG_FAILED; + + vpn_leak_prechange(dir, afi, bgp_get_default(), bgp); + + if (bgp->vpn_policy[afi].rmap_name[dir]) + XFREE(MTYPE_ROUTE_MAP_NAME, + bgp->vpn_policy[afi].rmap_name[dir]); + bgp->vpn_policy[afi].rmap_name[dir] = NULL; + bgp->vpn_policy[afi].rmap[dir] = NULL; + + if (bgp->vpn_policy[afi].import_vrf->count == 0) + UNSET_FLAG(bgp->af_flags[afi][SAFI_UNICAST], + BGP_CONFIG_VRF_TO_VRF_IMPORT); + + vpn_leak_postchange(dir, afi, bgp_get_default(), bgp); + + return CMD_SUCCESS; +} DEFPY(bgp_imexport_vrf, bgp_imexport_vrf_cmd, "[no] import vrf VIEWVRFNAME$import_name", @@ -7613,6 +7629,11 @@ DEFPY(bgp_imexport_vrf, bgp_imexport_vrf_cmd, return CMD_WARNING; } + if (strcmp(import_name, "route-map") == 0) { + vty_out(vty, "%% Must include route-map name\n"); + return CMD_WARNING; + } + if (argv_find(argv, argc, "no", &idx)) remove = true; @@ -7935,27 +7956,32 @@ static int bgp_clear_prefix(struct vty *vty, const char *view_name, if (safi == SAFI_MPLS_VPN) { for (rn = bgp_table_top(rib); rn; rn = bgp_route_next(rn)) { - if (prd && memcmp(rn->p.u.val, prd->val, 8) != 0) + const struct prefix *rn_p = bgp_node_get_prefix(rn); + + if (prd && memcmp(rn_p->u.val, prd->val, 8) != 0) continue; table = bgp_node_get_bgp_table_info(rn); - if (table != NULL) { + if (table == NULL) + continue; - if ((rm = bgp_node_match(table, &match)) - != NULL) { - if (rm->p.prefixlen - == match.prefixlen) { - SET_FLAG(rm->flags, - BGP_NODE_USER_CLEAR); - bgp_process(bgp, rm, afi, safi); - } - bgp_unlock_node(rm); + if ((rm = bgp_node_match(table, &match)) != NULL) { + const struct prefix *rm_p = + bgp_node_get_prefix(rm); + + if (rm_p->prefixlen == match.prefixlen) { + SET_FLAG(rm->flags, + BGP_NODE_USER_CLEAR); + bgp_process(bgp, rm, afi, safi); } + bgp_unlock_node(rm); } } } else { if ((rn = bgp_node_match(rib, &match)) != NULL) { - if (rn->p.prefixlen == match.prefixlen) { + const struct prefix *rn_p = bgp_node_get_prefix(rn); + + if (rn_p->prefixlen == match.prefixlen) { SET_FLAG(rn->flags, BGP_NODE_USER_CLEAR); bgp_process(bgp, rn, afi, safi); } @@ -9010,11 +9036,20 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi, json_object_int_add(json_peer, "msgSent", PEER_TOTAL_TX(peer)); + atomic_size_t outq_count, inq_count; + outq_count = atomic_load_explicit( + &peer->obuf->count, + memory_order_relaxed); + inq_count = atomic_load_explicit( + &peer->ibuf->count, + memory_order_relaxed); + json_object_int_add(json_peer, "tableVersion", peer->version[afi][safi]); json_object_int_add(json_peer, "outq", - peer->obuf->count); - json_object_int_add(json_peer, "inq", 0); + outq_count); + json_object_int_add(json_peer, "inq", + inq_count); peer_uptime(peer->uptime, timebuf, BGP_UPTIME_LEN, use_json, json_peer); @@ -9096,10 +9131,21 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi, vty_out(vty, "%*s", max_neighbor_width - len, " "); - vty_out(vty, "4 %10u %9u %9u %8" PRIu64 " %4d %4zd %8s", + atomic_size_t outq_count, inq_count; + outq_count = atomic_load_explicit( + &peer->obuf->count, + memory_order_relaxed); + inq_count = atomic_load_explicit( + &peer->ibuf->count, + memory_order_relaxed); + + vty_out(vty, + "4 %10u %9u %9u %8" PRIu64 + " %4zu %4zu %8s", peer->as, PEER_TOTAL_RX(peer), - PEER_TOTAL_TX(peer), peer->version[afi][safi], - 0, peer->obuf->count, + PEER_TOTAL_TX(peer), + peer->version[afi][safi], inq_count, + outq_count, peer_uptime(peer->uptime, timebuf, BGP_UPTIME_LEN, 0, NULL)); @@ -11683,9 +11729,17 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, json_object *json_stat = NULL; json_stat = json_object_new_object(); /* Packet counts. */ - json_object_int_add(json_stat, "depthInq", 0); + + atomic_size_t outq_count, inq_count; + outq_count = atomic_load_explicit(&p->obuf->count, + memory_order_relaxed); + inq_count = atomic_load_explicit(&p->ibuf->count, + memory_order_relaxed); + + json_object_int_add(json_stat, "depthInq", + (unsigned long)inq_count); json_object_int_add(json_stat, "depthOutq", - (unsigned long)p->obuf->count); + (unsigned long)outq_count); json_object_int_add(json_stat, "opensSent", atomic_load_explicit(&p->open_out, memory_order_relaxed)); @@ -11726,11 +11780,16 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, json_object_int_add(json_stat, "totalRecv", PEER_TOTAL_RX(p)); json_object_object_add(json_neigh, "messageStats", json_stat); } else { + atomic_size_t outq_count, inq_count; + outq_count = atomic_load_explicit(&p->obuf->count, + memory_order_relaxed); + inq_count = atomic_load_explicit(&p->ibuf->count, + memory_order_relaxed); + /* Packet counts. */ vty_out(vty, " Message statistics:\n"); - vty_out(vty, " Inq depth is 0\n"); - vty_out(vty, " Outq depth is %lu\n", - (unsigned long)p->obuf->count); + vty_out(vty, " Inq depth is %zu\n", inq_count); + vty_out(vty, " Outq depth is %zu\n", outq_count); vty_out(vty, " Sent Rcvd\n"); vty_out(vty, " Opens: %10d %10d\n", atomic_load_explicit(&p->open_out, @@ -14116,7 +14175,8 @@ static void bgp_vpn_policy_config_write_afi(struct vty *vty, struct bgp *bgp, int indent = 2; if (bgp->vpn_policy[afi].rmap_name[BGP_VPN_POLICY_DIR_FROMVPN]) { - if (listcount(bgp->vpn_policy[afi].import_vrf)) + if (CHECK_FLAG(bgp->af_flags[afi][SAFI_UNICAST], + BGP_CONFIG_VRF_TO_VRF_IMPORT)) vty_out(vty, "%*simport vrf route-map %s\n", indent, "", bgp->vpn_policy[afi] .rmap_name[BGP_VPN_POLICY_DIR_FROMVPN]); @@ -15212,7 +15272,7 @@ int bgp_config_write(struct vty *vty) hook_call(bgp_inst_config_write, bgp, vty); -#if ENABLE_BGP_VNC +#ifdef ENABLE_BGP_VNC bgp_rfapi_cfg_write(vty, bgp); #endif diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 1c0f3c99b7..dd0e35a745 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -51,7 +51,7 @@ #include "bgpd/bgp_nht.h" #include "bgpd/bgp_bfd.h" #include "bgpd/bgp_label.h" -#if ENABLE_BGP_VNC +#ifdef ENABLE_BGP_VNC #include "bgpd/rfapi/rfapi_backend.h" #include "bgpd/rfapi/vnc_export_bgp.h" #endif @@ -928,7 +928,7 @@ bgp_path_info_to_ipv6_nexthop(struct bgp_path_info *path, ifindex_t *ifindex) return nexthop; } -static bool bgp_table_map_apply(struct route_map *map, struct prefix *p, +static bool bgp_table_map_apply(struct route_map *map, const struct prefix *p, struct bgp_path_info *path) { route_map_result_t ret; @@ -1148,7 +1148,7 @@ static bool update_ipv6nh_for_route_install(int nh_othervrf, struct bgp *nh_bgp, return true; } -void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p, +void bgp_zebra_announce(struct bgp_node *rn, const struct prefix *p, struct bgp_path_info *info, struct bgp *bgp, afi_t afi, safi_t safi) { @@ -1184,7 +1184,8 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p, prefix2str(p, buf_prefix, sizeof(buf_prefix)); if (safi == SAFI_FLOWSPEC) { - bgp_pbr_update_entry(bgp, &rn->p, info, afi, safi, true); + bgp_pbr_update_entry(bgp, bgp_node_get_prefix(rn), + info, afi, safi, true); return; } @@ -1480,11 +1481,11 @@ void bgp_zebra_announce_table(struct bgp *bgp, afi_t afi, safi_t safi) && (pi->sub_type == BGP_ROUTE_NORMAL || pi->sub_type == BGP_ROUTE_IMPORTED))) - bgp_zebra_announce(rn, &rn->p, pi, bgp, afi, - safi); + bgp_zebra_announce(rn, bgp_node_get_prefix(rn), + pi, bgp, afi, safi); } -void bgp_zebra_withdraw(struct prefix *p, struct bgp_path_info *info, +void bgp_zebra_withdraw(const struct prefix *p, struct bgp_path_info *info, struct bgp *bgp, safi_t safi) { struct zapi_route api; @@ -1604,7 +1605,7 @@ int bgp_redistribute_set(struct bgp *bgp, afi_t afi, int type, if (vrf_bitmap_check(zclient->redist[afi][type], bgp->vrf_id)) return CMD_WARNING; -#if ENABLE_BGP_VNC +#ifdef ENABLE_BGP_VNC if (EVPN_ENABLED(bgp) && type == ZEBRA_ROUTE_VNC_DIRECT) { vnc_export_bgp_enable( bgp, afi); /* only enables if mode bits cfg'd */ @@ -1765,7 +1766,7 @@ int bgp_redistribute_unset(struct bgp *bgp, afi_t afi, int type, * they operate within bgpd irrespective of zebra connection * status. red lookup fails if there is no zebra connection. */ -#if ENABLE_BGP_VNC +#ifdef ENABLE_BGP_VNC if (EVPN_ENABLED(bgp) && type == ZEBRA_ROUTE_VNC_DIRECT) { vnc_export_bgp_disable(bgp, afi); } diff --git a/bgpd/bgp_zebra.h b/bgpd/bgp_zebra.h index 39c28c452c..e546cd5da7 100644 --- a/bgpd/bgp_zebra.h +++ b/bgpd/bgp_zebra.h @@ -32,12 +32,13 @@ extern void bgp_zebra_destroy(void); extern int bgp_zebra_get_table_range(uint32_t chunk_size, uint32_t *start, uint32_t *end); extern int bgp_if_update_all(void); -extern void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p, +extern void bgp_zebra_announce(struct bgp_node *rn, const struct prefix *p, struct bgp_path_info *path, struct bgp *bgp, afi_t afi, safi_t safi); extern void bgp_zebra_announce_table(struct bgp *, afi_t, safi_t); -extern void bgp_zebra_withdraw(struct prefix *p, struct bgp_path_info *path, - struct bgp *bgp, safi_t safi); +extern void bgp_zebra_withdraw(const struct prefix *p, + struct bgp_path_info *path, struct bgp *bgp, + safi_t safi); extern void bgp_zebra_initiate_radv(struct bgp *bgp, struct peer *peer); extern void bgp_zebra_terminate_radv(struct bgp *bgp, struct peer *peer); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 9452770100..238a692bdf 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -65,7 +65,7 @@ #include "bgpd/bgp_nexthop.h" #include "bgpd/bgp_damp.h" #include "bgpd/bgp_mplsvpn.h" -#if ENABLE_BGP_VNC +#ifdef ENABLE_BGP_VNC #include "bgpd/rfapi/bgp_rfapi_cfg.h" #include "bgpd/rfapi/rfapi_backend.h" #endif @@ -2976,7 +2976,7 @@ static struct bgp *bgp_create(as_t *as, const char *name, bgp->as = *as; -#if ENABLE_BGP_VNC +#ifdef ENABLE_BGP_VNC if (inst_type != BGP_INSTANCE_TYPE_VRF) { bgp->rfapi = bgp_rfapi_new(bgp); assert(bgp->rfapi); @@ -3375,7 +3375,7 @@ int bgp_delete(struct bgp *bgp) /* TODO - Other memory may need to be freed - e.g., NHT */ -#if ENABLE_BGP_VNC +#ifdef ENABLE_BGP_VNC rfapi_delete(bgp); #endif bgp_cleanup_routes(bgp); @@ -4199,6 +4199,19 @@ static int peer_af_flag_modify(struct peer *peer, afi_t afi, safi_t safi, } } + /* + * If the peer is a route server client let's not + * muck with the nexthop on the way out the door + */ + if (flag & PEER_FLAG_RSERVER_CLIENT) { + if (set) + SET_FLAG(peer->af_flags[afi][safi], + PEER_FLAG_NEXTHOP_UNCHANGED); + else + UNSET_FLAG(peer->af_flags[afi][safi], + PEER_FLAG_NEXTHOP_UNCHANGED); + } + /* Inherit from peer-group or set/unset flags accordingly. */ if (peer_group_active(peer) && set == invert) peer_af_flag_inherit(peer, afi, safi, flag); @@ -5787,7 +5800,7 @@ static void peer_distribute_update(struct access_list *access) } } } -#if ENABLE_BGP_VNC +#ifdef ENABLE_BGP_VNC vnc_prefix_list_update(bgp); #endif } @@ -7023,7 +7036,7 @@ void bgp_init(unsigned short instance) /* Init zebra. */ bgp_zebra_init(bm->master, instance); -#if ENABLE_BGP_VNC +#ifdef ENABLE_BGP_VNC vnc_zebra_init(bm->master); #endif @@ -7038,7 +7051,7 @@ void bgp_init(unsigned short instance) bgp_route_map_init(); bgp_scan_vty_init(); bgp_mplsvpn_init(); -#if ENABLE_BGP_VNC +#ifdef ENABLE_BGP_VNC rfapi_init(); #endif bgp_ethernetvpn_init(); diff --git a/bgpd/rfapi/bgp_rfapi_cfg.h b/bgpd/rfapi/bgp_rfapi_cfg.h index b72d38220b..f1548a6173 100644 --- a/bgpd/rfapi/bgp_rfapi_cfg.h +++ b/bgpd/rfapi/bgp_rfapi_cfg.h @@ -24,7 +24,7 @@ #include "lib/table.h" #include "lib/routemap.h" -#if ENABLE_BGP_VNC +#ifdef ENABLE_BGP_VNC #include "rfapi.h" struct rfapi_l2_group_cfg { diff --git a/bgpd/rfapi/rfapi.c b/bgpd/rfapi/rfapi.c index d87292f652..435b61edf0 100644 --- a/bgpd/rfapi/rfapi.c +++ b/bgpd/rfapi/rfapi.c @@ -355,7 +355,7 @@ int rfapi_check(void *handle) void del_vnc_route(struct rfapi_descriptor *rfd, struct peer *peer, /* rfd->peer for RFP regs */ - struct bgp *bgp, safi_t safi, struct prefix *p, + struct bgp *bgp, safi_t safi, const struct prefix *p, struct prefix_rd *prd, uint8_t type, uint8_t sub_type, struct rfapi_nexthop *lnh, int kill) { @@ -557,7 +557,7 @@ void rfapi_vn_options_free(struct rfapi_vn_option *p) /* Based on bgp_redistribute_add() */ void add_vnc_route(struct rfapi_descriptor *rfd, /* cookie, VPN UN addr, peer */ - struct bgp *bgp, int safi, struct prefix *p, + struct bgp *bgp, int safi, const struct prefix *p, struct prefix_rd *prd, struct rfapi_ip_addr *nexthop, uint32_t *local_pref, uint32_t *lifetime, /* NULL => dont send lifetime */ diff --git a/bgpd/rfapi/rfapi.h b/bgpd/rfapi/rfapi.h index 6af2ebeeb8..beb44aa780 100644 --- a/bgpd/rfapi/rfapi.h +++ b/bgpd/rfapi/rfapi.h @@ -21,7 +21,7 @@ #ifndef _QUAGGA_BGP_RFAPI_H #define _QUAGGA_BGP_RFAPI_H -#if ENABLE_BGP_VNC +#ifdef ENABLE_BGP_VNC #include <stdint.h> #include <netinet/in.h> diff --git a/bgpd/rfapi/rfapi_ap.c b/bgpd/rfapi/rfapi_ap.c index c5fda15d33..abb18aeb2c 100644 --- a/bgpd/rfapi/rfapi_ap.c +++ b/bgpd/rfapi/rfapi_ap.c @@ -81,10 +81,10 @@ * is used to spread out the sort for adbs with the same lifetime * and thereby make the skip list operations more efficient. */ -static int sl_adb_lifetime_cmp(void *adb1, void *adb2) +static int sl_adb_lifetime_cmp(const void *adb1, const void *adb2) { - struct rfapi_adb *a1 = adb1; - struct rfapi_adb *a2 = adb2; + const struct rfapi_adb *a1 = adb1; + const struct rfapi_adb *a2 = adb2; if (a1->lifetime < a2->lifetime) return -1; diff --git a/bgpd/rfapi/rfapi_backend.h b/bgpd/rfapi/rfapi_backend.h index 96e464d2ae..4d2ae0b02f 100644 --- a/bgpd/rfapi/rfapi_backend.h +++ b/bgpd/rfapi/rfapi_backend.h @@ -21,7 +21,7 @@ #ifndef _QUAGGA_BGP_RFAPI_BACKEND_H #define _QUAGGA_BGP_RFAPI_BACKEND_H -#if ENABLE_BGP_VNC +#ifdef ENABLE_BGP_VNC #include "bgpd/bgp_route.h" #include "bgpd/bgp_nexthop.h" @@ -35,16 +35,16 @@ extern void rfapi_delete(struct bgp *); struct rfapi *bgp_rfapi_new(struct bgp *bgp); void bgp_rfapi_destroy(struct bgp *bgp, struct rfapi *h); -extern void rfapiProcessUpdate(struct peer *peer, void *rfd, struct prefix *p, - struct prefix_rd *prd, struct attr *attr, - afi_t afi, safi_t safi, uint8_t type, - uint8_t sub_type, uint32_t *label); +extern void rfapiProcessUpdate(struct peer *peer, void *rfd, + const struct prefix *p, struct prefix_rd *prd, + struct attr *attr, afi_t afi, safi_t safi, + uint8_t type, uint8_t sub_type, uint32_t *label); -extern void rfapiProcessWithdraw(struct peer *peer, void *rfd, struct prefix *p, - struct prefix_rd *prd, struct attr *attr, - afi_t afi, safi_t safi, uint8_t type, - int kill); +extern void rfapiProcessWithdraw(struct peer *peer, void *rfd, + const struct prefix *p, struct prefix_rd *prd, + struct attr *attr, afi_t afi, safi_t safi, + uint8_t type, int kill); extern void rfapiProcessPeerDown(struct peer *peer); @@ -56,7 +56,7 @@ extern void vnc_zebra_withdraw(struct prefix *p, struct bgp_path_info *old_select); -extern void rfapi_vty_out_vncinfo(struct vty *vty, struct prefix *p, +extern void rfapi_vty_out_vncinfo(struct vty *vty, const struct prefix *p, struct bgp_path_info *bpi, safi_t safi); diff --git a/bgpd/rfapi/rfapi_import.c b/bgpd/rfapi/rfapi_import.c index 2f274015fc..d058fe3b28 100644 --- a/bgpd/rfapi/rfapi_import.c +++ b/bgpd/rfapi/rfapi_import.c @@ -663,14 +663,17 @@ rfapiMonitorMoveShorter(struct agg_node *original_vpn_node, int lockoffset) * If no less-specific routes, try to use the 0/0 node */ if (!par) { + const struct prefix *p; /* this isn't necessarily 0/0 */ par = agg_route_table_top(original_vpn_node); + if (par) + p = agg_node_get_prefix(par); /* * If we got the top node but it wasn't 0/0, * ignore it */ - if (par && par->p.prefixlen) { + if (par && p->prefixlen) { agg_unlock_node(par); /* maybe free */ par = NULL; } @@ -685,9 +688,10 @@ rfapiMonitorMoveShorter(struct agg_node *original_vpn_node, int lockoffset) */ if (!par) { struct prefix pfx_default; + const struct prefix *p = agg_node_get_prefix(original_vpn_node); memset(&pfx_default, 0, sizeof(pfx_default)); - pfx_default.family = original_vpn_node->p.family; + pfx_default.family = p->family; /* creates default node if none exists */ par = agg_node_get(agg_get_table(original_vpn_node), @@ -768,6 +772,7 @@ static void rfapiMonitorMoveLonger(struct agg_node *new_vpn_node) struct rfapi_monitor_vpn *mlast; struct bgp_path_info *bpi; struct agg_node *par; + const struct prefix *new_vpn_node_p = agg_node_get_prefix(new_vpn_node); RFAPI_CHECK_REFCOUNT(new_vpn_node, SAFI_MPLS_VPN, 0); @@ -808,12 +813,11 @@ static void rfapiMonitorMoveLonger(struct agg_node *new_vpn_node) * specific updated node */ for (mlast = NULL, monitor = RFAPI_MONITOR_VPN(par); monitor;) { - /* * If new longest match for monitor prefix is the new * route's prefix, move monitor to new route's prefix */ - if (prefix_match(&new_vpn_node->p, &monitor->p)) { + if (prefix_match(new_vpn_node_p, &monitor->p)) { /* detach */ if (mlast) { mlast->next = monitor->next; @@ -1040,7 +1044,7 @@ int rfapiEcommunityGetEthernetTag(struct ecommunity *ecom, uint16_t *tag_id) for (i = 0; i < ecom->size; ++i) { as_t as = 0; int encode = 0; - uint8_t *p = ecom->val + (i * ECOMMUNITY_SIZE); + const uint8_t *p = ecom->val + (i * ECOMMUNITY_SIZE); /* High-order octet of type. */ encode = *p++; @@ -1266,6 +1270,7 @@ rfapiRouteInfo2NextHopEntry(struct rfapi_ip_prefix *rprefix, { struct rfapi_next_hop_entry *new; int have_vnc_tunnel_un = 0; + const struct prefix *p = agg_node_get_prefix(rn); #ifdef DEBUG_ENCAP_MONITOR vnc_zlog_debug_verbose("%s: entry, bpi %p, rn %p", __func__, bpi, rn); @@ -1289,8 +1294,7 @@ rfapiRouteInfo2NextHopEntry(struct rfapi_ip_prefix *rprefix, vo->type = RFAPI_VN_OPTION_TYPE_L2ADDR; - memcpy(&vo->v.l2addr.macaddr, &rn->p.u.prefix_eth.octet, - ETH_ALEN); + memcpy(&vo->v.l2addr.macaddr, &p->u.prefix_eth.octet, ETH_ALEN); /* only low 3 bytes of this are significant */ (void)rfapiEcommunityGetLNI(bpi->attr->ecommunity, &vo->v.l2addr.logical_net_id); @@ -1493,7 +1497,8 @@ static int rfapiNhlAddNodeRoutes( struct prefix pfx_un; struct skiplist *seen_nexthops; int count = 0; - int is_l2 = (rn->p.family == AF_ETHERNET); + const struct prefix *p = agg_node_get_prefix(rn); + int is_l2 = (p->family == AF_ETHERNET); if (rfd_rib_node) { struct agg_table *atable = agg_get_table(rfd_rib_node); @@ -1626,14 +1631,14 @@ static int rfapiNhlAddSubtree( * hands in node->link */ if (agg_node_left(rn) && agg_node_left(rn) != omit_node) { if (agg_node_left(rn)->info) { + const struct prefix *p = + agg_node_get_prefix(agg_node_left(rn)); int count = 0; struct agg_node *rib_rn = NULL; - rfapiQprefix2Rprefix(&agg_node_left(rn)->p, &rprefix); - if (rfd_rib_table) { - rib_rn = agg_node_get(rfd_rib_table, - &agg_node_left(rn)->p); - } + rfapiQprefix2Rprefix(p, &rprefix); + if (rfd_rib_table) + rib_rn = agg_node_get(rfd_rib_table, p); count = rfapiNhlAddNodeRoutes( agg_node_left(rn), &rprefix, lifetime, 0, head, @@ -1653,14 +1658,15 @@ static int rfapiNhlAddSubtree( if (agg_node_right(rn) && agg_node_right(rn) != omit_node) { if (agg_node_right(rn)->info) { + const struct prefix *p = + agg_node_get_prefix(agg_node_right(rn)); int count = 0; struct agg_node *rib_rn = NULL; - rfapiQprefix2Rprefix(&agg_node_right(rn)->p, &rprefix); - if (rfd_rib_table) { - rib_rn = agg_node_get(rfd_rib_table, - &agg_node_right(rn)->p); - } + rfapiQprefix2Rprefix(p, &rprefix); + if (rfd_rib_table) + rib_rn = agg_node_get(rfd_rib_table, p); + count = rfapiNhlAddNodeRoutes( agg_node_right(rn), &rprefix, lifetime, 0, head, tail, exclude_vnaddr, rib_rn, @@ -1712,23 +1718,18 @@ struct rfapi_next_hop_entry *rfapiRouteNode2NextHopList( struct rfapi_next_hop_entry *answer = NULL; struct rfapi_next_hop_entry *last = NULL; struct agg_node *parent; + const struct prefix *p = agg_node_get_prefix(rn); int count = 0; struct agg_node *rib_rn; #ifdef DEBUG_RETURNED_NHL - { - char buf[PREFIX_STRLEN]; - - prefix2str(&rn->p, buf, sizeof(buf)); - vnc_zlog_debug_verbose("%s: called with node pfx=%s", __func__, - buf); - } + vnc_zlog_debug_verbose("%s: called with node pfx=%rRN", __func__, rn); rfapiDebugBacktrace(); #endif - rfapiQprefix2Rprefix(&rn->p, &rprefix); + rfapiQprefix2Rprefix(p, &rprefix); - rib_rn = rfd_rib_table ? agg_node_get(rfd_rib_table, &rn->p) : NULL; + rib_rn = rfd_rib_table ? agg_node_get(rfd_rib_table, p) : NULL; /* * Add non-withdrawn routes at this node @@ -1780,9 +1781,10 @@ struct rfapi_next_hop_entry *rfapiRouteNode2NextHopList( * Add non-withdrawn routes from less-specific prefix */ if (parent) { - rib_rn = rfd_rib_table ? agg_node_get(rfd_rib_table, &parent->p) - : NULL; - rfapiQprefix2Rprefix(&parent->p, &rprefix); + const struct prefix *p = agg_node_get_prefix(parent); + + rib_rn = rfd_rib_table ? agg_node_get(rfd_rib_table, p) : NULL; + rfapiQprefix2Rprefix(p, &rprefix); count += rfapiNhlAddNodeRoutes(parent, &rprefix, lifetime, 0, &answer, &last, exclude_vnaddr, rib_rn, pfx_target_original); @@ -1863,7 +1865,9 @@ struct rfapi_next_hop_entry *rfapiEthRouteNode2NextHopList( struct rfapi_next_hop_entry *last = NULL; struct agg_node *rib_rn; - rib_rn = rfd_rib_table ? agg_node_get(rfd_rib_table, &rn->p) : NULL; + rib_rn = rfd_rib_table + ? agg_node_get(rfd_rib_table, agg_node_get_prefix(rn)) + : NULL; count = rfapiNhlAddNodeRoutes(rn, rprefix, lifetime, 0, &answer, &last, NULL, rib_rn, pfx_target_original); @@ -2006,10 +2010,10 @@ static void rfapiBgpInfoDetach(struct agg_node *rn, struct bgp_path_info *bpi) /* * For L3-indexed import tables */ -static int rfapi_bi_peer_rd_cmp(void *b1, void *b2) +static int rfapi_bi_peer_rd_cmp(const void *b1, const void *b2) { - struct bgp_path_info *bpi1 = b1; - struct bgp_path_info *bpi2 = b2; + const struct bgp_path_info *bpi1 = b1; + const struct bgp_path_info *bpi2 = b2; /* * Compare peers @@ -2022,8 +2026,9 @@ static int rfapi_bi_peer_rd_cmp(void *b1, void *b2) /* * compare RDs */ - return vnc_prefix_cmp((struct prefix *)&bpi1->extra->vnc.import.rd, - (struct prefix *)&bpi2->extra->vnc.import.rd); + return vnc_prefix_cmp( + (const struct prefix *)&bpi1->extra->vnc.import.rd, + (const struct prefix *)&bpi2->extra->vnc.import.rd); } /* @@ -2031,10 +2036,10 @@ static int rfapi_bi_peer_rd_cmp(void *b1, void *b2) * The BPIs in these tables should ALWAYS have an aux_prefix set because * they arrive via IPv4 or IPv6 advertisements. */ -static int rfapi_bi_peer_rd_aux_cmp(void *b1, void *b2) +static int rfapi_bi_peer_rd_aux_cmp(const void *b1, const void *b2) { - struct bgp_path_info *bpi1 = b1; - struct bgp_path_info *bpi2 = b2; + const struct bgp_path_info *bpi1 = b1; + const struct bgp_path_info *bpi2 = b2; int rc; /* @@ -2089,6 +2094,7 @@ static void rfapiItBiIndexAdd(struct agg_node *rn, /* Import table VPN node */ struct bgp_path_info *bpi) /* new BPI */ { struct skiplist *sl; + const struct prefix *p; assert(rn); assert(bpi); @@ -2105,7 +2111,8 @@ static void rfapiItBiIndexAdd(struct agg_node *rn, /* Import table VPN node */ sl = RFAPI_RDINDEX_W_ALLOC(rn); if (!sl) { - if (AF_ETHERNET == rn->p.family) { + p = agg_node_get_prefix(rn); + if (AF_ETHERNET == p->family) { sl = skiplist_new(0, rfapi_bi_peer_rd_aux_cmp, NULL); } else { sl = skiplist_new(0, rfapi_bi_peer_rd_cmp, NULL); @@ -2152,7 +2159,7 @@ static void rfapiItBiIndexDump(struct agg_node *rn) static struct bgp_path_info *rfapiItBiIndexSearch( struct agg_node *rn, /* Import table VPN node */ struct prefix_rd *prd, struct peer *peer, - struct prefix *aux_prefix) /* optional L3 addr for L2 ITs */ + const struct prefix *aux_prefix) /* optional L3 addr for L2 ITs */ { struct skiplist *sl; int rc; @@ -2375,7 +2382,7 @@ static int rfapiWithdrawTimerVPN(struct thread *t) struct rfapi_withdraw *wcb = t->arg; struct bgp_path_info *bpi = wcb->info; struct bgp *bgp = bgp_get_default(); - + const struct prefix *p; struct rfapi_monitor_vpn *moved; afi_t afi; @@ -2398,15 +2405,8 @@ static int rfapiWithdrawTimerVPN(struct thread *t) RFAPI_CHECK_REFCOUNT(wcb->node, SAFI_MPLS_VPN, wcb->lockoffset); - { - char buf[BUFSIZ]; - - vnc_zlog_debug_verbose( - "%s: removing bpi %p at prefix %s/%d", __func__, bpi, - rfapi_ntop(wcb->node->p.family, &wcb->node->p.u.prefix, - buf, BUFSIZ), - wcb->node->p.prefixlen); - } + vnc_zlog_debug_verbose("%s: removing bpi %p at prefix %pRN", __func__, + bpi, wcb->node); /* * Remove the route (doubly-linked) @@ -2415,7 +2415,8 @@ static int rfapiWithdrawTimerVPN(struct thread *t) && VALID_INTERIOR_TYPE(bpi->type)) RFAPI_MONITOR_EXTERIOR(wcb->node)->valid_interior_count--; - afi = family2afi(wcb->node->p.family); + p = agg_node_get_prefix(wcb->node); + afi = family2afi(p->family); wcb->import_table->holddown_count[afi] -= 1; /* keep count consistent */ rfapiItBiIndexDel(wcb->node, bpi); rfapiBgpInfoDetach(wcb->node, bpi); /* with removed bpi */ @@ -2846,11 +2847,13 @@ rfapiBiStartWithdrawTimer(struct rfapi_import_table *import_table, } -typedef void(rfapi_bi_filtered_import_f)(struct rfapi_import_table *, int, - struct peer *, void *, struct prefix *, - struct prefix *, afi_t, - struct prefix_rd *, struct attr *, - uint8_t, uint8_t, uint32_t *); +typedef void(rfapi_bi_filtered_import_f)(struct rfapi_import_table *table, + int action, struct peer *peer, + void *rfd, const struct prefix *prefix, + const struct prefix *aux_prefix, + afi_t afi, struct prefix_rd *prd, + struct attr *attr, uint8_t type, + uint8_t sub_type, uint32_t *label); static void rfapiExpireEncapNow(struct rfapi_import_table *it, @@ -2899,11 +2902,11 @@ static int rfapiGetNexthop(struct attr *attr, struct prefix *prefix) static void rfapiBgpInfoFilteredImportEncap( struct rfapi_import_table *import_table, int action, struct peer *peer, void *rfd, /* set for looped back routes */ - struct prefix *p, - struct prefix *aux_prefix, /* Unused for encap routes */ + const struct prefix *p, + const struct prefix *aux_prefix, /* Unused for encap routes */ afi_t afi, struct prefix_rd *prd, struct attr *attr, /* part of bgp_path_info */ - uint8_t type, /* part of bgp_path_info */ + uint8_t type, /* part of bgp_path_info */ uint8_t sub_type, /* part of bgp_path_info */ uint32_t *label) /* part of bgp_path_info */ { @@ -3074,11 +3077,8 @@ static void rfapiBgpInfoFilteredImportEncap( if (action == FIF_ACTION_WITHDRAW) { vnc_zlog_debug_verbose( - "%s: withdrawing at prefix %s/%d", - __func__, - inet_ntop(rn->p.family, &rn->p.u.prefix, - buf, BUFSIZ), - rn->p.prefixlen); + "%s: withdrawing at prefix %pRN", + __func__, rn); rfapiBiStartWithdrawTimer( import_table, rn, bpi, afi, SAFI_ENCAP, @@ -3086,13 +3086,11 @@ static void rfapiBgpInfoFilteredImportEncap( } else { vnc_zlog_debug_verbose( - "%s: %s at prefix %s/%d", __func__, + "%s: %s at prefix %pRN", __func__, ((action == FIF_ACTION_KILL) ? "killing" : "replacing"), - inet_ntop(rn->p.family, &rn->p.u.prefix, - buf, BUFSIZ), - rn->p.prefixlen); + rn); /* * If this route is waiting to be deleted @@ -3160,10 +3158,8 @@ static void rfapiBgpInfoFilteredImportEncap( rn = agg_node_get(rt, p); } - vnc_zlog_debug_verbose( - "%s: (afi=%d, rn=%p) inserting at prefix %s/%d", __func__, afi, - rn, inet_ntop(rn->p.family, &rn->p.u.prefix, buf, BUFSIZ), - rn->p.prefixlen); + vnc_zlog_debug_verbose("%s: (afi=%d, rn=%p) inserting at prefix %pRN", + __func__, afi, rn, rn); rfapiBgpInfoAttachSorted(rn, info_new, afi, SAFI_ENCAP); @@ -3246,6 +3242,7 @@ static void rfapiBgpInfoFilteredImportEncap( __func__, rn); #endif for (m = RFAPI_MONITOR_ENCAP(rn); m; m = m->next) { + const struct prefix *p; /* * For each referenced bpi/route, copy the ENCAP route's @@ -3273,9 +3270,9 @@ static void rfapiBgpInfoFilteredImportEncap( * list * per prefix. */ - + p = agg_node_get_prefix(m->node); referenced_vpn_prefix = - agg_node_get(referenced_vpn_table, &m->node->p); + agg_node_get(referenced_vpn_table, p); assert(referenced_vpn_prefix); for (mnext = referenced_vpn_prefix->info; mnext; mnext = mnext->next) { @@ -3360,11 +3357,11 @@ static void rfapiExpireVpnNow(struct rfapi_import_table *it, void rfapiBgpInfoFilteredImportVPN( struct rfapi_import_table *import_table, int action, struct peer *peer, void *rfd, /* set for looped back routes */ - struct prefix *p, - struct prefix *aux_prefix, /* AFI_L2VPN: optional IP */ + const struct prefix *p, + const struct prefix *aux_prefix, /* AFI_L2VPN: optional IP */ afi_t afi, struct prefix_rd *prd, struct attr *attr, /* part of bgp_path_info */ - uint8_t type, /* part of bgp_path_info */ + uint8_t type, /* part of bgp_path_info */ uint8_t sub_type, /* part of bgp_path_info */ uint32_t *label) /* part of bgp_path_info */ { @@ -3525,11 +3522,8 @@ void rfapiBgpInfoFilteredImportVPN( BGP_PATH_REMOVED); vnc_zlog_debug_verbose( - "%s: withdrawing at prefix %s/%d%s", - __func__, rfapi_ntop(rn->p.family, - &rn->p.u.prefix, - buf, BUFSIZ), - rn->p.prefixlen, + "%s: withdrawing at prefix %pRN%s", + __func__, rn, (washolddown ? " (already being withdrawn)" : "")); @@ -3548,14 +3542,11 @@ void rfapiBgpInfoFilteredImportVPN( VNC_ITRCCK; } else { vnc_zlog_debug_verbose( - "%s: %s at prefix %s/%d", __func__, + "%s: %s at prefix %pRN", __func__, ((action == FIF_ACTION_KILL) ? "killing" : "replacing"), - rfapi_ntop(rn->p.family, - &rn->p.u.prefix, buf, - BUFSIZ), - rn->p.prefixlen); + rn); /* * If this route is waiting to be deleted @@ -3673,10 +3664,8 @@ void rfapiBgpInfoFilteredImportVPN( info_new->extra->vnc.import.aux_prefix = *aux_prefix; } - vnc_zlog_debug_verbose( - "%s: inserting bpi %p at prefix %s/%d #%d", __func__, info_new, - rfapi_ntop(rn->p.family, &rn->p.u.prefix, buf, BUFSIZ), - rn->p.prefixlen, rn->lock); + vnc_zlog_debug_verbose("%s: inserting bpi %p at prefix %pRN #%d", + __func__, info_new, rn, rn->lock); rfapiBgpInfoAttachSorted(rn, info_new, afi, SAFI_MPLS_VPN); rfapiItBiIndexAdd(rn, info_new); @@ -3839,11 +3828,11 @@ void rfapiBgpInfoFilteredImportVPN( static void rfapiBgpInfoFilteredImportBadSafi( struct rfapi_import_table *import_table, int action, struct peer *peer, void *rfd, /* set for looped back routes */ - struct prefix *p, - struct prefix *aux_prefix, /* AFI_L2VPN: optional IP */ + const struct prefix *p, + const struct prefix *aux_prefix, /* AFI_L2VPN: optional IP */ afi_t afi, struct prefix_rd *prd, struct attr *attr, /* part of bgp_path_info */ - uint8_t type, /* part of bgp_path_info */ + uint8_t type, /* part of bgp_path_info */ uint8_t sub_type, /* part of bgp_path_info */ uint32_t *label) /* part of bgp_path_info */ { @@ -3869,7 +3858,7 @@ rfapiBgpInfoFilteredImportFunction(safi_t safi) void rfapiProcessUpdate(struct peer *peer, void *rfd, /* set when looped from RFP/RFAPI */ - struct prefix *p, struct prefix_rd *prd, + const struct prefix *p, struct prefix_rd *prd, struct attr *attr, afi_t afi, safi_t safi, uint8_t type, uint8_t sub_type, uint32_t *label) { @@ -3953,7 +3942,7 @@ void rfapiProcessUpdate(struct peer *peer, } -void rfapiProcessWithdraw(struct peer *peer, void *rfd, struct prefix *p, +void rfapiProcessWithdraw(struct peer *peer, void *rfd, const struct prefix *p, struct prefix_rd *prd, struct attr *attr, afi_t afi, safi_t safi, uint8_t type, int kill) { @@ -4224,9 +4213,11 @@ static void rfapiBgpTableFilteredImport(struct bgp *bgp, safi))( it, /* which import table */ FIF_ACTION_UPDATE, bpi->peer, - NULL, &rn2->p, /* prefix */ + NULL, bgp_node_get_prefix(rn2), NULL, afi, - (struct prefix_rd *)&rn1->p, + (struct prefix_rd *) + bgp_node_get_prefix( + rn1), bpi->attr, bpi->type, bpi->sub_type, &label); } @@ -4444,27 +4435,20 @@ static void rfapiDeleteRemotePrefixesIt( for (rn = agg_route_top(rt); rn; rn = agg_route_next(rn)) { struct bgp_path_info *bpi; struct bgp_path_info *next; + const struct prefix *rn_p = agg_node_get_prefix(rn); if (p && VNC_DEBUG(IMPORT_DEL_REMOTE)) { char p1line[PREFIX_STRLEN]; - char p2line[PREFIX_STRLEN]; prefix2str(p, p1line, sizeof(p1line)); - prefix2str(&rn->p, p2line, sizeof(p2line)); - vnc_zlog_debug_any("%s: want %s, have %s", - __func__, p1line, p2line); + vnc_zlog_debug_any("%s: want %s, have %pRN", + __func__, p1line, rn); } - if (p && prefix_cmp(p, &rn->p)) + if (p && prefix_cmp(p, rn_p)) continue; - { - char buf_pfx[PREFIX_STRLEN]; - - prefix2str(&rn->p, buf_pfx, sizeof(buf_pfx)); - vnc_zlog_debug_verbose("%s: rn pfx=%s", - __func__, buf_pfx); - } + vnc_zlog_debug_verbose("%s: rn pfx=%pRN", __func__, rn); /* TBD is this valid for afi == AFI_L2VPN? */ RFAPI_CHECK_REFCOUNT(rn, SAFI_MPLS_VPN, 1); @@ -4596,7 +4580,7 @@ static void rfapiDeleteRemotePrefixesIt( } } - vnc_direct_bgp_rh_del_route(bgp, afi, &rn->p, + vnc_direct_bgp_rh_del_route(bgp, afi, rn_p, bpi->peer); RFAPI_UPDATE_ITABLE_COUNT(bpi, it, afi, -1); diff --git a/bgpd/rfapi/rfapi_import.h b/bgpd/rfapi/rfapi_import.h index 1ab9cc5193..50093111c2 100644 --- a/bgpd/rfapi/rfapi_import.h +++ b/bgpd/rfapi/rfapi_import.h @@ -143,11 +143,11 @@ extern void rfapiUnicastNexthop2Prefix(afi_t afi, struct attr *attr, extern void rfapiBgpInfoFilteredImportVPN( struct rfapi_import_table *import_table, int action, struct peer *peer, void *rfd, /* set for looped back routes */ - struct prefix *p, - struct prefix *aux_prefix, /* AFI_ETHER: optional IP */ + const struct prefix *p, + const struct prefix *aux_prefix, /* AFI_ETHER: optional IP */ afi_t afi, struct prefix_rd *prd, struct attr *attr, /* part of bgp_path_info */ - uint8_t type, /* part of bgp_path_info */ + uint8_t type, /* part of bgp_path_info */ uint8_t sub_type, /* part of bgp_path_info */ uint32_t *label); /* part of bgp_path_info */ diff --git a/bgpd/rfapi/rfapi_monitor.c b/bgpd/rfapi/rfapi_monitor.c index dc1f7e0fbb..0b8dfc3554 100644 --- a/bgpd/rfapi/rfapi_monitor.c +++ b/bgpd/rfapi/rfapi_monitor.c @@ -789,7 +789,8 @@ static void rfapiMonitorTimerRestart(struct rfapi_monitor_vpn *m) * been responsible for the response, i.e., any monitors for * the exact prefix or a parent of it. */ -void rfapiMonitorTimersRestart(struct rfapi_descriptor *rfd, struct prefix *p) +void rfapiMonitorTimersRestart(struct rfapi_descriptor *rfd, + const struct prefix *p) { struct agg_node *rn; @@ -818,12 +819,14 @@ void rfapiMonitorTimersRestart(struct rfapi_descriptor *rfd, struct prefix *p) for (rn = agg_route_top(rfd->mon); rn; rn = agg_route_next(rn)) { struct rfapi_monitor_vpn *m; + const struct prefix *p_node; if (!((m = rn->info))) continue; + p_node = agg_node_get_prefix(m->node); /* NB order of test is significant ! */ - if (!m->node || prefix_match(&m->node->p, p)) { + if (!m->node || prefix_match(p_node, p)) { rfapiMonitorTimerRestart(m); } } @@ -841,7 +844,8 @@ void rfapiMonitorItNodeChanged( struct skiplist *nves_seen; struct agg_node *rn = it_node; struct bgp *bgp = bgp_get_default(); - afi_t afi = family2afi(rn->p.family); + const struct prefix *p = agg_node_get_prefix(rn); + afi_t afi = family2afi(p->family); #if DEBUG_L2_EXTRA char buf_prefix[PREFIX_STRLEN]; #endif @@ -931,17 +935,14 @@ void rfapiMonitorItNodeChanged( assert(!skiplist_insert(nves_seen, m->rfd, NULL)); - char buf_attach_pfx[PREFIX_STRLEN]; char buf_target_pfx[PREFIX_STRLEN]; - prefix2str(&m->node->p, buf_attach_pfx, - sizeof(buf_attach_pfx)); prefix2str(&m->p, buf_target_pfx, sizeof(buf_target_pfx)); vnc_zlog_debug_verbose( - "%s: update rfd %p attached to pfx %s (targ=%s)", - __func__, m->rfd, - buf_attach_pfx, buf_target_pfx); + "%s: update rfd %p attached to pfx %pRN (targ=%s)", + __func__, m->rfd, m->node, + buf_target_pfx); /* * update its RIB @@ -1103,10 +1104,10 @@ static void rfapiMonitorEthTimerRestart(struct rfapi_monitor_eth *m) m->rfd->response_lifetime, &m->timer); } -static int mon_eth_cmp(void *a, void *b) +static int mon_eth_cmp(const void *a, const void *b) { - struct rfapi_monitor_eth *m1; - struct rfapi_monitor_eth *m2; + const struct rfapi_monitor_eth *m1; + const struct rfapi_monitor_eth *m2; int i; @@ -1272,7 +1273,7 @@ static void rfapiMonitorEthDetachImport( #if DEBUG_L2_EXTRA char buf_prefix[PREFIX_STRLEN]; - prefix2str(&rn->p, buf_prefix, sizeof(buf_prefix)); + prefix2str(agg_node_get_prefix(rn), buf_prefix, sizeof(buf_prefix)); #endif /* diff --git a/bgpd/rfapi/rfapi_monitor.h b/bgpd/rfapi/rfapi_monitor.h index b8eec56475..3a2248aa60 100644 --- a/bgpd/rfapi/rfapi_monitor.h +++ b/bgpd/rfapi/rfapi_monitor.h @@ -167,7 +167,7 @@ extern void rfapiMonitorResponseRemovalOn(struct bgp *bgp); extern void rfapiMonitorExtraPrune(safi_t safi, struct agg_node *rn); extern void rfapiMonitorTimersRestart(struct rfapi_descriptor *rfd, - struct prefix *p); + const struct prefix *p); extern void rfapiMonitorItNodeChanged(struct rfapi_import_table *import_table, struct agg_node *it_node, diff --git a/bgpd/rfapi/rfapi_nve_addr.c b/bgpd/rfapi/rfapi_nve_addr.c index ee54d88c3f..b8193f1431 100644 --- a/bgpd/rfapi/rfapi_nve_addr.c +++ b/bgpd/rfapi/rfapi_nve_addr.c @@ -58,10 +58,10 @@ static void logdifferent(const char *tag, struct rfapi_nve_addr *a, #endif -int rfapi_nve_addr_cmp(void *k1, void *k2) +int rfapi_nve_addr_cmp(const void *k1, const void *k2) { - struct rfapi_nve_addr *a = (struct rfapi_nve_addr *)k1; - struct rfapi_nve_addr *b = (struct rfapi_nve_addr *)k2; + const struct rfapi_nve_addr *a = (struct rfapi_nve_addr *)k1; + const struct rfapi_nve_addr *b = (struct rfapi_nve_addr *)k2; int ret = 0; if (!a || !b) { diff --git a/bgpd/rfapi/rfapi_nve_addr.h b/bgpd/rfapi/rfapi_nve_addr.h index 2d54d4a3cc..7bcb3cab69 100644 --- a/bgpd/rfapi/rfapi_nve_addr.h +++ b/bgpd/rfapi/rfapi_nve_addr.h @@ -30,7 +30,7 @@ struct rfapi_nve_addr { }; -extern int rfapi_nve_addr_cmp(void *k1, void *k2); +extern int rfapi_nve_addr_cmp(const void *k1, const void *k2); extern void rfapiNveAddr2Str(struct rfapi_nve_addr *na, char *buf, int bufsize); diff --git a/bgpd/rfapi/rfapi_private.h b/bgpd/rfapi/rfapi_private.h index ff1cf7ef42..68caba600a 100644 --- a/bgpd/rfapi/rfapi_private.h +++ b/bgpd/rfapi/rfapi_private.h @@ -272,16 +272,13 @@ struct rfapi { ? ((prefix)->prefixlen == 128) \ : 0)) -extern void rfapiQprefix2Rprefix(struct prefix *qprefix, - struct rfapi_ip_prefix *rprefix); - extern int rfapi_find_rfd(struct bgp *bgp, struct rfapi_ip_addr *vn_addr, struct rfapi_ip_addr *un_addr, struct rfapi_descriptor **rfd); extern void add_vnc_route(struct rfapi_descriptor *rfd, /* cookie + UN addr for VPN */ - struct bgp *bgp, int safi, struct prefix *p, + struct bgp *bgp, int safi, const struct prefix *p, struct prefix_rd *prd, struct rfapi_ip_addr *nexthop, uint32_t *local_pref, /* host byte order */ uint32_t *lifetime, /* host byte order */ @@ -297,7 +294,7 @@ add_vnc_route(struct rfapi_descriptor *rfd, /* cookie + UN addr for VPN */ #endif extern void del_vnc_route(struct rfapi_descriptor *rfd, struct peer *peer, - struct bgp *bgp, safi_t safi, struct prefix *p, + struct bgp *bgp, safi_t safi, const struct prefix *p, struct prefix_rd *prd, uint8_t type, uint8_t sub_type, struct rfapi_nexthop *lnh, int kill); diff --git a/bgpd/rfapi/rfapi_rib.c b/bgpd/rfapi/rfapi_rib.c index 3d4bdef75a..04a538dc63 100644 --- a/bgpd/rfapi/rfapi_rib.c +++ b/bgpd/rfapi/rfapi_rib.c @@ -340,7 +340,6 @@ static void rfapiRibStartTimer(struct rfapi_descriptor *rfd, { struct thread *t = ri->timer; struct rfapi_rib_tcb *tcb = NULL; - char buf_prefix[PREFIX_STRLEN]; if (t) { tcb = t->arg; @@ -361,9 +360,8 @@ static void rfapiRibStartTimer(struct rfapi_descriptor *rfd, UNSET_FLAG(tcb->flags, RFAPI_RIB_TCB_FLAG_DELETED); } - prefix2str(&rn->p, buf_prefix, sizeof(buf_prefix)); - vnc_zlog_debug_verbose("%s: rfd %p pfx %s life %u", __func__, rfd, - buf_prefix, ri->lifetime); + vnc_zlog_debug_verbose("%s: rfd %p pfx %pRN life %u", __func__, rfd, rn, + ri->lifetime); ri->timer = NULL; thread_add_timer(bm->master, rfapiRibExpireTimer, tcb, ri->lifetime, &ri->timer); @@ -388,10 +386,10 @@ extern void rfapi_rib_key_init(struct prefix *prefix, /* may be NULL */ /* * Compares two <struct rfapi_rib_key>s */ -int rfapi_rib_key_cmp(void *k1, void *k2) +int rfapi_rib_key_cmp(const void *k1, const void *k2) { - struct rfapi_rib_key *a = (struct rfapi_rib_key *)k1; - struct rfapi_rib_key *b = (struct rfapi_rib_key *)k2; + const struct rfapi_rib_key *a = (struct rfapi_rib_key *)k1; + const struct rfapi_rib_key *b = (struct rfapi_rib_key *)k2; int ret; if (!a || !b) @@ -741,11 +739,12 @@ int rfapiRibPreloadBi( struct rfapi_rib_key rk; struct agg_node *trn; afi_t afi; + const struct prefix *p = agg_node_get_prefix(rfd_rib_node); if (!rfd_rib_node) return 0; - afi = family2afi(rfd_rib_node->p.family); + afi = family2afi(p->family); rfd = agg_get_table_info(agg_get_table(rfd_rib_node)); @@ -803,8 +802,7 @@ int rfapiRibPreloadBi( /* * Update last sent time for prefix */ - trn = agg_node_get(rfd->rsp_times[afi], - &rfd_rib_node->p); /* locks trn */ + trn = agg_node_get(rfd->rsp_times[afi], p); /* locks trn */ trn->info = (void *)(uintptr_t)bgp_clock(); if (trn->lock > 1) agg_unlock_node(trn); @@ -852,10 +850,9 @@ static void process_pending_node(struct bgp *bgp, struct rfapi_descriptor *rfd, struct list *lPendCost = NULL; struct list *delete_list = NULL; int printedprefix = 0; - char buf_prefix[PREFIX_STRLEN]; int rib_node_started_nonempty = 0; int sendingsomeroutes = 0; - + const struct prefix *p; #if DEBUG_PROCESS_PENDING_NODE unsigned int count_rib_initial = 0; unsigned int count_pend_vn_initial = 0; @@ -863,12 +860,12 @@ static void process_pending_node(struct bgp *bgp, struct rfapi_descriptor *rfd, #endif assert(pn); - prefix2str(&pn->p, buf_prefix, sizeof(buf_prefix)); - vnc_zlog_debug_verbose("%s: afi=%d, %s pn->info=%p", __func__, afi, - buf_prefix, pn->info); + p = agg_node_get_prefix(pn); + vnc_zlog_debug_verbose("%s: afi=%d, %pRN pn->info=%p", __func__, afi, + pn, pn->info); if (AFI_L2VPN != afi) { - rfapiQprefix2Rprefix(&pn->p, &hp); + rfapiQprefix2Rprefix(p, &hp); } RFAPI_RIB_CHECK_COUNTS(1, 0); @@ -876,7 +873,7 @@ static void process_pending_node(struct bgp *bgp, struct rfapi_descriptor *rfd, /* * Find corresponding RIB node */ - rn = agg_node_get(rfd->rib[afi], &pn->p); /* locks rn */ + rn = agg_node_get(rfd->rib[afi], p); /* locks rn */ /* * RIB skiplist has key=rfapi_addr={vn,un}, val = rfapi_info, @@ -935,9 +932,9 @@ static void process_pending_node(struct bgp *bgp, struct rfapi_descriptor *rfd, prefix2str(&ri->rk.vn, buf, sizeof(buf)); prefix2str(&ri->un, buf2, sizeof(buf2)); vnc_zlog_debug_verbose( - "%s: put dl pfx=%s vn=%s un=%s cost=%d life=%d vn_options=%p", - __func__, buf_prefix, buf, buf2, - ri->cost, ri->lifetime, ri->vn_options); + "%s: put dl pfx=%pRN vn=%s un=%s cost=%d life=%d vn_options=%p", + __func__, pn, buf, buf2, ri->cost, + ri->lifetime, ri->vn_options); skiplist_delete_first(slRibPt); } @@ -1186,8 +1183,7 @@ callback: vnc_zlog_debug_verbose("%s: lPendCost->count now %d", __func__, lPendCost->count); - vnc_zlog_debug_verbose("%s: For prefix %s (a)", __func__, - buf_prefix); + vnc_zlog_debug_verbose("%s: For prefix %pRN (a)", __func__, pn); printedprefix = 1; for (ALL_LIST_ELEMENTS(lPendCost, node, nnode, ri)) { @@ -1246,7 +1242,7 @@ callback: * update this NVE's timestamp for this prefix */ trn = agg_node_get(rfd->rsp_times[afi], - &pn->p); /* locks trn */ + p); /* locks trn */ trn->info = (void *)(uintptr_t)bgp_clock(); if (trn->lock > 1) agg_unlock_node(trn); @@ -1268,8 +1264,8 @@ callback: char buf2[BUFSIZ]; if (!printedprefix) { - vnc_zlog_debug_verbose("%s: For prefix %s (d)", - __func__, buf_prefix); + vnc_zlog_debug_verbose("%s: For prefix %pRN (d)", + __func__, pn); } vnc_zlog_debug_verbose("%s: delete_list has %d elements", __func__, delete_list->count); @@ -1465,7 +1461,7 @@ callback: } if (sendingsomeroutes) - rfapiMonitorTimersRestart(rfd, &pn->p); + rfapiMonitorTimersRestart(rfd, p); agg_unlock_node(rn); /* agg_node_get() */ @@ -1589,7 +1585,7 @@ void rfapiRibUpdatePendingNode( struct rfapi_import_table *it, /* needed for L2 */ struct agg_node *it_node, uint32_t lifetime) { - struct prefix *prefix; + const struct prefix *prefix; struct bgp_path_info *bpi; struct agg_node *pn; afi_t afi; @@ -1606,7 +1602,7 @@ void rfapiRibUpdatePendingNode( RFAPI_RIB_CHECK_COUNTS(1, 0); - prefix = &it_node->p; + prefix = agg_node_get_prefix(it_node); afi = family2afi(prefix->family); prefix2str(prefix, buf, sizeof(buf)); vnc_zlog_debug_verbose("%s: prefix=%s", __func__, buf); @@ -1794,7 +1790,8 @@ int rfapiRibFTDFilterRecentPrefix( struct prefix *pfx_target_original) /* query target */ { struct bgp *bgp = rfd->bgp; - afi_t afi = family2afi(it_rn->p.family); + const struct prefix *p = agg_node_get_prefix(it_rn); + afi_t afi = family2afi(p->family); time_t prefix_time; struct agg_node *trn; @@ -1809,14 +1806,15 @@ int rfapiRibFTDFilterRecentPrefix( * This matches behavior of now-obsolete rfapiRibFTDFilterRecent(), * but we need to decide if that is correct. */ - if (it_rn->p.family == AF_ETHERNET) + if (p->family == AF_ETHERNET) return 0; #ifdef DEBUG_FTD_FILTER_RECENT { char buf_pfx[PREFIX_STRLEN]; - prefix2str(&it_rn->p, buf_pfx, sizeof(buf_pfx)); + prefix2str(agg_node_get_prefix(it_rn), buf_pfx, + sizeof(buf_pfx)); vnc_zlog_debug_verbose("%s: prefix %s", __func__, buf_pfx); } #endif @@ -1824,7 +1822,7 @@ int rfapiRibFTDFilterRecentPrefix( /* * prefix covers target address, so allow prefix */ - if (prefix_match(&it_rn->p, pfx_target_original)) { + if (prefix_match(p, pfx_target_original)) { #ifdef DEBUG_FTD_FILTER_RECENT vnc_zlog_debug_verbose("%s: prefix covers target, allowed", __func__); @@ -1835,7 +1833,7 @@ int rfapiRibFTDFilterRecentPrefix( /* * check this NVE's timestamp for this prefix */ - trn = agg_node_get(rfd->rsp_times[afi], &it_rn->p); /* locks trn */ + trn = agg_node_get(rfd->rsp_times[afi], p); /* locks trn */ prefix_time = (time_t)trn->info; if (trn->lock > 1) agg_unlock_node(trn); @@ -1997,7 +1995,8 @@ rfapiRibPreload(struct bgp *bgp, struct rfapi_descriptor *rfd, } vnc_zlog_debug_verbose( "%s: RIB skiplist for this prefix follows", __func__); - rfapiRibShowRibSl(NULL, &rn->p, (struct skiplist *)rn->info); + rfapiRibShowRibSl(NULL, agg_node_get_prefix(rn), + (struct skiplist *)rn->info); #endif @@ -2114,11 +2113,10 @@ void rfapiRibPendingDeleteRoute(struct bgp *bgp, struct rfapi_import_table *it, { struct rfapi_descriptor *rfd; struct listnode *node; - char buf[PREFIX_STRLEN]; + const struct prefix *p = agg_node_get_prefix(it_node); - prefix2str(&it_node->p, buf, sizeof(buf)); - vnc_zlog_debug_verbose("%s: entry, it=%p, afi=%d, it_node=%p, pfx=%s", - __func__, it, afi, it_node, buf); + vnc_zlog_debug_verbose("%s: entry, it=%p, afi=%d, it_node=%p, pfx=%pRN", + __func__, it, afi, it_node, it_node); if (AFI_L2VPN == afi) { /* @@ -2157,7 +2155,7 @@ void rfapiRibPendingDeleteRoute(struct bgp *bgp, struct rfapi_import_table *it, * delete */ if ((rn = agg_node_lookup(m->rfd->rib[afi], - &it_node->p))) { + p))) { rfapiRibUpdatePendingNode( bgp, m->rfd, it, it_node, m->rfd->response_lifetime); @@ -2179,8 +2177,7 @@ void rfapiRibPendingDeleteRoute(struct bgp *bgp, struct rfapi_import_table *it, * this * NVE, it's OK to send an update with the delete */ - if ((rn = agg_node_lookup(m->rfd->rib[afi], - &it_node->p))) { + if ((rn = agg_node_lookup(m->rfd->rib[afi], p))) { rfapiRibUpdatePendingNode( bgp, m->rfd, it, it_node, m->rfd->response_lifetime); @@ -2212,8 +2209,7 @@ void rfapiRibPendingDeleteRoute(struct bgp *bgp, struct rfapi_import_table *it, * prefix * previously, we should send an updated response. */ - if ((rn = agg_node_lookup(rfd->rib[afi], - &it_node->p))) { + if ((rn = agg_node_lookup(rfd->rib[afi], p))) { rfapiRibUpdatePendingNode( bgp, rfd, it, it_node, rfd->response_lifetime); @@ -2416,7 +2412,8 @@ void rfapiRibShowResponses(void *stream, struct prefix *pfx_match, for (rn = agg_route_top(rfd->rib[afi]); rn; rn = agg_route_next(rn)) { - + const struct prefix *p = + agg_node_get_prefix(rn); struct skiplist *sl; char str_pfx[PREFIX_STRLEN]; int printedprefix = 0; @@ -2433,9 +2430,8 @@ void rfapiRibShowResponses(void *stream, struct prefix *pfx_match, nhs_total += skiplist_count(sl); ++prefixes_total; - if (pfx_match - && !prefix_match(pfx_match, &rn->p) - && !prefix_match(&rn->p, pfx_match)) + if (pfx_match && !prefix_match(pfx_match, p) + && !prefix_match(p, pfx_match)) continue; ++prefixes_displayed; @@ -2472,7 +2468,7 @@ void rfapiRibShowResponses(void *stream, struct prefix *pfx_match, str_un, BUFSIZ)); } - prefix2str(&rn->p, str_pfx, sizeof(str_pfx)); + prefix2str(p, str_pfx, sizeof(str_pfx)); // fp(out, " %s\n", buf); /* prefix */ routes_displayed++; diff --git a/bgpd/rfapi/rfapi_rib.h b/bgpd/rfapi/rfapi_rib.h index 38a6df9fbf..3ad021b4f4 100644 --- a/bgpd/rfapi/rfapi_rib.h +++ b/bgpd/rfapi/rfapi_rib.h @@ -147,7 +147,7 @@ extern void rfapi_rib_key_init(struct prefix *prefix, /* may be NULL */ struct prefix *aux, /* may be NULL */ struct rfapi_rib_key *rk); -extern int rfapi_rib_key_cmp(void *k1, void *k2); +extern int rfapi_rib_key_cmp(const void *k1, const void *k2); extern void rfapiAdbFree(struct rfapi_adb *adb); diff --git a/bgpd/rfapi/rfapi_vty.c b/bgpd/rfapi/rfapi_vty.c index 58fdc7c130..5a84d14bd9 100644 --- a/bgpd/rfapi/rfapi_vty.c +++ b/bgpd/rfapi/rfapi_vty.c @@ -194,7 +194,7 @@ int rfapiQprefix2Raddr(struct prefix *qprefix, struct rfapi_ip_addr *raddr) * Translate Quagga prefix to RFAPI prefix */ /* rprefix->cost set to 0 */ -void rfapiQprefix2Rprefix(struct prefix *qprefix, +void rfapiQprefix2Rprefix(const struct prefix *qprefix, struct rfapi_ip_prefix *rprefix) { memset(rprefix, 0, sizeof(struct rfapi_ip_prefix)); @@ -393,7 +393,7 @@ int rfapiStream2Vty(void *stream, /* input */ } /* called from bgpd/bgp_vty.c'route_vty_out() */ -void rfapi_vty_out_vncinfo(struct vty *vty, struct prefix *p, +void rfapi_vty_out_vncinfo(struct vty *vty, const struct prefix *p, struct bgp_path_info *bpi, safi_t safi) { char *s; @@ -743,7 +743,6 @@ static void rfapiDebugPrintMonitorEncap(void *stream, void rfapiShowItNode(void *stream, struct agg_node *rn) { struct bgp_path_info *bpi; - char buf[BUFSIZ]; int (*fp)(void *, const char *, ...); struct vty *vty; @@ -753,9 +752,7 @@ void rfapiShowItNode(void *stream, struct agg_node *rn) if (rfapiStream2Vty(stream, &fp, &vty, &out, &vty_newline) == 0) return; - fp(out, "%s/%d @%p #%d%s", - rfapi_ntop(rn->p.family, &rn->p.u.prefix, buf, BUFSIZ), - rn->p.prefixlen, rn, rn->lock, HVTYNL); + fp(out, "%pRN @%p #%d%s", rn, rn, rn->lock, HVTYNL); for (bpi = rn->info; bpi; bpi = bpi->next) { rfapiPrintBi(stream, bpi); @@ -782,14 +779,15 @@ void rfapiShowImportTable(void *stream, const char *label, struct agg_table *rt, for (rn = agg_route_top(rt); rn; rn = agg_route_next(rn)) { struct bgp_path_info *bpi; + const struct prefix *p = agg_node_get_prefix(rn); - if (rn->p.family == AF_ETHERNET) { - rfapiEthAddr2Str(&rn->p.u.prefix_eth, buf, BUFSIZ); + if (p->family == AF_ETHERNET) { + rfapiEthAddr2Str(&p->u.prefix_eth, buf, BUFSIZ); } else { - inet_ntop(rn->p.family, &rn->p.u.prefix, buf, BUFSIZ); + inet_ntop(p->family, &p->u.prefix, buf, BUFSIZ); } - fp(out, "%s/%d @%p #%d%s", buf, rn->p.prefixlen, rn, + fp(out, "%s/%d @%p #%d%s", buf, p->prefixlen, rn, rn->lock - 1, /* account for loop iterator locking */ HVTYNL); @@ -868,6 +866,8 @@ int rfapiShowVncQueries(void *stream, struct prefix *pfx_match) if (rfd->mon) { for (rn = agg_route_top(rfd->mon); rn; rn = agg_route_next(rn)) { + const struct prefix *p = + agg_node_get_prefix(rn); struct rfapi_monitor_vpn *m; char buf_remain[BUFSIZ]; char buf_pfx[BUFSIZ]; @@ -879,9 +879,8 @@ int rfapiShowVncQueries(void *stream, struct prefix *pfx_match) ++queries_total; - if (pfx_match - && !prefix_match(pfx_match, &rn->p) - && !prefix_match(&rn->p, pfx_match)) + if (pfx_match && !prefix_match(pfx_match, p) + && !prefix_match(p, pfx_match)) continue; ++queries_displayed; @@ -1028,6 +1027,7 @@ static int rfapiPrintRemoteRegBi(struct bgp *bgp, void *stream, char buf_vn[BUFSIZ]; char buf_lifetime[BUFSIZ]; int nlines = 0; + const struct prefix *p = agg_node_get_prefix(rn); if (!stream) return 0; /* for debug log, print into buf & call output once */ @@ -1040,8 +1040,8 @@ static int rfapiPrintRemoteRegBi(struct bgp *bgp, void *stream, */ buf_pfx[0] = 0; snprintf(buf_pfx, BUFSIZ, "%s/%d", - rfapi_ntop(rn->p.family, &rn->p.u.prefix, buf_ntop, BUFSIZ), - rn->p.prefixlen); + rfapi_ntop(p->family, &p->u.prefix, buf_ntop, BUFSIZ), + p->prefixlen); buf_pfx[BUFSIZ - 1] = 0; nlines++; @@ -1155,7 +1155,7 @@ static int rfapiPrintRemoteRegBi(struct bgp *bgp, void *stream, } fp(out, "%s", HVTYNL); - if (rn->p.family == AF_ETHERNET) { + if (p->family == AF_ETHERNET) { /* * If there is a corresponding IP address && != VN address, * print that on the next line @@ -1221,13 +1221,13 @@ static int rfapiShowRemoteRegistrationsIt(struct bgp *bgp, void *stream, for (rn = agg_route_top(it->imported_vpn[afi]); rn; rn = agg_route_next(rn)) { - + const struct prefix *p = agg_node_get_prefix(rn); struct bgp_path_info *bpi; int count_only; /* allow for wider or more narrow mask from user */ - if (prefix_only && !prefix_match(prefix_only, &rn->p) - && !prefix_match(&rn->p, prefix_only)) + if (prefix_only && !prefix_match(prefix_only, p) + && !prefix_match(p, prefix_only)) count_only = 1; else count_only = 0; @@ -2754,10 +2754,10 @@ static void nve_addr_free(void *hap) XFREE(MTYPE_RFAPI_NVE_ADDR, hap); } -static int nve_addr_cmp(void *k1, void *k2) +static int nve_addr_cmp(const void *k1, const void *k2) { - struct nve_addr *a = (struct nve_addr *)k1; - struct nve_addr *b = (struct nve_addr *)k2; + const struct nve_addr *a = (struct nve_addr *)k1; + const struct nve_addr *b = (struct nve_addr *)k2; int ret = 0; if (!a || !b) { diff --git a/bgpd/rfapi/rfapi_vty.h b/bgpd/rfapi/rfapi_vty.h index 8b881292ac..b5e1c38b0d 100644 --- a/bgpd/rfapi/rfapi_vty.h +++ b/bgpd/rfapi/rfapi_vty.h @@ -43,7 +43,7 @@ extern void rfapiRprefixApplyMask(struct rfapi_ip_prefix *rprefix); extern int rfapiQprefix2Raddr(struct prefix *qprefix, struct rfapi_ip_addr *raddr); -extern void rfapiQprefix2Rprefix(struct prefix *qprefix, +extern void rfapiQprefix2Rprefix(const struct prefix *qprefix, struct rfapi_ip_prefix *rprefix); extern int rfapiRprefix2Qprefix(struct rfapi_ip_prefix *rprefix, diff --git a/bgpd/rfapi/vnc_debug.h b/bgpd/rfapi/vnc_debug.h index dd49383072..c472b6366e 100644 --- a/bgpd/rfapi/vnc_debug.h +++ b/bgpd/rfapi/vnc_debug.h @@ -20,7 +20,7 @@ #ifndef _QUAGGA_BGP_VNC_DEBUG_H #define _QUAGGA_BGP_VNC_DEBUG_H -#if ENABLE_BGP_VNC +#ifdef ENABLE_BGP_VNC /* * debug state storage diff --git a/bgpd/rfapi/vnc_export_bgp.c b/bgpd/rfapi/vnc_export_bgp.c index 3d34d696b5..a7aa4c66fa 100644 --- a/bgpd/rfapi/vnc_export_bgp.c +++ b/bgpd/rfapi/vnc_export_bgp.c @@ -177,7 +177,7 @@ void vnc_direct_bgp_add_route_ce(struct bgp *bgp, struct agg_node *rn, { struct attr *attr = bpi->attr; struct peer *peer = bpi->peer; - struct prefix *prefix = &rn->p; + const struct prefix *prefix = agg_node_get_prefix(rn); afi_t afi = family2afi(prefix->family); struct bgp_node *urn; struct bgp_path_info *ubpi; @@ -330,7 +330,8 @@ void vnc_direct_bgp_add_route_ce(struct bgp *bgp, struct agg_node *rn, void vnc_direct_bgp_del_route_ce(struct bgp *bgp, struct agg_node *rn, struct bgp_path_info *bpi) { - afi_t afi = family2afi(rn->p.family); + const struct prefix *p = agg_node_get_prefix(rn); + afi_t afi = family2afi(p->family); struct bgp_path_info *vbpi; struct prefix ce_nexthop; @@ -395,8 +396,8 @@ void vnc_direct_bgp_del_route_ce(struct bgp *bgp, struct agg_node *rn, /* * withdraw the route */ - bgp_withdraw(bpi->peer, &rn->p, 0, /* addpath_id */ - NULL, /* attr, ignored */ + bgp_withdraw(bpi->peer, p, 0, /* addpath_id */ + NULL, /* attr, ignored */ afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT, BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */ NULL, 0, NULL); /* tag not used for unicast */ @@ -432,17 +433,11 @@ static void vnc_direct_bgp_vpn_enable_ce(struct bgp *bgp, afi_t afi) */ for (rn = agg_route_top(bgp->rfapi->it_ce->imported_vpn[afi]); rn; rn = agg_route_next(rn)) { - if (!rn->info) continue; - { - char prefixstr[PREFIX_STRLEN]; - - prefix2str(&rn->p, prefixstr, sizeof(prefixstr)); - vnc_zlog_debug_verbose("%s: checking prefix %s", - __func__, prefixstr); - } + vnc_zlog_debug_verbose("%s: checking prefix %pRN", __func__, + rn); for (ri = rn->info; ri; ri = ri->next) { @@ -492,9 +487,9 @@ static void vnc_direct_bgp_vpn_disable_ce(struct bgp *bgp, afi_t afi) && ri->sub_type == BGP_ROUTE_REDISTRIBUTE) { bgp_withdraw( - ri->peer, &rn->p, /* prefix */ - 0, /* addpath_id */ - NULL, /* ignored */ + ri->peer, bgp_node_get_prefix(rn), + 0, /* addpath_id */ + NULL, /* ignored */ AFI_IP, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT, BGP_ROUTE_REDISTRIBUTE, @@ -698,7 +693,8 @@ void vnc_direct_bgp_add_prefix(struct bgp *bgp, struct attr attr = {0}; struct listnode *node, *nnode; struct rfapi_rfg_name *rfgn; - afi_t afi = family2afi(rn->p.family); + const struct prefix *p = agg_node_get_prefix(rn); + afi_t afi = family2afi(p->family); if (!afi) { flog_err(EC_LIB_DEVELOPMENT, "%s: can't get afi of route node", @@ -769,7 +765,7 @@ void vnc_direct_bgp_add_prefix(struct bgp *bgp, */ if (rfgn->rfg->plist_export_bgp[afi]) { if (prefix_list_apply(rfgn->rfg->plist_export_bgp[afi], - &rn->p) + p) == PREFIX_DENY) continue; @@ -808,7 +804,8 @@ void vnc_direct_bgp_del_prefix(struct bgp *bgp, { struct listnode *node, *nnode; struct rfapi_rfg_name *rfgn; - afi_t afi = family2afi(rn->p.family); + const struct prefix *p = agg_node_get_prefix(rn); + afi_t afi = family2afi(p->family); if (!afi) { flog_err(EC_LIB_DEVELOPMENT, "%s: can't get afi route node", @@ -877,9 +874,9 @@ void vnc_direct_bgp_del_prefix(struct bgp *bgp, if (rfapiRaddr2Qprefix(&irfd->vn_addr, &nhp)) continue; - bgp_withdraw(irfd->peer, &rn->p, /* prefix */ - 0, /* addpath_id */ - NULL, /* attr, ignored */ + bgp_withdraw(irfd->peer, p, /* prefix */ + 0, /* addpath_id */ + NULL, /* attr, ignored */ afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT, BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */ @@ -907,9 +904,9 @@ void vnc_direct_bgp_del_prefix(struct bgp *bgp, if (rfapiRaddr2Qprefix(&irfd->vn_addr, &nhp)) continue; - bgp_withdraw(irfd->peer, &rn->p, /* prefix */ - 0, /* addpath_id */ - NULL, /* attr, ignored */ + bgp_withdraw(irfd->peer, p, /* prefix */ + 0, /* addpath_id */ + NULL, /* attr, ignored */ afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT, BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */ @@ -998,6 +995,8 @@ void vnc_direct_bgp_add_nve(struct bgp *bgp, struct rfapi_descriptor *rfd) struct attr hattr; struct attr *iattr; struct bgp_path_info info; + const struct prefix *p = + agg_node_get_prefix(rn); if (rfapiRaddr2Qprefix(&irfd->vn_addr, &nhp)) @@ -1010,7 +1009,7 @@ void vnc_direct_bgp_add_nve(struct bgp *bgp, struct rfapi_descriptor *rfd) if (prefix_list_apply( rfgn->rfg->plist_export_bgp [afi], - &rn->p) + p) == PREFIX_DENY) continue; @@ -1033,8 +1032,7 @@ void vnc_direct_bgp_add_nve(struct bgp *bgp, struct rfapi_descriptor *rfd) ret = route_map_apply( rfgn->rfg ->routemap_export_bgp, - &rn->p, RMAP_BGP, - &info); + p, RMAP_BGP, &info); if (ret == RMAP_DENYMATCH) { bgp_attr_flush(&hattr); continue; @@ -1044,8 +1042,8 @@ void vnc_direct_bgp_add_nve(struct bgp *bgp, struct rfapi_descriptor *rfd) iattr = bgp_attr_intern(&hattr); bgp_attr_flush(&hattr); bgp_update( - irfd->peer, &rn->p, /* prefix */ - 0, /* addpath_id */ + irfd->peer, p, /* prefix */ + 0, /* addpath_id */ iattr, /* bgp_update copies it */ afi, SAFI_UNICAST, @@ -1134,7 +1132,8 @@ void vnc_direct_bgp_del_nve(struct bgp *bgp, struct rfapi_descriptor *rfd) rn = agg_route_next(rn)) { if (rn->info) { - + const struct prefix *p = + agg_node_get_prefix(rn); struct prefix nhp; struct rfapi_descriptor *irfd = rfd; @@ -1142,10 +1141,9 @@ void vnc_direct_bgp_del_nve(struct bgp *bgp, struct rfapi_descriptor *rfd) &nhp)) continue; - bgp_withdraw(irfd->peer, - &rn->p, /* prefix */ - 0, /* addpath_id */ - NULL, /* attr, ignored */ + bgp_withdraw(irfd->peer, p, /* prefix */ + 0, /* addpath_id */ + NULL, /* attr, ignored */ afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT, BGP_ROUTE_REDISTRIBUTE, @@ -1169,6 +1167,7 @@ static void vnc_direct_add_rn_group_rd(struct bgp *bgp, struct bgp_path_info info; struct attr hattr; struct attr *iattr; + const struct prefix *p = agg_node_get_prefix(rn); if (irfd == NULL && rfg->type != RFAPI_GROUP_CFG_VRF) { /* need new rfapi_handle, for peer strcture @@ -1242,8 +1241,8 @@ static void vnc_direct_add_rn_group_rd(struct bgp *bgp, info.peer = irfd->peer; info.attr = &hattr; - ret = route_map_apply(rfg->routemap_export_bgp, &rn->p, - RMAP_BGP, &info); + ret = route_map_apply(rfg->routemap_export_bgp, p, RMAP_BGP, + &info); if (ret == RMAP_DENYMATCH) { bgp_attr_flush(&hattr); vnc_zlog_debug_verbose( @@ -1261,9 +1260,9 @@ static void vnc_direct_add_rn_group_rd(struct bgp *bgp, iattr = bgp_attr_intern(&hattr); bgp_attr_flush(&hattr); - bgp_update(irfd->peer, &rn->p, /* prefix */ - 0, /* addpath_id */ - iattr, /* bgp_update copies it */ + bgp_update(irfd->peer, p, /* prefix */ + 0, /* addpath_id */ + iattr, /* bgp_update copies it */ afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT, BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */ NULL, /* tag not used for unicast */ @@ -1317,7 +1316,7 @@ static void vnc_direct_bgp_add_group_afi(struct bgp *bgp, for (rn = agg_route_top(rt); rn; rn = agg_route_next(rn)) { if (rn->info) { - + const struct prefix *p = agg_node_get_prefix(rn); struct listnode *ln; /* @@ -1325,7 +1324,7 @@ static void vnc_direct_bgp_add_group_afi(struct bgp *bgp, */ if (rfg->plist_export_bgp[afi]) { if (prefix_list_apply( - rfg->plist_export_bgp[afi], &rn->p) + rfg->plist_export_bgp[afi], p) == PREFIX_DENY) continue; @@ -1374,9 +1373,10 @@ static void vnc_direct_del_rn_group_rd(struct bgp *bgp, { if (irfd == NULL) return; - bgp_withdraw(irfd->peer, &rn->p, /* prefix */ - 0, /* addpath_id */ - NULL, /* attr, ignored */ + + bgp_withdraw(irfd->peer, agg_node_get_prefix(rn), /* prefix */ + 0, /* addpath_id */ + NULL, /* attr, ignored */ afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT, BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */ NULL, 0, NULL); /* tag not used for unicast */ @@ -1493,9 +1493,9 @@ static void vnc_direct_bgp_unexport_table(afi_t afi, struct agg_table *rt, irfd)) { bgp_withdraw(irfd->peer, - &rn->p, /* prefix */ - 0, /* addpath_id */ - NULL, /* attr, ignored */ + agg_node_get_prefix(rn), + 0, /* addpath_id */ + NULL, /* attr, ignored */ afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT, BGP_ROUTE_REDISTRIBUTE, @@ -1633,7 +1633,7 @@ void vnc_direct_bgp_vpn_disable(struct bgp *bgp, afi_t afi) * caller do it? */ void vnc_direct_bgp_rh_add_route(struct bgp *bgp, afi_t afi, - struct prefix *prefix, struct peer *peer, + const struct prefix *prefix, struct peer *peer, struct attr *attr) { struct vnc_export_info *eti; @@ -1732,13 +1732,14 @@ void vnc_direct_bgp_rh_add_route(struct bgp *bgp, afi_t afi, static int vncExportWithdrawTimer(struct thread *t) { struct vnc_export_info *eti = t->arg; + const struct prefix *p = agg_node_get_prefix(eti->node); /* * withdraw the route */ - bgp_withdraw(eti->peer, &eti->node->p, 0, /* addpath_id */ - NULL, /* attr, ignored */ - family2afi(eti->node->p.family), SAFI_UNICAST, eti->type, + bgp_withdraw(eti->peer, p, 0, /* addpath_id */ + NULL, /* attr, ignored */ + family2afi(p->family), SAFI_UNICAST, eti->type, eti->subtype, NULL, /* RD not used for unicast */ NULL, 0, NULL); /* tag not used for unicast, EVPN neither */ @@ -1757,7 +1758,7 @@ static int vncExportWithdrawTimer(struct thread *t) * caller do it? */ void vnc_direct_bgp_rh_del_route(struct bgp *bgp, afi_t afi, - struct prefix *prefix, struct peer *peer) + const struct prefix *prefix, struct peer *peer) { struct vnc_export_info *eti; @@ -1840,11 +1841,12 @@ void vnc_direct_bgp_rh_vpn_enable(struct bgp *bgp, afi_t afi) struct bgp_table *table; struct bgp_node *rn; struct bgp_path_info *ri; + const struct prefix *prn_p = bgp_node_get_prefix(prn); memset(&prd, 0, sizeof(prd)); prd.family = AF_UNSPEC; prd.prefixlen = 64; - memcpy(prd.val, prn->p.u.val, 8); + memcpy(prd.val, prn_p->u.val, 8); /* This is the per-RD table of prefixes */ table = bgp_node_get_bgp_table_info(prn); @@ -1853,6 +1855,7 @@ void vnc_direct_bgp_rh_vpn_enable(struct bgp *bgp, afi_t afi) continue; for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) { + const struct prefix *rn_p; /* * skip prefix list check if no routes here @@ -1860,21 +1863,17 @@ void vnc_direct_bgp_rh_vpn_enable(struct bgp *bgp, afi_t afi) if (!bgp_node_has_bgp_path_info_data(rn)) continue; - { - char prefixstr[PREFIX_STRLEN]; + vnc_zlog_debug_verbose("%s: checking prefix %pRN", + __func__, rn); - prefix2str(&rn->p, prefixstr, - sizeof(prefixstr)); - vnc_zlog_debug_verbose("%s: checking prefix %s", - __func__, prefixstr); - } + rn_p = bgp_node_get_prefix(rn); /* * prefix list check */ if (hc->plist_export_bgp[afi]) { if (prefix_list_apply(hc->plist_export_bgp[afi], - &rn->p) + rn_p) == PREFIX_DENY) { vnc_zlog_debug_verbose( @@ -1919,8 +1918,7 @@ void vnc_direct_bgp_rh_vpn_enable(struct bgp *bgp, afi_t afi) info.attr = &hattr; ret = route_map_apply( hc->routemap_export_bgp, - &rn->p, RMAP_BGP, - &info); + rn_p, RMAP_BGP, &info); if (ret == RMAP_DENYMATCH) { bgp_attr_flush(&hattr); vnc_zlog_debug_verbose( @@ -1939,7 +1937,7 @@ void vnc_direct_bgp_rh_vpn_enable(struct bgp *bgp, afi_t afi) * this route */ eti = vnc_eti_get( - bgp, EXPORT_TYPE_BGP, &rn->p, + bgp, EXPORT_TYPE_BGP, rn_p, ri->peer, ZEBRA_ROUTE_VNC_DIRECT_RH, BGP_ROUTE_REDISTRIBUTE); @@ -1960,19 +1958,19 @@ void vnc_direct_bgp_rh_vpn_enable(struct bgp *bgp, afi_t afi) "%s: calling bgp_update", __func__); - bgp_update( - ri->peer, &rn->p, /* prefix */ - 0, /* addpath_id */ - iattr, /* bgp_update copies - it */ - AFI_IP, SAFI_UNICAST, - ZEBRA_ROUTE_VNC_DIRECT_RH, - BGP_ROUTE_REDISTRIBUTE, NULL, - /* RD not used for unicast */ - NULL, - /* tag not used for unicast, - or EVPN */ - 0, 0, NULL); /* EVPN not used */ + bgp_update(ri->peer, rn_p, /* prefix */ + 0, /* addpath_id */ + iattr, /* bgp_update copies + it */ + AFI_IP, SAFI_UNICAST, + ZEBRA_ROUTE_VNC_DIRECT_RH, + BGP_ROUTE_REDISTRIBUTE, NULL, + /* RD not used for unicast */ + NULL, + /* tag not used for unicast, + or EVPN */ + 0, 0, + NULL); /* EVPN not used */ bgp_attr_unintern(&iattr); } @@ -2001,7 +1999,7 @@ void vnc_direct_bgp_rh_vpn_disable(struct bgp *bgp, afi_t afi) */ for (rn = bgp_table_top(bgp->rib[afi][SAFI_UNICAST]); rn; rn = bgp_route_next(rn)) { - + const struct prefix *rn_p = bgp_node_get_prefix(rn); struct bgp_path_info *ri; struct bgp_path_info *next; @@ -2018,7 +2016,7 @@ void vnc_direct_bgp_rh_vpn_disable(struct bgp *bgp, afi_t afi) * Delete routes immediately (no timer) */ eti = vnc_eti_checktimer( - bgp, EXPORT_TYPE_BGP, &rn->p, ri->peer, + bgp, EXPORT_TYPE_BGP, rn_p, ri->peer, ZEBRA_ROUTE_VNC_DIRECT_RH, BGP_ROUTE_REDISTRIBUTE); if (eti) { @@ -2027,8 +2025,8 @@ void vnc_direct_bgp_rh_vpn_disable(struct bgp *bgp, afi_t afi) vnc_eti_delete(eti); } - bgp_withdraw(ri->peer, &rn->p, /* prefix */ - 0, /* addpath_id */ + bgp_withdraw(ri->peer, rn_p, /* prefix */ + 0, /* addpath_id */ NULL, /* ignored */ AFI_IP, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT_RH, diff --git a/bgpd/rfapi/vnc_export_bgp_p.h b/bgpd/rfapi/vnc_export_bgp_p.h index a1cb972740..bf292abb0a 100644 --- a/bgpd/rfapi/vnc_export_bgp_p.h +++ b/bgpd/rfapi/vnc_export_bgp_p.h @@ -61,12 +61,12 @@ extern void vnc_direct_bgp_reexport_group_afi(struct bgp *bgp, extern void vnc_direct_bgp_rh_add_route(struct bgp *bgp, afi_t afi, - struct prefix *prefix, + const struct prefix *prefix, struct peer *peer, struct attr *attr); extern void vnc_direct_bgp_rh_del_route(struct bgp *bgp, afi_t afi, - struct prefix *prefix, + const struct prefix *prefix, struct peer *peer); extern void vnc_direct_bgp_reexport(struct bgp *bgp, afi_t afi); diff --git a/bgpd/rfapi/vnc_export_table.c b/bgpd/rfapi/vnc_export_table.c index 5e00a1017b..255f868bdf 100644 --- a/bgpd/rfapi/vnc_export_table.c +++ b/bgpd/rfapi/vnc_export_table.c @@ -34,7 +34,7 @@ #include "bgpd/rfapi/vnc_debug.h" struct agg_node *vnc_etn_get(struct bgp *bgp, vnc_export_type_t type, - struct prefix *p) + const struct prefix *p) { struct agg_table *t = NULL; struct agg_node *rn = NULL; @@ -66,7 +66,7 @@ struct agg_node *vnc_etn_get(struct bgp *bgp, vnc_export_type_t type, } struct agg_node *vnc_etn_lookup(struct bgp *bgp, vnc_export_type_t type, - struct prefix *p) + const struct prefix *p) { struct agg_table *t = NULL; struct agg_node *rn = NULL; @@ -98,7 +98,7 @@ struct agg_node *vnc_etn_lookup(struct bgp *bgp, vnc_export_type_t type, } struct vnc_export_info *vnc_eti_get(struct bgp *bgp, vnc_export_type_t etype, - struct prefix *p, struct peer *peer, + const struct prefix *p, struct peer *peer, uint8_t type, uint8_t subtype) { struct agg_node *etn; @@ -165,8 +165,9 @@ void vnc_eti_delete(struct vnc_export_info *goner) struct vnc_export_info *vnc_eti_checktimer(struct bgp *bgp, vnc_export_type_t etype, - struct prefix *p, struct peer *peer, - uint8_t type, uint8_t subtype) + const struct prefix *p, + struct peer *peer, uint8_t type, + uint8_t subtype) { struct agg_node *etn; struct vnc_export_info *eti; diff --git a/bgpd/rfapi/vnc_export_table.h b/bgpd/rfapi/vnc_export_table.h index fdb35e81e1..8a1fc9aaef 100644 --- a/bgpd/rfapi/vnc_export_table.h +++ b/bgpd/rfapi/vnc_export_table.h @@ -46,21 +46,21 @@ struct vnc_export_info { }; extern struct agg_node *vnc_etn_get(struct bgp *bgp, vnc_export_type_t type, - struct prefix *p); + const struct prefix *p); extern struct agg_node *vnc_etn_lookup(struct bgp *bgp, vnc_export_type_t type, - struct prefix *p); + const struct prefix *p); -extern struct vnc_export_info *vnc_eti_get(struct bgp *bgp, - vnc_export_type_t etype, - struct prefix *p, struct peer *peer, - uint8_t type, uint8_t subtype); +extern struct vnc_export_info * +vnc_eti_get(struct bgp *bgp, vnc_export_type_t etype, const struct prefix *p, + struct peer *peer, uint8_t type, uint8_t subtype); extern void vnc_eti_delete(struct vnc_export_info *goner); extern struct vnc_export_info * -vnc_eti_checktimer(struct bgp *bgp, vnc_export_type_t etype, struct prefix *p, - struct peer *peer, uint8_t type, uint8_t subtype); +vnc_eti_checktimer(struct bgp *bgp, vnc_export_type_t etype, + const struct prefix *p, struct peer *peer, uint8_t type, + uint8_t subtype); #endif /* _QUAGGA_VNC_VNC_EXPORT_TABLE_H_ */ diff --git a/bgpd/rfapi/vnc_import_bgp.c b/bgpd/rfapi/vnc_import_bgp.c index ba6ef14257..915dfaabf2 100644 --- a/bgpd/rfapi/vnc_import_bgp.c +++ b/bgpd/rfapi/vnc_import_bgp.c @@ -104,7 +104,7 @@ uint32_t calc_local_pref(struct attr *attr, struct peer *peer) return local_pref; } -static int is_host_prefix(struct prefix *p) +static int is_host_prefix(const struct prefix *p) { switch (p->family) { case AF_INET: @@ -128,14 +128,14 @@ struct prefix_bag { static const uint8_t maskbit[] = {0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff}; -int vnc_prefix_cmp(void *pfx1, void *pfx2) +int vnc_prefix_cmp(const void *pfx1, const void *pfx2) { int offset; int shift; uint8_t mask; - struct prefix *p1 = pfx1; - struct prefix *p2 = pfx2; + const struct prefix *p1 = pfx1; + const struct prefix *p2 = pfx2; if (p1->family < p2->family) return -1; @@ -299,9 +299,9 @@ static void vnc_rhnck(char *tag) */ static int process_unicast_route(struct bgp *bgp, /* in */ afi_t afi, /* in */ - struct prefix *prefix, /* in */ - struct bgp_path_info *info, /* in */ - struct ecommunity **ecom, /* OUT */ + const struct prefix *prefix, /* in */ + struct bgp_path_info *info, /* in */ + struct ecommunity **ecom, /* OUT */ struct prefix *unicast_nexthop) /* OUT */ { struct rfapi_cfg *hc = bgp->rfapi_cfg; @@ -425,10 +425,10 @@ static int process_unicast_route(struct bgp *bgp, /* in */ static void vnc_import_bgp_add_route_mode_resolve_nve_one_bi( struct bgp *bgp, afi_t afi, struct bgp_path_info *bpi, /* VPN bpi */ struct prefix_rd *prd, /* RD */ - struct prefix *prefix, /* unicast route prefix */ - uint32_t *local_pref, /* NULL = no local_pref */ - uint32_t *med, /* NULL = no med */ - struct ecommunity *ecom) /* generated ecoms */ + const struct prefix *prefix, /* unicast route prefix */ + uint32_t *local_pref, /* NULL = no local_pref */ + uint32_t *med, /* NULL = no med */ + struct ecommunity *ecom) /* generated ecoms */ { struct prefix un; struct prefix nexthop; @@ -509,11 +509,12 @@ static void vnc_import_bgp_add_route_mode_resolve_nve_one_bi( } static void vnc_import_bgp_add_route_mode_resolve_nve_one_rd( - struct prefix_rd *prd, /* RD */ + struct prefix_rd *prd, /* RD */ struct bgp_table *table_rd, /* per-rd VPN route table */ - afi_t afi, struct bgp *bgp, struct prefix *prefix, /* unicast prefix */ - struct ecommunity *ecom, /* generated ecoms */ - uint32_t *local_pref, /* NULL = no local_pref */ + afi_t afi, struct bgp *bgp, + const struct prefix *prefix, /* unicast prefix */ + struct ecommunity *ecom, /* generated ecoms */ + uint32_t *local_pref, /* NULL = no local_pref */ uint32_t *med, /* NULL = no med */ struct prefix *ubpi_nexthop) /* unicast nexthop */ { @@ -552,8 +553,8 @@ static void vnc_import_bgp_add_route_mode_resolve_nve_one_rd( } static void vnc_import_bgp_add_route_mode_resolve_nve( - struct bgp *bgp, struct prefix *prefix, /* unicast prefix */ - struct bgp_path_info *info) /* unicast info */ + struct bgp *bgp, const struct prefix *prefix, /* unicast prefix */ + struct bgp_path_info *info) /* unicast info */ { afi_t afi = family2afi(prefix->family); @@ -673,8 +674,9 @@ static void vnc_import_bgp_add_route_mode_resolve_nve( continue; vnc_import_bgp_add_route_mode_resolve_nve_one_rd( - (struct prefix_rd *)&bnp->p, table, afi, bgp, prefix, - ecom, &local_pref, med, &pfx_unicast_nexthop); + (struct prefix_rd *)bgp_node_get_prefix(bnp), table, + afi, bgp, prefix, ecom, &local_pref, med, + &pfx_unicast_nexthop); } @@ -686,7 +688,7 @@ static void vnc_import_bgp_add_route_mode_resolve_nve( static void vnc_import_bgp_add_route_mode_plain(struct bgp *bgp, - struct prefix *prefix, + const struct prefix *prefix, struct bgp_path_info *info) { afi_t afi = family2afi(prefix->family); @@ -874,10 +876,9 @@ static void vnc_import_bgp_add_route_mode_plain(struct bgp *bgp, ecommunity_free(&ecom); } -static void -vnc_import_bgp_add_route_mode_nvegroup(struct bgp *bgp, struct prefix *prefix, - struct bgp_path_info *info, - struct rfapi_nve_group_cfg *rfg) +static void vnc_import_bgp_add_route_mode_nvegroup( + struct bgp *bgp, const struct prefix *prefix, + struct bgp_path_info *info, struct rfapi_nve_group_cfg *rfg) { afi_t afi = family2afi(prefix->family); struct peer *peer = info->peer; @@ -1080,7 +1081,7 @@ vnc_import_bgp_add_route_mode_nvegroup(struct bgp *bgp, struct prefix *prefix, } static void vnc_import_bgp_del_route_mode_plain(struct bgp *bgp, - struct prefix *prefix, + const struct prefix *prefix, struct bgp_path_info *info) { struct prefix_rd prd; @@ -1153,7 +1154,7 @@ static void vnc_import_bgp_del_route_mode_plain(struct bgp *bgp, } static void vnc_import_bgp_del_route_mode_nvegroup(struct bgp *bgp, - struct prefix *prefix, + const struct prefix *prefix, struct bgp_path_info *info) { struct prefix_rd prd; @@ -1236,7 +1237,7 @@ static void vnc_import_bgp_del_route_mode_nvegroup(struct bgp *bgp, static void vnc_import_bgp_del_route_mode_resolve_nve_one_bi( struct bgp *bgp, afi_t afi, struct bgp_path_info *bpi, /* VPN bpi */ struct prefix_rd *prd, /* RD */ - struct prefix *prefix) /* unicast route prefix */ + const struct prefix *prefix) /* unicast route prefix */ { struct prefix un; @@ -1272,8 +1273,9 @@ static void vnc_import_bgp_del_route_mode_resolve_nve_one_bi( static void vnc_import_bgp_del_route_mode_resolve_nve_one_rd( struct prefix_rd *prd, struct bgp_table *table_rd, /* per-rd VPN route table */ - afi_t afi, struct bgp *bgp, struct prefix *prefix, /* unicast prefix */ - struct prefix *ubpi_nexthop) /* unicast bpi's nexthop */ + afi_t afi, struct bgp *bgp, + const struct prefix *prefix, /* unicast prefix */ + const struct prefix *ubpi_nexthop) /* unicast bpi's nexthop */ { struct bgp_node *bn; struct bgp_path_info *bpi; @@ -1312,7 +1314,7 @@ static void vnc_import_bgp_del_route_mode_resolve_nve_one_rd( static void vnc_import_bgp_del_route_mode_resolve_nve(struct bgp *bgp, afi_t afi, - struct prefix *prefix, + const struct prefix *prefix, struct bgp_path_info *info) { struct ecommunity *ecom = NULL; @@ -1376,8 +1378,8 @@ vnc_import_bgp_del_route_mode_resolve_nve(struct bgp *bgp, afi_t afi, continue; vnc_import_bgp_del_route_mode_resolve_nve_one_rd( - (struct prefix_rd *)&bnp->p, table, afi, bgp, prefix, - &pfx_unicast_nexthop); /* TBD how is this set? */ + (struct prefix_rd *)bgp_node_get_prefix(bnp), table, + afi, bgp, prefix, &pfx_unicast_nexthop); } if (ecom) @@ -1396,7 +1398,7 @@ vnc_import_bgp_del_route_mode_resolve_nve(struct bgp *bgp, afi_t afi, void vnc_import_bgp_add_vnc_host_route_mode_resolve_nve( struct bgp *bgp, struct prefix_rd *prd, /* RD */ struct bgp_table *table_rd, /* per-rd VPN route table */ - struct prefix *prefix, /* VPN prefix */ + const struct prefix *prefix, /* VPN prefix */ struct bgp_path_info *bpi) /* new VPN host route */ { afi_t afi = family2afi(prefix->family); @@ -1533,7 +1535,7 @@ void vnc_import_bgp_add_vnc_host_route_mode_resolve_nve( void vnc_import_bgp_del_vnc_host_route_mode_resolve_nve( struct bgp *bgp, struct prefix_rd *prd, /* RD */ struct bgp_table *table_rd, /* per-rd VPN route table */ - struct prefix *prefix, /* VPN prefix */ + const struct prefix *prefix, /* VPN prefix */ struct bgp_path_info *bpi) /* old VPN host route */ { afi_t afi = family2afi(prefix->family); @@ -1675,8 +1677,8 @@ static int is_usable_interior_route(struct bgp_path_info *bpi_interior) */ static void vnc_import_bgp_exterior_add_route_it( struct bgp *bgp, /* exterior instance, we hope */ - struct prefix *prefix, /* unicast prefix */ - struct bgp_path_info *info, /* unicast info */ + const struct prefix *prefix, /* unicast prefix */ + struct bgp_path_info *info, /* unicast info */ struct rfapi_import_table *it_only) /* NULL, or limit to this IT */ { struct rfapi *h; @@ -1844,9 +1846,9 @@ static void vnc_import_bgp_exterior_add_route_it( } void vnc_import_bgp_exterior_add_route( - struct bgp *bgp, /* exterior instance, we hope */ - struct prefix *prefix, /* unicast prefix */ - struct bgp_path_info *info) /* unicast info */ + struct bgp *bgp, /* exterior instance, we hope */ + const struct prefix *prefix, /* unicast prefix */ + struct bgp_path_info *info) /* unicast info */ { vnc_import_bgp_exterior_add_route_it(bgp, prefix, info, NULL); } @@ -1861,8 +1863,8 @@ void vnc_import_bgp_exterior_add_route( * right routes. */ void vnc_import_bgp_exterior_del_route( - struct bgp *bgp, struct prefix *prefix, /* unicast prefix */ - struct bgp_path_info *info) /* unicast info */ + struct bgp *bgp, const struct prefix *prefix, /* unicast prefix */ + struct bgp_path_info *info) /* unicast info */ { struct rfapi *h; struct rfapi_cfg *hc; @@ -2027,7 +2029,8 @@ void vnc_import_bgp_exterior_add_route_interior( struct agg_node *rn_interior, /* VPN IT node */ struct bgp_path_info *bpi_interior) /* VPN IT route */ { - afi_t afi = family2afi(rn_interior->p.family); + const struct prefix *p = agg_node_get_prefix(rn_interior); + afi_t afi = family2afi(p->family); struct agg_node *par; struct bgp_path_info *bpi_exterior; struct prefix *pfx_exterior; /* exterior pfx */ @@ -2057,13 +2060,8 @@ void vnc_import_bgp_exterior_add_route_interior( } /*debugging */ - { - char str_pfx[PREFIX_STRLEN]; - - prefix2str(&rn_interior->p, str_pfx, sizeof(str_pfx)); - vnc_zlog_debug_verbose("%s: interior prefix=%s, bpi type=%d", - __func__, str_pfx, bpi_interior->type); - } + vnc_zlog_debug_verbose("%s: interior prefix=%pRN, bpi type=%d", + __func__, rn_interior, bpi_interior->type); if (RFAPI_HAS_MONITOR_EXTERIOR(rn_interior)) { @@ -2178,7 +2176,7 @@ void vnc_import_bgp_exterior_add_route_interior( rfapiUnicastNexthop2Prefix(afi, bpi_exterior->attr, &pfx_nexthop); - if (prefix_match(&rn_interior->p, &pfx_nexthop)) { + if (prefix_match(p, &pfx_nexthop)) { struct bgp_path_info *bpi; struct prefix_rd *prd; @@ -2321,7 +2319,7 @@ void vnc_import_bgp_exterior_add_route_interior( rfapiUnicastNexthop2Prefix(afi, bpi_exterior->attr, &pfx_nexthop); - if (prefix_match(&rn_interior->p, &pfx_nexthop)) { + if (prefix_match(p, &pfx_nexthop)) { struct prefix_rd *prd; struct attr new_attr; @@ -2409,7 +2407,8 @@ void vnc_import_bgp_exterior_del_route_interior( struct agg_node *rn_interior, /* VPN IT node */ struct bgp_path_info *bpi_interior) /* VPN IT route */ { - afi_t afi = family2afi(rn_interior->p.family); + const struct prefix *p = agg_node_get_prefix(rn_interior); + afi_t afi = family2afi(p->family); struct agg_node *par; struct bgp_path_info *bpi_exterior; struct prefix *pfx_exterior; /* exterior pfx */ @@ -2443,14 +2442,8 @@ void vnc_import_bgp_exterior_del_route_interior( } /*debugging */ - { - char str_pfx[PREFIX_STRLEN]; - - prefix2str(&rn_interior->p, str_pfx, sizeof(str_pfx)); - - vnc_zlog_debug_verbose("%s: interior prefix=%s, bpi type=%d", - __func__, str_pfx, bpi_interior->type); - } + vnc_zlog_debug_verbose("%s: interior prefix=%pRN, bpi type=%d", + __func__, rn_interior, bpi_interior->type); /* * Remove constructed routes based on the deleted interior route @@ -2597,7 +2590,7 @@ void vnc_import_bgp_exterior_del_route_interior( * Generic add/delete unicast routes ***********************************************************************/ -void vnc_import_bgp_add_route(struct bgp *bgp, struct prefix *prefix, +void vnc_import_bgp_add_route(struct bgp *bgp, const struct prefix *prefix, struct bgp_path_info *info) { afi_t afi = family2afi(prefix->family); @@ -2666,7 +2659,7 @@ void vnc_import_bgp_add_route(struct bgp *bgp, struct prefix *prefix, /* * "Withdrawing a Route" import process */ -void vnc_import_bgp_del_route(struct bgp *bgp, struct prefix *prefix, +void vnc_import_bgp_del_route(struct bgp *bgp, const struct prefix *prefix, struct bgp_path_info *info) /* unicast info */ { afi_t afi = family2afi(prefix->family); @@ -2762,7 +2755,8 @@ void vnc_import_bgp_redist_enable(struct bgp *bgp, afi_t afi) if (CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED)) continue; - vnc_import_bgp_add_route(bgp, &rn->p, bpi); + vnc_import_bgp_add_route(bgp, bgp_node_get_prefix(rn), + bpi); } } vnc_zlog_debug_verbose( @@ -2803,8 +2797,8 @@ void vnc_import_bgp_exterior_redist_enable(struct bgp *bgp, afi_t afi) if (CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED)) continue; - vnc_import_bgp_exterior_add_route(bgp_exterior, &rn->p, - bpi); + vnc_import_bgp_exterior_add_route( + bgp_exterior, bgp_node_get_prefix(rn), bpi); } } vnc_zlog_debug_verbose( @@ -2850,7 +2844,8 @@ void vnc_import_bgp_exterior_redist_enable_it( continue; vnc_import_bgp_exterior_add_route_it( - bgp_exterior, &rn->p, bpi, it_only); + bgp_exterior, bgp_node_get_prefix(rn), bpi, + it_only); } } } @@ -2880,58 +2875,49 @@ void vnc_import_bgp_redist_disable(struct bgp *bgp, afi_t afi) */ for (rn1 = bgp_table_top(bgp->rib[afi][SAFI_MPLS_VPN]); rn1; rn1 = bgp_route_next(rn1)) { + const struct prefix *rn1_p; - if (bgp_node_has_bgp_path_info_data(rn1)) { - - for (rn2 = bgp_table_top( - bgp_node_get_bgp_table_info(rn1)); - rn2; rn2 = bgp_route_next(rn2)) { - - struct bgp_path_info *bpi; - struct bgp_path_info *nextbpi; - - for (bpi = bgp_node_get_bgp_path_info(rn2); bpi; - bpi = nextbpi) { - - nextbpi = bpi->next; + if (!bgp_node_has_bgp_path_info_data(rn1)) + continue; - if (bpi->type - == ZEBRA_ROUTE_BGP_DIRECT) { + rn1_p = bgp_node_get_prefix(rn1); + for (rn2 = bgp_table_top(bgp_node_get_bgp_table_info(rn1)); rn2; + rn2 = bgp_route_next(rn2)) { + const struct prefix *rn2_p = bgp_node_get_prefix(rn2); + struct bgp_path_info *bpi; + struct bgp_path_info *nextbpi; - struct rfapi_descriptor *rfd; - vncHDBgpDirect.peer = bpi->peer; + for (bpi = bgp_node_get_bgp_path_info(rn2); bpi; + bpi = nextbpi) { - assert(bpi->extra); + nextbpi = bpi->next; - rfd = bpi->extra->vnc.export - .rfapi_handle; + if (bpi->type != ZEBRA_ROUTE_BGP_DIRECT) + continue; - vnc_zlog_debug_verbose( - "%s: deleting bpi=%p, bpi->peer=%p, bpi->type=%d, bpi->sub_type=%d, bpi->extra->vnc.export.rfapi_handle=%p [passing rfd=%p]", - __func__, bpi, - bpi->peer, bpi->type, - bpi->sub_type, - (bpi->extra - ? bpi->extra - ->vnc - .export - .rfapi_handle - : NULL), - rfd); + struct rfapi_descriptor *rfd; + vncHDBgpDirect.peer = bpi->peer; + assert(bpi->extra); - del_vnc_route( - rfd, bpi->peer, bgp, - SAFI_MPLS_VPN, &rn2->p, - (struct prefix_rd *)&rn1 - ->p, - bpi->type, - bpi->sub_type, NULL, - 1); /* kill */ + rfd = bpi->extra->vnc.export.rfapi_handle; - vncHDBgpDirect.peer = NULL; - } - } + vnc_zlog_debug_verbose( + "%s: deleting bpi=%p, bpi->peer=%p, bpi->type=%d, bpi->sub_type=%d, bpi->extra->vnc.export.rfapi_handle=%p [passing rfd=%p]", + __func__, bpi, bpi->peer, bpi->type, + bpi->sub_type, + (bpi->extra ? bpi->extra->vnc.export + .rfapi_handle + : NULL), + rfd); + + del_vnc_route(rfd, bpi->peer, bgp, + SAFI_MPLS_VPN, rn2_p, + (struct prefix_rd *)rn1_p, + bpi->type, bpi->sub_type, NULL, + 1); /* kill */ + + vncHDBgpDirect.peer = NULL; } } } @@ -2987,8 +2973,9 @@ void vnc_import_bgp_exterior_redist_disable(struct bgp *bgp, afi_t afi) if (CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED)) continue; - vnc_import_bgp_exterior_del_route(bgp_exterior, - &rn->p, bpi); + vnc_import_bgp_exterior_del_route( + bgp_exterior, bgp_node_get_prefix(rn), + bpi); } } #if DEBUG_RHN_LIST diff --git a/bgpd/rfapi/vnc_import_bgp.h b/bgpd/rfapi/vnc_import_bgp.h index 3db6f4010a..ab2ec1a748 100644 --- a/bgpd/rfapi/vnc_import_bgp.h +++ b/bgpd/rfapi/vnc_import_bgp.h @@ -32,12 +32,14 @@ extern uint32_t calc_local_pref(struct attr *attr, struct peer *peer); -extern int vnc_prefix_cmp(void *pfx1, void *pfx2); +extern int vnc_prefix_cmp(const void *pfx1, const void *pfx2); -extern void vnc_import_bgp_add_route(struct bgp *bgp, struct prefix *prefix, +extern void vnc_import_bgp_add_route(struct bgp *bgp, + const struct prefix *prefix, struct bgp_path_info *info); -extern void vnc_import_bgp_del_route(struct bgp *bgp, struct prefix *prefix, +extern void vnc_import_bgp_del_route(struct bgp *bgp, + const struct prefix *prefix, struct bgp_path_info *info); extern void vnc_import_bgp_redist_enable(struct bgp *bgp, afi_t afi); @@ -51,23 +53,23 @@ extern void vnc_import_bgp_exterior_redist_disable(struct bgp *bgp, afi_t afi); extern void vnc_import_bgp_exterior_add_route( struct bgp *bgp, /* exterior instance, we hope */ - struct prefix *prefix, /* unicast prefix */ + const struct prefix *prefix, /* unicast prefix */ struct bgp_path_info *info); /* unicast info */ extern void vnc_import_bgp_exterior_del_route( - struct bgp *bgp, struct prefix *prefix, /* unicast prefix */ - struct bgp_path_info *info); /* unicast info */ + struct bgp *bgp, const struct prefix *prefix, /* unicast prefix */ + struct bgp_path_info *info); /* unicast info */ extern void vnc_import_bgp_add_vnc_host_route_mode_resolve_nve( struct bgp *bgp, struct prefix_rd *prd, /* RD */ struct bgp_table *table_rd, /* per-rd VPN route table */ - struct prefix *prefix, /* VPN prefix */ + const struct prefix *prefix, /* VPN prefix */ struct bgp_path_info *bpi); /* new VPN host route */ extern void vnc_import_bgp_del_vnc_host_route_mode_resolve_nve( struct bgp *bgp, struct prefix_rd *prd, /* RD */ struct bgp_table *table_rd, /* per-rd VPN route table */ - struct prefix *prefix, /* VPN prefix */ + const struct prefix *prefix, /* VPN prefix */ struct bgp_path_info *bpi); /* old VPN host route */ #endif /* _QUAGGA_RFAPI_VNC_IMPORT_BGP_H_ */ diff --git a/bgpd/rfapi/vnc_zebra.c b/bgpd/rfapi/vnc_zebra.c index 80a590f56a..686dc394a7 100644 --- a/bgpd/rfapi/vnc_zebra.c +++ b/bgpd/rfapi/vnc_zebra.c @@ -304,10 +304,12 @@ static void vnc_redistribute_withdraw(struct bgp *bgp, afi_t afi, uint8_t type) */ for (prn = bgp_table_top(bgp->rib[afi][SAFI_MPLS_VPN]); prn; prn = bgp_route_next(prn)) { + const struct prefix *prn_p = bgp_node_get_prefix(prn); + memset(&prd, 0, sizeof(prd)); prd.family = AF_UNSPEC; prd.prefixlen = 64; - memcpy(prd.val, prn->p.u.val, 8); + memcpy(prd.val, prn_p->u.val, 8); /* This is the per-RD table of prefixes */ table = bgp_node_get_bgp_table_info(prn); @@ -329,7 +331,7 @@ static void vnc_redistribute_withdraw(struct bgp *bgp, afi_t afi, uint8_t type) del_vnc_route( &vncHD1VR, /* use dummy ptr as cookie */ vncHD1VR.peer, bgp, SAFI_MPLS_VPN, - &(rn->p), &prd, type, + bgp_node_get_prefix(rn), &prd, type, BGP_ROUTE_REDISTRIBUTE, NULL, 0); } } @@ -380,7 +382,7 @@ static int vnc_zebra_read_route(ZAPI_CALLBACK_ARGS) /* * low-level message builder */ -static void vnc_zebra_route_msg(struct prefix *p, unsigned int nhp_count, +static void vnc_zebra_route_msg(const struct prefix *p, unsigned int nhp_count, void *nhp_ary, int add) /* 1 = add, 0 = del */ { struct zapi_route api; @@ -560,7 +562,7 @@ static void vnc_zebra_add_del_prefix(struct bgp *bgp, int add) /* !0 = add, 0 = del */ { struct list *nves; - + const struct prefix *p = agg_node_get_prefix(rn); unsigned int nexthop_count = 0; void *nh_ary = NULL; void *nhp_ary = NULL; @@ -570,15 +572,15 @@ static void vnc_zebra_add_del_prefix(struct bgp *bgp, if (zclient_vnc->sock < 0) return; - if (rn->p.family != AF_INET && rn->p.family != AF_INET6) { + if (p->family != AF_INET && p->family != AF_INET6) { flog_err(EC_LIB_DEVELOPMENT, "%s: invalid route node addr family", __func__); return; } - if (!vrf_bitmap_check(zclient_vnc->redist[family2afi(rn->p.family)] - [ZEBRA_ROUTE_VNC], - VRF_DEFAULT)) + if (!vrf_bitmap_check( + zclient_vnc->redist[family2afi(p->family)][ZEBRA_ROUTE_VNC], + VRF_DEFAULT)) return; if (!bgp->rfapi_cfg) { @@ -592,17 +594,16 @@ static void vnc_zebra_add_del_prefix(struct bgp *bgp, return; } - import_table_to_nve_list_zebra(bgp, import_table, &nves, rn->p.family); + import_table_to_nve_list_zebra(bgp, import_table, &nves, p->family); if (nves) { - nve_list_to_nh_array(rn->p.family, nves, &nexthop_count, - &nh_ary, &nhp_ary); + nve_list_to_nh_array(p->family, nves, &nexthop_count, &nh_ary, + &nhp_ary); list_delete(&nves); if (nexthop_count) - vnc_zebra_route_msg(&rn->p, nexthop_count, nhp_ary, - add); + vnc_zebra_route_msg(p, nexthop_count, nhp_ary, add); } XFREE(MTYPE_TMP, nhp_ary); @@ -695,15 +696,14 @@ static void vnc_zebra_add_del_nve(struct bgp *bgp, struct rfapi_descriptor *rfd, */ for (rn = agg_route_top(rt); rn; rn = agg_route_next(rn)) { - - if (rn->info) { - - vnc_zlog_debug_verbose( - "%s: sending %s", __func__, - (add ? "add" : "del")); - vnc_zebra_route_msg(&rn->p, 1, &pAddr, - add); - } + if (!rn->info) + continue; + + vnc_zlog_debug_verbose("%s: sending %s", + __func__, + (add ? "add" : "del")); + vnc_zebra_route_msg(agg_node_get_prefix(rn), 1, + &pAddr, add); } } } @@ -778,9 +778,9 @@ static void vnc_zebra_add_del_group_afi(struct bgp *bgp, for (rn = agg_route_top(rt); rn; rn = agg_route_next(rn)) { if (rn->info) { - vnc_zebra_route_msg(&rn->p, - nexthop_count, - nhp_ary, add); + vnc_zebra_route_msg( + agg_node_get_prefix(rn), + nexthop_count, nhp_ary, add); } } } diff --git a/configure.ac b/configure.ac index 41d1911c37..628e0c8afc 100755 --- a/configure.ac +++ b/configure.ac @@ -182,13 +182,13 @@ dnl - specifically, options to control warnings AC_USE_SYSTEM_EXTENSIONS AC_DEFUN([AC_C_FLAG], [{ - m4_pushdef([cachename],[m4_translit([frr_cv_$1],[ =-+],[____])]) + m4_pushdef([cachename],[m4_translit([frr_cv_$1],[ =-+/{}$],[________])]) AC_CACHE_CHECK([[whether $CC supports $1]], cachename, [ AC_LANG_PUSH([C]) ac_c_flag_save="$CFLAGS" CFLAGS="$CFLAGS $1" AC_COMPILE_IFELSE( - [AC_LANG_PROGRAM([[]])], + [AC_LANG_PROGRAM([[$4]])], [ cachename=yes ], [ @@ -295,6 +295,7 @@ AC_C_FLAG([-Wmissing-declarations]) AC_C_FLAG([-Wpointer-arith]) AC_C_FLAG([-Wbad-function-cast]) AC_C_FLAG([-Wwrite-strings]) +AC_C_FLAG([-Wundef]) if test "$enable_gcc_ultra_verbose" = "yes" ; then AC_C_FLAG([-Wcast-qual]) AC_C_FLAG([-Wstrict-prototypes]) @@ -354,6 +355,44 @@ if test "$enable_undefined_sanitizer" = "yes"; then fi AC_SUBST([SAN_FLAGS]) +dnl frr-format.so +if test "$with_frr_format" != "no" -a "$with_frr_format" != "yes" -a -n "$with_frr_format"; then + AC_C_FLAG([-fplugin=${with_frr_format}], [ + AC_MSG_ERROR([specified frr-format plugin ($with_frr_format) does not work]) + ],,[ +#ifndef _FRR_ATTRIBUTE_PRINTFRR +#error plugin not loaded +#endif +#if _FRR_ATTRIBUTE_PRINTFRR < 0x10000 +#error plugin too old +#endif + ]) +elif test "$with_frr_format" = "no"; then + : #nothing +else + AC_C_FLAG([-fplugin=tools/gcc-plugins/frr-format.so],[ + AC_C_FLAG([-fplugin=frr-format],[ + if test "$with_frr_format" = "yes"; then + AC_MSG_ERROR([frr-format plugin requested but not found]) + fi + ],,[ +#ifndef _FRR_ATTRIBUTE_PRINTFRR +#error plugin not loaded +#endif +#if _FRR_ATTRIBUTE_PRINTFRR < 0x10000 +#error plugin too old +#endif + ]) + ],,[ +#ifndef _FRR_ATTRIBUTE_PRINTFRR +#error plugin not loaded +#endif +#if _FRR_ATTRIBUTE_PRINTFRR < 0x10000 +#error plugin too old +#endif + ]) +fi + dnl ---------- dnl Essentials dnl ---------- @@ -600,6 +639,8 @@ AC_ARG_ENABLE([undefined-sanitizer], AS_HELP_STRING([--undefined-sanitizer], [enable UndefinedBehaviorSanitizer support for detecting undefined behavior])) AC_ARG_WITH([crypto], AS_HELP_STRING([--with-crypto=<internal|openssl>], [choose between different implementations of cryptographic functions(default value is --with-crypto=internal)])) +AC_ARG_WITH([frr-format], + AS_HELP_STRING([--with-frr-format[=<.../frr-format.so>]], [use frr-format GCC plugin])) #if openssl, else use the internal AS_IF([test "$with_crypto" = "openssl"], [ @@ -2006,6 +2047,10 @@ AC_CHECK_DECL([CLOCK_MONOTONIC], AC_DEFINE([HAVE_CLOCK_MONOTONIC], [1], [Have monotonic clock]) ], [AC_MSG_RESULT([no])], [FRR_INCLUDES]) +AC_SEARCH_LIBS([clock_nanosleep], [rt], [ + AC_DEFINE([HAVE_CLOCK_NANOSLEEP], [1], [Have clock_nanosleep()]) +]) + dnl -------------------------------------- dnl checking for flex and bison dnl -------------------------------------- diff --git a/doc/developer/ospf-sr.rst b/doc/developer/ospf-sr.rst index d798ba78ef..070465db5b 100644 --- a/doc/developer/ospf-sr.rst +++ b/doc/developer/ospf-sr.rst @@ -22,7 +22,7 @@ Interoperability ---------------- * Tested on various topology including point-to-point and LAN interfaces - in a mix of Free Range Routing instance and Cisco IOS-XR 6.0.x + in a mix of FRRouting instance and Cisco IOS-XR 6.0.x * Check OSPF LSA conformity with latest wireshark release 2.5.0-rc Implementation details diff --git a/doc/developer/workflow.rst b/doc/developer/workflow.rst index 8ce3bdeeb2..e36b57a5aa 100644 --- a/doc/developer/workflow.rst +++ b/doc/developer/workflow.rst @@ -992,6 +992,11 @@ Miscellaneous When in doubt, follow the guidelines in the Linux kernel style guide, or ask on the development mailing list / public Slack instance. +JSON Output +^^^^^^^^^^^ + +All JSON keys are to be camelCased, with no spaces. + .. _documentation: diff --git a/doc/user/ldpd.rst b/doc/user/ldpd.rst index 977195d6a7..2df4ba3005 100644 --- a/doc/user/ldpd.rst +++ b/doc/user/ldpd.rst @@ -108,6 +108,11 @@ LDP Configuration The following command located under MPLS router node configures the MPLS router-id of the local device. +.. index:: [no] ordered-control +.. clicmd:: [no] ordered-control + + Configure LDP Ordered Label Distribution Control. + .. index:: [no] address-family [ipv4 | ipv6] .. clicmd:: [no] address-family [ipv4 | ipv6] diff --git a/isisd/fabricd.c b/isisd/fabricd.c index b9c27d51bd..4a4b25fa1d 100644 --- a/isisd/fabricd.c +++ b/isisd/fabricd.c @@ -3,7 +3,7 @@ * * Copyright (C) 2018 Christian Franke * - * This file is part of FreeRangeRouting (FRR) + * This file is part of FRRouting (FRR) * * FRR is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -122,9 +122,9 @@ static bool neighbor_entry_hash_cmp(const void *a, const void *b) return memcmp(na->id, nb->id, sizeof(na->id)) == 0; } -static int neighbor_entry_list_cmp(void *a, void *b) +static int neighbor_entry_list_cmp(const void *a, const void *b) { - struct neighbor_entry *na = a, *nb = b; + const struct neighbor_entry *na = a, *nb = b; return -memcmp(na->id, nb->id, sizeof(na->id)); } diff --git a/isisd/fabricd.h b/isisd/fabricd.h index 6e93440f3a..9455cdb0f0 100644 --- a/isisd/fabricd.h +++ b/isisd/fabricd.h @@ -3,7 +3,7 @@ * * Copyright (C) 2018 Christian Franke * - * This file is part of FreeRangeRouting (FRR) + * This file is part of FRRouting (FRR) * * FRR is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the diff --git a/isisd/isis_adjacency.c b/isisd/isis_adjacency.c index 1d70521e68..9beed206e8 100644 --- a/isisd/isis_adjacency.c +++ b/isisd/isis_adjacency.c @@ -353,7 +353,7 @@ void isis_adj_print(struct isis_adjacency *adj) if (dyn) zlog_debug("%s", dyn->hostname); - zlog_debug("SystemId %20s SNPA %s, level %d\nHolding Time %d", + zlog_debug("SystemId %20s SNPA %s, level %d; Holding Time %d", sysid_print(adj->sysid), snpa_print(adj->snpa), adj->level, adj->hold_time); if (adj->ipv4_address_count) { diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c index e4152a8712..7d4f7b355d 100644 --- a/isisd/isis_circuit.c +++ b/isisd/isis_circuit.c @@ -345,8 +345,7 @@ void isis_circuit_del_addr(struct isis_circuit *circuit, } else { prefix2str(connected->address, buf, sizeof(buf)); zlog_warn( - "Nonexistent ip address %s removal attempt from \ - circuit %s", + "Nonexistent ip address %s removal attempt from circuit %s", buf, circuit->interface->name); zlog_warn("Current ip addresses on %s:", circuit->interface->name); @@ -394,8 +393,7 @@ void isis_circuit_del_addr(struct isis_circuit *circuit, if (!found) { prefix2str(connected->address, buf, sizeof(buf)); zlog_warn( - "Nonexistent ip address %s removal attempt from \ - circuit %s", + "Nonexistent ip address %s removal attempt from circuit %s", buf, circuit->interface->name); zlog_warn("Current ip addresses on %s:", circuit->interface->name); diff --git a/isisd/isis_cli.c b/isisd/isis_cli.c index fc70a344c8..2483d26833 100644 --- a/isisd/isis_cli.c +++ b/isisd/isis_cli.c @@ -1456,8 +1456,8 @@ void cli_show_ip_isis_hello_interval(struct vty *vty, struct lyd_node *dnode, if (strmatch(l1, l2)) vty_out(vty, " isis hello-interval %s\n", l1); else { - vty_out(vty, " isis hello-interval %s level-1\n", l1); - vty_out(vty, " isis hello-interval %s level-2\n", l2); + vty_out(vty, " isis hello-interval level-1 %s\n", l1); + vty_out(vty, " isis hello-interval level-2 %s\n", l2); } } @@ -1514,8 +1514,8 @@ void cli_show_ip_isis_hello_multi(struct vty *vty, struct lyd_node *dnode, if (strmatch(l1, l2)) vty_out(vty, " isis hello-multiplier %s\n", l1); else { - vty_out(vty, " isis hello-multiplier %s level-1\n", l1); - vty_out(vty, " isis hello-multiplier %s level-2\n", l2); + vty_out(vty, " isis hello-multiplier level-1 %s\n", l1); + vty_out(vty, " isis hello-multiplier level-2 %s\n", l2); } } diff --git a/isisd/isis_mt.c b/isisd/isis_mt.c index 36413bac59..e8e35ae63b 100644 --- a/isisd/isis_mt.c +++ b/isisd/isis_mt.c @@ -3,7 +3,7 @@ * * Copyright (C) 2017 Christian Franke * - * This file is part of FreeRangeRouting (FRR) + * This file is part of FRRouting (FRR) * * FRR is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the diff --git a/isisd/isis_mt.h b/isisd/isis_mt.h index b40139c50a..fd9ee133ca 100644 --- a/isisd/isis_mt.h +++ b/isisd/isis_mt.h @@ -3,7 +3,7 @@ * * Copyright (C) 2017 Christian Franke * - * This file is part of FreeRangeRouting (FRR) + * This file is part of FRRouting (FRR) * * FRR is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the diff --git a/isisd/isis_spf_private.h b/isisd/isis_spf_private.h index a8185a8be0..05aae14b94 100644 --- a/isisd/isis_spf_private.h +++ b/isisd/isis_spf_private.h @@ -117,11 +117,11 @@ static bool isis_vertex_queue_hash_cmp(const void *a, const void *b) * Compares vertizes for sorting in the TENT list. Returns true * if candidate should be considered before current, false otherwise. */ -__attribute__((__unused__)) -static int isis_vertex_queue_tent_cmp(void *a, void *b) +__attribute__((__unused__)) static int isis_vertex_queue_tent_cmp(const void *a, + const void *b) { - struct isis_vertex *va = a; - struct isis_vertex *vb = b; + const struct isis_vertex *va = a; + const struct isis_vertex *vb = b; if (va->d_N < vb->d_N) return -1; diff --git a/isisd/isis_tx_queue.c b/isisd/isis_tx_queue.c index 507fd489bc..27e57db16c 100644 --- a/isisd/isis_tx_queue.c +++ b/isisd/isis_tx_queue.c @@ -3,7 +3,7 @@ * * Copyright (C) 2018 Christian Franke * - * This file is part of FreeRangeRouting (FRR) + * This file is part of FRRouting (FRR) * * FRR is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the diff --git a/isisd/isis_tx_queue.h b/isisd/isis_tx_queue.h index c2beda45b7..f0f1184d58 100644 --- a/isisd/isis_tx_queue.h +++ b/isisd/isis_tx_queue.h @@ -3,7 +3,7 @@ * * Copyright (C) 2018 Christian Franke * - * This file is part of FreeRangeRouting (FRR) + * This file is part of FRRouting (FRR) * * FRR is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the diff --git a/ldpd/lde.c b/ldpd/lde.c index 5f94031320..ae883078dd 100644 --- a/ldpd/lde.c +++ b/ldpd/lde.c @@ -61,6 +61,8 @@ static void lde_label_list_init(void); static int lde_get_label_chunk(void); static void on_get_label_chunk_response(uint32_t start, uint32_t end); static uint32_t lde_get_next_label(void); +static bool lde_fec_connected(const struct fec_node *); +static bool lde_fec_outside_mpls_network(const struct fec_node *); RB_GENERATE(nbr_tree, lde_nbr, entry, lde_nbr_compare) RB_GENERATE(lde_map_head, lde_map, entry, lde_map_compare) @@ -658,18 +660,31 @@ lde_acl_check(char *acl_name, int af, union ldpd_addr *addr, uint8_t prefixlen) return ldp_acl_request(iev_main_sync, acl_name, af, addr, prefixlen); } +static bool lde_fec_connected(const struct fec_node *fn) +{ + struct fec_nh *fnh; + + LIST_FOREACH(fnh, &fn->nexthops, entry) + if (fnh->flags & F_FEC_NH_CONNECTED) + return true; + + return false; +} + +static bool lde_fec_outside_mpls_network(const struct fec_node *fn) +{ + struct fec_nh *fnh; + + LIST_FOREACH(fnh, &fn->nexthops, entry) + if (!(fnh->flags & F_FEC_NH_NO_LDP)) + return false; + + return true; +} + uint32_t lde_update_label(struct fec_node *fn) { - struct fec_nh *fnh; - int connected = 0; - - LIST_FOREACH(fnh, &fn->nexthops, entry) { - if (fnh->flags & F_FEC_NH_CONNECTED) { - connected = 1; - break; - } - } /* should we allocate a label for this fec? */ switch (fn->fec.type) { @@ -695,7 +710,14 @@ lde_update_label(struct fec_node *fn) break; } - if (connected) { + /* + * If connected interface act as egress for fec. + * If LDP is not configured on an interface but there + * are other NHs with interfaces configured with LDP + * then don't act as an egress for the fec, otherwise + * act as an egress for the fec + */ + if (lde_fec_connected(fn) || lde_fec_outside_mpls_network(fn)) { /* choose implicit or explicit-null depending on configuration */ switch (fn->fec.type) { case FEC_TYPE_IPV4: @@ -735,6 +757,13 @@ lde_send_change_klabel(struct fec_node *fn, struct fec_nh *fnh) struct zapi_pw zpw; struct l2vpn_pw *pw; + /* + * Ordered Control: don't program label into HW until a + * labelmap msg has been received from upstream router + */ + if (fnh->flags & F_FEC_NH_DEFER) + return; + switch (fn->fec.type) { case FEC_TYPE_IPV4: memset(&kr, 0, sizeof(kr)); @@ -901,6 +930,27 @@ lde_send_labelmapping(struct lde_nbr *ln, struct fec_node *fn, int single) struct lde_req *lre; struct map map; struct l2vpn_pw *pw; + struct fec_nh *fnh; + bool allow = false; + + /* + * Ordered Control: do not send a labelmap msg until + * a labelmap message is received from downstream router + * and don't send labelmap back to downstream router + */ + if (ldeconf->flags & F_LDPD_ORDERED_CONTROL) { + LIST_FOREACH(fnh, &fn->nexthops, entry) { + if (fnh->flags & F_FEC_NH_DEFER) + continue; + + if (lde_address_find(ln, fnh->af, &fnh->nexthop)) + return; + allow = true; + break; + } + if (!allow) + return; + } /* * We shouldn't send a new label mapping if we have a pending @@ -1241,6 +1291,7 @@ lde_nbr_del(struct lde_nbr *ln) struct fec_node *fn; struct fec_nh *fnh; struct l2vpn_pw *pw; + struct lde_nbr *lnbr; if (ln == NULL) return; @@ -1256,6 +1307,25 @@ lde_nbr_del(struct lde_nbr *ln) if (!lde_address_find(ln, fnh->af, &fnh->nexthop)) continue; + + /* + * Ordered Control: must mark any non-connected + * NH to wait until we receive a labelmap msg + * before installing in kernel and sending to + * peer, must do this as NHs are not removed + * when lsps go down. Also send label withdraw + * to other neighbors for all fecs from neighbor + * going down + */ + if (ldeconf->flags & F_LDPD_ORDERED_CONTROL) { + fnh->flags |= F_FEC_NH_DEFER; + + RB_FOREACH(lnbr, nbr_tree, &lde_nbrs) { + if (ln->peerid == lnbr->peerid) + continue; + lde_send_labelwithdraw(lnbr, fn, NULL, NULL); + } + } break; case FEC_TYPE_PWID: if (f->u.pwid.lsr_id.s_addr != ln->id.s_addr) @@ -1567,6 +1637,56 @@ lde_change_egress_label(int af) NULL, 0); } +void +lde_change_host_label(int af) +{ + struct lde_nbr *ln; + struct fec *f; + struct fec_node *fn; + uint32_t new_label; + + RB_FOREACH(f, fec_tree, &ft) { + fn = (struct fec_node *)f; + + switch (af) { + case AF_INET: + if (fn->fec.type != FEC_TYPE_IPV4) + continue; + break; + case AF_INET6: + if (fn->fec.type != FEC_TYPE_IPV6) + continue; + break; + default: + fatalx("lde_change_host_label: unknown af"); + } + + /* + * If the local label has changed to NO_LABEL, send a label + * withdraw to all peers. + * If the local label has changed and it's different from + * NO_LABEL, send a label mapping to all peers advertising + * the new label. + * If the local label hasn't changed, do nothing + */ + new_label = lde_update_label(fn); + if (fn->local_label != new_label) { + if (new_label == NO_LABEL) + RB_FOREACH(ln, nbr_tree, &lde_nbrs) + lde_send_labelwithdraw(ln, fn, + NULL, NULL); + + fn->local_label = new_label; + if (fn->local_label != NO_LABEL) + RB_FOREACH(ln, nbr_tree, &lde_nbrs) + lde_send_labelmapping(ln, fn, 0); + } + } + RB_FOREACH(ln, nbr_tree, &lde_nbrs) + lde_imsg_compose_ldpe(IMSG_MAPPING_ADD_END, ln->peerid, 0, + NULL, 0); +} + static int lde_address_add(struct lde_nbr *ln, struct lde_addr *lde_addr) { @@ -1628,8 +1748,11 @@ lde_address_list_free(struct lde_nbr *ln) static void zclient_sync_init(unsigned short instance) { + struct zclient_options options = zclient_options_default; + options.synchronous = true; + /* Initialize special zclient for synchronous message exchanges. */ - zclient_sync = zclient_new(master, &zclient_options_default); + zclient_sync = zclient_new(master, &options); zclient_sync->sock = -1; zclient_sync->redist_default = ZEBRA_ROUTE_LDP; zclient_sync->instance = instance; @@ -1642,6 +1765,12 @@ static void zclient_sync_init(unsigned short instance) /* make socket non-blocking */ sock_set_nonblock(zclient_sync->sock); + /* Send hello to notify zebra this is a synchronous client */ + while (zclient_send_hello(zclient_sync) < 0) { + log_warnx("Error sending hello for synchronous zclient!"); + sleep(1); + } + /* Connect to label manager */ while (lm_label_manager_connect(zclient_sync, 0) != 0) { log_warnx("Error connecting to label manager!"); diff --git a/ldpd/lde.h b/ldpd/lde.h index ce466c16b9..36196a3d08 100644 --- a/ldpd/lde.h +++ b/ldpd/lde.h @@ -114,6 +114,8 @@ struct fec_nh { }; #define F_FEC_NH_NEW 0x01 #define F_FEC_NH_CONNECTED 0x02 +#define F_FEC_NH_DEFER 0x04 /* running ordered control */ +#define F_FEC_NH_NO_LDP 0x08 /* no ldp on this interface */ struct fec_node { struct fec fec; @@ -181,6 +183,7 @@ void lde_req_del(struct lde_nbr *, struct lde_req *, int); struct lde_wdraw *lde_wdraw_add(struct lde_nbr *, struct fec_node *); void lde_wdraw_del(struct lde_nbr *, struct lde_wdraw *); void lde_change_egress_label(int); +void lde_change_host_label(int); struct lde_addr *lde_address_find(struct lde_nbr *, int, union ldpd_addr *); diff --git a/ldpd/lde_lib.c b/ldpd/lde_lib.c index eb1a6d9434..8f524e0aa9 100644 --- a/ldpd/lde_lib.c +++ b/ldpd/lde_lib.c @@ -20,6 +20,7 @@ #include <zebra.h> #include "ldpd.h" +#include "ldpe.h" #include "lde.h" #include "log.h" @@ -325,6 +326,7 @@ lde_kernel_insert(struct fec *fec, int af, union ldpd_addr *nexthop, { struct fec_node *fn; struct fec_nh *fnh; + struct iface *iface; fn = (struct fec_node *)fec_find(&ft, fec); if (fn == NULL) @@ -333,9 +335,21 @@ lde_kernel_insert(struct fec *fec, int af, union ldpd_addr *nexthop, fn->data = data; fnh = fec_nh_find(fn, af, nexthop, ifindex, route_type, route_instance); - if (fnh == NULL) + if (fnh == NULL) { fnh = fec_nh_add(fn, af, nexthop, ifindex, route_type, route_instance); + /* + * Ordered Control: if not a connected route and not a route + * learned over an interface not running LDP and not a PW + * then mark to wait until we receive labelmap msg before + * installing in kernel and sending to peer + */ + iface = if_lookup(ldeconf, ifindex); + if ((ldeconf->flags & F_LDPD_ORDERED_CONTROL) && + !connected && iface != NULL && fec->type != FEC_TYPE_PWID) + fnh->flags |= F_FEC_NH_DEFER; + } + fnh->flags |= F_FEC_NH_NEW; if (connected) fnh->flags |= F_FEC_NH_CONNECTED; @@ -374,15 +388,25 @@ lde_kernel_update(struct fec *fec) struct fec_nh *fnh, *safe; struct lde_nbr *ln; struct lde_map *me; + struct iface *iface; fn = (struct fec_node *)fec_find(&ft, fec); if (fn == NULL) return; LIST_FOREACH_SAFE(fnh, &fn->nexthops, entry, safe) { - if (fnh->flags & F_FEC_NH_NEW) + if (fnh->flags & F_FEC_NH_NEW) { fnh->flags &= ~F_FEC_NH_NEW; - else { + /* + * if LDP configured on interface or a static route + * clear flag else treat fec as a connected route + */ + iface = if_lookup(ldeconf,fnh->ifindex); + if (iface || fnh->route_type == ZEBRA_ROUTE_STATIC) + fnh->flags &=~F_FEC_NH_NO_LDP; + else + fnh->flags |= F_FEC_NH_NO_LDP; + } else { lde_send_delete_klabel(fn, fnh); fec_nh_del(fnh); } @@ -445,6 +469,7 @@ lde_check_mapping(struct map *map, struct lde_nbr *ln) struct lde_req *lre; struct lde_map *me; struct l2vpn_pw *pw; + bool send_map = false; lde_map2fec(map, ln->id, &fec); @@ -525,6 +550,15 @@ lde_check_mapping(struct map *map, struct lde_nbr *ln) if (!lde_address_find(ln, fnh->af, &fnh->nexthop)) continue; + /* + * Ordered Control: labelmap msg received from + * NH so clear flag and send labelmap msg to + * peer + */ + if (ldeconf->flags & F_LDPD_ORDERED_CONTROL) { + send_map = true; + fnh->flags &= ~F_FEC_NH_DEFER; + } fnh->remote_label = map->label; lde_send_change_klabel(fn, fnh); break; @@ -558,6 +592,15 @@ lde_check_mapping(struct map *map, struct lde_nbr *ln) * loop detection. LMp.28 - LMp.30 are unnecessary because we are * merging capable. */ + + /* + * Ordered Control: just received a labelmap for this fec from NH so + * need to send labelmap to all peers + * LMp.20 - LMp21 Execute procedure to send Label Mapping + */ + if (send_map && fn->local_label != NO_LABEL) + RB_FOREACH(ln, nbr_tree, &lde_nbrs) + lde_send_labelmapping(ln, fn, 1); } void @@ -757,6 +800,7 @@ lde_check_withdraw(struct map *map, struct lde_nbr *ln) struct fec_nh *fnh; struct lde_map *me; struct l2vpn_pw *pw; + struct lde_nbr *lnbr; /* wildcard label withdraw */ if (map->type == MAP_TYPE_WILDCARD || @@ -803,6 +847,26 @@ lde_check_withdraw(struct map *map, struct lde_nbr *ln) if (me && (map->label == NO_LABEL || map->label == me->map.label)) /* LWd.4: remove record of previously received lbl mapping */ lde_map_del(ln, me, 0); + + /* Ordered Control: additional withdraw steps */ + if (ldeconf->flags & F_LDPD_ORDERED_CONTROL) { + /* LWd.8: for each neighbor other that src of withdraw msg */ + RB_FOREACH(lnbr, nbr_tree, &lde_nbrs) { + if (ln->peerid == lnbr->peerid) + continue; + + /* LWd.9: check if previously sent a label mapping */ + me = (struct lde_map *)fec_find(&lnbr->sent_map, + &fn->fec); + /* + * LWd.10: does label sent to peer "map" to withdraw + * label + */ + if (me) + /* LWd.11: send label withdraw */ + lde_send_labelwithdraw(lnbr, fn, NULL, NULL); + } + } } void @@ -813,6 +877,7 @@ lde_check_withdraw_wcard(struct map *map, struct lde_nbr *ln) struct fec_nh *fnh; struct lde_map *me; struct l2vpn_pw *pw; + struct lde_nbr *lnbr; /* LWd.2: send label release */ lde_send_labelrelease(ln, NULL, map, map->label); @@ -859,6 +924,26 @@ lde_check_withdraw_wcard(struct map *map, struct lde_nbr *ln) * label mapping */ lde_map_del(ln, me, 0); + + /* Ordered Control: additional withdraw steps */ + if (ldeconf->flags & F_LDPD_ORDERED_CONTROL) { + /* LWd.8: for each neighbor other that src of withdraw msg */ + RB_FOREACH(lnbr, nbr_tree, &lde_nbrs) { + if (ln->peerid == lnbr->peerid) + continue; + + /* LWd.9: check if previously sent a label mapping */ + me = (struct lde_map *)fec_find(&lnbr->sent_map, + &fn->fec); + /* + * LWd.10: does label sent to peer "map" to withdraw + * label + */ + if (me) + /* LWd.11: send label withdraw */ + lde_send_labelwithdraw(lnbr, fn, NULL, NULL); + } + } } } diff --git a/ldpd/ldp_vty.h b/ldpd/ldp_vty.h index 5e9df4aafe..af5f1d5616 100644 --- a/ldpd/ldp_vty.h +++ b/ldpd/ldp_vty.h @@ -52,6 +52,7 @@ int ldp_vty_label_expnull(struct vty *, const char *, const char *); int ldp_vty_label_accept(struct vty *, const char *, const char *, const char *); int ldp_vty_ttl_security(struct vty *, const char *); int ldp_vty_router_id(struct vty *, const char *, struct in_addr); +int ldp_vty_ordered_control(struct vty *, const char *); int ldp_vty_ds_cisco_interop(struct vty *, const char *); int ldp_vty_trans_pref_ipv4(struct vty *, const char *); int ldp_vty_neighbor_password(struct vty *, const char *, struct in_addr, const char *); diff --git a/ldpd/ldp_vty_cmds.c b/ldpd/ldp_vty_cmds.c index c24e1917cc..c10c6ae35c 100644 --- a/ldpd/ldp_vty_cmds.c +++ b/ldpd/ldp_vty_cmds.c @@ -221,6 +221,15 @@ DEFPY (ldp_router_id, return (ldp_vty_router_id(vty, no, address)); } +DEFPY (ldp_ordered_control, + ldp_ordered_control_cmd, + "[no] ordered-control", + NO_STR + "Configure LDP ordered label distribution control mode\n") +{ + return (ldp_vty_ordered_control(vty, no)); +} + DEFPY (ldp_discovery_targeted_hello_accept, ldp_discovery_targeted_hello_accept_cmd, "[no] discovery targeted-hello accept [from <(1-199)|(1300-2699)|WORD>$from_acl]", @@ -807,6 +816,7 @@ ldp_vty_init (void) install_element(LDP_NODE, &ldp_neighbor_session_holdtime_cmd); install_element(LDP_NODE, &ldp_neighbor_ttl_security_cmd); install_element(LDP_NODE, &ldp_router_id_cmd); + install_element(LDP_NODE, &ldp_ordered_control_cmd); install_element(LDP_IPV4_NODE, &ldp_discovery_link_holdtime_cmd); install_element(LDP_IPV4_NODE, &ldp_discovery_targeted_holdtime_cmd); diff --git a/ldpd/ldp_vty_conf.c b/ldpd/ldp_vty_conf.c index 816fcc64b8..05b8962563 100644 --- a/ldpd/ldp_vty_conf.c +++ b/ldpd/ldp_vty_conf.c @@ -278,6 +278,9 @@ ldp_config_write(struct vty *vty) if (ldpd_conf->flags & F_LDPD_DS_CISCO_INTEROP) vty_out (vty, " dual-stack cisco-interop\n"); + if (ldpd_conf->flags & F_LDPD_ORDERED_CONTROL) + vty_out (vty, " ordered-control\n"); + RB_FOREACH(nbrp, nbrp_head, &ldpd_conf->nbrp_tree) { if (nbrp->flags & F_NBRP_KEEPALIVE) vty_out (vty, " neighbor %s session holdtime %u\n", @@ -997,6 +1000,19 @@ ldp_vty_router_id(struct vty *vty, const char *negate, struct in_addr address) } int +ldp_vty_ordered_control(struct vty *vty, const char *negate) +{ + if (negate) + vty_conf->flags &= ~F_LDPD_ORDERED_CONTROL; + else + vty_conf->flags |= F_LDPD_ORDERED_CONTROL; + + ldp_config_apply(vty, vty_conf); + + return (CMD_SUCCESS); +} + +int ldp_vty_ds_cisco_interop(struct vty *vty, const char * negate) { if (negate) diff --git a/ldpd/ldpd.c b/ldpd/ldpd.c index 78b1c3e544..741c8c4655 100644 --- a/ldpd/ldpd.c +++ b/ldpd/ldpd.c @@ -1285,6 +1285,14 @@ merge_global(struct ldpd_conf *conf, struct ldpd_conf *xconf) conf->rtr_id = xconf->rtr_id; } + /* + * Configuration of ordered-control or independent-control + * requires resetting all neighborships. + */ + if ((conf->flags & F_LDPD_ORDERED_CONTROL) != + (xconf->flags & F_LDPD_ORDERED_CONTROL)) + ldpe_reset_nbrs(AF_UNSPEC); + conf->lhello_holdtime = xconf->lhello_holdtime; conf->lhello_interval = xconf->lhello_interval; conf->thello_holdtime = xconf->thello_holdtime; @@ -1311,6 +1319,7 @@ merge_af(int af, struct ldpd_af_conf *af_conf, struct ldpd_af_conf *xa) int stop_init_backoff = 0; int remove_dynamic_tnbrs = 0; int change_egress_label = 0; + int change_host_label = 0; int reset_nbrs_ipv4 = 0; int reset_nbrs = 0; int update_sockets = 0; @@ -1341,6 +1350,12 @@ merge_af(int af, struct ldpd_af_conf *af_conf, struct ldpd_af_conf *xa) if ((af_conf->flags & F_LDPD_AF_EXPNULL) != (xa->flags & F_LDPD_AF_EXPNULL)) change_egress_label = 1; + + /* changing config of host only fec filtering */ + if ((af_conf->flags & F_LDPD_AF_ALLOCHOSTONLY) + != (xa->flags & F_LDPD_AF_ALLOCHOSTONLY)) + change_host_label = 1; + af_conf->flags = xa->flags; /* update the transport address */ @@ -1350,6 +1365,10 @@ merge_af(int af, struct ldpd_af_conf *af_conf, struct ldpd_af_conf *xa) } /* update ACLs */ + if (strcmp(af_conf->acl_label_allocate_for, + xa->acl_label_allocate_for)) + change_host_label = 1; + if (strcmp(af_conf->acl_label_advertise_to, xa->acl_label_advertise_to) || strcmp(af_conf->acl_label_advertise_for, @@ -1383,6 +1402,8 @@ merge_af(int af, struct ldpd_af_conf *af_conf, struct ldpd_af_conf *xa) case PROC_LDE_ENGINE: if (change_egress_label) lde_change_egress_label(af); + if (change_host_label) + lde_change_host_label(af); break; case PROC_LDP_ENGINE: if (stop_init_backoff) diff --git a/ldpd/ldpd.h b/ldpd/ldpd.h index 006780f032..a736b4ca37 100644 --- a/ldpd/ldpd.h +++ b/ldpd/ldpd.h @@ -511,6 +511,8 @@ DECLARE_QOBJ_TYPE(ldpd_conf) #define F_LDPD_NO_FIB_UPDATE 0x0001 #define F_LDPD_DS_CISCO_INTEROP 0x0002 #define F_LDPD_ENABLED 0x0004 +#define F_LDPD_ORDERED_CONTROL 0x0008 + struct ldpd_af_global { struct thread *disc_ev; diff --git a/lib/agg_table.h b/lib/agg_table.h index f95fed6758..e98476f1b7 100644 --- a/lib/agg_table.h +++ b/lib/agg_table.h @@ -155,6 +155,16 @@ static inline struct agg_table *agg_get_table(struct agg_node *node) return (struct agg_table *)route_table_get_info(node->table); } +static inline const struct prefix * +agg_node_get_prefix(const struct agg_node *node) +{ + return &node->p; +} + +#ifdef _FRR_ATTRIBUTE_PRINTFRR +#pragma FRR printfrr_ext "%pRN" (struct agg_node *) +#endif + #ifdef __cplusplus } #endif diff --git a/lib/compiler.h b/lib/compiler.h index e430925e69..217a60d888 100644 --- a/lib/compiler.h +++ b/lib/compiler.h @@ -305,7 +305,14 @@ extern "C" { #include <inttypes.h> #ifdef _FRR_ATTRIBUTE_PRINTFRR -#define PRINTFRR(a, b) __attribute__((printfrr(a, b))) +#define PRINTFRR(a, b) __attribute__((frr_format("frr_printf", a, b))) + +#undef PRIu64 +#undef PRId64 +#undef PRIx64 +#define PRIu64 "Lu" +#define PRId64 "Ld" +#define PRIx64 "Lx" #else /* !_FRR_ATTRIBUTE_PRINTFRR */ #define PRINTFRR(a, b) __attribute__((format(printf, a, b))) diff --git a/lib/frrlua.c b/lib/frrlua.c index 26610556dc..9f9cf8c1f6 100644 --- a/lib/frrlua.c +++ b/lib/frrlua.c @@ -5,7 +5,7 @@ * Copyright (C) 2016 Cumulus Networks, Inc. * Donald Sharp * - * This file is part of FreeRangeRouting (FRR). + * This file is part of FRRouting (FRR). * * FRR is free software; you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software diff --git a/lib/frrlua.h b/lib/frrlua.h index 374eb70311..40c7a67b89 100644 --- a/lib/frrlua.h +++ b/lib/frrlua.h @@ -5,7 +5,7 @@ * Copyright (C) 2016 Cumulus Networks, Inc. * Donald Sharp * - * This file is part of FreeRangeRouting (FRR). + * This file is part of FRRouting (FRR). * * FRR is free software; you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software diff --git a/lib/grammar_sandbox_main.c b/lib/grammar_sandbox_main.c index 4bd8f5138a..5d3f6675a3 100644 --- a/lib/grammar_sandbox_main.c +++ b/lib/grammar_sandbox_main.c @@ -7,7 +7,7 @@ * Copyright (C) 2016 Cumulus Networks, Inc. * Copyright (C) 2017 David Lamparter for NetDEF, Inc. * - * This file is part of FreeRangeRouting (FRR). + * This file is part of FRRouting (FRR). * * FRR is free software; you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software diff --git a/lib/ipaddr.h b/lib/ipaddr.h index c6372f1abb..cd7f79a04e 100644 --- a/lib/ipaddr.h +++ b/lib/ipaddr.h @@ -112,7 +112,7 @@ static inline void ipv4_to_ipv4_mapped_ipv6(struct in6_addr *in6, /* * convert an ipv4 mapped ipv6 address back to ipv4 address */ -static inline void ipv4_mapped_ipv6_to_ipv4(struct in6_addr *in6, +static inline void ipv4_mapped_ipv6_to_ipv4(const struct in6_addr *in6, struct in_addr *in) { memset(in, 0, sizeof(struct in_addr)); @@ -1228,59 +1228,47 @@ int proto_redistnum(int afi, const char *s) return -1; } -void zlog_hexdump(const void *mem, unsigned int len) +void zlog_hexdump(const void *mem, size_t len) { - unsigned long i = 0; - unsigned int j = 0; - unsigned int columns = 8; - /* - * 19 bytes for 0xADDRESS: - * 24 bytes for data; 2 chars plus a space per data byte - * 1 byte for space - * 8 bytes for ASCII representation - * 1 byte for a newline - * ===================== - * 53 bytes per 8 bytes of data - * 1 byte for null term - */ - size_t bs = ((len / 8) + 1) * 53 + 1; - char buf[bs]; - char *s = buf; - const unsigned char *memch = mem; - - memset(buf, 0, sizeof(buf)); - - for (i = 0; i < len + ((len % columns) ? (columns - len % columns) : 0); - i++) { - /* print offset */ - if (i % columns == 0) - s += snprintf(s, bs - (s - buf), - "0x%016lx: ", (unsigned long)memch + i); - - /* print hex data */ - if (i < len) - s += snprintf(s, bs - (s - buf), "%02x ", memch[i]); - - /* end of block, just aligning for ASCII dump */ - else - s += snprintf(s, bs - (s - buf), " "); - - /* print ASCII dump */ - if (i % columns == (columns - 1)) { - for (j = i - (columns - 1); j <= i; j++) { - /* end of block not really printing */ - if (j >= len) - s += snprintf(s, bs - (s - buf), " "); - else if (isprint(memch[j])) - s += snprintf(s, bs - (s - buf), "%c", - memch[j]); - else /* other char */ - s += snprintf(s, bs - (s - buf), "."); - } - s += snprintf(s, bs - (s - buf), "\n"); + char line[64]; + const uint8_t *src = mem; + const uint8_t *end = src + len; + + if (len == 0) { + zlog_debug("%016lx: (zero length / no data)", (long)src); + return; + } + + while (src < end) { + struct fbuf fb = { + .buf = line, + .pos = line, + .len = sizeof(line), + }; + const uint8_t *lineend = src + 8; + unsigned line_bytes = 0; + + bprintfrr(&fb, "%016lx: ", (long)src); + + while (src < lineend && src < end) { + bprintfrr(&fb, "%02x ", *src++); + line_bytes++; + } + if (line_bytes < 8) + bprintfrr(&fb, "%*s", (8 - line_bytes) * 3, ""); + + src -= line_bytes; + while (src < lineend && src < end && fb.pos < fb.buf + fb.len) { + uint8_t byte = *src++; + + if (isprint(byte)) + *fb.pos++ = byte; + else + *fb.pos++ = '.'; } + + zlog_debug("%.*s", (int)(fb.pos - fb.buf), fb.buf); } - zlog_debug("\n%s", buf); } const char *zlog_sanitize(char *buf, size_t bufsz, const void *in, size_t inlen) @@ -152,7 +152,7 @@ extern void zlog_backtrace_sigsafe(int priority, void *program_counter); extern size_t quagga_timestamp(int timestamp_precision /* # subsecond digits */, char *buf, size_t buflen); -extern void zlog_hexdump(const void *mem, unsigned int len); +extern void zlog_hexdump(const void *mem, size_t len); extern const char *zlog_sanitize(char *buf, size_t bufsz, const void *in, size_t inlen); diff --git a/lib/mpls.c b/lib/mpls.c index 759fe1206d..ac5792a686 100644 --- a/lib/mpls.c +++ b/lib/mpls.c @@ -79,7 +79,7 @@ int mpls_str2label(const char *label_str, uint8_t *num_labels, /* * Label to string conversion, labels in string separated by '/'. */ -char *mpls_label2str(uint8_t num_labels, mpls_label_t *labels, char *buf, +char *mpls_label2str(uint8_t num_labels, const mpls_label_t *labels, char *buf, int len, int pretty) { char label_buf[BUFSIZ]; diff --git a/lib/mpls.h b/lib/mpls.h index 635ecc77a1..05cf2935e8 100644 --- a/lib/mpls.h +++ b/lib/mpls.h @@ -209,10 +209,13 @@ static inline char *label2str(mpls_label_t label, char *buf, size_t len) int mpls_str2label(const char *label_str, uint8_t *num_labels, mpls_label_t *labels); +/* Generic string buffer for label-stack-to-str */ +#define MPLS_LABEL_STRLEN 1024 + /* * Label to string conversion, labels in string separated by '/'. */ -char *mpls_label2str(uint8_t num_labels, mpls_label_t *labels, char *buf, +char *mpls_label2str(uint8_t num_labels, const mpls_label_t *labels, char *buf, int len, int pretty); #ifdef __cplusplus diff --git a/lib/nexthop.c b/lib/nexthop.c index e23f8b0792..0d239e091b 100644 --- a/lib/nexthop.c +++ b/lib/nexthop.c @@ -23,11 +23,9 @@ #include "table.h" #include "memory.h" #include "command.h" -#include "if.h" #include "log.h" #include "sockunion.h" #include "linklist.h" -#include "thread.h" #include "prefix.h" #include "nexthop.h" #include "mpls.h" @@ -155,7 +153,24 @@ static int _nexthop_cmp_no_labels(const struct nexthop *next1, } ret = _nexthop_source_cmp(next1, next2); + if (ret != 0) + goto done; + + if (!CHECK_FLAG(next1->flags, NEXTHOP_FLAG_HAS_BACKUP) && + CHECK_FLAG(next2->flags, NEXTHOP_FLAG_HAS_BACKUP)) + return -1; + + if (CHECK_FLAG(next1->flags, NEXTHOP_FLAG_HAS_BACKUP) && + !CHECK_FLAG(next2->flags, NEXTHOP_FLAG_HAS_BACKUP)) + return 1; + + if (next1->backup_idx < next2->backup_idx) + return -1; + if (next1->backup_idx > next2->backup_idx) + return 1; + +done: return ret; } @@ -240,7 +255,7 @@ struct nexthop *nexthop_new(void) * The linux kernel does some weird stuff with adding +1 to * all nexthop weights it gets over netlink. * To handle this, just default everything to 1 right from - * from the beggining so we don't have to special case + * from the beginning so we don't have to special case * default weights in the linux netlink code. * * 1 should be a valid on all platforms anyway. @@ -393,8 +408,8 @@ struct nexthop *nexthop_from_blackhole(enum blackhole_type bh_type) } /* Update nexthop with label information. */ -void nexthop_add_labels(struct nexthop *nexthop, enum lsp_types_t type, - uint8_t num_labels, mpls_label_t *label) +void nexthop_add_labels(struct nexthop *nexthop, enum lsp_types_t ltype, + uint8_t num_labels, const mpls_label_t *labels) { struct mpls_label_stack *nh_label; int i; @@ -402,23 +417,26 @@ void nexthop_add_labels(struct nexthop *nexthop, enum lsp_types_t type, if (num_labels == 0) return; - nexthop->nh_label_type = type; + /* Enforce limit on label stack size */ + if (num_labels > MPLS_MAX_LABELS) + num_labels = MPLS_MAX_LABELS; + + nexthop->nh_label_type = ltype; + nh_label = XCALLOC(MTYPE_NH_LABEL, sizeof(struct mpls_label_stack) + num_labels * sizeof(mpls_label_t)); nh_label->num_labels = num_labels; for (i = 0; i < num_labels; i++) - nh_label->label[i] = *(label + i); + nh_label->label[i] = *(labels + i); nexthop->nh_label = nh_label; } /* Free label information of nexthop, if present. */ void nexthop_del_labels(struct nexthop *nexthop) { - if (nexthop->nh_label) { - XFREE(MTYPE_NH_LABEL, nexthop->nh_label); - nexthop->nh_label_type = ZEBRA_LSP_NONE; - } + XFREE(MTYPE_NH_LABEL, nexthop->nh_label); + nexthop->nh_label_type = ZEBRA_LSP_NONE; } const char *nexthop2str(const struct nexthop *nexthop, char *str, int size) @@ -505,6 +523,7 @@ unsigned int nexthop_level(struct nexthop *nexthop) uint32_t nexthop_hash_quick(const struct nexthop *nexthop) { uint32_t key = 0x45afe398; + uint32_t val; key = jhash_3words(nexthop->type, nexthop->vrf_id, nexthop->nh_label_type, key); @@ -534,8 +553,12 @@ uint32_t nexthop_hash_quick(const struct nexthop *nexthop) key = jhash_1word(nexthop->nh_label->label[i], key); } - key = jhash_2words(nexthop->ifindex, - CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK), + val = 0; + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP)) + val = (uint32_t)nexthop->backup_idx; + + key = jhash_3words(nexthop->ifindex, + CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK), val, key); return key; @@ -575,6 +598,7 @@ void nexthop_copy_no_recurse(struct nexthop *copy, copy->type = nexthop->type; copy->flags = nexthop->flags; copy->weight = nexthop->weight; + copy->backup_idx = nexthop->backup_idx; memcpy(©->gate, &nexthop->gate, sizeof(nexthop->gate)); memcpy(©->src, &nexthop->src, sizeof(nexthop->src)); memcpy(©->rmap_src, &nexthop->rmap_src, sizeof(nexthop->rmap_src)); diff --git a/lib/nexthop.h b/lib/nexthop.h index 6710914e40..c4e88dd844 100644 --- a/lib/nexthop.h +++ b/lib/nexthop.h @@ -86,6 +86,8 @@ struct nexthop { * active one */ #define NEXTHOP_FLAG_RNH_FILTERED (1 << 5) /* rmap filtered, used by rnh */ +#define NEXTHOP_FLAG_HAS_BACKUP (1 << 6) /* Backup nexthop index is set */ + #define NEXTHOP_IS_ACTIVE(flags) \ (CHECK_FLAG(flags, NEXTHOP_FLAG_ACTIVE) \ && !CHECK_FLAG(flags, NEXTHOP_FLAG_DUPLICATE)) @@ -116,15 +118,31 @@ struct nexthop { /* Weight of the nexthop ( for unequal cost ECMP ) */ uint8_t weight; + + /* Index of a corresponding backup nexthop in a backup list; + * only meaningful if the HAS_BACKUP flag is set. + */ + uint8_t backup_idx; }; +/* Backup index value is limited */ +#define NEXTHOP_BACKUP_IDX_MAX 255 + +/* Utility to append one nexthop to another. */ +#define NEXTHOP_APPEND(to, new) \ + do { \ + (to)->next = (new); \ + (new)->prev = (to); \ + (new)->next = NULL; \ + } while (0) + struct nexthop *nexthop_new(void); void nexthop_free(struct nexthop *nexthop); void nexthops_free(struct nexthop *nexthop); -void nexthop_add_labels(struct nexthop *, enum lsp_types_t, uint8_t, - mpls_label_t *); +void nexthop_add_labels(struct nexthop *nexthop, enum lsp_types_t ltype, + uint8_t num_labels, const mpls_label_t *labels); void nexthop_del_labels(struct nexthop *); /* @@ -201,6 +219,10 @@ extern struct nexthop *nexthop_dup(const struct nexthop *nexthop, extern struct nexthop *nexthop_dup_no_recurse(const struct nexthop *nexthop, struct nexthop *rparent); +#ifdef _FRR_ATTRIBUTE_PRINTFRR +#pragma FRR printfrr_ext "%pNH" (struct nexthop *) +#endif + #ifdef __cplusplus } #endif diff --git a/lib/nexthop_group.c b/lib/nexthop_group.c index d660428bcd..8c3bbbdcd4 100644 --- a/lib/nexthop_group.c +++ b/lib/nexthop_group.c @@ -43,8 +43,12 @@ struct nexthop_hold { char *intf; char *labels; uint32_t weight; + int backup_idx; /* Index of backup nexthop, if >= 0 */ }; +/* Invalid/unset value for nexthop_hold's backup_idx */ +#define NHH_BACKUP_IDX_INVALID -1 + struct nexthop_group_hooks { void (*new)(const char *name); void (*add_nexthop)(const struct nexthop_group_cmd *nhg, @@ -225,6 +229,10 @@ void nexthop_group_copy(struct nexthop_group *to, void nexthop_group_delete(struct nexthop_group **nhg) { + /* OK to call with NULL group */ + if ((*nhg) == NULL) + return; + if ((*nhg)->nexthop) nexthops_free((*nhg)->nexthop); @@ -567,11 +575,36 @@ DEFUN_NOSH(no_nexthop_group, no_nexthop_group_cmd, "no nexthop-group NHGNAME", return CMD_SUCCESS; } +DEFPY(nexthop_group_backup, nexthop_group_backup_cmd, + "backup-group WORD$name", + "Specify a group name containing backup nexthops\n" + "The name of the backup group\n") +{ + VTY_DECLVAR_CONTEXT(nexthop_group_cmd, nhgc); + + strlcpy(nhgc->backup_list_name, name, sizeof(nhgc->backup_list_name)); + + return CMD_SUCCESS; +} + +DEFPY(no_nexthop_group_backup, no_nexthop_group_backup_cmd, + "no backup-group [WORD$name]", + NO_STR + "Clear group name containing backup nexthops\n" + "The name of the backup group\n") +{ + VTY_DECLVAR_CONTEXT(nexthop_group_cmd, nhgc); + + nhgc->backup_list_name[0] = 0; + + return CMD_SUCCESS; +} + static void nexthop_group_save_nhop(struct nexthop_group_cmd *nhgc, const char *nhvrf_name, const union sockunion *addr, const char *intf, const char *labels, - const uint32_t weight) + const uint32_t weight, int backup_idx) { struct nexthop_hold *nh; @@ -588,6 +621,8 @@ static void nexthop_group_save_nhop(struct nexthop_group_cmd *nhgc, nh->weight = weight; + nh->backup_idx = backup_idx; + listnode_add_sort(nhgc->nhg_list, nh); } @@ -629,7 +664,7 @@ static bool nexthop_group_parse_nexthop(struct nexthop *nhop, const union sockunion *addr, const char *intf, const char *name, const char *labels, int *lbl_ret, - uint32_t weight) + uint32_t weight, int backup_idx) { int ret = 0; struct vrf *vrf; @@ -688,6 +723,15 @@ static bool nexthop_group_parse_nexthop(struct nexthop *nhop, nhop->weight = weight; + if (backup_idx != NHH_BACKUP_IDX_INVALID) { + /* Validate index value */ + if (backup_idx > NEXTHOP_BACKUP_IDX_MAX) + return false; + + SET_FLAG(nhop->flags, NEXTHOP_FLAG_HAS_BACKUP); + nhop->backup_idx = backup_idx; + } + return true; } @@ -699,7 +743,7 @@ static bool nexthop_group_parse_nhh(struct nexthop *nhop, { return (nexthop_group_parse_nexthop(nhop, nhh->addr, nhh->intf, nhh->nhvrf_name, nhh->labels, NULL, - nhh->weight)); + nhh->weight, nhh->backup_idx)); } DEFPY(ecmp_nexthops, ecmp_nexthops_cmd, @@ -712,6 +756,7 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd, nexthop-vrf NAME$vrf_name \ |label WORD \ |weight (1-255) \ + |backup-idx$bi_str (0-254)$idx \ }]", NO_STR "Specify one of the nexthops in this ECMP group\n" @@ -724,16 +769,23 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd, "Specify label(s) for this nexthop\n" "One or more labels in the range (16-1048575) separated by '/'\n" "Weight to be used by the nexthop for purposes of ECMP\n" - "Weight value to be used\n") + "Weight value to be used\n" + "Backup nexthop index in another group\n" + "Nexthop index value\n") { VTY_DECLVAR_CONTEXT(nexthop_group_cmd, nhgc); struct nexthop nhop; struct nexthop *nh; int lbl_ret = 0; bool legal; + int backup_idx = idx; + bool add_update = false; + + if (bi_str == NULL) + backup_idx = NHH_BACKUP_IDX_INVALID; legal = nexthop_group_parse_nexthop(&nhop, addr, intf, vrf_name, label, - &lbl_ret, weight); + &lbl_ret, weight, backup_idx); if (nhop.type == NEXTHOP_TYPE_IPV6 && IN6_IS_ADDR_LINKLOCAL(&nhop.gate.ipv6)) { @@ -765,19 +817,30 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd, nh = nexthop_exists(&nhgc->nhg, &nhop); - if (no) { + if (no || nh) { + /* Remove or replace cases */ + + /* Remove existing config */ nexthop_group_unsave_nhop(nhgc, vrf_name, addr, intf, label, weight); if (nh) { + /* Remove nexthop object */ _nexthop_del(&nhgc->nhg, nh); if (nhg_hooks.del_nexthop) nhg_hooks.del_nexthop(nhgc, nh); nexthop_free(nh); + nh = NULL; } - } else if (!nh) { - /* must be adding new nexthop since !no and !nexthop_exists */ + } + + add_update = !no; + + if (add_update) { + /* Add or replace cases */ + + /* If valid config, add nexthop object */ if (legal) { nh = nexthop_new(); @@ -785,8 +848,9 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd, _nexthop_add(&nhgc->nhg.nexthop, nh); } + /* Save config always */ nexthop_group_save_nhop(nhgc, vrf_name, addr, intf, label, - weight); + weight, backup_idx); if (legal && nhg_hooks.add_nexthop) nhg_hooks.add_nexthop(nhgc, nh); @@ -849,6 +913,9 @@ void nexthop_group_write_nexthop(struct vty *vty, struct nexthop *nh) if (nh->weight) vty_out(vty, " weight %u", nh->weight); + if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_HAS_BACKUP)) + vty_out(vty, " backup-idx %d", nh->backup_idx); + vty_out(vty, "\n"); } @@ -874,6 +941,9 @@ static void nexthop_group_write_nexthop_internal(struct vty *vty, if (nh->weight) vty_out(vty, " weight %u", nh->weight); + if (nh->backup_idx != NHH_BACKUP_IDX_INVALID) + vty_out(vty, " backup-idx %d", nh->backup_idx); + vty_out(vty, "\n"); } @@ -887,6 +957,10 @@ static int nexthop_group_write(struct vty *vty) vty_out(vty, "nexthop-group %s\n", nhgc->name); + if (nhgc->backup_list_name[0]) + vty_out(vty, " backup-group %s\n", + nhgc->backup_list_name); + for (ALL_LIST_ELEMENTS_RO(nhgc->nhg_list, node, nh)) { vty_out(vty, " "); nexthop_group_write_nexthop_internal(vty, nh); @@ -1067,6 +1141,8 @@ void nexthop_group_init(void (*new)(const char *name), install_element(CONFIG_NODE, &no_nexthop_group_cmd); install_default(NH_GROUP_NODE); + install_element(NH_GROUP_NODE, &nexthop_group_backup_cmd); + install_element(NH_GROUP_NODE, &no_nexthop_group_backup_cmd); install_element(NH_GROUP_NODE, &ecmp_nexthops_cmd); memset(&nhg_hooks, 0, sizeof(nhg_hooks)); diff --git a/lib/nexthop_group.h b/lib/nexthop_group.h index f99a53f694..3a5a1299c1 100644 --- a/lib/nexthop_group.h +++ b/lib/nexthop_group.h @@ -57,6 +57,8 @@ void copy_nexthops(struct nexthop **tnh, const struct nexthop *nh, uint32_t nexthop_group_hash_no_recurse(const struct nexthop_group *nhg); uint32_t nexthop_group_hash(const struct nexthop_group *nhg); void nexthop_group_mark_duplicates(struct nexthop_group *nhg); + +/* Add a nexthop to a list, enforcing the canonical sort order. */ void nexthop_group_add_sorted(struct nexthop_group *nhg, struct nexthop *nexthop); @@ -79,11 +81,16 @@ void nexthop_group_add_sorted(struct nexthop_group *nhg, (nhop) = nexthop_next(nhop) +#define NHGC_NAME_SIZE 80 + struct nexthop_group_cmd { RB_ENTRY(nexthop_group_cmd) nhgc_entry; - char name[80]; + char name[NHGC_NAME_SIZE]; + + /* Name of group containing backup nexthops (if set) */ + char backup_list_name[NHGC_NAME_SIZE]; struct nexthop_group nhg; diff --git a/lib/northbound_grpc.cpp b/lib/northbound_grpc.cpp index 089899368d..b195f1aeca 100644 --- a/lib/northbound_grpc.cpp +++ b/lib/northbound_grpc.cpp @@ -884,7 +884,14 @@ static int frr_grpc_finish(void) return 0; } -static int frr_grpc_module_late_init(struct thread_master *tm) +/* + * This is done this way because module_init and module_late_init are both + * called during daemon pre-fork initialization. Because the GRPC library + * spawns threads internally, we need to delay initializing it until after + * fork. This is done by scheduling this init function as an event task, since + * the event loop doesn't run until after fork. + */ +static int frr_grpc_module_very_late_init(struct thread *thread) { static unsigned long port = GRPC_DEFAULT_PORT; const char *args = THIS_MODULE->load_args; @@ -910,15 +917,19 @@ static int frr_grpc_module_late_init(struct thread_master *tm) if (frr_grpc_init(&port) < 0) goto error; - hook_register(frr_fini, frr_grpc_finish); - - return 0; - error: flog_err(EC_LIB_GRPC_INIT, "failed to initialize the gRPC module"); return -1; } +static int frr_grpc_module_late_init(struct thread_master *tm) +{ + thread_add_event(tm, frr_grpc_module_very_late_init, NULL, 0, NULL); + hook_register(frr_fini, frr_grpc_finish); + + return 0; +} + static int frr_grpc_module_init(void) { hook_register(frr_late_init, frr_grpc_module_late_init); diff --git a/lib/plist.c b/lib/plist.c index 40131aebed..b7a020c6f7 100644 --- a/lib/plist.c +++ b/lib/plist.c @@ -778,7 +778,7 @@ static void __attribute__((unused)) prefix_list_print(struct prefix_list *plist) p = &pentry->prefix; - printf(" seq %" PRId64 " %s %s/%d", pentry->seq, + printf(" seq %lld %s %s/%d", (long long)pentry->seq, prefix_list_type_str(pentry), inet_ntop(p->family, p->u.val, buf, BUFSIZ), p->prefixlen); diff --git a/lib/prefix.h b/lib/prefix.h index b01f7d1fdc..f2952c38c3 100644 --- a/lib/prefix.h +++ b/lib/prefix.h @@ -531,7 +531,7 @@ static inline int is_host_route(struct prefix *p) return 0; } -static inline int is_default_host_route(struct prefix *p) +static inline int is_default_host_route(const struct prefix *p) { if (p->family == AF_INET) { return (p->u.prefix4.s_addr == INADDR_ANY && @@ -544,6 +544,22 @@ static inline int is_default_host_route(struct prefix *p) return 0; } +#ifdef _FRR_ATTRIBUTE_PRINTFRR +#pragma FRR printfrr_ext "%pI4" (struct in_addr *) +#pragma FRR printfrr_ext "%pI4" (in_addr_t *) + +#pragma FRR printfrr_ext "%pI6" (struct in6_addr *) + +#pragma FRR printfrr_ext "%pFX" (struct prefix *) +#pragma FRR printfrr_ext "%pFX" (struct prefix_ipv4 *) +#pragma FRR printfrr_ext "%pFX" (struct prefix_ipv6 *) +#pragma FRR printfrr_ext "%pFX" (struct prefix_eth *) +#pragma FRR printfrr_ext "%pFX" (struct prefix_evpn *) +#pragma FRR printfrr_ext "%pFX" (struct prefix_fs *) + +#pragma FRR printfrr_ext "%pSG4" (struct prefix_sg *) +#endif + #ifdef __cplusplus } #endif diff --git a/lib/printfrr.h b/lib/printfrr.h index f9584bcacc..7d9e288655 100644 --- a/lib/printfrr.h +++ b/lib/printfrr.h @@ -30,8 +30,7 @@ struct fbuf { size_t len; }; -#define at(a, b) \ - __attribute__((format(printf, a, b))) +#define at(a, b) PRINTFRR(a, b) #define atn(a, b) \ at(a, b) __attribute__((nonnull(1) _RET_NONNULL)) #define atm(a, b) \ @@ -73,8 +72,19 @@ char *vasnprintfrr(struct memtype *mt, char *out, size_t sz, char *asnprintfrr(struct memtype *mt, char *out, size_t sz, const char *fmt, ...) atn(4, 5); +#define printfrr(fmt, ...) \ + do { \ + char buf[256], *out; \ + out = asnprintfrr(MTYPE_TMP, buf, sizeof(buf), fmt, \ + ##__VA_ARGS__); \ + fputs(out, stdout); \ + if (out != buf) \ + XFREE(MTYPE_TMP, out); \ + } while (0) + #undef at #undef atm +#undef atn /* extension specs must start with a capital letter (this is a restriction * for both performance's and human understanding's sake.) diff --git a/lib/routemap_cli.c b/lib/routemap_cli.c index 5b03b5266f..41e8cacd81 100644 --- a/lib/routemap_cli.c +++ b/lib/routemap_cli.c @@ -148,6 +148,12 @@ void route_map_instance_show(struct vty *vty, struct lyd_node *dnode, SKIP_RULE("ipv6 next-hop type"); SKIP_RULE("metric"); SKIP_RULE("tag"); + /* Zebra specific match conditions. */ + SKIP_RULE("ip address prefix-len"); + SKIP_RULE("ipv6 address prefix-len"); + SKIP_RULE("ip next-hop prefix-len"); + SKIP_RULE("source-protocol"); + SKIP_RULE("source-instance"); vty_out(vty, " match %s %s\n", rmr->cmd->str, rmr->rule_str ? rmr->rule_str : ""); @@ -158,6 +164,8 @@ void route_map_instance_show(struct vty *vty, struct lyd_node *dnode, /* Skip all sets implemented by northbound. */ SKIP_RULE("metric"); SKIP_RULE("tag"); + /* Zebra specific set actions. */ + SKIP_RULE("src"); vty_out(vty, " set %s %s\n", rmr->cmd->str, rmr->rule_str ? rmr->rule_str : ""); @@ -666,8 +674,25 @@ void route_map_condition_show(struct vty *vty, struct lyd_node *dnode, vty_out(vty, " match tag %s\n", yang_dnode_get_string(dnode, "./tag")); break; - case 100: - /* NOTHING: custom field, should be handled by daemon. */ + case 100: /* ipv4-prefix-length */ + vty_out(vty, " match ip address prefix-len %s\n", + yang_dnode_get_string(dnode,"./frr-zebra:ipv4-prefix-length")); + break; + case 101: /* ipv6-prefix-length */ + vty_out(vty, " match ipv6 address prefix-len %s\n", + yang_dnode_get_string(dnode, "./frr-zebra:ipv6-prefix-length")); + break; + case 102: /* ipv4-next-hop-prefix-length */ + vty_out(vty, " match ip next-hop prefix-len %s\n", + yang_dnode_get_string(dnode, "./frr-zebra:ipv4-prefix-length")); + break; + case 103: /* source-protocol */ + vty_out(vty, " match source-protocol %s\n", + yang_dnode_get_string(dnode, "./frr-zebra:source-protocol")); + break; + case 104: /* source-instance */ + vty_out(vty, " match source-instance %s\n", + yang_dnode_get_string(dnode, "./frr-zebra:source-instance")); break; } } @@ -868,8 +893,13 @@ void route_map_action_show(struct vty *vty, struct lyd_node *dnode, vty_out(vty, " set tag %s\n", yang_dnode_get_string(dnode, "./tag")); break; - case 100: - /* NOTHING: custom field, should be handled by daemon. */ + case 100: /* source */ + if (yang_dnode_exists(dnode, "./frr-zebra:source-v4")) + vty_out(vty, " set src %s\n", + yang_dnode_get_string(dnode, "./frr-zebra:source-v4")); + else + vty_out(vty, " set src %s\n", + yang_dnode_get_string(dnode, "./frr-zebra:source-v6")); break; } } diff --git a/lib/skiplist.c b/lib/skiplist.c index d955c6eb9e..fa25770efa 100644 --- a/lib/skiplist.c +++ b/lib/skiplist.c @@ -112,7 +112,7 @@ static int randomLevel(void) return level; } -static int default_cmp(void *key1, void *key2) +static int default_cmp(const void *key1, const void *key2) { if (key1 < key2) return -1; @@ -126,7 +126,8 @@ unsigned int skiplist_count(struct skiplist *l) return l->count; } -struct skiplist *skiplist_new(int flags, int (*cmp)(void *key1, void *key2), +struct skiplist *skiplist_new(int flags, + int (*cmp)(const void *key1, const void *key2), void (*del)(void *val)) { struct skiplist *new; @@ -329,8 +330,8 @@ int skiplist_delete(register struct skiplist *l, register void *key, * Also set a cursor for use with skiplist_next_value. */ int skiplist_first_value(register struct skiplist *l, /* in */ - register void *key, /* in */ - void **valuePointer, /* out */ + register const void *key, /* in */ + void **valuePointer, /* out */ void **cursor) /* out */ { register int k; @@ -374,7 +375,7 @@ int skiplist_search(register struct skiplist *l, register void *key, * last element with the given key, -1 is returned. */ int skiplist_next_value(register struct skiplist *l, /* in */ - register void *key, /* in */ + register const void *key, /* in */ void **valuePointer, /* in/out */ void **cursor) /* in/out */ { diff --git a/lib/skiplist.h b/lib/skiplist.h index 2ab37331c9..a106a455d6 100644 --- a/lib/skiplist.h +++ b/lib/skiplist.h @@ -68,7 +68,7 @@ struct skiplist { * Returns -1 if val1 < val2, 0 if equal?, 1 if val1 > val2. * Used as definition of sorted for listnode_add_sort */ - int (*cmp)(void *val1, void *val2); + int (*cmp)(const void *val1, const void *val2); /* callback to free user-owned data when listnode is deleted. supplying * this callback is very much encouraged! @@ -81,8 +81,9 @@ struct skiplist { extern struct skiplist * skiplist_new(/* encouraged: set list.del callback on new lists */ int flags, - int (*cmp)(void *key1, void *key2), /* NULL => default cmp */ - void (*del)(void *val)); /* NULL => no auto val free */ + int (*cmp)(const void *key1, + const void *key2), /* NULL => default cmp */ + void (*del)(void *val)); /* NULL => no auto val free */ extern void skiplist_free(struct skiplist *); @@ -96,12 +97,12 @@ extern int skiplist_search(register struct skiplist *l, register void *key, void **valuePointer); extern int skiplist_first_value(register struct skiplist *l, /* in */ - register void *key, /* in */ - void **valuePointer, /* in/out */ + register const void *key, /* in */ + void **valuePointer, /* in/out */ void **cursor); /* out */ extern int skiplist_next_value(register struct skiplist *l, /* in */ - register void *key, /* in */ + register const void *key, /* in */ void **valuePointer, /* in/out */ void **cursor); /* in/out */ diff --git a/lib/smux.h b/lib/smux.h index 3f860db0dc..6896f02354 100644 --- a/lib/smux.h +++ b/lib/smux.h @@ -105,7 +105,7 @@ extern int smux_trap(struct variable *, size_t, const oid *, size_t, extern int oid_compare(const oid *, int, const oid *, int); extern void oid2in_addr(oid[], int, struct in_addr *); extern void *oid_copy(void *, const void *, size_t); -extern void oid_copy_addr(oid[], struct in_addr *, int); +extern void oid_copy_addr(oid[], const struct in_addr *, int); #ifdef __cplusplus } diff --git a/lib/snmp.c b/lib/snmp.c index f11d9dc8cf..736a3c62b8 100644 --- a/lib/snmp.c +++ b/lib/snmp.c @@ -64,10 +64,10 @@ void oid2in_addr(oid oid[], int len, struct in_addr *addr) *pnt++ = oid[i]; } -void oid_copy_addr(oid oid[], struct in_addr *addr, int len) +void oid_copy_addr(oid oid[], const struct in_addr *addr, int len) { int i; - uint8_t *pnt; + const uint8_t *pnt; if (len == 0) return; diff --git a/lib/spf_backoff.c b/lib/spf_backoff.c index 41d4e2bb57..4e74714489 100644 --- a/lib/spf_backoff.c +++ b/lib/spf_backoff.c @@ -7,7 +7,7 @@ * Copyright (C) 2017 Orange Labs http://www.orange.com/ * Copyright (C) 2017 by Christian Franke, Open Source Routing / NetDEF Inc. * - * This file is part of FreeRangeRouting (FRR) + * This file is part of FRRouting (FRR) * * FRR is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the diff --git a/lib/spf_backoff.h b/lib/spf_backoff.h index 11b2701e3e..2617195d79 100644 --- a/lib/spf_backoff.h +++ b/lib/spf_backoff.h @@ -7,7 +7,7 @@ * Copyright (C) 2017 Orange Labs http://www.orange.com/ * Copyright (C) 2017 by Christian Franke, Open Source Routing / NetDEF Inc. * - * This file is part of FreeRangeRouting (FRR) + * This file is part of FRRouting (FRR) * * FRR is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the diff --git a/lib/srcdest_table.c b/lib/srcdest_table.c index ee87d73077..66b735919b 100644 --- a/lib/srcdest_table.c +++ b/lib/srcdest_table.c @@ -4,7 +4,7 @@ * Copyright (C) 2017 by David Lamparter & Christian Franke, * Open Source Routing / NetDEF Inc. * - * This file is part of FreeRangeRouting (FRR) + * This file is part of FRRouting (FRR) * * FRR is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the diff --git a/lib/srcdest_table.h b/lib/srcdest_table.h index 90418944c7..7982260777 100644 --- a/lib/srcdest_table.h +++ b/lib/srcdest_table.h @@ -4,7 +4,7 @@ * Copyright (C) 2017 by David Lamparter & Christian Franke, * Open Source Routing / NetDEF Inc. * - * This file is part of FreeRangeRouting (FRR) + * This file is part of FRRouting (FRR) * * FRR is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the diff --git a/lib/stream.c b/lib/stream.c index dd4d5bd96d..f046572f41 100644 --- a/lib/stream.c +++ b/lib/stream.c @@ -898,7 +898,7 @@ int stream_put_prefix(struct stream *s, const struct prefix *p) } /* Put NLRI with label */ -int stream_put_labeled_prefix(struct stream *s, struct prefix *p, +int stream_put_labeled_prefix(struct stream *s, const struct prefix *p, mpls_label_t *label, int addpath_encode, uint32_t addpath_tx_id) { diff --git a/lib/stream.h b/lib/stream.h index 36c65afa3c..6fcf9a53cf 100644 --- a/lib/stream.h +++ b/lib/stream.h @@ -196,7 +196,7 @@ extern int stream_put_prefix_addpath(struct stream *s, int addpath_encode, uint32_t addpath_tx_id); extern int stream_put_prefix(struct stream *s, const struct prefix *p); -extern int stream_put_labeled_prefix(struct stream *, struct prefix *, +extern int stream_put_labeled_prefix(struct stream *, const struct prefix *, mpls_label_t *, int addpath_encode, uint32_t addpath_tx_id); extern void stream_get(void *, struct stream *, size_t); @@ -354,9 +354,10 @@ extern void stream_fifo_free(struct stream_fifo *fifo); * bit), for 64-bit values (you need to cast them anyway), and neither for * encoding (because it's downcasted.) */ -static inline uint8_t *ptr_get_be32(uint8_t *ptr, uint32_t *out) +static inline const uint8_t *ptr_get_be32(const uint8_t *ptr, uint32_t *out) { uint32_t tmp; + memcpy(&tmp, ptr, sizeof(tmp)); *out = ntohl(tmp); return ptr + 4; diff --git a/lib/table.h b/lib/table.h index 7743d51681..9cd9503376 100644 --- a/lib/table.h +++ b/lib/table.h @@ -331,6 +331,10 @@ static inline int route_table_iter_started(route_table_iter_t *iter) return iter->state != RT_ITER_STATE_INIT; } +#ifdef _FRR_ATTRIBUTE_PRINTFRR +#pragma FRR printfrr_ext "%pRN" (struct route_node *) +#endif + #ifdef __cplusplus } #endif diff --git a/lib/thread.c b/lib/thread.c index 2217a60f0a..dbf668a699 100644 --- a/lib/thread.c +++ b/lib/thread.c @@ -114,11 +114,10 @@ static void vty_out_cpu_thread_history(struct vty *vty, struct cpu_thread_history *a) { vty_out(vty, "%5zu %10zu.%03zu %9zu %8zu %9zu %8zu %9zu", - (size_t)a->total_active, - a->cpu.total / 1000, a->cpu.total % 1000, - (size_t)a->total_calls, - a->cpu.total / a->total_calls, a->cpu.max, - a->real.total / a->total_calls, a->real.max); + (size_t)a->total_active, a->cpu.total / 1000, + a->cpu.total % 1000, (size_t)a->total_calls, + (size_t)(a->cpu.total / a->total_calls), a->cpu.max, + (size_t)(a->real.total / a->total_calls), a->real.max); vty_out(vty, " %c%c%c%c%c %s\n", a->types & (1 << THREAD_READ) ? 'R' : ' ', a->types & (1 << THREAD_WRITE) ? 'W' : ' ', @@ -231,8 +231,13 @@ int vty_out(struct vty *vty, const char *format, ...) strlen(filtered)); break; case VTY_SHELL: - fprintf(vty->of, "%s", filtered); - fflush(vty->of); + if (vty->of) { + fprintf(vty->of, "%s", filtered); + fflush(vty->of); + } else if (vty->of_saved) { + fprintf(vty->of_saved, "%s", filtered); + fflush(vty->of_saved); + } break; case VTY_SHELL_SERV: case VTY_FILE: diff --git a/lib/yang_wrappers.c b/lib/yang_wrappers.c index a308b18b73..2b502d635b 100644 --- a/lib/yang_wrappers.c +++ b/lib/yang_wrappers.c @@ -22,6 +22,7 @@ #include "log.h" #include "lib_errors.h" #include "northbound.h" +#include "printfrr.h" static const char *yang_get_default_value(const char *xpath) { @@ -443,7 +444,7 @@ struct yang_data *yang_data_new_int64(const char *xpath, int64_t value) { char value_str[BUFSIZ]; - snprintf(value_str, sizeof(value_str), "%" PRId64, value); + snprintfrr(value_str, sizeof(value_str), "%" PRId64, value); return yang_data_new(xpath, value_str); } @@ -651,7 +652,7 @@ struct yang_data *yang_data_new_uint64(const char *xpath, uint64_t value) { char value_str[BUFSIZ]; - snprintf(value_str, sizeof(value_str), "%" PRIu64, value); + snprintfrr(value_str, sizeof(value_str), "%" PRIu64, value); return yang_data_new(xpath, value_str); } diff --git a/lib/zclient.c b/lib/zclient.c index eac6c7081d..d380267a70 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -52,7 +52,8 @@ static void zclient_event(enum event, struct zclient *); static void zebra_interface_if_set_value(struct stream *s, struct interface *ifp); -struct zclient_options zclient_options_default = {.receive_notify = false}; +struct zclient_options zclient_options_default = {.receive_notify = false, + .synchronous = false}; struct sockaddr_storage zclient_addr; socklen_t zclient_addr_len; @@ -76,6 +77,7 @@ struct zclient *zclient_new(struct thread_master *master, zclient->master = master; zclient->receive_notify = opt->receive_notify; + zclient->synchronous = opt->synchronous; return zclient; } @@ -374,11 +376,11 @@ static int zebra_message_send(struct zclient *zclient, int command, return zclient_send_message(zclient); } -static int zebra_hello_send(struct zclient *zclient) +int zclient_send_hello(struct zclient *zclient) { struct stream *s; - if (zclient->redist_default) { + if (zclient->redist_default || zclient->synchronous) { s = zclient->obuf; stream_reset(s); @@ -390,6 +392,10 @@ static int zebra_hello_send(struct zclient *zclient) stream_putc(s, 1); else stream_putc(s, 0); + if (zclient->synchronous) + stream_putc(s, 1); + else + stream_putc(s, 0); stream_putw_at(s, 0, stream_get_endp(s)); return zclient_send_message(zclient); @@ -629,7 +635,7 @@ int zclient_start(struct zclient *zclient) /* Create read thread. */ zclient_event(ZCLIENT_READ, zclient); - zebra_hello_send(zclient); + zclient_send_hello(zclient); zebra_message_send(zclient, ZEBRA_INTERFACE_ADD, VRF_DEFAULT); @@ -690,8 +696,9 @@ static int zclient_connect(struct thread *t) return zclient_start(zclient); } -int zclient_send_rnh(struct zclient *zclient, int command, struct prefix *p, - bool exact_match, vrf_id_t vrf_id) +int zclient_send_rnh(struct zclient *zclient, int command, + const struct prefix *p, bool exact_match, + vrf_id_t vrf_id) { struct stream *s; @@ -897,6 +904,7 @@ int zapi_nexthop_encode(struct stream *s, const struct zapi_nexthop *api_nh, } } + /* If present, set 'weight' flag before encoding flags */ if (api_nh->weight) SET_FLAG(nh_flags, ZAPI_NEXTHOP_FLAG_WEIGHT); @@ -941,6 +949,10 @@ int zapi_nexthop_encode(struct stream *s, const struct zapi_nexthop *api_nh, stream_put(s, &(api_nh->rmac), sizeof(struct ethaddr)); + /* Index of backup nexthop */ + if (CHECK_FLAG(nh_flags, ZAPI_NEXTHOP_FLAG_HAS_BACKUP)) + stream_putc(s, api_nh->backup_idx); + done: return ret; } @@ -1000,6 +1012,10 @@ int zapi_route_encode(uint8_t cmd, struct stream *s, struct zapi_route *api) return -1; } + /* We canonicalize the nexthops by sorting them; this allows + * zebra to resolve the list of nexthops to a nexthop-group + * more efficiently. + */ zapi_nexthop_group_sort(api->nexthops, api->nexthop_num); stream_putw(s, api->nexthop_num); @@ -1026,6 +1042,50 @@ int zapi_route_encode(uint8_t cmd, struct stream *s, struct zapi_route *api) } } + /* Backup nexthops */ + if (CHECK_FLAG(api->message, ZAPI_MESSAGE_BACKUP_NEXTHOPS)) { + /* limit the number of nexthops if necessary */ + if (api->backup_nexthop_num > MULTIPATH_NUM) { + char buf[PREFIX2STR_BUFFER]; + + prefix2str(&api->prefix, buf, sizeof(buf)); + flog_err( + EC_LIB_ZAPI_ENCODE, + "%s: prefix %s: can't encode %u backup nexthops (maximum is %u)", + __func__, buf, api->backup_nexthop_num, + MULTIPATH_NUM); + return -1; + } + + /* Note that we do not sort the list of backup nexthops - + * this list is treated as an array and indexed by each + * primary nexthop that is associated with a backup. + */ + + stream_putw(s, api->backup_nexthop_num); + + for (i = 0; i < api->backup_nexthop_num; i++) { + api_nh = &api->backup_nexthops[i]; + + /* MPLS labels for BGP-LU or Segment Routing */ + if (api_nh->label_num > MPLS_MAX_LABELS) { + char buf[PREFIX2STR_BUFFER]; + + prefix2str(&api->prefix, buf, sizeof(buf)); + + flog_err(EC_LIB_ZAPI_ENCODE, + "%s: prefix %s: backup: can't encode %u labels (maximum is %u)", + __func__, buf, + api_nh->label_num, + MPLS_MAX_LABELS); + return -1; + } + + if (zapi_nexthop_encode(s, api_nh, api->flags) != 0) + return -1; + } + } + /* Attributes. */ if (CHECK_FLAG(api->message, ZAPI_MESSAGE_DISTANCE)) stream_putc(s, api->distance); @@ -1101,6 +1161,10 @@ static int zapi_nexthop_decode(struct stream *s, struct zapi_nexthop *api_nh, STREAM_GET(&(api_nh->rmac), s, sizeof(struct ethaddr)); + /* Backup nexthop index */ + if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_HAS_BACKUP)) + STREAM_GETC(s, api_nh->backup_idx); + /* Success */ ret = 0; @@ -1207,6 +1271,24 @@ int zapi_route_decode(struct stream *s, struct zapi_route *api) } } + /* Backup nexthops. */ + if (CHECK_FLAG(api->message, ZAPI_MESSAGE_BACKUP_NEXTHOPS)) { + STREAM_GETW(s, api->backup_nexthop_num); + if (api->backup_nexthop_num > MULTIPATH_NUM) { + flog_err(EC_LIB_ZAPI_ENCODE, + "%s: invalid number of backup nexthops (%u)", + __func__, api->backup_nexthop_num); + return -1; + } + + for (i = 0; i < api->backup_nexthop_num; i++) { + api_nh = &api->backup_nexthops[i]; + + if (zapi_nexthop_decode(s, api_nh, api->flags) != 0) + return -1; + } + } + /* Attributes. */ if (CHECK_FLAG(api->message, ZAPI_MESSAGE_DISTANCE)) STREAM_GETC(s, api->distance); @@ -1381,7 +1463,7 @@ stream_failure: return false; } -struct nexthop *nexthop_from_zapi_nexthop(struct zapi_nexthop *znh) +struct nexthop *nexthop_from_zapi_nexthop(const struct zapi_nexthop *znh) { struct nexthop *n = nexthop_new(); @@ -1398,6 +1480,11 @@ struct nexthop *nexthop_from_zapi_nexthop(struct zapi_nexthop *znh) znh->labels); } + if (CHECK_FLAG(znh->flags, ZAPI_NEXTHOP_FLAG_HAS_BACKUP)) { + SET_FLAG(n->flags, NEXTHOP_FLAG_HAS_BACKUP); + n->backup_idx = znh->backup_idx; + } + return n; } @@ -1413,10 +1500,16 @@ int zapi_nexthop_from_nexthop(struct zapi_nexthop *znh, znh->type = nh->type; znh->vrf_id = nh->vrf_id; + znh->weight = nh->weight; znh->ifindex = nh->ifindex; znh->gate = nh->gate; if (nh->nh_label && (nh->nh_label->num_labels > 0)) { + + /* Validate */ + if (nh->nh_label->num_labels > MPLS_MAX_LABELS) + return -1; + for (i = 0; i < nh->nh_label->num_labels; i++) znh->labels[i] = nh->nh_label->label[i]; @@ -1424,10 +1517,31 @@ int zapi_nexthop_from_nexthop(struct zapi_nexthop *znh, SET_FLAG(znh->flags, ZAPI_NEXTHOP_FLAG_LABEL); } + if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_HAS_BACKUP)) { + SET_FLAG(znh->flags, ZAPI_NEXTHOP_FLAG_HAS_BACKUP); + znh->backup_idx = nh->backup_idx; + } + return 0; } /* + * Wrapper that converts backup nexthop + */ +int zapi_backup_nexthop_from_nexthop(struct zapi_nexthop *znh, + const struct nexthop *nh) +{ + int ret; + + /* Ensure that zapi flags are correct: backups don't have backups */ + ret = zapi_nexthop_from_nexthop(znh, nh); + if (ret == 0) + UNSET_FLAG(znh->flags, ZAPI_NEXTHOP_FLAG_HAS_BACKUP); + + return ret; +} + +/* * Decode the nexthop-tracking update message */ bool zapi_nexthop_update_decode(struct stream *s, struct zapi_route *nhr) diff --git a/lib/zclient.h b/lib/zclient.h index e6f4c747e3..e747809f16 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -255,6 +255,9 @@ struct zclient { /* Do we care about failure events for route install? */ bool receive_notify; + /* Is this a synchronous client? */ + bool synchronous; + /* Socket to zebra daemon. */ int sock; @@ -338,6 +341,9 @@ struct zclient { #define ZAPI_MESSAGE_TAG 0x08 #define ZAPI_MESSAGE_MTU 0x10 #define ZAPI_MESSAGE_SRCPFX 0x20 +/* Backup nexthops are present */ +#define ZAPI_MESSAGE_BACKUP_NEXTHOPS 0x40 + /* * This should only be used by a DAEMON that needs to communicate * the table being used is not in the VRF. You must pass the @@ -374,14 +380,21 @@ struct zapi_nexthop { struct ethaddr rmac; uint32_t weight; + + /* Index of backup nexthop */ + uint8_t backup_idx; }; /* - * ZAPI nexthop flags values + * ZAPI nexthop flags values - we're encoding a single octet + * initially, so ensure that the on-the-wire encoding continues + * to match the number of valid flags. */ + #define ZAPI_NEXTHOP_FLAG_ONLINK 0x01 #define ZAPI_NEXTHOP_FLAG_LABEL 0x02 #define ZAPI_NEXTHOP_FLAG_WEIGHT 0x04 +#define ZAPI_NEXTHOP_FLAG_HAS_BACKUP 0x08 /* Nexthop has a backup */ /* * Some of these data structures do not map easily to @@ -445,6 +458,10 @@ struct zapi_route { uint16_t nexthop_num; struct zapi_nexthop nexthops[MULTIPATH_NUM]; + /* Support backup routes for IP FRR, TI-LFA, traffic engineering */ + uint16_t backup_nexthop_num; + struct zapi_nexthop backup_nexthops[MULTIPATH_NUM]; + uint8_t distance; uint32_t metric; @@ -569,6 +586,7 @@ enum zebra_neigh_state { ZEBRA_NEIGH_INACTIVE = 0, ZEBRA_NEIGH_ACTIVE = 1 }; struct zclient_options { bool receive_notify; + bool synchronous; }; extern struct zclient_options zclient_options_default; @@ -738,7 +756,7 @@ extern void zebra_read_pw_status_update(ZAPI_CALLBACK_ARGS, struct zapi_pw_statu extern int zclient_route_send(uint8_t, struct zclient *, struct zapi_route *); extern int zclient_send_rnh(struct zclient *zclient, int command, - struct prefix *p, bool exact_match, + const struct prefix *p, bool exact_match, vrf_id_t vrf_id); int zapi_nexthop_encode(struct stream *s, const struct zapi_nexthop *api_nh, uint32_t api_flags); @@ -765,9 +783,12 @@ bool zapi_iptable_notify_decode(struct stream *s, uint32_t *unique, enum zapi_iptable_notify_owner *note); -extern struct nexthop *nexthop_from_zapi_nexthop(struct zapi_nexthop *znh); +extern struct nexthop * +nexthop_from_zapi_nexthop(const struct zapi_nexthop *znh); int zapi_nexthop_from_nexthop(struct zapi_nexthop *znh, const struct nexthop *nh); +int zapi_backup_nexthop_from_nexthop(struct zapi_nexthop *znh, + const struct nexthop *nh); extern bool zapi_nexthop_update_decode(struct stream *s, struct zapi_route *nhr); @@ -796,4 +817,9 @@ extern void zclient_send_mlag_deregister(struct zclient *client); extern void zclient_send_mlag_data(struct zclient *client, struct stream *client_s); +/* Send the hello message. + * Returns 0 for success or -1 on an I/O error. + */ +extern int zclient_send_hello(struct zclient *client); + #endif /* _ZEBRA_ZCLIENT_H */ diff --git a/ospf6d/ospf6_abr.c b/ospf6d/ospf6_abr.c index ead186b6fc..9721446112 100644 --- a/ospf6d/ospf6_abr.c +++ b/ospf6d/ospf6_abr.c @@ -1427,7 +1427,7 @@ void install_element_ospf6_debug_abr(void) install_element(CONFIG_NODE, &no_debug_ospf6_abr_cmd); } -static const struct ospf6_lsa_handler inter_prefix_handler = { +static struct ospf6_lsa_handler inter_prefix_handler = { .lh_type = OSPF6_LSTYPE_INTER_PREFIX, .lh_name = "Inter-Prefix", .lh_short_name = "IAP", @@ -1435,7 +1435,7 @@ static const struct ospf6_lsa_handler inter_prefix_handler = { .lh_get_prefix_str = ospf6_inter_area_prefix_lsa_get_prefix_str, .lh_debug = 0}; -static const struct ospf6_lsa_handler inter_router_handler = { +static struct ospf6_lsa_handler inter_router_handler = { .lh_type = OSPF6_LSTYPE_INTER_ROUTER, .lh_name = "Inter-Router", .lh_short_name = "IAR", diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c index 805e411c7b..e059bfbc55 100644 --- a/ospf6d/ospf6_asbr.c +++ b/ospf6d/ospf6_asbr.c @@ -1853,7 +1853,7 @@ DEFUN (show_ipv6_ospf6_redistribute, return CMD_SUCCESS; } -static const struct ospf6_lsa_handler as_external_handler = { +static struct ospf6_lsa_handler as_external_handler = { .lh_type = OSPF6_LSTYPE_AS_EXTERNAL, .lh_name = "AS-External", .lh_short_name = "ASE", diff --git a/ospf6d/ospf6_intra.c b/ospf6d/ospf6_intra.c index 9c239b75ff..b700899ccf 100644 --- a/ospf6d/ospf6_intra.c +++ b/ospf6d/ospf6_intra.c @@ -2235,7 +2235,7 @@ void ospf6_intra_brouter_calculation(struct ospf6_area *oa) __func__, oa->name); } -static const struct ospf6_lsa_handler router_handler = { +static struct ospf6_lsa_handler router_handler = { .lh_type = OSPF6_LSTYPE_ROUTER, .lh_name = "Router", .lh_short_name = "Rtr", @@ -2243,7 +2243,7 @@ static const struct ospf6_lsa_handler router_handler = { .lh_get_prefix_str = ospf6_router_lsa_get_nbr_id, .lh_debug = 0}; -static const struct ospf6_lsa_handler network_handler = { +static struct ospf6_lsa_handler network_handler = { .lh_type = OSPF6_LSTYPE_NETWORK, .lh_name = "Network", .lh_short_name = "Net", @@ -2251,7 +2251,7 @@ static const struct ospf6_lsa_handler network_handler = { .lh_get_prefix_str = ospf6_network_lsa_get_ar_id, .lh_debug = 0}; -static const struct ospf6_lsa_handler link_handler = { +static struct ospf6_lsa_handler link_handler = { .lh_type = OSPF6_LSTYPE_LINK, .lh_name = "Link", .lh_short_name = "Lnk", @@ -2259,7 +2259,7 @@ static const struct ospf6_lsa_handler link_handler = { .lh_get_prefix_str = ospf6_link_lsa_get_prefix_str, .lh_debug = 0}; -static const struct ospf6_lsa_handler intra_prefix_handler = { +static struct ospf6_lsa_handler intra_prefix_handler = { .lh_type = OSPF6_LSTYPE_INTRA_PREFIX, .lh_name = "Intra-Prefix", .lh_short_name = "INP", diff --git a/ospf6d/ospf6_lsa.c b/ospf6d/ospf6_lsa.c index 9acbd09b1a..c63ea47f29 100644 --- a/ospf6d/ospf6_lsa.c +++ b/ospf6d/ospf6_lsa.c @@ -77,16 +77,16 @@ static struct ospf6_lsa_handler unknown_handler = { .lh_debug = 0 /* No default debug */ }; -void ospf6_install_lsa_handler(const struct ospf6_lsa_handler *handler) +void ospf6_install_lsa_handler(struct ospf6_lsa_handler *handler) { /* type in handler is host byte order */ int index = handler->lh_type & OSPF6_LSTYPE_FCODE_MASK; vector_set_index(ospf6_lsa_handler_vector, index, (void *)handler); } -const struct ospf6_lsa_handler *ospf6_get_lsa_handler(uint16_t type) +struct ospf6_lsa_handler *ospf6_get_lsa_handler(uint16_t type) { - const struct ospf6_lsa_handler *handler = NULL; + struct ospf6_lsa_handler *handler = NULL; unsigned int index = ntohs(type) & OSPF6_LSTYPE_FCODE_MASK; if (index >= vector_active(ospf6_lsa_handler_vector)) diff --git a/ospf6d/ospf6_lsa.h b/ospf6d/ospf6_lsa.h index d871a8842e..02f9f9d26c 100644 --- a/ospf6d/ospf6_lsa.h +++ b/ospf6d/ospf6_lsa.h @@ -237,8 +237,8 @@ extern int ospf6_lsa_checksum_valid(struct ospf6_lsa_header *); extern int ospf6_lsa_prohibited_duration(uint16_t type, uint32_t id, uint32_t adv_router, void *scope); -extern void ospf6_install_lsa_handler(const struct ospf6_lsa_handler *handler); -extern const struct ospf6_lsa_handler *ospf6_get_lsa_handler(uint16_t type); +extern void ospf6_install_lsa_handler(struct ospf6_lsa_handler *handler); +extern struct ospf6_lsa_handler *ospf6_get_lsa_handler(uint16_t type); extern void ospf6_lsa_init(void); extern void ospf6_lsa_terminate(void); diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c index 96eee51929..dc10fa52cb 100644 --- a/ospf6d/ospf6_top.c +++ b/ospf6d/ospf6_top.c @@ -52,8 +52,8 @@ DEFINE_QOBJ_TYPE(ospf6) FRR_CFG_DEFAULT_BOOL(OSPF6_LOG_ADJACENCY_CHANGES, - { .val_long = true, .match_profile = "datacenter", }, - { .val_long = false }, + { .val_bool = true, .match_profile = "datacenter", }, + { .val_bool = false }, ) /* global ospf6d variable */ diff --git a/ospfd/ospf_ase.c b/ospfd/ospf_ase.c index 2c80d485a3..30940cf010 100644 --- a/ospfd/ospf_ase.c +++ b/ospfd/ospf_ase.c @@ -691,7 +691,7 @@ static int ospf_ase_calculate_timer(struct thread *t) if (IS_DEBUG_OSPF_EVENT) zlog_info( - "SPF Processing Time(usecs): External Routes: %lld\n", + "SPF Processing Time(usecs): External Routes: %lld", (stop_time.tv_sec - start_time.tv_sec) * 1000000LL + (stop_time.tv_usec diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c index 55ec638522..d50f390e30 100644 --- a/ospfd/ospf_lsa.c +++ b/ospfd/ospf_lsa.c @@ -2805,7 +2805,7 @@ static int ospf_maxage_lsa_remover(struct thread *thread) if (CHECK_FLAG(lsa->flags, OSPF_LSA_PREMATURE_AGE)) { if (IS_DEBUG_OSPF(lsa, LSA_FLOODING)) zlog_debug( - "originating new lsa for lsa 0x%p\n", + "originating new lsa for lsa 0x%p", (void *)lsa); ospf_lsa_refresh(ospf, lsa); } diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c index 0808f245e2..aa50aeacbc 100644 --- a/ospfd/ospf_packet.c +++ b/ospfd/ospf_packet.c @@ -611,7 +611,7 @@ static void ospf_write_frags(int fd, struct ospf_packet *op, struct ip *iph, if (IS_DEBUG_OSPF_PACKET(type - 1, SEND)) { zlog_debug( - "ospf_write_frags: sent id %d, off %d, len %d to %s\n", + "ospf_write_frags: sent id %d, off %d, len %d to %s", iph->ip_id, iph->ip_off, iph->ip_len, inet_ntoa(iph->ip_dst)); } diff --git a/ospfd/ospf_ri.c b/ospfd/ospf_ri.c index 5f01edfbdf..fbe513cea0 100644 --- a/ospfd/ospf_ri.c +++ b/ospfd/ospf_ri.c @@ -1382,9 +1382,8 @@ static uint16_t show_vty_sr_algorithm(struct vty *vty, struct tlv_header *tlvh) zlog_debug(" Algorithm %d: Strict SPF", i); break; default: - zlog_debug( - " Algorithm %d: Unknown value %d\n", - i, algo->value[i]); + zlog_debug(" Algorithm %d: Unknown value %d", + i, algo->value[i]); break; } } diff --git a/ospfd/ospf_route.c b/ospfd/ospf_route.c index b6e8338ee7..a661c80a91 100644 --- a/ospfd/ospf_route.c +++ b/ospfd/ospf_route.c @@ -631,27 +631,15 @@ void ospf_route_table_dump(struct route_table *rt) { struct route_node *rn; struct ospf_route * or ; - char buf1[BUFSIZ]; - char buf2[BUFSIZ]; struct listnode *pnode; struct ospf_path *path; -#if 0 - zlog_debug ("Type Dest Area Path Type Cost Next Adv."); - zlog_debug (" Hop(s) Router(s)"); -#endif /* 0 */ - zlog_debug("========== OSPF routing table =========="); for (rn = route_top(rt); rn; rn = route_next(rn)) if ((or = rn->info) != NULL) { if (or->type == OSPF_DESTINATION_NETWORK) { - zlog_debug("N %s/%d\t%s\t%s\t%d", - inet_ntop(AF_INET, &rn->p.u.prefix4, - buf1, BUFSIZ), - rn->p.prefixlen, - inet_ntop(AF_INET, - & or->u.std.area_id, buf2, - BUFSIZ), + zlog_debug("N %-18pFX %-15pI4 %s %d", &rn->p, + &or->u.std.area_id, ospf_path_type_str[or->path_type], or->cost); for (ALL_LIST_ELEMENTS_RO(or->paths, pnode, @@ -659,12 +647,9 @@ void ospf_route_table_dump(struct route_table *rt) zlog_debug(" -> %s", inet_ntoa(path->nexthop)); } else - zlog_debug("R %s\t%s\t%s\t%d", - inet_ntop(AF_INET, &rn->p.u.prefix4, - buf1, BUFSIZ), - inet_ntop(AF_INET, - & or->u.std.area_id, buf2, - BUFSIZ), + zlog_debug("R %-18pI4 %-15pI4 %s %d", + &rn->p.u.prefix4, + &or->u.std.area_id, ospf_path_type_str[or->path_type], or->cost); } diff --git a/ospfd/ospf_spf.c b/ospfd/ospf_spf.c index 8b605b3bac..ae70a5c789 100644 --- a/ospfd/ospf_spf.c +++ b/ospfd/ospf_spf.c @@ -1401,13 +1401,13 @@ static int ospf_spf_calculate_timer(struct thread *thread) if (IS_DEBUG_OSPF_EVENT) { zlog_info("SPF Processing Time(usecs): %ld", total_spf_time); - zlog_info("\t SPF Time: %ld", spf_time); - zlog_info("\t InterArea: %ld", ia_time); - zlog_info("\t Prune: %ld", prune_time); - zlog_info("\tRouteInstall: %ld", rt_time); + zlog_info(" SPF Time: %ld", spf_time); + zlog_info(" InterArea: %ld", ia_time); + zlog_info(" Prune: %ld", prune_time); + zlog_info(" RouteInstall: %ld", rt_time); if (IS_OSPF_ABR(ospf)) - zlog_info("\t ABR: %ld (%d areas)", abr_time, - areas_processed); + zlog_info(" ABR: %ld (%d areas)", + abr_time, areas_processed); zlog_info("Reason(s) for SPF: %s", rbuf); } diff --git a/ospfd/ospf_te.c b/ospfd/ospf_te.c index 8da99843e6..a2084e3214 100644 --- a/ospfd/ospf_te.c +++ b/ospfd/ospf_te.c @@ -1780,7 +1780,7 @@ static uint16_t show_vty_link_subtlv_unrsv_bw(struct vty *vty, i, fval1, i + 1, fval2); else zlog_debug( - " [%d]: %g (Bytes/sec),\t[%d]: %g (Bytes/sec)", + " [%d]: %g (Bytes/sec), [%d]: %g (Bytes/sec)", i, fval1, i + 1, fval2); } diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index 75f556e39f..ea73834a66 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -54,8 +54,8 @@ #include "ospfd/ospf_bfd.h" FRR_CFG_DEFAULT_BOOL(OSPF_LOG_ADJACENCY_CHANGES, - { .val_long = true, .match_profile = "datacenter", }, - { .val_long = false }, + { .val_bool = true, .match_profile = "datacenter", }, + { .val_bool = false }, ) static const char *const ospf_network_type_str[] = { diff --git a/pbrd/pbr_vty.c b/pbrd/pbr_vty.c index e395b7831d..dfc8bec1bc 100644 --- a/pbrd/pbr_vty.c +++ b/pbrd/pbr_vty.c @@ -423,7 +423,6 @@ DEFPY(pbr_map_vrf, pbr_map_vrf_cmd, "Use the interface's VRF for lookup\n") { struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence); - int ret = CMD_SUCCESS; if (no) { pbr_map_delete_vrf(pbrms); @@ -434,28 +433,51 @@ DEFPY(pbr_map_vrf, pbr_map_vrf_cmd, pbrms->vrf_lookup = false; pbrms->vrf_unchanged = false; - goto done; + return CMD_SUCCESS; } if (pbrms->nhgrp_name || pbrms->nhg) { vty_out(vty, "A `set nexthop/nexthop-group XX` command already exits, please remove that first\n"); - ret = CMD_WARNING_CONFIG_FAILED; - goto done; + return CMD_WARNING_CONFIG_FAILED; } - if (pbrms->vrf_lookup || pbrms->vrf_unchanged) { - vty_out(vty, SET_VRF_EXISTS_STR); - ret = CMD_WARNING_CONFIG_FAILED; - goto done; + /* + * Determine if a set vrf * command already exists. + * + * If its equivalent, just return success. + * + * Else, return failure, we don't allow atomic swaps yet. + */ + if (vrf_name && pbrms->vrf_lookup) { + /* New vrf specified and one already exists */ + + /* Is this vrf different from one already configured? */ + if (strncmp(pbrms->vrf_name, vrf_name, sizeof(pbrms->vrf_name)) + != 0) + goto vrf_exists; + + return CMD_SUCCESS; + + } else if (!vrf_name && pbrms->vrf_unchanged) { + /* Unchanged specified and unchanged already exists */ + return CMD_SUCCESS; + + } else if (vrf_name && pbrms->vrf_unchanged) { + /* New vrf specified and unchanged is already set */ + goto vrf_exists; + + } else if (!vrf_name && pbrms->vrf_lookup) { + /* Unchanged specified and vrf to lookup already exists */ + goto vrf_exists; } + /* Create new lookup VRF or Unchanged */ if (vrf_name) { if (!pbr_vrf_lookup_by_name(vrf_name)) { vty_out(vty, "Specified: %s is non-existent\n", vrf_name); - ret = CMD_WARNING_CONFIG_FAILED; - goto done; + return CMD_WARNING_CONFIG_FAILED; } pbrms->vrf_lookup = true; @@ -465,8 +487,11 @@ DEFPY(pbr_map_vrf, pbr_map_vrf_cmd, pbr_map_check(pbrms); -done: - return ret; + return CMD_SUCCESS; + +vrf_exists: + vty_out(vty, SET_VRF_EXISTS_STR); + return CMD_WARNING_CONFIG_FAILED; } DEFPY (pbr_policy, diff --git a/pimd/README b/pimd/README index 3d03979a9a..1db0aad83c 100644 --- a/pimd/README +++ b/pimd/README @@ -33,7 +33,7 @@ HOME SITE qpimd lives at: - https://github.com/freerangerouting/frr + https://github.com/frrouting/frr PLATFORMS @@ -57,7 +57,7 @@ SUPPORT Please post comments, questions, patches, bug reports at the support site: - https://freerangerouting/frr + https://frrouting.org/frr RELATED WORK diff --git a/pimd/pim_bsm.c b/pimd/pim_bsm.c index bcf11aedbd..ad47427101 100644 --- a/pimd/pim_bsm.c +++ b/pimd/pim_bsm.c @@ -601,7 +601,8 @@ static bool is_preferred_bsr(struct pim_instance *pim, struct in_addr bsr, return true; else if (bsr_prio == pim->global_scope.current_bsr_prio) { - if (bsr.s_addr >= pim->global_scope.current_bsr.s_addr) + if (ntohl(bsr.s_addr) + >= ntohl(pim->global_scope.current_bsr.s_addr)) return true; else return false; @@ -874,6 +875,17 @@ static void pim_bsm_fwd_whole_sz(struct pim_instance *pim, uint8_t *buf, pim_ifp = ifp->info; if ((!pim_ifp) || (!pim_ifp->bsm_enable)) continue; + + /* + * RFC 5059 Sec 3.4: + * When a Bootstrap message is forwarded, it is forwarded out + * of every multicast-capable interface that has PIM neighbors. + * + * So skipping pim interfaces with no neighbors. + */ + if (listcount(pim_ifp->pim_neighbor_list) == 0) + continue; + pim_hello_require(ifp); pim_mtu = ifp->mtu - MAX_IP_HDR_LEN; if (pim_mtu < len) { @@ -1056,13 +1068,13 @@ static bool pim_install_bsm_grp_rp(struct pim_instance *pim, if (listnode_add_sort_nodup(grpnode->partial_bsrp_list, bsm_rpinfo)) { if (PIM_DEBUG_BSM) zlog_debug( - "%s, bs_rpinfo node added to the partial bs_rplist.\r\n", + "%s, bs_rpinfo node added to the partial bs_rplist.", __func__); return true; } if (PIM_DEBUG_BSM) - zlog_debug("%s: list node not added\n", __func__); + zlog_debug("%s: list node not added", __func__); XFREE(MTYPE_PIM_BSRP_NODE, bsm_rpinfo); return false; @@ -1080,7 +1092,7 @@ static void pim_update_pending_rp_cnt(struct bsm_scope *sz, if (bsm_frag_tag != bsgrp->frag_tag) { if (PIM_DEBUG_BSM) zlog_debug( - "%s,Received a new BSM ,so clear the pending bs_rpinfo list.\r\n", + "%s,Received a new BSM ,so clear the pending bs_rpinfo list.", __func__); list_delete_all_node(bsgrp->partial_bsrp_list); bsgrp->pend_rp_cnt = total_rp_count; @@ -1120,7 +1132,7 @@ static bool pim_bsm_parse_install_g2rp(struct bsm_scope *scope, uint8_t *buf, pim_inet4_dump("<Group?>", grpinfo.group.addr, grp_str, sizeof(grp_str)); zlog_debug( - "%s, Group %s Rpcount:%d Fragment-Rp-count:%d\r\n", + "%s, Group %s Rpcount:%d Fragment-Rp-count:%d", __func__, grp_str, grpinfo.rp_count, grpinfo.frag_rp_count); } @@ -1134,9 +1146,8 @@ static bool pim_bsm_parse_install_g2rp(struct bsm_scope *scope, uint8_t *buf, pim_inet4_dump("<Group?>", grpinfo.group.addr, grp_str, sizeof(grp_str)); - zlog_debug( - "%s, Rp count is zero for group: %s\r\n", - __func__, grp_str); + zlog_debug("%s, Rp count is zero for group: %s", + __func__, grp_str); } return false; } @@ -1157,9 +1168,8 @@ static bool pim_bsm_parse_install_g2rp(struct bsm_scope *scope, uint8_t *buf, if (!bsgrp) { if (PIM_DEBUG_BSM) - zlog_debug( - "%s, Create new BSM Group node.\r\n", - __func__); + zlog_debug("%s, Create new BSM Group node.", + __func__); /* create a new node to be added to the tree. */ bsgrp = pim_bsm_new_bsgrp_node(scope->bsrp_table, @@ -1167,7 +1177,7 @@ static bool pim_bsm_parse_install_g2rp(struct bsm_scope *scope, uint8_t *buf, if (!bsgrp) { zlog_debug( - "%s, Failed to get the BSM group node.\r\n", + "%s, Failed to get the BSM group node.", __func__); continue; } @@ -1202,7 +1212,7 @@ static bool pim_bsm_parse_install_g2rp(struct bsm_scope *scope, uint8_t *buf, pim_inet4_dump("<Rpaddr?>", rpinfo.rpaddr.addr, rp_str, sizeof(rp_str)); zlog_debug( - "%s, Rp address - %s; pri:%d hold:%d\r\n", + "%s, Rp address - %s; pri:%d hold:%d", __func__, rp_str, rpinfo.rp_pri, rpinfo.rp_holdtime); } @@ -1366,7 +1376,7 @@ int pim_bsm_process(struct interface *ifp, struct ip *ip_hdr, uint8_t *buf, (buf_size - PIM_BSM_HDR_LEN - PIM_MSG_HEADER_LEN), frag_tag)) { if (PIM_DEBUG_BSM) { - zlog_debug("%s, Parsing BSM failed.\r\n", __func__); + zlog_debug("%s, Parsing BSM failed.", __func__); } pim->bsm_dropped++; return -1; diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index 8bfad8ee27..0c14aff9ff 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -3023,7 +3023,7 @@ static void pim_show_bsm_db(struct pim_instance *pim, struct vty *vty, bool uj) } for (ALL_LIST_ELEMENTS_RO(pim->global_scope.bsm_list, bsmnode, bsm)) { - char grp_str[INET_ADDRSTRLEN]; + char grp_str[PREFIX_STRLEN]; char rp_str[INET_ADDRSTRLEN]; char bsr_str[INET_ADDRSTRLEN]; struct bsmmsg_grpinfo *group; @@ -3192,7 +3192,7 @@ static void pim_show_group_rp_mappings_info(struct pim_instance *pim, if (!bsgrp) continue; - char grp_str[INET_ADDRSTRLEN]; + char grp_str[PREFIX_STRLEN]; prefix2str(&bsgrp->group, grp_str, sizeof(grp_str)); @@ -5807,7 +5807,7 @@ static void show_mroute(struct pim_instance *pim, struct vty *vty, vty_out(vty, " R - RP-bit set, F - Register flag, T - SPT-bit set\n"); vty_out(vty, - "\nSource Group Flags Proto Input Output TTL Uptime\n"); + "\nSource Group Flags Proto Input Output TTL Uptime\n"); } now = pim_time_monotonic_sec(); @@ -7289,11 +7289,20 @@ DEFUN (no_ip_pim_ecmp_rebalance, static int pim_cmd_igmp_start(struct vty *vty, struct interface *ifp) { struct pim_interface *pim_ifp; + struct pim_instance *pim; uint8_t need_startup = 0; pim_ifp = ifp->info; if (!pim_ifp) { + pim = pim_get_pim_instance(ifp->vrf_id); + /* Limit mcast interfaces to number of vifs available */ + if (pim->mcast_if_count == MAXVIFS) { + vty_out(vty, + "Max multicast interfaces(%d) Reached. Could not enable IGMP on interface %s\n", + MAXVIFS, ifp->name); + return CMD_WARNING_CONFIG_FAILED; + } (void)pim_if_new(ifp, true, false, false, false); need_startup = 1; } else { @@ -8043,13 +8052,21 @@ DEFPY_HIDDEN (interface_ip_igmp_query_generate, return CMD_SUCCESS; } -static int pim_cmd_interface_add(struct interface *ifp) +static int pim_cmd_interface_add(struct vty *vty, struct interface *ifp) { struct pim_interface *pim_ifp = ifp->info; + struct pim_instance *pim; - if (!pim_ifp) + if (!pim_ifp) { + pim = pim_get_pim_instance(ifp->vrf_id); + /* Limiting mcast interfaces to number of VIFs */ + if (pim->mcast_if_count == MAXVIFS) { + vty_out(vty, "Max multicast interfaces(%d) reached.", + MAXVIFS); + return 0; + } pim_ifp = pim_if_new(ifp, false, true, false, false); - else + } else PIM_IF_DO_PIM(pim_ifp->options); pim_if_addr_add_all(ifp); @@ -8120,15 +8137,17 @@ DEFPY (interface_ip_pim_activeactive, VTY_DECLVAR_CONTEXT(interface, ifp); struct pim_interface *pim_ifp; - if (!no && !pim_cmd_interface_add(ifp)) { - vty_out(vty, "Could not enable PIM SM active-active on interface\n"); + if (!no && !pim_cmd_interface_add(vty, ifp)) { + vty_out(vty, + "Could not enable PIM SM active-active on interface %s\n", + ifp->name); return CMD_WARNING_CONFIG_FAILED; } - if (PIM_DEBUG_MLAG) - zlog_debug("%sConfiguring PIM active-active on Interface: %s", - no ? "Un-":" ", ifp->name); + if (PIM_DEBUG_MLAG) + zlog_debug("%sConfiguring PIM active-active on Interface: %s", + no ? "Un-" : " ", ifp->name); pim_ifp = ifp->info; if (no) @@ -8148,8 +8167,9 @@ DEFUN_HIDDEN (interface_ip_pim_ssm, { VTY_DECLVAR_CONTEXT(interface, ifp); - if (!pim_cmd_interface_add(ifp)) { - vty_out(vty, "Could not enable PIM SM on interface\n"); + if (!pim_cmd_interface_add(vty, ifp)) { + vty_out(vty, "Could not enable PIM SM on interface %s\n", + ifp->name); return CMD_WARNING_CONFIG_FAILED; } @@ -8165,8 +8185,9 @@ static int interface_ip_pim_helper(struct vty *vty) VTY_DECLVAR_CONTEXT(interface, ifp); - if (!pim_cmd_interface_add(ifp)) { - vty_out(vty, "Could not enable PIM SM on interface\n"); + if (!pim_cmd_interface_add(vty, ifp)) { + vty_out(vty, "Could not enable PIM SM on interface %s\n", + ifp->name); return CMD_WARNING_CONFIG_FAILED; } @@ -8454,8 +8475,10 @@ DEFUN (interface_ip_pim_hello, struct pim_interface *pim_ifp = ifp->info; if (!pim_ifp) { - if (!pim_cmd_interface_add(ifp)) { - vty_out(vty, "Could not enable PIM SM on interface\n"); + if (!pim_cmd_interface_add(vty, ifp)) { + vty_out(vty, + "Could not enable PIM SM on interface %s\n", + ifp->name); return CMD_WARNING_CONFIG_FAILED; } } @@ -9197,8 +9220,10 @@ DEFUN (ip_pim_bfd, struct bfd_info *bfd_info = NULL; if (!pim_ifp) { - if (!pim_cmd_interface_add(ifp)) { - vty_out(vty, "Could not enable PIM SM on interface\n"); + if (!pim_cmd_interface_add(vty, ifp)) { + vty_out(vty, + "Could not enable PIM SM on interface %s\n", + ifp->name); return CMD_WARNING; } } @@ -9248,8 +9273,10 @@ DEFUN (ip_pim_bsm, struct pim_interface *pim_ifp = ifp->info; if (!pim_ifp) { - if (!pim_cmd_interface_add(ifp)) { - vty_out(vty, "Could not enable PIM SM on interface\n"); + if (!pim_cmd_interface_add(vty, ifp)) { + vty_out(vty, + "Could not enable PIM SM on interface %s\n", + ifp->name); return CMD_WARNING; } } @@ -9292,8 +9319,10 @@ DEFUN (ip_pim_ucast_bsm, struct pim_interface *pim_ifp = ifp->info; if (!pim_ifp) { - if (!pim_cmd_interface_add(ifp)) { - vty_out(vty, "Could not enable PIM SM on interface\n"); + if (!pim_cmd_interface_add(vty, ifp)) { + vty_out(vty, + "Could not enable PIM SM on interface %s\n", + ifp->name); return CMD_WARNING; } } @@ -9360,8 +9389,10 @@ DEFUN( struct pim_interface *pim_ifp = ifp->info; if (!pim_ifp) { - if (!pim_cmd_interface_add(ifp)) { - vty_out(vty, "Could not enable PIM SM on interface\n"); + if (!pim_cmd_interface_add(vty, ifp)) { + vty_out(vty, + "Could not enable PIM SM on interface %s\n", + ifp->name); return CMD_WARNING; } } diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c index cb31878e01..07c4172f22 100644 --- a/pimd/pim_iface.c +++ b/pimd/pim_iface.c @@ -186,6 +186,7 @@ struct pim_interface *pim_if_new(struct interface *ifp, bool igmp, bool pim, pim_sock_reset(ifp); pim_if_add_vif(ifp, ispimreg, is_vxlan_term); + pim_ifp->pim->mcast_if_count++; return pim_ifp; } @@ -209,6 +210,7 @@ void pim_if_delete(struct interface *ifp) pim_neighbor_delete_all(ifp, "Interface removed from configuration"); pim_if_del_vif(ifp); + pim_ifp->pim->mcast_if_count--; list_delete(&pim_ifp->igmp_socket_list); list_delete(&pim_ifp->pim_neighbor_list); @@ -275,7 +277,7 @@ static void pim_addr_change(struct interface *ifp) 1) Before an interface goes down or changes primary IP address, a Hello message with a zero HoldTime should be sent immediately (with the old IP address if the IP address changed). - -- FIXME See CAVEAT C13 + -- Done at the caller of the function as new ip already updated here 2) After an interface has changed its IP address, it MUST send a Hello message with its new IP address. @@ -320,6 +322,10 @@ static int detect_primary_address_change(struct interface *ifp, } if (changed) { + /* Before updating pim_ifp send Hello time with 0 hold time */ + if (PIM_IF_TEST_PIM(pim_ifp->options)) { + pim_hello_send(ifp, 0 /* zero-sec holdtime */); + } pim_ifp->primary_address = new_prim_addr; } @@ -1583,8 +1589,14 @@ int pim_ifp_create(struct interface *ifp) } if (!strncmp(ifp->name, PIM_VXLAN_TERM_DEV_NAME, - sizeof(PIM_VXLAN_TERM_DEV_NAME))) - pim_vxlan_add_term_dev(pim, ifp); + sizeof(PIM_VXLAN_TERM_DEV_NAME))) { + if (pim->mcast_if_count < MAXVIFS) + pim_vxlan_add_term_dev(pim, ifp); + else + zlog_warn( + "%s: Cannot enable pim on %s. MAXVIFS(%d) reached. Deleting and readding the vxlan termimation device after unconfiguring pim from other interfaces may succeed.", + __func__, ifp->name, MAXVIFS); + } return 0; } diff --git a/pimd/pim_instance.c b/pimd/pim_instance.c index 2cda628a90..b4c2dd28cc 100644 --- a/pimd/pim_instance.c +++ b/pimd/pim_instance.c @@ -83,6 +83,7 @@ static struct pim_instance *pim_instance_init(struct vrf *vrf) pim_if_init(pim); + pim->mcast_if_count = 0; pim->keep_alive_time = PIM_KEEPALIVE_PERIOD; pim->rp_keep_alive_time = PIM_RP_KEEPALIVE_PERIOD; diff --git a/pimd/pim_instance.h b/pimd/pim_instance.h index 48dc2d9530..71bd7c1089 100644 --- a/pimd/pim_instance.h +++ b/pimd/pim_instance.h @@ -168,6 +168,7 @@ struct pim_instance { struct route_table *rp_table; int iface_vif_index[MAXVIFS]; + int mcast_if_count; struct rb_pim_oil_head channel_oil_head; diff --git a/pimd/pim_join.c b/pimd/pim_join.c index 62bd2360c3..3a88de2070 100644 --- a/pimd/pim_join.c +++ b/pimd/pim_join.c @@ -140,18 +140,19 @@ static void recv_prune(struct interface *ifp, struct pim_neighbor *neigh, if ((source_flags & PIM_RPT_BIT_MASK) && (source_flags & PIM_WILDCARD_BIT_MASK)) { - struct pim_rpf *rp = RP(pim_ifp->pim, sg->grp); + /* + * RFC 4601 Section 4.5.2: + * Received Prune(*,G) messages are processed even if the + * RP in the message does not match RP(G). + */ + if (PIM_DEBUG_PIM_TRACE) { + char received_rp[INET_ADDRSTRLEN]; - if (!rp) { - if (PIM_DEBUG_PIM_TRACE) - zlog_debug( - "%s: RP for %pSG4 completely failed lookup", - __func__, sg); - return; + pim_inet4_dump("<received?>", sg->src, received_rp, + sizeof(received_rp)); + zlog_debug("%s: Prune received with RP(%s) for %pSG4", + __func__, received_rp, sg); } - // Ignoring Prune *,G's at the moment. - if (sg->src.s_addr != rp->rpf_addr.u.prefix4.s_addr) - return; sg->src.s_addr = INADDR_ANY; } diff --git a/pimd/pim_mroute.c b/pimd/pim_mroute.c index 2e08ae28be..9060b6a95a 100644 --- a/pimd/pim_mroute.c +++ b/pimd/pim_mroute.c @@ -232,6 +232,8 @@ static int pim_mroute_msg_nocache(int fd, struct interface *ifp, pim_upstream_mroute_iif_update(up->channel_oil, __func__); } pim_register_join(up); + /* if we have receiver, inherit from parent */ + pim_upstream_inherited_olist_decide(pim_ifp->pim, up); return 0; } @@ -484,7 +486,10 @@ static int pim_mroute_msg_wrvifwhole(int fd, struct interface *ifp, struct pim_upstream *parent; struct pim_nexthop source; struct pim_rpf *rpf = RP(pim_ifp->pim, sg.grp); - if (!rpf || !rpf->source_nexthop.interface) + + /* No RPF or No RPF interface or No mcast on RPF interface */ + if (!rpf || !rpf->source_nexthop.interface + || !rpf->source_nexthop.interface->info) return 0; /* diff --git a/pimd/pim_neighbor.c b/pimd/pim_neighbor.c index ca7ca11402..d8a797f980 100644 --- a/pimd/pim_neighbor.c +++ b/pimd/pim_neighbor.c @@ -779,6 +779,7 @@ void pim_neighbor_update(struct pim_neighbor *neigh, uint32_t dr_priority, struct list *addr_list) { struct pim_interface *pim_ifp = neigh->interface->info; + uint32_t old, new; /* Received holdtime ? */ if (PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_HOLDTIME)) { @@ -818,6 +819,16 @@ void pim_neighbor_update(struct pim_neighbor *neigh, neigh->prefix_list = addr_list; update_dr_priority(neigh, hello_options, dr_priority); + new = PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_LAN_PRUNE_DELAY); + old = PIM_OPTION_IS_SET(neigh->hello_options, + PIM_OPTION_MASK_LAN_PRUNE_DELAY); + + if (old != new) { + if (old) + ++pim_ifp->pim_number_of_nonlandelay_neighbors; + else + --pim_ifp->pim_number_of_nonlandelay_neighbors; + } /* Copy flags */ diff --git a/pimd/pim_pim.c b/pimd/pim_pim.c index 8d7a921cf4..f37c140bf2 100644 --- a/pimd/pim_pim.c +++ b/pimd/pim_pim.c @@ -42,7 +42,6 @@ #include "pim_bsm.h" static int on_pim_hello_send(struct thread *t); -static int pim_hello_send(struct interface *ifp, uint16_t holdtime); static const char *pim_pim_msgtype2str(enum pim_msg_type type) { @@ -137,6 +136,18 @@ void pim_sock_delete(struct interface *ifp, const char *delete_message) sock_close(ifp); } +/* For now check dst address for hello, assrt and join/prune is all pim rtr */ +static bool pim_pkt_dst_addr_ok(enum pim_msg_type type, in_addr_t addr) +{ + if ((type == PIM_MSG_TYPE_HELLO) || (type == PIM_MSG_TYPE_ASSERT) + || (type == PIM_MSG_TYPE_JOIN_PRUNE)) { + if (addr != qpim_all_pim_routers_addr.s_addr) + return false; + } + + return true; +} + int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len) { struct ip *ip_hdr; @@ -237,6 +248,21 @@ int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len) } } + if (!pim_pkt_dst_addr_ok(header->type, ip_hdr->ip_dst.s_addr)) { + char dst_str[INET_ADDRSTRLEN]; + char src_str[INET_ADDRSTRLEN]; + + pim_inet4_dump("<dst?>", ip_hdr->ip_dst, dst_str, + sizeof(dst_str)); + pim_inet4_dump("<src?>", ip_hdr->ip_src, src_str, + sizeof(src_str)); + zlog_warn( + "%s: Ignoring Pkt. Unexpected IP destination %s for %s (Expected: all_pim_routers_addr) from %s", + __func__, dst_str, pim_pim_msgtype2str(header->type), + src_str); + return -1; + } + switch (header->type) { case PIM_MSG_TYPE_HELLO: return pim_hello_recv(ifp, ip_hdr->ip_src, @@ -662,7 +688,7 @@ static int hello_send(struct interface *ifp, uint16_t holdtime) return 0; } -static int pim_hello_send(struct interface *ifp, uint16_t holdtime) +int pim_hello_send(struct interface *ifp, uint16_t holdtime) { struct pim_interface *pim_ifp = ifp->info; diff --git a/pimd/pim_pim.h b/pimd/pim_pim.h index e930ab7c2d..b9fdb14dc0 100644 --- a/pimd/pim_pim.h +++ b/pimd/pim_pim.h @@ -59,4 +59,5 @@ int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len); int pim_msg_send(int fd, struct in_addr src, struct in_addr dst, uint8_t *pim_msg, int pim_msg_size, const char *ifname); +int pim_hello_send(struct interface *ifp, uint16_t holdtime); #endif /* PIM_PIM_H */ diff --git a/pimd/pim_register.c b/pimd/pim_register.c index 7b0af89993..cb6aae7fae 100644 --- a/pimd/pim_register.c +++ b/pimd/pim_register.c @@ -186,7 +186,7 @@ void pim_register_send(const uint8_t *buf, int buf_size, struct in_addr src, if (!pinfo) { if (PIM_DEBUG_PIM_REG) zlog_debug( - "%s: Interface: %s not configured for pim to trasmit on!\n", + "%s: Interface: %s not configured for pim to transmit on!", __func__, ifp->name); return; } diff --git a/pimd/pim_tlv.c b/pimd/pim_tlv.c index 5a751ac929..881a3e332a 100644 --- a/pimd/pim_tlv.c +++ b/pimd/pim_tlv.c @@ -473,7 +473,7 @@ int pim_parse_addr_ucast(struct prefix *p, const uint8_t *buf, int buf_size) case PIM_MSG_ADDRESS_FAMILY_IPV4: if ((addr + sizeof(struct in_addr)) > pastend) { zlog_warn( - "%s: IPv4 unicast address overflow: left=%zd needed=%zu", + "%s: IPv4 unicast address overflow: left=%td needed=%zu", __func__, pastend - addr, sizeof(struct in_addr)); return -3; @@ -489,7 +489,7 @@ int pim_parse_addr_ucast(struct prefix *p, const uint8_t *buf, int buf_size) case PIM_MSG_ADDRESS_FAMILY_IPV6: if ((addr + sizeof(struct in6_addr)) > pastend) { zlog_warn( - "%s: IPv6 unicast address overflow: left=%zd needed %zu", + "%s: IPv6 unicast address overflow: left=%td needed %zu", __func__, pastend - addr, sizeof(struct in6_addr)); return -3; @@ -548,7 +548,7 @@ int pim_parse_addr_group(struct prefix_sg *sg, const uint8_t *buf, int buf_size) if ((addr + sizeof(struct in_addr)) > pastend) { zlog_warn( - "%s: IPv4 group address overflow: left=%zd needed=%zu from", + "%s: IPv4 group address overflow: left=%td needed=%zu from", __func__, pastend - addr, sizeof(struct in_addr)); return -3; @@ -607,7 +607,7 @@ int pim_parse_addr_source(struct prefix_sg *sg, uint8_t *flags, case PIM_MSG_ADDRESS_FAMILY_IPV4: if ((addr + sizeof(struct in_addr)) > pastend) { zlog_warn( - "%s: IPv4 source address overflow: left=%zd needed=%zu", + "%s: IPv4 source address overflow: left=%td needed=%zu", __func__, pastend - addr, sizeof(struct in_addr)); return -3; diff --git a/pimd/pim_upstream.c b/pimd/pim_upstream.c index 07f8315a19..872883dfde 100644 --- a/pimd/pim_upstream.c +++ b/pimd/pim_upstream.c @@ -1697,10 +1697,12 @@ static int pim_upstream_register_stop_timer(struct thread *t) case PIM_REG_JOIN: break; case PIM_REG_PRUNE: + /* This is equalent to Couldreg -> False */ if (!up->rpf.source_nexthop.interface) { if (PIM_DEBUG_PIM_TRACE) zlog_debug("%s: up %s RPF is not present", __func__, up->sg_str); + up->reg_state = PIM_REG_NOINFO; return 0; } diff --git a/pimd/pim_zlookup.c b/pimd/pim_zlookup.c index fc486f4998..84fac4f951 100644 --- a/pimd/pim_zlookup.c +++ b/pimd/pim_zlookup.c @@ -61,6 +61,14 @@ static int zclient_lookup_connect(struct thread *t) zlookup->fail = 0; /* reset counter on connection */ } + if (zclient_send_hello(zlookup) < 0) { + if (close(zlookup->sock)) { + zlog_warn("%s: closing fd=%d: errno=%d %s", __func__, + zlookup->sock, errno, safe_strerror(errno)); + } + zlookup->sock = -1; + } + if (zlookup->sock < 0) { /* Since last connect failed, retry within 10 secs */ zclient_lookup_sched(zlookup, 10); @@ -125,7 +133,10 @@ void zclient_lookup_free(void) void zclient_lookup_new(void) { - zlookup = zclient_new(router->master, &zclient_options_default); + struct zclient_options options = zclient_options_default; + options.synchronous = true; + + zlookup = zclient_new(router->master, &options); if (!zlookup) { flog_err(EC_LIB_ZAPI_SOCKET, "%s: zclient_new() failure", __func__); @@ -161,6 +172,7 @@ static int zclient_read_nexthop(struct pim_instance *pim, if (PIM_DEBUG_PIM_NHT_DETAIL) { char addr_str[INET_ADDRSTRLEN]; + pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str)); zlog_debug("%s: addr=%s(%s)", __func__, addr_str, pim->vrf->name); diff --git a/ripngd/ripng_interface.c b/ripngd/ripng_interface.c index 6a30c07d99..25d9ed2b9e 100644 --- a/ripngd/ripng_interface.c +++ b/ripngd/ripng_interface.c @@ -867,17 +867,12 @@ int ripng_network_write(struct vty *vty, struct ripng *ripng) unsigned int i; const char *ifname; struct agg_node *node; - char buf[BUFSIZ]; /* Write enable network. */ for (node = agg_route_top(ripng->enable_network); node; node = agg_route_next(node)) - if (node->info) { - struct prefix *p = &node->p; - vty_out(vty, " %s/%d\n", - inet_ntop(p->family, &p->u.prefix, buf, BUFSIZ), - p->prefixlen); - } + if (node->info) + vty_out(vty, " %pRN\n", node); /* Write enable interface. */ for (i = 0; i < vector_active(ripng->enable_if); i++) diff --git a/ripngd/ripng_nb_state.c b/ripngd/ripng_nb_state.c index 167077ea29..75dec3cb3e 100644 --- a/ripngd/ripng_nb_state.c +++ b/ripngd/ripng_nb_state.c @@ -158,7 +158,8 @@ int ripngd_instance_state_routes_route_get_keys(const void *list_entry, const struct agg_node *rn = list_entry; keys->num = 1; - (void)prefix2str(&rn->p, keys->key[0], sizeof(keys->key[0])); + (void)prefix2str(agg_node_get_prefix(rn), keys->key[0], + sizeof(keys->key[0])); return NB_OK; } @@ -191,7 +192,7 @@ ripngd_instance_state_routes_route_prefix_get_elem(const char *xpath, const struct agg_node *rn = list_entry; const struct ripng_info *rinfo = listnode_head(rn->info); - return yang_data_new_ipv6p(xpath, &rinfo->rp->p); + return yang_data_new_ipv6p(xpath, agg_node_get_prefix(rinfo->rp)); } /* diff --git a/ripngd/ripng_zebra.c b/ripngd/ripng_zebra.c index f9bd56d1df..baf7f00961 100644 --- a/ripngd/ripng_zebra.c +++ b/ripngd/ripng_zebra.c @@ -46,12 +46,13 @@ static void ripng_zebra_ipv6_send(struct ripng *ripng, struct agg_node *rp, struct listnode *listnode = NULL; struct ripng_info *rinfo = NULL; int count = 0; + const struct prefix *p = agg_node_get_prefix(rp); memset(&api, 0, sizeof(api)); api.vrf_id = ripng->vrf->vrf_id; api.type = ZEBRA_ROUTE_RIPNG; api.safi = SAFI_UNICAST; - api.prefix = rp->p; + api.prefix = *p; SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); for (ALL_LIST_ELEMENTS_RO(list, listnode, rinfo)) { @@ -85,18 +86,17 @@ static void ripng_zebra_ipv6_send(struct ripng *ripng, struct agg_node *rp, if (IS_RIPNG_DEBUG_ZEBRA) { if (ripng->ecmp) - zlog_debug("%s: %s/%d nexthops %d", + zlog_debug("%s: %pRN nexthops %d", (cmd == ZEBRA_ROUTE_ADD) ? "Install into zebra" : "Delete from zebra", - inet6_ntoa(rp->p.u.prefix6), rp->p.prefixlen, - count); + rp, count); else - zlog_debug( - "%s: %s/%d", - (cmd == ZEBRA_ROUTE_ADD) ? "Install into zebra" - : "Delete from zebra", - inet6_ntoa(rp->p.u.prefix6), rp->p.prefixlen); + zlog_debug("%s: %pRN", + (cmd == ZEBRA_ROUTE_ADD) + ? "Install into zebra" + : "Delete from zebra", + rp); } } diff --git a/ripngd/ripngd.c b/ripngd/ripngd.c index bb33abdb2c..1ea006abd6 100644 --- a/ripngd/ripngd.c +++ b/ripngd/ripngd.c @@ -1087,7 +1087,8 @@ void ripng_redistribute_withdraw(struct ripng *ripng, int type) if (IS_RIPNG_DEBUG_EVENT) { struct prefix_ipv6 *p = - (struct prefix_ipv6 *)&rp->p; + (struct prefix_ipv6 *) + agg_node_get_prefix(rp); zlog_debug( "Poisone %s/%d on the interface %s [withdraw]", @@ -1619,7 +1620,7 @@ void ripng_output_process(struct interface *ifp, struct sockaddr_in6 *to, * following * information. */ - p = (struct prefix_ipv6 *)&rp->p; + p = (struct prefix_ipv6 *)agg_node_get_prefix(rp); rinfo->metric_out = rinfo->metric; rinfo->tag_out = rinfo->tag; memset(&rinfo->nexthop_out, 0, @@ -1761,7 +1762,7 @@ void ripng_output_process(struct interface *ifp, struct sockaddr_in6 *to, * following * information. */ - p = (struct prefix_ipv6 *)&rp->p; + p = (struct prefix_ipv6 *)agg_node_get_prefix(rp); aggregate->metric_set = 0; aggregate->metric_out = aggregate->metric; aggregate->tag_out = aggregate->tag; @@ -2053,7 +2054,6 @@ DEFUN (show_ipv6_ripng, struct agg_node *rp; struct ripng_info *rinfo; struct ripng_aggregate *aggregate; - struct prefix_ipv6 *p; struct list *list = NULL; struct listnode *listnode = NULL; int len; @@ -2085,15 +2085,11 @@ DEFUN (show_ipv6_ripng, for (rp = agg_route_top(ripng->table); rp; rp = agg_route_next(rp)) { if ((aggregate = rp->aggregate) != NULL) { - p = (struct prefix_ipv6 *)&rp->p; - #ifdef DEBUG - vty_out(vty, "R(a) %d/%d %s/%d ", aggregate->count, - aggregate->suppress, inet6_ntoa(p->prefix), - p->prefixlen); + vty_out(vty, "R(a) %d/%d %pRN ", aggregate->count, + aggregate->suppress, rp); #else - vty_out(vty, "R(a) %s/%d ", inet6_ntoa(p->prefix), - p->prefixlen); + vty_out(vty, "R(a) %pRN ", rp); #endif /* DEBUG */ vty_out(vty, "\n"); vty_out(vty, "%*s", 18, " "); @@ -2105,19 +2101,15 @@ DEFUN (show_ipv6_ripng, if ((list = rp->info) != NULL) for (ALL_LIST_ELEMENTS_RO(list, listnode, rinfo)) { - p = (struct prefix_ipv6 *)&rp->p; - #ifdef DEBUG - vty_out(vty, "%c(%s) 0/%d %s/%d ", + vty_out(vty, "%c(%s) 0/%d %pRN ", zebra_route_char(rinfo->type), ripng_route_subtype_print(rinfo), - rinfo->suppress, inet6_ntoa(p->prefix), - p->prefixlen); + rinfo->suppress, rp); #else - vty_out(vty, "%c(%s) %s/%d ", + vty_out(vty, "%c(%s) %pRN ", zebra_route_char(rinfo->type), - ripng_route_subtype_print(rinfo), - inet6_ntoa(p->prefix), p->prefixlen); + ripng_route_subtype_print(rinfo), rp); #endif /* DEBUG */ vty_out(vty, "\n"); vty_out(vty, "%*s", 18, " "); diff --git a/sharpd/sharp_globals.h b/sharpd/sharp_globals.h index 4e5c933667..8eba57f4dd 100644 --- a/sharpd/sharp_globals.h +++ b/sharpd/sharp_globals.h @@ -28,9 +28,11 @@ struct sharp_routes { /* The original prefix for route installation */ struct prefix orig_prefix; - /* The nexthop group we are using for installation */ + /* The nexthop info we are using for installation */ struct nexthop nhop; + struct nexthop backup_nhop; struct nexthop_group nhop_group; + struct nexthop_group backup_nhop_group; uint32_t total_routes; uint32_t installed_routes; diff --git a/sharpd/sharp_logpump.c b/sharpd/sharp_logpump.c new file mode 100644 index 0000000000..d07e2d273f --- /dev/null +++ b/sharpd/sharp_logpump.c @@ -0,0 +1,153 @@ +/* + * testing log message generator + * Copyright (C) 2019-2020 David Lamparter for NetDEF, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <zebra.h> + +#include "vty.h" +#include "command.h" +#include "prefix.h" +#include "nexthop.h" +#include "log.h" +#include "thread.h" +#include "vrf.h" +#include "zclient.h" +#include "frr_pthread.h" + +#include "sharpd/sharp_vty.h" + +/* this is quite hacky, but then again it's a test tool and it does its job. */ +static struct frr_pthread *lpt; + +static unsigned long lp_duration; +static unsigned lp_frequency; +static unsigned lp_burst; +static size_t lp_ctr, lp_expect; +static struct rusage lp_rusage; +static struct vty *lp_vty; + +extern struct thread_master *master; + +static int logpump_done(struct thread *thread) +{ + double x; + + vty_out(lp_vty, "\nlogpump done\n"); + vty_out(lp_vty, "%9zu messages written\n", lp_ctr); + x = (double)lp_ctr / (double)lp_expect * 100.; + vty_out(lp_vty, "%9zu messages targeted = %5.1lf%%\n", lp_expect, x); + + x = lp_rusage.ru_utime.tv_sec * 1000000 + lp_rusage.ru_utime.tv_usec; + x /= (double)lp_ctr; + vty_out(lp_vty, "%6llu.%06u usr %9.1lfns/msg\n", + (unsigned long long)lp_rusage.ru_utime.tv_sec, + (unsigned)lp_rusage.ru_utime.tv_usec, x * 1000.); + + x = lp_rusage.ru_stime.tv_sec * 1000000 + lp_rusage.ru_stime.tv_usec; + x /= (double)lp_ctr; + vty_out(lp_vty, "%6llu.%06u sys %9.1lfns/msg\n", + (unsigned long long)lp_rusage.ru_stime.tv_sec, + (unsigned)lp_rusage.ru_stime.tv_usec, x * 1000.); + + frr_pthread_stop(lpt, NULL); + frr_pthread_destroy(lpt); + lpt = NULL; + return 0; +} + +static void *logpump_run(void *arg) +{ + struct timespec start, next, now; + unsigned long delta, period; + + period = 1000000000L / lp_frequency; + + clock_gettime(CLOCK_MONOTONIC, &start); + next = start; + do { + for (size_t inburst = 0; inburst < lp_burst; inburst++) + zlog_debug("log pump: %zu (burst %zu)", + lp_ctr++, inburst); + + clock_gettime(CLOCK_MONOTONIC, &now); + delta = (now.tv_sec - start.tv_sec) * 1000000000L + + (now.tv_nsec - start.tv_nsec); + + next.tv_nsec += period; + if (next.tv_nsec > 1000000000L) { + next.tv_sec++; + next.tv_nsec -= 1000000000L; + } +#ifdef HAVE_CLOCK_NANOSLEEP + clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &next, NULL); +#else + struct timespec slpdur; + + slpdur.tv_sec = next.tv_sec - now.tv_sec; + slpdur.tv_nsec = next.tv_nsec - now.tv_nsec; + if (slpdur.tv_nsec < 0) { + slpdur.tv_sec--; + slpdur.tv_nsec += 1000000000L; + } + + nanosleep(&slpdur, NULL); +#endif + } while (delta < lp_duration); + +#ifdef RUSAGE_THREAD + getrusage(RUSAGE_THREAD, &lp_rusage); +#else + getrusage(RUSAGE_SELF, &lp_rusage); +#endif + + thread_add_timer_msec(master, logpump_done, NULL, 0, NULL); + return NULL; +} + +static int logpump_halt(struct frr_pthread *fpt, void **res) +{ + return 0; +} + +/* default frr_pthread attributes */ +static const struct frr_pthread_attr attr = { + .start = logpump_run, + .stop = logpump_halt, +}; + +void sharp_logpump_run(struct vty *vty, unsigned duration, unsigned frequency, + unsigned burst) +{ + if (lpt != NULL) { + vty_out(vty, "logpump already running\n"); + return; + } + + vty_out(vty, "starting logpump...\n"); + vty_out(vty, "keep this VTY open and press Enter to see results\n"); + + lp_vty = vty; + lp_duration = duration * 1000000000UL; + lp_frequency = frequency; + lp_burst = burst; + lp_expect = duration * frequency * burst; + lp_ctr = 0; + + lpt = frr_pthread_new(&attr, "logpump", "logpump"); + frr_pthread_run(lpt, NULL); +} diff --git a/sharpd/sharp_vty.c b/sharpd/sharp_vty.c index fd2e37e675..8a787c8e83 100644 --- a/sharpd/sharp_vty.c +++ b/sharpd/sharp_vty.c @@ -162,7 +162,12 @@ DEFPY (install_routes_data_dump, DEFPY (install_routes, install_routes_cmd, - "sharp install routes [vrf NAME$vrf_name] <A.B.C.D$start4|X:X::X:X$start6> <nexthop <A.B.C.D$nexthop4|X:X::X:X$nexthop6>|nexthop-group NHGNAME$nexthop_group> (1-1000000)$routes [instance (0-255)$instance] [repeat (2-1000)$rpt]", + "sharp install routes [vrf NAME$vrf_name]\ + <A.B.C.D$start4|X:X::X:X$start6>\ + <nexthop <A.B.C.D$nexthop4|X:X::X:X$nexthop6>|\ + nexthop-group NHGNAME$nexthop_group>\ + [backup$backup <A.B.C.D$backup_nexthop4|X:X::X:X$backup_nexthop6>] \ + (1-1000000)$routes [instance (0-255)$instance] [repeat (2-1000)$rpt]", "Sharp routing Protocol\n" "install some routes\n" "Routes to install\n" @@ -175,6 +180,9 @@ DEFPY (install_routes, "V6 Nexthop address to use\n" "Nexthop-Group to use\n" "The Name of the nexthop-group\n" + "Backup nexthop to use(Can be an IPv4 or IPv6 address)\n" + "Backup V4 Nexthop address to use\n" + "Backup V6 Nexthop address to use\n" "How many to create\n" "Instance to use\n" "Instance\n" @@ -197,6 +205,8 @@ DEFPY (install_routes, memset(&sg.r.orig_prefix, 0, sizeof(sg.r.orig_prefix)); memset(&sg.r.nhop, 0, sizeof(sg.r.nhop)); memset(&sg.r.nhop_group, 0, sizeof(sg.r.nhop_group)); + memset(&sg.r.backup_nhop, 0, sizeof(sg.r.nhop)); + memset(&sg.r.backup_nhop_group, 0, sizeof(sg.r.nhop_group)); if (start4.s_addr != 0) { prefix.family = AF_INET; @@ -219,6 +229,12 @@ DEFPY (install_routes, return CMD_WARNING; } + /* Explicit backup not available with named nexthop-group */ + if (backup && nexthop_group) { + vty_out(vty, "%% Invalid: cannot specify both nexthop-group and backup\n"); + return CMD_WARNING; + } + if (nexthop_group) { struct nexthop_group_cmd *nhgc = nhgc_find(nexthop_group); if (!nhgc) { @@ -229,6 +245,22 @@ DEFPY (install_routes, } sg.r.nhop_group.nexthop = nhgc->nhg.nexthop; + + /* Use group's backup nexthop info if present */ + if (nhgc->backup_list_name[0]) { + struct nexthop_group_cmd *bnhgc = + nhgc_find(nhgc->backup_list_name); + + if (!bnhgc) { + vty_out(vty, "%% Backup group %s not found for group %s\n", + nhgc->backup_list_name, + nhgc->name); + return CMD_WARNING; + } + + sg.r.backup_nhop.vrf_id = vrf->vrf_id; + sg.r.backup_nhop_group.nexthop = bnhgc->nhg.nexthop; + } } else { if (nexthop4.s_addr != INADDR_ANY) { sg.r.nhop.gate.ipv4 = nexthop4; @@ -242,11 +274,30 @@ DEFPY (install_routes, sg.r.nhop_group.nexthop = &sg.r.nhop; } + /* Use single backup nexthop if specified */ + if (backup) { + /* Set flag and index in primary nexthop */ + SET_FLAG(sg.r.nhop.flags, NEXTHOP_FLAG_HAS_BACKUP); + sg.r.nhop.backup_idx = 0; + + if (backup_nexthop4.s_addr != INADDR_ANY) { + sg.r.backup_nhop.gate.ipv4 = backup_nexthop4; + sg.r.backup_nhop.type = NEXTHOP_TYPE_IPV4; + } else { + sg.r.backup_nhop.gate.ipv6 = backup_nexthop6; + sg.r.backup_nhop.type = NEXTHOP_TYPE_IPV6; + } + + sg.r.backup_nhop.vrf_id = vrf->vrf_id; + sg.r.backup_nhop_group.nexthop = &sg.r.backup_nhop; + } + sg.r.inst = instance; sg.r.vrf_id = vrf->vrf_id; rts = routes; - sharp_install_routes_helper(&prefix, sg.r.vrf_id, - sg.r.inst, &sg.r.nhop_group, rts); + sharp_install_routes_helper(&prefix, sg.r.vrf_id, sg.r.inst, + &sg.r.nhop_group, &sg.r.backup_nhop_group, + rts); return CMD_SUCCESS; } @@ -460,6 +511,22 @@ DEFPY(sharp_remove_lsp_prefix_v4, sharp_remove_lsp_prefix_v4_cmd, } } +DEFPY (logpump, + logpump_cmd, + "sharp logpump duration (1-60) frequency (1-1000000) burst (1-1000)", + "Sharp Routing Protocol\n" + "Generate bulk log messages for testing\n" + "Duration of run (s)\n" + "Duration of run (s)\n" + "Frequency of bursts (s^-1)\n" + "Frequency of bursts (s^-1)\n" + "Number of log messages per each burst\n" + "Number of log messages per each burst\n") +{ + sharp_logpump_run(vty, duration, frequency, burst); + return CMD_SUCCESS; +} + void sharp_vty_init(void) { install_element(ENABLE_NODE, &install_routes_data_dump_cmd); @@ -471,6 +538,7 @@ void sharp_vty_init(void) install_element(ENABLE_NODE, &watch_nexthop_v4_cmd); install_element(ENABLE_NODE, &sharp_lsp_prefix_v4_cmd); install_element(ENABLE_NODE, &sharp_remove_lsp_prefix_v4_cmd); + install_element(ENABLE_NODE, &logpump_cmd); install_element(VIEW_NODE, &show_debugging_sharpd_cmd); diff --git a/sharpd/sharp_vty.h b/sharpd/sharp_vty.h index d4af095e89..0d1327259c 100644 --- a/sharpd/sharp_vty.h +++ b/sharpd/sharp_vty.h @@ -23,4 +23,10 @@ #define __SHARP_VTY_H__ extern void sharp_vty_init(void); + +struct vty; + +extern void sharp_logpump_run(struct vty *vty, unsigned duration, + unsigned frequency, unsigned burst); + #endif diff --git a/sharpd/sharp_zebra.c b/sharpd/sharp_zebra.c index 882e73f873..e1bd6f5722 100644 --- a/sharpd/sharp_zebra.c +++ b/sharpd/sharp_zebra.c @@ -143,7 +143,9 @@ int sharp_install_lsps_helper(bool install_p, const struct prefix *p, } void sharp_install_routes_helper(struct prefix *p, vrf_id_t vrf_id, - uint8_t instance, struct nexthop_group *nhg, + uint8_t instance, + const struct nexthop_group *nhg, + const struct nexthop_group *backup_nhg, uint32_t routes) { uint32_t temp, i; @@ -157,9 +159,13 @@ void sharp_install_routes_helper(struct prefix *p, vrf_id_t vrf_id, } else temp = ntohl(p->u.val32[3]); + /* Only use backup route/nexthops if present */ + if (backup_nhg && (backup_nhg->nexthop == NULL)) + backup_nhg = NULL; + monotime(&sg.r.t_start); for (i = 0; i < routes; i++) { - route_add(p, vrf_id, (uint8_t)instance, nhg); + route_add(p, vrf_id, (uint8_t)instance, nhg, backup_nhg); if (v4) p->u.prefix4.s_addr = htonl(++temp); else @@ -209,6 +215,7 @@ static void handle_repeated(bool installed) sg.r.installed_routes = 0; sharp_install_routes_helper(&p, sg.r.vrf_id, sg.r.inst, &sg.r.nhop_group, + &sg.r.backup_nhop_group, sg.r.total_routes); } } @@ -276,8 +283,9 @@ void vrf_label_add(vrf_id_t vrf_id, afi_t afi, mpls_label_t label) zclient_send_vrf_label(zclient, vrf_id, afi, label, ZEBRA_LSP_SHARP); } -void route_add(struct prefix *p, vrf_id_t vrf_id, - uint8_t instance, struct nexthop_group *nhg) +void route_add(const struct prefix *p, vrf_id_t vrf_id, + uint8_t instance, const struct nexthop_group *nhg, + const struct nexthop_group *backup_nhg) { struct zapi_route api; struct zapi_nexthop *api_nh; @@ -298,10 +306,27 @@ void route_add(struct prefix *p, vrf_id_t vrf_id, api_nh = &api.nexthops[i]; zapi_nexthop_from_nexthop(api_nh, nh); + i++; } api.nexthop_num = i; + /* Include backup nexthops, if present */ + if (backup_nhg && backup_nhg->nexthop) { + SET_FLAG(api.message, ZAPI_MESSAGE_BACKUP_NEXTHOPS); + + i = 0; + for (ALL_NEXTHOPS_PTR(backup_nhg, nh)) { + api_nh = &api.backup_nexthops[i]; + + zapi_backup_nexthop_from_nexthop(api_nh, nh); + + i++; + } + + api.backup_nexthop_num = i; + } + zclient_route_send(ZEBRA_ROUTE_ADD, zclient, &api); } @@ -353,7 +378,7 @@ static int sharp_debug_nexthops(struct zapi_route *api) case NEXTHOP_TYPE_IPV4_IFINDEX: case NEXTHOP_TYPE_IPV4: zlog_debug( - "\tNexthop %s, type: %d, ifindex: %d, vrf: %d, label_num: %d", + " Nexthop %s, type: %d, ifindex: %d, vrf: %d, label_num: %d", inet_ntop(AF_INET, &znh->gate.ipv4.s_addr, buf, sizeof(buf)), znh->type, znh->ifindex, znh->vrf_id, @@ -362,18 +387,18 @@ static int sharp_debug_nexthops(struct zapi_route *api) case NEXTHOP_TYPE_IPV6_IFINDEX: case NEXTHOP_TYPE_IPV6: zlog_debug( - "\tNexthop %s, type: %d, ifindex: %d, vrf: %d, label_num: %d", + " Nexthop %s, type: %d, ifindex: %d, vrf: %d, label_num: %d", inet_ntop(AF_INET6, &znh->gate.ipv6, buf, sizeof(buf)), znh->type, znh->ifindex, znh->vrf_id, znh->label_num); break; case NEXTHOP_TYPE_IFINDEX: - zlog_debug("\tNexthop IFINDEX: %d, ifindex: %d", + zlog_debug(" Nexthop IFINDEX: %d, ifindex: %d", znh->type, znh->ifindex); break; case NEXTHOP_TYPE_BLACKHOLE: - zlog_debug("\tNexthop blackhole"); + zlog_debug(" Nexthop blackhole"); break; } } diff --git a/sharpd/sharp_zebra.h b/sharpd/sharp_zebra.h index c995d557af..926bff676b 100644 --- a/sharpd/sharp_zebra.h +++ b/sharpd/sharp_zebra.h @@ -25,15 +25,17 @@ extern void sharp_zebra_init(void); extern void vrf_label_add(vrf_id_t vrf_id, afi_t afi, mpls_label_t label); -extern void route_add(struct prefix *p, vrf_id_t, uint8_t instance, - struct nexthop_group *nhg); +extern void route_add(const struct prefix *p, vrf_id_t, uint8_t instance, + const struct nexthop_group *nhg, + const struct nexthop_group *backup_nhg); extern void route_delete(struct prefix *p, vrf_id_t vrf_id, uint8_t instance); extern void sharp_zebra_nexthop_watch(struct prefix *p, vrf_id_t vrf_id, bool import, bool watch, bool connected); extern void sharp_install_routes_helper(struct prefix *p, vrf_id_t vrf_id, uint8_t instance, - struct nexthop_group *nhg, + const struct nexthop_group *nhg, + const struct nexthop_group *backup_nhg, uint32_t routes); extern void sharp_remove_routes_helper(struct prefix *p, vrf_id_t vrf_id, uint8_t instance, uint32_t routes); diff --git a/sharpd/subdir.am b/sharpd/subdir.am index 89b183d832..8b32b2370c 100644 --- a/sharpd/subdir.am +++ b/sharpd/subdir.am @@ -14,6 +14,7 @@ sharpd_libsharp_a_SOURCES = \ sharpd/sharp_nht.c \ sharpd/sharp_zebra.c \ sharpd/sharp_vty.c \ + sharpd/sharp_logpump.c \ # end noinst_HEADERS += \ diff --git a/staticd/static_debug.c b/staticd/static_debug.c index 9906e805a7..e43d4e79ff 100644 --- a/staticd/static_debug.c +++ b/staticd/static_debug.c @@ -3,7 +3,7 @@ * Copyright (C) 2019 Volta Networks Inc. * Mark Stapp * - * This file is part of Free Range Routing (FRR). + * This file is part of FRRouting (FRR). * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the diff --git a/staticd/static_debug.h b/staticd/static_debug.h index 8932e2d429..481c266e14 100644 --- a/staticd/static_debug.h +++ b/staticd/static_debug.h @@ -3,7 +3,7 @@ * Copyright (C) 2019 Volta Networks Inc. * Mark Stapp * - * This file is part of Free Range Routing (FRR). + * This file is part of FRRouting (FRR). * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the diff --git a/staticd/static_vty.c b/staticd/static_vty.c index 40bcf2b5d3..a950b0473e 100644 --- a/staticd/static_vty.c +++ b/staticd/static_vty.c @@ -867,7 +867,7 @@ DEFPY(ip_route_address_interface, "Table to configure\n" "The table number to configure\n" VRF_CMD_HELP_STR - "Treat the nexthop as directly attached to the interface") + "Treat the nexthop as directly attached to the interface\n") { struct static_vrf *svrf; struct static_vrf *nh_svrf; @@ -935,7 +935,7 @@ DEFPY(ip_route_address_interface_vrf, "Table to configure\n" "The table number to configure\n" VRF_CMD_HELP_STR - "Treat the nexthop as directly attached to the interface") + "Treat the nexthop as directly attached to the interface\n") { VTY_DECLVAR_CONTEXT(vrf, vrf); const char *flag = NULL; @@ -1211,7 +1211,7 @@ DEFPY(ipv6_route_address_interface, "Table to configure\n" "The table number to configure\n" VRF_CMD_HELP_STR - "Treat the nexthop as directly attached to the interface") + "Treat the nexthop as directly attached to the interface\n") { struct static_vrf *svrf; struct static_vrf *nh_svrf; @@ -1279,7 +1279,7 @@ DEFPY(ipv6_route_address_interface_vrf, "Table to configure\n" "The table number to configure\n" VRF_CMD_HELP_STR - "Treat the nexthop as directly attached to the interface") + "Treat the nexthop as directly attached to the interface\n") { VTY_DECLVAR_CONTEXT(vrf, vrf); struct static_vrf *svrf = vrf->info; diff --git a/tests/bgpd/test_bgp_table.c b/tests/bgpd/test_bgp_table.c index 819c2d7282..79a8bb4408 100644 --- a/tests/bgpd/test_bgp_table.c +++ b/tests/bgpd/test_bgp_table.c @@ -82,7 +82,7 @@ static void print_range_result(struct list *list) for (ALL_LIST_ELEMENTS_RO(list, listnode, bnode)) { char buf[PREFIX2STR_BUFFER]; - prefix2str(&bnode->p, buf, PREFIX2STR_BUFFER); + prefix2str(bgp_node_get_prefix(bnode), buf, PREFIX2STR_BUFFER); printf("%s\n", buf); } } @@ -106,7 +106,7 @@ static void check_lookup_result(struct list *list, va_list arglist) assert(0); for (ALL_LIST_ELEMENTS_RO(list, listnode, bnode)) { - if (prefix_same(&bnode->p, &p)) + if (prefix_same(bgp_node_get_prefix(bnode), &p)) found = true; } diff --git a/tests/lib/test_atomlist.c b/tests/lib/test_atomlist.c index 238ee9539e..40837b4722 100644 --- a/tests/lib/test_atomlist.c +++ b/tests/lib/test_atomlist.c @@ -29,6 +29,7 @@ #include "atomlist.h" #include "seqlock.h" #include "monotime.h" +#include "printfrr.h" /* * maybe test: @@ -288,7 +289,7 @@ static void run_tr(struct testrun *tr) size_t c = 0, s = 0, n = 0; struct item *item, *prev, dummy; - printf("[%02u] %35s %s\n", seqlock_cur(&sqlo) >> 2, "", desc); + printfrr("[%02u] %35s %s\n", seqlock_cur(&sqlo) >> 2, "", desc); fflush(stdout); if (tr->prefill != NOCLEAR) @@ -324,7 +325,7 @@ static void run_tr(struct testrun *tr) } assert(c == alist_count(&ahead)); } - printf("\033[1A[%02u] %9"PRId64"us c=%5zu s=%5zu n=%5zu %s\n", + printfrr("\033[1A[%02u] %9"PRId64"us c=%5zu s=%5zu n=%5zu %s\n", sv >> 2, delta, c, s, n, desc); } @@ -334,9 +335,9 @@ static void dump(const char *lbl) struct item *item, *safe; size_t ctr = 0; - printf("dumping %s:\n", lbl); + printfrr("dumping %s:\n", lbl); frr_each_safe(alist, &ahead, item) { - printf("%s %3zu %p %3"PRIu64" %3"PRIu64"\n", lbl, ctr++, + printfrr("%s %3zu %p %3"PRIu64" %3"PRIu64"\n", lbl, ctr++, (void *)item, item->val1, item->val2); } } @@ -362,12 +363,12 @@ static void basic_tests(void) dump(""); alist_del(&ahead, &itm[1]); dump(""); - printf("POP: %p\n", alist_pop(&ahead)); + printfrr("POP: %p\n", alist_pop(&ahead)); dump(""); - printf("POP: %p\n", alist_pop(&ahead)); - printf("POP: %p\n", alist_pop(&ahead)); - printf("POP: %p\n", alist_pop(&ahead)); - printf("POP: %p\n", alist_pop(&ahead)); + printfrr("POP: %p\n", alist_pop(&ahead)); + printfrr("POP: %p\n", alist_pop(&ahead)); + printfrr("POP: %p\n", alist_pop(&ahead)); + printfrr("POP: %p\n", alist_pop(&ahead)); dump(""); } #else diff --git a/tests/lib/test_srcdest_table.c b/tests/lib/test_srcdest_table.c index 0fca571d28..935ee500a3 100644 --- a/tests/lib/test_srcdest_table.c +++ b/tests/lib/test_srcdest_table.c @@ -4,7 +4,7 @@ * Copyright (C) 2017 by David Lamparter & Christian Franke, * Open Source Routing / NetDEF Inc. * - * This file is part of FreeRangeRouting (FRR) + * This file is part of FRRouting (FRR) * * FRR is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the diff --git a/tests/lib/test_stream.c b/tests/lib/test_stream.c index 2ecfc87942..a45c2b4d54 100644 --- a/tests/lib/test_stream.c +++ b/tests/lib/test_stream.c @@ -23,6 +23,8 @@ #include <stream.h> #include <thread.h> +#include "printfrr.h" + static unsigned long long ham = 0xdeadbeefdeadbeef; struct thread_master *master; @@ -30,15 +32,15 @@ static void print_stream(struct stream *s) { size_t getp = stream_get_getp(s); - printf("endp: %zu, readable: %zu, writeable: %zu\n", stream_get_endp(s), - STREAM_READABLE(s), STREAM_WRITEABLE(s)); + printfrr("endp: %zu, readable: %zu, writeable: %zu\n", + stream_get_endp(s), STREAM_READABLE(s), STREAM_WRITEABLE(s)); while (STREAM_READABLE(s)) { - printf("0x%x ", *stream_pnt(s)); + printfrr("0x%x ", *stream_pnt(s)); stream_forward_getp(s, 1); } - printf("\n"); + printfrr("\n"); /* put getp back to where it was */ stream_set_getp(s, getp); @@ -61,10 +63,10 @@ int main(void) print_stream(s); - printf("c: 0x%hhx\n", stream_getc(s)); - printf("w: 0x%hx\n", stream_getw(s)); - printf("l: 0x%x\n", stream_getl(s)); - printf("q: 0x%" PRIx64 "\n", stream_getq(s)); + printfrr("c: 0x%hhx\n", stream_getc(s)); + printfrr("w: 0x%hx\n", stream_getw(s)); + printfrr("l: 0x%x\n", stream_getl(s)); + printfrr("q: 0x%" PRIx64 "\n", stream_getq(s)); return 0; } diff --git a/tests/lib/test_typelist.c b/tests/lib/test_typelist.c index 2438fb5f08..607e29e56b 100644 --- a/tests/lib/test_typelist.c +++ b/tests/lib/test_typelist.c @@ -35,6 +35,7 @@ #include "monotime.h" #include "jhash.h" #include "sha256.h" +#include "printfrr.h" #include "tests/helpers/c/prng.h" @@ -90,14 +91,14 @@ static void ts_ref(const char *text) { int64_t us; us = monotime_since(&ref, NULL); - printf("%7"PRId64"us %s\n", us, text); + printfrr("%7"PRId64"us %s\n", us, text); monotime(&ref); } static void ts_end(void) { int64_t us; us = monotime_since(&ref0, NULL); - printf("%7"PRId64"us total\n", us); + printfrr("%7"PRId64"us total\n", us); } #define TYPE LIST diff --git a/tests/lib/test_typelist.h b/tests/lib/test_typelist.h index 9039fa8a46..da3530e9c0 100644 --- a/tests/lib/test_typelist.h +++ b/tests/lib/test_typelist.h @@ -123,10 +123,10 @@ static void ts_hash(const char *text, const char *expect) for (i = 0; i < sizeof(hash); i++) sprintf(hashtext + i * 2, "%02x", hash[i]); - printf("%7"PRId64"us %-25s %s%s\n", us, text, + printfrr("%7"PRId64"us %-25s %s%s\n", us, text, expect ? " " : "*", hashtext); if (expect && strcmp(expect, hashtext)) { - printf("%-21s %s\n", "EXPECTED:", expect); + printfrr("%-21s %s\n", "EXPECTED:", expect); assert(0); } monotime(&ref); @@ -149,7 +149,7 @@ static void concat(test_, TYPE)(void) for (i = 0; i < NITEM; i++) itm[i].val = i; - printf("%s start\n", str(TYPE)); + printfrr("%s start\n", str(TYPE)); ts_start(); list_init(&head); @@ -530,7 +530,7 @@ static void concat(test_, TYPE)(void) list_fini(&head); ts_ref("fini"); ts_end(); - printf("%s end\n", str(TYPE)); + printfrr("%s end\n", str(TYPE)); } #undef ts_hashx diff --git a/tests/lib/test_zlog.c b/tests/lib/test_zlog.c index 790e65cfe9..07885d9847 100644 --- a/tests/lib/test_zlog.c +++ b/tests/lib/test_zlog.c @@ -34,12 +34,14 @@ static bool test_zlog_hexdump(void) unsigned int nl = 1; do { - long d[nl]; + uint8_t d[nl]; for (unsigned int i = 0; i < nl; i++) d[i] = random(); - zlog_hexdump(d, nl * sizeof(long)); - } while (++nl * sizeof(long) <= MAXDATA); + zlog_hexdump(d, nl - 1); + + nl += 1 + (nl / 2); + } while (nl <= MAXDATA); return true; } diff --git a/tests/subdir.am b/tests/subdir.am index d87d348949..bce08c4034 100644 --- a/tests/subdir.am +++ b/tests/subdir.am @@ -38,8 +38,11 @@ else TESTS_OSPF6D = endif +tests/lib/cli/test_cli_clippy.c: $(CLIPPY_DEPS) tests/lib/cli/tests_lib_cli_test_cli-test_cli.$(OBJEXT): tests/lib/cli/test_cli_clippy.c tests/lib/cli/test_cli-test_cli.$(OBJEXT): tests/lib/cli/test_cli_clippy.c + +tests/ospf6d/test_lsdb_clippy.c: $(CLIPPY_DEPS) tests/ospf6d/tests_ospf6d_test_lsdb-test_lsdb.$(OBJEXT): tests/ospf6d/test_lsdb_clippy.c tests/ospf6d/test_lsdb-test_lsdb.$(OBJEXT): tests/ospf6d/test_lsdb_clippy.c diff --git a/tests/topotests/bfd-bgp-cbit-topo3/r1/bgp_ipv6_routes_down.json b/tests/topotests/bfd-bgp-cbit-topo3/r1/bgp_ipv6_routes_down.json index 54ae57f7be..ac5fd04074 100644 --- a/tests/topotests/bfd-bgp-cbit-topo3/r1/bgp_ipv6_routes_down.json +++ b/tests/topotests/bfd-bgp-cbit-topo3/r1/bgp_ipv6_routes_down.json @@ -14,7 +14,6 @@ "prefix": "2001:db8:6::", "prefixLen": 64, "network": "2001:db8:6::\/64", - "med": 0, "metric": 0, "weight": 0, "peerId": "2001:db8:4::1", @@ -37,7 +36,6 @@ "prefix": "2001:db8:7::", "prefixLen": 64, "network": "2001:db8:7::\/64", - "med": 0, "metric": 0, "weight": 0, "peerId": "2001:db8:4::1", @@ -60,7 +58,6 @@ "prefix": "2001:db8:8::", "prefixLen": 64, "network": "2001:db8:8::\/64", - "med": 0, "metric": 0, "weight": 32768, "peerId": "(unspec)", @@ -83,7 +80,6 @@ "prefix": "2001:db8:9::", "prefixLen": 64, "network": "2001:db8:9::\/64", - "med": 0, "metric": 0, "weight": 32768, "peerId": "(unspec)", diff --git a/tests/topotests/bfd-bgp-cbit-topo3/r3/bgp_ipv6_routes_down.json b/tests/topotests/bfd-bgp-cbit-topo3/r3/bgp_ipv6_routes_down.json index a3bb222504..ab42b05e85 100644 --- a/tests/topotests/bfd-bgp-cbit-topo3/r3/bgp_ipv6_routes_down.json +++ b/tests/topotests/bfd-bgp-cbit-topo3/r3/bgp_ipv6_routes_down.json @@ -13,7 +13,6 @@ "prefix": "2001:db8:6::", "prefixLen": 64, "network": "2001:db8:6::\/64", - "med": 0, "metric": 0, "weight": 32768, "peerId": "(unspec)", @@ -36,7 +35,6 @@ "prefix": "2001:db8:7::", "prefixLen": 64, "network": "2001:db8:7::\/64", - "med": 0, "metric": 0, "weight": 32768, "peerId": "(unspec)", diff --git a/tests/topotests/bfd-bgp-cbit-topo3/test_bfd_bgp_cbit_topo3.py b/tests/topotests/bfd-bgp-cbit-topo3/test_bfd_bgp_cbit_topo3.py index e2bd80daa8..22a4547a30 100755 --- a/tests/topotests/bfd-bgp-cbit-topo3/test_bfd_bgp_cbit_topo3.py +++ b/tests/topotests/bfd-bgp-cbit-topo3/test_bfd_bgp_cbit_topo3.py @@ -142,7 +142,7 @@ def test_bfd_connection(): test_func = partial(topotest.router_json_cmp, router, 'show bfd peers json', expected) - _, result = topotest.run_and_expect(test_func, None, count=16, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=32, wait=0.5) assertmsg = '"{}" JSON output mismatches'.format(router.name) assert result is None, assertmsg @@ -173,7 +173,7 @@ def test_bfd_loss_intermediate(): test_func = partial(topotest.router_json_cmp, router, 'show bfd peers json', expected) - _, result = topotest.run_and_expect(test_func, None, count=16, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=32, wait=0.5) assertmsg = '"{}" JSON output mismatches'.format(router.name) assert result is None, assertmsg diff --git a/tests/topotests/bfd-topo1/r1/bgp_prefixes.json b/tests/topotests/bfd-topo1/r1/bgp_prefixes.json index 4b2cc1ad62..1262f5e984 100644 --- a/tests/topotests/bfd-topo1/r1/bgp_prefixes.json +++ b/tests/topotests/bfd-topo1/r1/bgp_prefixes.json @@ -2,7 +2,7 @@ "routes": { "10.254.254.2/32": [ { - "aspath": "102", + "path": "102", "prefix": "10.254.254.2", "valid": true, "peerId": "192.168.0.2", @@ -18,7 +18,7 @@ ], "10.254.254.3/32": [ { - "aspath": "102 103", + "path": "102 103", "prefix": "10.254.254.3", "valid": true, "peerId": "192.168.0.2", @@ -34,7 +34,7 @@ ], "10.254.254.4/32": [ { - "aspath": "102 104", + "path": "102 104", "prefix": "10.254.254.4", "valid": true, "peerId": "192.168.0.2", diff --git a/tests/topotests/bfd-topo1/r2/bgp_prefixes.json b/tests/topotests/bfd-topo1/r2/bgp_prefixes.json index 39f3c0a835..0d47c0fc30 100644 --- a/tests/topotests/bfd-topo1/r2/bgp_prefixes.json +++ b/tests/topotests/bfd-topo1/r2/bgp_prefixes.json @@ -2,7 +2,7 @@ "routes": { "10.254.254.1/32": [ { - "aspath": "101", + "path": "101", "prefix": "10.254.254.1", "valid": true, "peerId": "192.168.0.1", @@ -18,7 +18,7 @@ ], "10.254.254.3/32": [ { - "aspath": "103", + "path": "103", "prefix": "10.254.254.3", "valid": true, "peerId": "192.168.1.1", @@ -34,7 +34,7 @@ ], "10.254.254.4/32": [ { - "aspath": "104", + "path": "104", "prefix": "10.254.254.4", "valid": true, "peerId": "192.168.2.1", diff --git a/tests/topotests/bfd-topo1/r3/bgp_prefixes.json b/tests/topotests/bfd-topo1/r3/bgp_prefixes.json index c92d4e052a..36fca17bbf 100644 --- a/tests/topotests/bfd-topo1/r3/bgp_prefixes.json +++ b/tests/topotests/bfd-topo1/r3/bgp_prefixes.json @@ -2,7 +2,7 @@ "routes": { "10.254.254.1/32": [ { - "aspath": "102 101", + "path": "102 101", "prefix": "10.254.254.1", "valid": true, "peerId": "192.168.1.2", @@ -18,7 +18,7 @@ ], "10.254.254.2/32": [ { - "aspath": "102", + "path": "102", "prefix": "10.254.254.2", "valid": true, "peerId": "192.168.1.2", @@ -34,7 +34,7 @@ ], "10.254.254.4/32": [ { - "aspath": "102 104", + "path": "102 104", "prefix": "10.254.254.4", "valid": true, "peerId": "192.168.1.2", diff --git a/tests/topotests/bfd-topo1/r4/bgp_prefixes.json b/tests/topotests/bfd-topo1/r4/bgp_prefixes.json index cc8510dd61..efe7d47b1a 100644 --- a/tests/topotests/bfd-topo1/r4/bgp_prefixes.json +++ b/tests/topotests/bfd-topo1/r4/bgp_prefixes.json @@ -2,7 +2,7 @@ "routes": { "10.254.254.1/32": [ { - "aspath": "102 101", + "path": "102 101", "prefix": "10.254.254.1", "valid": true, "peerId": "192.168.2.2", @@ -18,7 +18,7 @@ ], "10.254.254.2/32": [ { - "aspath": "102", + "path": "102", "prefix": "10.254.254.2", "valid": true, "peerId": "192.168.2.2", @@ -34,7 +34,7 @@ ], "10.254.254.3/32": [ { - "aspath": "102 103", + "path": "102 103", "prefix": "10.254.254.3", "valid": true, "peerId": "192.168.2.2", diff --git a/tests/topotests/bfd-vrf-topo1/r1/bgp_prefixes.json b/tests/topotests/bfd-vrf-topo1/r1/bgp_prefixes.json index 4b2cc1ad62..1262f5e984 100644 --- a/tests/topotests/bfd-vrf-topo1/r1/bgp_prefixes.json +++ b/tests/topotests/bfd-vrf-topo1/r1/bgp_prefixes.json @@ -2,7 +2,7 @@ "routes": { "10.254.254.2/32": [ { - "aspath": "102", + "path": "102", "prefix": "10.254.254.2", "valid": true, "peerId": "192.168.0.2", @@ -18,7 +18,7 @@ ], "10.254.254.3/32": [ { - "aspath": "102 103", + "path": "102 103", "prefix": "10.254.254.3", "valid": true, "peerId": "192.168.0.2", @@ -34,7 +34,7 @@ ], "10.254.254.4/32": [ { - "aspath": "102 104", + "path": "102 104", "prefix": "10.254.254.4", "valid": true, "peerId": "192.168.0.2", diff --git a/tests/topotests/bfd-vrf-topo1/r2/bgp_prefixes.json b/tests/topotests/bfd-vrf-topo1/r2/bgp_prefixes.json index 39f3c0a835..0d47c0fc30 100644 --- a/tests/topotests/bfd-vrf-topo1/r2/bgp_prefixes.json +++ b/tests/topotests/bfd-vrf-topo1/r2/bgp_prefixes.json @@ -2,7 +2,7 @@ "routes": { "10.254.254.1/32": [ { - "aspath": "101", + "path": "101", "prefix": "10.254.254.1", "valid": true, "peerId": "192.168.0.1", @@ -18,7 +18,7 @@ ], "10.254.254.3/32": [ { - "aspath": "103", + "path": "103", "prefix": "10.254.254.3", "valid": true, "peerId": "192.168.1.1", @@ -34,7 +34,7 @@ ], "10.254.254.4/32": [ { - "aspath": "104", + "path": "104", "prefix": "10.254.254.4", "valid": true, "peerId": "192.168.2.1", diff --git a/tests/topotests/bfd-vrf-topo1/r3/bgp_prefixes.json b/tests/topotests/bfd-vrf-topo1/r3/bgp_prefixes.json index c92d4e052a..36fca17bbf 100644 --- a/tests/topotests/bfd-vrf-topo1/r3/bgp_prefixes.json +++ b/tests/topotests/bfd-vrf-topo1/r3/bgp_prefixes.json @@ -2,7 +2,7 @@ "routes": { "10.254.254.1/32": [ { - "aspath": "102 101", + "path": "102 101", "prefix": "10.254.254.1", "valid": true, "peerId": "192.168.1.2", @@ -18,7 +18,7 @@ ], "10.254.254.2/32": [ { - "aspath": "102", + "path": "102", "prefix": "10.254.254.2", "valid": true, "peerId": "192.168.1.2", @@ -34,7 +34,7 @@ ], "10.254.254.4/32": [ { - "aspath": "102 104", + "path": "102 104", "prefix": "10.254.254.4", "valid": true, "peerId": "192.168.1.2", diff --git a/tests/topotests/bfd-vrf-topo1/r4/bgp_prefixes.json b/tests/topotests/bfd-vrf-topo1/r4/bgp_prefixes.json index cc8510dd61..efe7d47b1a 100644 --- a/tests/topotests/bfd-vrf-topo1/r4/bgp_prefixes.json +++ b/tests/topotests/bfd-vrf-topo1/r4/bgp_prefixes.json @@ -2,7 +2,7 @@ "routes": { "10.254.254.1/32": [ { - "aspath": "102 101", + "path": "102 101", "prefix": "10.254.254.1", "valid": true, "peerId": "192.168.2.2", @@ -18,7 +18,7 @@ ], "10.254.254.2/32": [ { - "aspath": "102", + "path": "102", "prefix": "10.254.254.2", "valid": true, "peerId": "192.168.2.2", @@ -34,7 +34,7 @@ ], "10.254.254.3/32": [ { - "aspath": "102 103", + "path": "102 103", "prefix": "10.254.254.3", "valid": true, "peerId": "192.168.2.2", diff --git a/tests/topotests/bgp-path-attributes-topo1/test_bgp_path_attributes.py b/tests/topotests/bgp-path-attributes-topo1/test_bgp_path_attributes.py index 3b2d9c25d7..1cd2c4417f 100755 --- a/tests/topotests/bgp-path-attributes-topo1/test_bgp_path_attributes.py +++ b/tests/topotests/bgp-path-attributes-topo1/test_bgp_path_attributes.py @@ -430,7 +430,7 @@ def test_aspath_attribute(request): # Verifying best path dut = "r1" - attribute = "aspath" + attribute = "path" for addr_type in ADDR_TYPES: result = verify_best_path_as_per_bgp_attribute(tgen, addr_type, dut, {"r7": input_dict["r7"]}, @@ -479,7 +479,7 @@ def test_aspath_attribute(request): } }, "set": { - "aspath": { + "path": { "as_num": "111 222", "as_action": "prepend" } @@ -493,7 +493,7 @@ def test_aspath_attribute(request): } }, "set": { - "aspath": { + "path": { "as_num": "111 222", "as_action": "prepend" } @@ -553,7 +553,7 @@ def test_aspath_attribute(request): # Verifying best path dut = "r1" - attribute = "aspath" + attribute = "path" for addr_type in ADDR_TYPES: result = verify_best_path_as_per_bgp_attribute(tgen, addr_type, dut, {"r7": input_dict["r7"]}, @@ -714,7 +714,7 @@ def test_localpref_attribute(request): } }, "set": { - "localpref": 1111 + "locPrf": 1111 } }, { @@ -726,7 +726,7 @@ def test_localpref_attribute(request): } }, "set": { - "localpref": 1111 + "locPrf": 1111 } }] } @@ -783,7 +783,7 @@ def test_localpref_attribute(request): # Verifying best path dut = "r1" - attribute = "localpref" + attribute = "locPrf" for addr_type in ADDR_TYPES: result = verify_best_path_as_per_bgp_attribute(tgen, addr_type, dut, {"r7": input_dict["r7"]}, @@ -804,7 +804,7 @@ def test_localpref_attribute(request): } }, "set": { - "localpref": 50 + "locPrf": 50 } }, { @@ -816,7 +816,7 @@ def test_localpref_attribute(request): } }, "set": { - "localpref": 50 + "locPrf": 50 } }] } @@ -828,7 +828,7 @@ def test_localpref_attribute(request): # Verifying best path dut = "r1" - attribute = "localpref" + attribute = "locPrf" for addr_type in ADDR_TYPES: result = verify_best_path_as_per_bgp_attribute(tgen, addr_type, dut, {"r7": input_dict["r7"]}, @@ -1437,7 +1437,7 @@ def test_med_attribute(request): } }, "set": { - "med": 100 + "metric": 100 } }, { @@ -1449,7 +1449,7 @@ def test_med_attribute(request): } }, "set": { - "med": 100 + "metric": 100 } }] } @@ -1465,7 +1465,7 @@ def test_med_attribute(request): } }, "set": { - "med": 10 + "metric": 10 } }, { @@ -1477,7 +1477,7 @@ def test_med_attribute(request): } }, "set": { - "med": 10 + "metric": 10 } }] } @@ -1593,7 +1593,7 @@ def test_med_attribute(request): # Verifying best path dut = "r1" - attribute = "med" + attribute = "metric" for addr_type in ADDR_TYPES: result = verify_best_path_as_per_bgp_attribute(tgen, addr_type, dut, input_dict, attribute) @@ -1613,7 +1613,7 @@ def test_med_attribute(request): } }, "set": { - "med": 200 + "metric": 200 } }, { @@ -1625,7 +1625,7 @@ def test_med_attribute(request): } }, "set": { - "med": 200 + "metric": 200 } }] } @@ -1638,7 +1638,7 @@ def test_med_attribute(request): # Verifying best path dut = "r1" - attribute = "med" + attribute = "metric" for addr_type in ADDR_TYPES: result = verify_best_path_as_per_bgp_attribute(tgen, addr_type, dut, input_dict, attribute) diff --git a/tests/topotests/bgp-route-map/test_route_map_topo1.py b/tests/topotests/bgp-route-map/test_route_map_topo1.py index 22dd3a6380..c854e5a444 100755 --- a/tests/topotests/bgp-route-map/test_route_map_topo1.py +++ b/tests/topotests/bgp-route-map/test_route_map_topo1.py @@ -763,7 +763,7 @@ def test_route_map_multiple_seq_different_match_set_clause_p0(request): } }, "set": { - "aspath": { + "path": { "as_num": 500 } } @@ -777,7 +777,7 @@ def test_route_map_multiple_seq_different_match_set_clause_p0(request): } }, "set": { - "localpref": 150, + "locPrf": 150, } }, { @@ -789,7 +789,7 @@ def test_route_map_multiple_seq_different_match_set_clause_p0(request): } }, "set": { - "med": 50 + "metric": 50 } } ] @@ -878,7 +878,7 @@ def test_route_map_multiple_seq_different_match_set_clause_p0(request): "route_maps": { "rmap_match_pf_list1": [{ "set": { - "med": 50, + "metric": 50, } }], } @@ -972,8 +972,8 @@ def test_route_map_set_only_no_match_p0(request): { "action": "permit", "set": { - "med": 50, - "localpref": 150, + "metric": 50, + "locPrf": 150, "weight": 4000 } } @@ -1059,7 +1059,7 @@ def test_route_map_set_only_no_match_p0(request): { "action": "permit", "set": { - "med": 50, + "metric": 50, } } ] @@ -1176,8 +1176,8 @@ def test_route_map_match_only_no_set_p0(request): "rmap_match_pf_1_{}".format(addr_type): [{ "action": "permit", "set": { - "med": 50, - "localpref": 150, + "metric": 50, + "locPrf": 150, } } ] diff --git a/tests/topotests/bgp-route-map/test_route_map_topo2.py b/tests/topotests/bgp-route-map/test_route_map_topo2.py index f2398c33ff..609cea5f92 100755 --- a/tests/topotests/bgp-route-map/test_route_map_topo2.py +++ b/tests/topotests/bgp-route-map/test_route_map_topo2.py @@ -288,7 +288,7 @@ def test_rmap_match_prefix_list_permit_in_and_outbound_prefixes_p0(): } }, "set": { - "localpref": 150, + "locPrf": 150, "weight": 100 } }, @@ -302,7 +302,7 @@ def test_rmap_match_prefix_list_permit_in_and_outbound_prefixes_p0(): } }, "set": { - "med": 50 + "metric": 50 } }, ] @@ -506,7 +506,7 @@ def test_modify_set_match_clauses_in_rmap_p0(): } }, "set": { - "localpref": 150, + "locPrf": 150, } }], "rmap_match_pf_2_{}".format(addr_type): [{ @@ -518,7 +518,7 @@ def test_modify_set_match_clauses_in_rmap_p0(): } }, "set": { - "med": 50 + "metric": 50 } }] } @@ -658,7 +658,7 @@ def test_modify_set_match_clauses_in_rmap_p0(): } }, "set": { - "localpref": 1000, + "locPrf": 1000, } }], "rmap_match_pf_2_{}".format(addr_type): [{ @@ -670,7 +670,7 @@ def test_modify_set_match_clauses_in_rmap_p0(): } }, "set": { - "med": 2000 + "metric": 2000 } }] } @@ -844,7 +844,7 @@ def test_modify_prefix_list_referenced_by_rmap_p0(): } }, "set": { - "localpref": 150, + "locPrf": 150, "weight": 100 } }], @@ -857,7 +857,7 @@ def test_modify_prefix_list_referenced_by_rmap_p0(): } }, "set": { - "med": 50 + "metric": 50 } }] } @@ -1093,7 +1093,7 @@ def test_remove_prefix_list_referenced_by_rmap_p0(): } }, "set": { - "localpref": 150, + "locPrf": 150, } }], "rmap_match_pf_2_{}".format(addr_type): [{ @@ -1105,7 +1105,7 @@ def test_remove_prefix_list_referenced_by_rmap_p0(): } }, "set": { - "med": 50 + "metric": 50 } }] } @@ -1639,7 +1639,7 @@ def test_multiple_match_statement_in_route_map_logical_ORed_p0(): } }, "set": { - "localpref": 150 + "locPrf": 150 } }] } @@ -1664,7 +1664,7 @@ def test_multiple_match_statement_in_route_map_logical_ORed_p0(): } }, "set": { - "localpref": 200 + "locPrf": 200 } }] } @@ -1894,7 +1894,7 @@ def test_multiple_match_statement_in_route_map_logical_ANDed_p1(): } }, "set": { - "localpref": 150, + "locPrf": 150, } }] } @@ -1919,7 +1919,7 @@ def test_multiple_match_statement_in_route_map_logical_ANDed_p1(): } }, "set": { - "localpref": 150, + "locPrf": 150, } }] } @@ -2043,7 +2043,7 @@ def test_add_remove_rmap_to_specific_neighbor_p0(): } }, "set": { - "localpref": 150, + "locPrf": 150, } }] } @@ -2234,7 +2234,7 @@ def test_clear_bgp_and_flap_interface_to_verify_rmap_properties_p0(): } }, "set": { - "localpref": 150, + "locPrf": 150, "weight": 100 } }] @@ -2578,7 +2578,7 @@ def test_set_localpref_weight_to_ebgp_and_med_to_ibgp_peers_p0(): } }, "set": { - "med": 50 + "metric": 50 } }], "rmap_match_pf_2_{}".format(addr_type): [{ @@ -2589,7 +2589,7 @@ def test_set_localpref_weight_to_ebgp_and_med_to_ibgp_peers_p0(): addr_type) }}, "set": { - "localpref": 150 + "locPrf": 150 } }], "rmap_match_pf_3_{}".format(addr_type): [{ @@ -2841,9 +2841,9 @@ def test_multiple_set_on_single_sequence_in_rmap_p0(): } }, "set": { - "localpref": 150, + "locPrf": 150, "weight": 100, - "med": 50 + "metric": 50 } }] } @@ -2985,7 +2985,7 @@ def test_route_maps_with_continue_clause_p0(): } }, "set": { - "localpref": 150 + "locPrf": 150 }, "continue": "30" }, @@ -2998,7 +2998,7 @@ def test_route_maps_with_continue_clause_p0(): } }, "set": { - "med": 200 + "metric": 200 } }, { @@ -3010,7 +3010,7 @@ def test_route_maps_with_continue_clause_p0(): } }, "set": { - "med": 100 + "metric": 100 } } ] @@ -3167,7 +3167,7 @@ def test_route_maps_with_goto_clause_p0(): } }, "set": { - "med": 100 + "metric": 100 } }, { @@ -3179,7 +3179,7 @@ def test_route_maps_with_goto_clause_p0(): } }, "set": { - "med": 200 + "metric": 200 } } ] @@ -3325,7 +3325,7 @@ def test_route_maps_with_call_clause_p0(): } }, "set": { - "localpref": 150 + "locPrf": 150 }, "call": "rmap_match_pf_2_{}".format(addr_type) }], @@ -3337,7 +3337,7 @@ def test_route_maps_with_call_clause_p0(): } }, "set": { - "med": 200 + "metric": 200 } }] } @@ -3486,7 +3486,7 @@ def test_create_rmap_match_prefix_list_to_deny_in_and_outbound_prefixes_p0(): } }, "set": { - "localpref": 150, + "locPrf": 150, } }], "rmap_match_pf_2_{}".format(addr_type): [{ @@ -3497,7 +3497,7 @@ def test_create_rmap_match_prefix_list_to_deny_in_and_outbound_prefixes_p0(): } }, "set": { - "med": 50 + "metric": 50 } }] } diff --git a/tests/topotests/bgp_aggregate-address_route-map/test_bgp_aggregate-address_route-map.py b/tests/topotests/bgp_aggregate-address_route-map/test_bgp_aggregate-address_route-map.py index d6753e9b23..053f928810 100644 --- a/tests/topotests/bgp_aggregate-address_route-map/test_bgp_aggregate-address_route-map.py +++ b/tests/topotests/bgp_aggregate-address_route-map/test_bgp_aggregate-address_route-map.py @@ -110,7 +110,7 @@ def test_bgp_maximum_prefix_invalid(): expected = { 'paths': [ { - 'med': 123 + 'metric': 123 } ] } diff --git a/tests/topotests/bgp_default-route_route-map/test_bgp_default-originate_route-map.py b/tests/topotests/bgp_default-route_route-map/test_bgp_default-originate_route-map.py index 992ee85ab1..04a04cce37 100644 --- a/tests/topotests/bgp_default-route_route-map/test_bgp_default-originate_route-map.py +++ b/tests/topotests/bgp_default-route_route-map/test_bgp_default-originate_route-map.py @@ -110,7 +110,7 @@ def test_bgp_default_originate_route_map(): expected = { 'paths': [ { - 'med': 123 + 'metric': 123 } ] } diff --git a/tests/topotests/bgp_large_community/test_bgp_large_community_topo_1.py b/tests/topotests/bgp_large_community/test_bgp_large_community_topo_1.py index 83ec1e784d..fcea958a93 100755 --- a/tests/topotests/bgp_large_community/test_bgp_large_community_topo_1.py +++ b/tests/topotests/bgp_large_community/test_bgp_large_community_topo_1.py @@ -598,7 +598,7 @@ def config_for_as_path(tgen, topo, tc_name): "community_list": {"id": "ANY"} }, "set": { - "aspath": { + "path": { "as_num": "4000000", "as_action": "prepend" } diff --git a/tests/topotests/bgp_multiview_topo1/README.md b/tests/topotests/bgp_multiview_topo1/README.md index 2a2747344a..c1a1445894 100644 --- a/tests/topotests/bgp_multiview_topo1/README.md +++ b/tests/topotests/bgp_multiview_topo1/README.md @@ -1,4 +1,4 @@ -# Simple FreeRangeRouting Route-Server Test +# Simple FRRouting Route-Server Test ## Topology +----------+ +----------+ +----------+ +----------+ +----------+ diff --git a/tests/topotests/bgp_reject_as_sets/test_bgp_reject_as_sets.py b/tests/topotests/bgp_reject_as_sets/test_bgp_reject_as_sets.py index f307edc678..d95adc185d 100644 --- a/tests/topotests/bgp_reject_as_sets/test_bgp_reject_as_sets.py +++ b/tests/topotests/bgp_reject_as_sets/test_bgp_reject_as_sets.py @@ -130,13 +130,13 @@ def test_bgp_reject_as_sets(): expected = { 'advertisedRoutes': { '172.16.0.0/16': { - 'asPath': '' + 'path': '' }, '192.168.254.0/30': { - 'asPath': '65003' + 'path': '65003' }, '192.168.255.0/30': { - 'asPath': '65001' + 'path': '65001' } }, 'totalPrefixCounter': 3 diff --git a/tests/topotests/bgp_rr_ibgp/spine1/show_ip_route.json_ref b/tests/topotests/bgp_rr_ibgp/spine1/show_ip_route.json_ref index 552e96ddb9..75ce1b149e 100644 --- a/tests/topotests/bgp_rr_ibgp/spine1/show_ip_route.json_ref +++ b/tests/topotests/bgp_rr_ibgp/spine1/show_ip_route.json_ref @@ -11,15 +11,12 @@ "table":254, "internalStatus":16, "internalFlags":13, - "internalNextHopNum":1, - "internalNextHopActiveNum":1, "nexthops":[ { "flags":3, "fib":true, "ip":"192.168.2.1", "afi":"ipv4", - "interfaceIndex":2, "interfaceName":"spine1-eth0", "active":true } @@ -38,14 +35,11 @@ "table":254, "internalStatus":16, "internalFlags":8, - "internalNextHopNum":1, - "internalNextHopActiveNum":1, "nexthops":[ { "flags":3, "fib":true, "directlyConnected":true, - "interfaceIndex":2, "interfaceName":"spine1-eth0", "active":true } @@ -64,15 +58,12 @@ "table":254, "internalStatus":16, "internalFlags":13, - "internalNextHopNum":1, - "internalNextHopActiveNum":1, "nexthops":[ { "flags":3, "fib":true, "ip":"192.168.4.2", "afi":"ipv4", - "interfaceIndex":3, "interfaceName":"spine1-eth1", "active":true } @@ -91,23 +82,20 @@ "table":254, "internalStatus":16, "internalFlags":8, - "internalNextHopNum":1, - "internalNextHopActiveNum":1, "nexthops":[ { "flags":3, "fib":true, "directlyConnected":true, - "interfaceIndex":3, "interfaceName":"spine1-eth1", "active":true } ] } ], - "192.168.5.0\/24":[ + "192.168.5.1\/32":[ { - "prefix":"192.168.5.0\/24", + "prefix":"192.168.5.1\/32", "protocol":"bgp", "selected":true, "destSelected":true, @@ -117,24 +105,21 @@ "table":254, "internalStatus":16, "internalFlags":13, - "internalNextHopNum":1, - "internalNextHopActiveNum":1, "nexthops":[ { "flags":3, "fib":true, "ip":"192.168.2.1", "afi":"ipv4", - "interfaceIndex":2, "interfaceName":"spine1-eth0", "active":true } ] } ], - "192.168.6.0\/24":[ + "192.168.6.2\/32":[ { - "prefix":"192.168.6.0\/24", + "prefix":"192.168.6.2\/32", "protocol":"bgp", "selected":true, "destSelected":true, @@ -144,19 +129,16 @@ "table":254, "internalStatus":16, "internalFlags":13, - "internalNextHopNum":1, - "internalNextHopActiveNum":1, "nexthops":[ { "flags":3, "fib":true, "ip":"192.168.4.2", "afi":"ipv4", - "interfaceIndex":3, "interfaceName":"spine1-eth1", "active":true } ] } ] -} +}
\ No newline at end of file diff --git a/tests/topotests/bgp_rr_ibgp/spine2/bgpd.conf b/tests/topotests/bgp_rr_ibgp/spine2/bgpd.conf deleted file mode 100644 index a865b388ac..0000000000 --- a/tests/topotests/bgp_rr_ibgp/spine2/bgpd.conf +++ /dev/null @@ -1,8 +0,0 @@ -hostname spine2 -router bgp 99 - neighbor 192.168.5.1 remote-as internal - neighbor 192.168.6.2 remote-as internal - address-family ipv4 uni - redistribute connected - neighbor 192.168.5.1 route-reflector-client - neighbor 192.168.6.2 route-reflector-client diff --git a/tests/topotests/bgp_rr_ibgp/spine2/show_ip_route.json_ref b/tests/topotests/bgp_rr_ibgp/spine2/show_ip_route.json_ref deleted file mode 100644 index c428a8832f..0000000000 --- a/tests/topotests/bgp_rr_ibgp/spine2/show_ip_route.json_ref +++ /dev/null @@ -1,162 +0,0 @@ -{ - "192.168.1.0\/24":[ - { - "prefix":"192.168.1.0\/24", - "protocol":"bgp", - "selected":true, - "destSelected":true, - "distance":200, - "metric":0, - "installed":true, - "table":254, - "internalStatus":16, - "internalFlags":13, - "internalNextHopNum":1, - "internalNextHopActiveNum":1, - "nexthops":[ - { - "flags":3, - "fib":true, - "ip":"192.168.5.1", - "afi":"ipv4", - "interfaceIndex":2, - "interfaceName":"spine2-eth0", - "active":true - } - ] - } - ], - "192.168.2.0\/24":[ - { - "prefix":"192.168.2.0\/24", - "protocol":"bgp", - "selected":true, - "destSelected":true, - "distance":200, - "metric":0, - "installed":true, - "table":254, - "internalStatus":16, - "internalFlags":13, - "internalNextHopNum":1, - "internalNextHopActiveNum":1, - "nexthops":[ - { - "flags":3, - "fib":true, - "ip":"192.168.5.1", - "afi":"ipv4", - "interfaceIndex":2, - "interfaceName":"spine2-eth0", - "active":true - } - ] - } - ], - "192.168.3.0\/24":[ - { - "prefix":"192.168.3.0\/24", - "protocol":"bgp", - "selected":true, - "destSelected":true, - "distance":200, - "metric":0, - "installed":true, - "table":254, - "internalStatus":16, - "internalFlags":13, - "internalNextHopNum":1, - "internalNextHopActiveNum":1, - "nexthops":[ - { - "flags":3, - "fib":true, - "ip":"192.168.6.2", - "afi":"ipv4", - "interfaceIndex":3, - "interfaceName":"spine2-eth1", - "active":true - } - ] - } - ], - "192.168.4.0\/24":[ - { - "prefix":"192.168.4.0\/24", - "protocol":"bgp", - "selected":true, - "destSelected":true, - "distance":200, - "metric":0, - "installed":true, - "table":254, - "internalStatus":16, - "internalFlags":13, - "internalNextHopNum":1, - "internalNextHopActiveNum":1, - "nexthops":[ - { - "flags":3, - "fib":true, - "ip":"192.168.6.2", - "afi":"ipv4", - "interfaceIndex":3, - "interfaceName":"spine2-eth1", - "active":true - } - ] - } - ], - "192.168.5.0\/24":[ - { - "prefix":"192.168.5.0\/24", - "protocol":"connected", - "selected":true, - "destSelected":true, - "distance":0, - "metric":0, - "installed":true, - "table":254, - "internalStatus":16, - "internalFlags":8, - "internalNextHopNum":1, - "internalNextHopActiveNum":1, - "nexthops":[ - { - "flags":3, - "fib":true, - "directlyConnected":true, - "interfaceIndex":2, - "interfaceName":"spine2-eth0", - "active":true - } - ] - } - ], - "192.168.6.0\/24":[ - { - "prefix":"192.168.6.0\/24", - "protocol":"connected", - "selected":true, - "destSelected":true, - "distance":0, - "metric":0, - "installed":true, - "table":254, - "internalStatus":16, - "internalFlags":8, - "internalNextHopNum":1, - "internalNextHopActiveNum":1, - "nexthops":[ - { - "flags":3, - "fib":true, - "directlyConnected":true, - "interfaceIndex":3, - "interfaceName":"spine2-eth1", - "active":true - } - ] - } - ] -} diff --git a/tests/topotests/bgp_rr_ibgp/spine2/staticd.conf b/tests/topotests/bgp_rr_ibgp/spine2/staticd.conf deleted file mode 100644 index 3ee14d262c..0000000000 --- a/tests/topotests/bgp_rr_ibgp/spine2/staticd.conf +++ /dev/null @@ -1 +0,0 @@ -hostname spine2 diff --git a/tests/topotests/bgp_rr_ibgp/spine2/zebra.conf b/tests/topotests/bgp_rr_ibgp/spine2/zebra.conf deleted file mode 100644 index a06681fbc4..0000000000 --- a/tests/topotests/bgp_rr_ibgp/spine2/zebra.conf +++ /dev/null @@ -1,9 +0,0 @@ -hostname spine2 -ip forwarding -ipv6 forwarding - -int spine2-eth0 - ip addr 192.168.5.4/24 - -int spine2-eth1 - ip addr 192.168.6.4/24 diff --git a/tests/topotests/bgp_rr_ibgp/test_bgp_rr_ibgp_topo1.py b/tests/topotests/bgp_rr_ibgp/test_bgp_rr_ibgp_topo1.py index c28394a7a7..c7daa06b76 100755 --- a/tests/topotests/bgp_rr_ibgp/test_bgp_rr_ibgp_topo1.py +++ b/tests/topotests/bgp_rr_ibgp/test_bgp_rr_ibgp_topo1.py @@ -25,47 +25,8 @@ """ test_bgp_rr_ibgp_topo1.py: Testing IBGP with RR and no IGP - - In a leaf/spine topology with only IBGP connections, where - the same network is being redistributed at multiple points - in the network ( say a redistribute connected at both leaf and spines ) - we end up in a state where zebra gets very confused. - - eva# show ip route - Codes: K - kernel route, C - connected, S - static, R - RIP, - O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP, - T - Table, v - VNC, V - VNC-Direct, A - Babel, D - SHARP, - F - PBR, f - OpenFabric, - > - selected route, * - FIB route, q - queued route, r - rejected route - - C>* 192.168.1.0/24 is directly connected, tor1-eth0, 00:00:30 - C>* 192.168.2.0/24 is directly connected, tor1-eth1, 00:00:30 - B 192.168.3.0/24 [200/0] via 192.168.4.2 inactive, 00:00:25 - via 192.168.6.2 inactive, 00:00:25 - B>* 192.168.4.0/24 [200/0] via 192.168.2.3, tor1-eth1, 00:00:25 - * via 192.168.6.2 inactive, 00:00:25 - C>* 192.168.5.0/24 is directly connected, tor1-eth2, 00:00:30 - B>* 192.168.6.0/24 [200/0] via 192.168.4.2 inactive, 00:00:25 - * via 192.168.5.4, tor1-eth2, 00:00:25 - - Effectively we have ibgp routes recursing through ibgp routes - and there is no metric to discern whom to listen to. - - This draft: - https://tools.ietf.org/html/draft-ietf-idr-bgp-optimal-route-reflection-19 - - appears to address this issue. From looking at both cisco and arista - deployments they are handling this issue by having the route reflector - prefer the localy learned routes over from their clients. - - Add this topology, in a broken state, so that when we do fix this issue - it is a simple matter of touching this topology up and re-adding it - to the normal daily builds. I also wanted to add this topology - since it is in a state of `doneness` and I wanted to move onto - my normal day job without having to remember about this test. - - This topology is not configured to be run as part of the normal - topotests. +Ensure that a basic rr topology comes up and correctly passes +routes around """ @@ -105,7 +66,6 @@ class NetworkTopo(Topo): tgen.add_router('tor1') tgen.add_router('tor2') tgen.add_router('spine1') - tgen.add_router('spine2') # First switch is for a dummy interface (for local network) # on tor1 @@ -128,15 +88,6 @@ class NetworkTopo(Topo): switch.add_link(tgen.gears['tor2']) switch.add_link(tgen.gears['spine1']) - # 192.168.5.0/24 - tor1 <-> spine2 connection - switch = tgen.add_switch('sw5') - switch.add_link(tgen.gears['tor1']) - switch.add_link(tgen.gears['spine2']) - - # 192.168.6.0/24 - tor2 <-> spine2 connection - switch = tgen.add_switch('sw6') - switch.add_link(tgen.gears['tor2']) - switch.add_link(tgen.gears['spine2']) ##################################################### ## diff --git a/tests/topotests/bgp_rr_ibgp/tor1/bgpd.conf b/tests/topotests/bgp_rr_ibgp/tor1/bgpd.conf index 44a78dffd7..e8ec0f7680 100644 --- a/tests/topotests/bgp_rr_ibgp/tor1/bgpd.conf +++ b/tests/topotests/bgp_rr_ibgp/tor1/bgpd.conf @@ -1,5 +1,4 @@ hostname tor1 router bgp 99 neighbor 192.168.2.3 remote-as internal - neighbor 192.168.5.4 remote-as internal redistribute connected diff --git a/tests/topotests/bgp_rr_ibgp/tor1/show_ip_route.json_ref b/tests/topotests/bgp_rr_ibgp/tor1/show_ip_route.json_ref index 223dcebbca..6cfa02441f 100644 --- a/tests/topotests/bgp_rr_ibgp/tor1/show_ip_route.json_ref +++ b/tests/topotests/bgp_rr_ibgp/tor1/show_ip_route.json_ref @@ -11,14 +11,11 @@ "table":254, "internalStatus":16, "internalFlags":8, - "internalNextHopNum":1, - "internalNextHopActiveNum":1, "nexthops":[ { "flags":3, "fib":true, "directlyConnected":true, - "interfaceIndex":2, "interfaceName":"tor1-eth0", "active":true } @@ -37,14 +34,11 @@ "table":254, "internalStatus":16, "internalFlags":8, - "internalNextHopNum":1, - "internalNextHopActiveNum":1, "nexthops":[ { "flags":3, "fib":true, "directlyConnected":true, - "interfaceIndex":3, "interfaceName":"tor1-eth1", "active":true } @@ -55,23 +49,29 @@ { "prefix":"192.168.3.0\/24", "protocol":"bgp", + "selected":true, + "destSelected":true, "distance":200, "metric":0, + "installed":true, "table":254, - "internalStatus":0, - "internalFlags":5, - "internalNextHopNum":2, - "internalNextHopActiveNum":0, + "internalStatus":16, + "internalFlags":13, "nexthops":[ { - "flags":0, + "flags":5, "ip":"192.168.4.2", - "afi":"ipv4" + "afi":"ipv4", + "active":true, + "recursive":true }, { - "flags":0, - "ip":"192.168.6.2", - "afi":"ipv4" + "flags":3, + "fib":true, + "ip":"192.168.2.3", + "afi":"ipv4", + "interfaceName":"tor1-eth1", + "active":true } ] } @@ -88,29 +88,21 @@ "table":254, "internalStatus":16, "internalFlags":13, - "internalNextHopNum":2, - "internalNextHopActiveNum":1, "nexthops":[ { "flags":3, "fib":true, "ip":"192.168.2.3", "afi":"ipv4", - "interfaceIndex":3, "interfaceName":"tor1-eth1", "active":true - }, - { - "flags":0, - "ip":"192.168.6.2", - "afi":"ipv4" } ] } ], - "192.168.5.0\/24":[ + "192.168.5.1\/32":[ { - "prefix":"192.168.5.0\/24", + "prefix":"192.168.5.1\/32", "protocol":"connected", "selected":true, "destSelected":true, @@ -120,23 +112,20 @@ "table":254, "internalStatus":16, "internalFlags":8, - "internalNextHopNum":1, - "internalNextHopActiveNum":1, "nexthops":[ { "flags":3, "fib":true, "directlyConnected":true, - "interfaceIndex":4, - "interfaceName":"tor1-eth2", + "interfaceName":"lo", "active":true } ] } ], - "192.168.6.0\/24":[ + "192.168.6.2\/32":[ { - "prefix":"192.168.6.0\/24", + "prefix":"192.168.6.2\/32", "protocol":"bgp", "selected":true, "destSelected":true, @@ -146,21 +135,20 @@ "table":254, "internalStatus":16, "internalFlags":13, - "internalNextHopNum":2, - "internalNextHopActiveNum":1, "nexthops":[ { - "flags":0, + "flags":5, "ip":"192.168.4.2", - "afi":"ipv4" + "afi":"ipv4", + "active":true, + "recursive":true }, { "flags":3, "fib":true, - "ip":"192.168.5.4", + "ip":"192.168.2.3", "afi":"ipv4", - "interfaceIndex":4, - "interfaceName":"tor1-eth2", + "interfaceName":"tor1-eth1", "active":true } ] diff --git a/tests/topotests/bgp_rr_ibgp/tor1/zebra.conf b/tests/topotests/bgp_rr_ibgp/tor1/zebra.conf index f2fa713507..25b4fcfd0f 100644 --- a/tests/topotests/bgp_rr_ibgp/tor1/zebra.conf +++ b/tests/topotests/bgp_rr_ibgp/tor1/zebra.conf @@ -8,5 +8,5 @@ int tor1-eth0 int tor1-eth1 ip addr 192.168.2.1/24 -int tor1-eth2 - ip addr 192.168.5.1/24 +int lo + ip addr 192.168.5.1/32 diff --git a/tests/topotests/bgp_rr_ibgp/tor2/bgpd.conf b/tests/topotests/bgp_rr_ibgp/tor2/bgpd.conf index 5ef1de260e..b091c97ac3 100644 --- a/tests/topotests/bgp_rr_ibgp/tor2/bgpd.conf +++ b/tests/topotests/bgp_rr_ibgp/tor2/bgpd.conf @@ -1,5 +1,4 @@ hostname tor2 router bgp 99 neighbor 192.168.4.3 remote-as internal - neighbor 192.168.6.4 remote-as internal redistribute connected diff --git a/tests/topotests/bgp_rr_ibgp/tor2/show_ip_route.json_ref b/tests/topotests/bgp_rr_ibgp/tor2/show_ip_route.json_ref index 5f041b8c62..d9e9290e61 100644 --- a/tests/topotests/bgp_rr_ibgp/tor2/show_ip_route.json_ref +++ b/tests/topotests/bgp_rr_ibgp/tor2/show_ip_route.json_ref @@ -3,23 +3,29 @@ { "prefix":"192.168.1.0\/24", "protocol":"bgp", + "selected":true, + "destSelected":true, "distance":200, "metric":0, + "installed":true, "table":254, - "internalStatus":0, - "internalFlags":5, - "internalNextHopNum":2, - "internalNextHopActiveNum":0, + "internalStatus":16, + "internalFlags":13, "nexthops":[ { - "flags":0, + "flags":5, "ip":"192.168.2.1", - "afi":"ipv4" + "afi":"ipv4", + "active":true, + "recursive":true }, { - "flags":0, - "ip":"192.168.5.1", - "afi":"ipv4" + "flags":3, + "fib":true, + "ip":"192.168.4.3", + "afi":"ipv4", + "interfaceName":"tor2-eth1", + "active":true } ] } @@ -36,22 +42,14 @@ "table":254, "internalStatus":16, "internalFlags":13, - "internalNextHopNum":2, - "internalNextHopActiveNum":1, "nexthops":[ { "flags":3, "fib":true, "ip":"192.168.4.3", "afi":"ipv4", - "interfaceIndex":3, "interfaceName":"tor2-eth1", "active":true - }, - { - "flags":0, - "ip":"192.168.5.1", - "afi":"ipv4" } ] } @@ -68,14 +66,11 @@ "table":254, "internalStatus":16, "internalFlags":8, - "internalNextHopNum":1, - "internalNextHopActiveNum":1, "nexthops":[ { "flags":3, "fib":true, "directlyConnected":true, - "interfaceIndex":2, "interfaceName":"tor2-eth0", "active":true } @@ -94,23 +89,20 @@ "table":254, "internalStatus":16, "internalFlags":8, - "internalNextHopNum":1, - "internalNextHopActiveNum":1, "nexthops":[ { "flags":3, "fib":true, "directlyConnected":true, - "interfaceIndex":3, "interfaceName":"tor2-eth1", "active":true } ] } ], - "192.168.5.0\/24":[ + "192.168.5.1\/32":[ { - "prefix":"192.168.5.0\/24", + "prefix":"192.168.5.1\/32", "protocol":"bgp", "selected":true, "destSelected":true, @@ -120,29 +112,28 @@ "table":254, "internalStatus":16, "internalFlags":13, - "internalNextHopNum":2, - "internalNextHopActiveNum":1, "nexthops":[ { - "flags":0, + "flags":5, "ip":"192.168.2.1", - "afi":"ipv4" + "afi":"ipv4", + "active":true, + "recursive":true }, { "flags":3, "fib":true, - "ip":"192.168.6.4", + "ip":"192.168.4.3", "afi":"ipv4", - "interfaceIndex":4, - "interfaceName":"tor2-eth2", + "interfaceName":"tor2-eth1", "active":true } ] } ], - "192.168.6.0\/24":[ + "192.168.6.2\/32":[ { - "prefix":"192.168.6.0\/24", + "prefix":"192.168.6.2\/32", "protocol":"connected", "selected":true, "destSelected":true, @@ -152,15 +143,12 @@ "table":254, "internalStatus":16, "internalFlags":8, - "internalNextHopNum":1, - "internalNextHopActiveNum":1, "nexthops":[ { "flags":3, "fib":true, "directlyConnected":true, - "interfaceIndex":4, - "interfaceName":"tor2-eth2", + "interfaceName":"lo", "active":true } ] diff --git a/tests/topotests/bgp_rr_ibgp/tor2/zebra.conf b/tests/topotests/bgp_rr_ibgp/tor2/zebra.conf index 3318cbb196..e1a06b14fc 100644 --- a/tests/topotests/bgp_rr_ibgp/tor2/zebra.conf +++ b/tests/topotests/bgp_rr_ibgp/tor2/zebra.conf @@ -9,5 +9,5 @@ int tor2-eth1 ip addr 192.168.4.2/24 -int tor2-eth2 - ip addr 192.168.6.2/24 +int lo + ip addr 192.168.6.2/32 diff --git a/tests/topotests/bgp_set_local-preference_add_subtract/test_bgp_set_local-preference_add_subtract.py b/tests/topotests/bgp_set_local-preference_add_subtract/test_bgp_set_local-preference_add_subtract.py index 09e195e22d..387cb0b42f 100644 --- a/tests/topotests/bgp_set_local-preference_add_subtract/test_bgp_set_local-preference_add_subtract.py +++ b/tests/topotests/bgp_set_local-preference_add_subtract/test_bgp_set_local-preference_add_subtract.py @@ -113,7 +113,7 @@ def test_bgp_set_local_preference(): expected = { 'paths': [ { - 'localpref': 50, + 'locPrf': 50, 'nexthops': [ { 'ip': '192.168.255.3' @@ -121,7 +121,7 @@ def test_bgp_set_local_preference(): ] }, { - 'localpref': 150, + 'locPrf': 150, 'nexthops': [ { 'ip': '192.168.255.2' diff --git a/tests/topotests/ldp-oc-acl-topo1/r1/ldpd.conf b/tests/topotests/ldp-oc-acl-topo1/r1/ldpd.conf new file mode 100644 index 0000000000..85bb970fdf --- /dev/null +++ b/tests/topotests/ldp-oc-acl-topo1/r1/ldpd.conf @@ -0,0 +1,25 @@ +hostname r1 +log file ldpd.log +! +debug mpls ldp zebra +debug mpls ldp event +debug mpls ldp errors +debug mpls ldp messages recv +debug mpls ldp messages sent +debug mpls ldp discovery hello recv +debug mpls ldp discovery hello sent +! +mpls ldp + router-id 1.1.1.1 + ordered-control + ! + address-family ipv4 + discovery transport-address 1.1.1.1 + label local allocate host-routes + ! + interface r1-eth0 + ! + ! +! +line vty +! diff --git a/tests/topotests/ldp-oc-acl-topo1/r1/ospfd.conf b/tests/topotests/ldp-oc-acl-topo1/r1/ospfd.conf new file mode 100644 index 0000000000..6daf034d18 --- /dev/null +++ b/tests/topotests/ldp-oc-acl-topo1/r1/ospfd.conf @@ -0,0 +1,7 @@ +hostname r1 +log file ospfd.log +! +router ospf + router-id 1.1.1.1 + network 0.0.0.0/0 area 0 +! diff --git a/tests/topotests/ldp-oc-acl-topo1/r1/show_ip_ospf_neighbor.json b/tests/topotests/ldp-oc-acl-topo1/r1/show_ip_ospf_neighbor.json new file mode 100644 index 0000000000..2c493173f5 --- /dev/null +++ b/tests/topotests/ldp-oc-acl-topo1/r1/show_ip_ospf_neighbor.json @@ -0,0 +1,12 @@ +{ + "neighbors":{ + "2.2.2.2":[ + { + "priority":1, + "state":"Full\/DR", + "address":"10.0.1.2", + "ifaceName":"r1-eth0:10.0.1.1" + } + ] + } +} diff --git a/tests/topotests/ldp-oc-acl-topo1/r1/show_ip_route.ref b/tests/topotests/ldp-oc-acl-topo1/r1/show_ip_route.ref new file mode 100644 index 0000000000..d75b8f21db --- /dev/null +++ b/tests/topotests/ldp-oc-acl-topo1/r1/show_ip_route.ref @@ -0,0 +1,171 @@ +{ + "1.1.1.1/32":[ + { + "prefix":"1.1.1.1/32", + "protocol":"ospf", + "nexthops":[ + { + "directlyConnected":true, + "interfaceIndex":1, + "interfaceName":"lo", + "active":true + } + ] + }, + { + "prefix":"1.1.1.1/32", + "protocol":"connected", + "selected":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceIndex":1, + "interfaceName":"lo", + "active":true + } + ] + } + ], + "2.2.2.2/32":[ + { + "prefix":"2.2.2.2/32", + "protocol":"ospf", + "selected":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceIndex":2, + "interfaceName":"r1-eth0", + "active":true + } + ] + } + ], + "3.3.3.3/32":[ + { + "prefix":"3.3.3.3/32", + "protocol":"ospf", + "selected":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceIndex":2, + "interfaceName":"r1-eth0", + "active":true + } + ] + } + ], + "4.4.4.4/32":[ + { + "prefix":"4.4.4.4/32", + "protocol":"ospf", + "selected":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceIndex":2, + "interfaceName":"r1-eth0", + "active":true + } + ] + } + ], + "10.0.1.0/24":[ + { + "prefix":"10.0.1.0/24", + "protocol":"ospf", + "nexthops":[ + { + "directlyConnected":true, + "interfaceIndex":2, + "interfaceName":"r1-eth0", + "active":true + } + ] + }, + { + "prefix":"10.0.1.0/24", + "protocol":"connected", + "selected":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceIndex":2, + "interfaceName":"r1-eth0", + "active":true + } + ] + } + ], + "10.0.2.0/24":[ + { + "prefix":"10.0.2.0/24", + "protocol":"ospf", + "selected":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceIndex":2, + "interfaceName":"r1-eth0", + "active":true + } + ] + } + ], + "10.0.3.0/24":[ + { + "prefix":"10.0.3.0/24", + "protocol":"ospf", + "selected":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceIndex":2, + "interfaceName":"r1-eth0", + "active":true + } + ] + } + ], + "123.0.1.0/24":[ + { + "prefix":"123.0.1.0/24", + "protocol":"ospf", + "nexthops":[ + { + "directlyConnected":true, + "interfaceIndex":2, + "interfaceName":"r1-eth0", + "active":true + } + ] + }, + { + "prefix":"123.0.1.0/24", + "protocol":"connected", + "selected":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceIndex":2, + "interfaceName":"r1-eth0", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/ldp-oc-acl-topo1/r1/show_ldp_all_binding.ref b/tests/topotests/ldp-oc-acl-topo1/r1/show_ldp_all_binding.ref new file mode 100644 index 0000000000..99a59668f8 --- /dev/null +++ b/tests/topotests/ldp-oc-acl-topo1/r1/show_ldp_all_binding.ref @@ -0,0 +1,61 @@ +{ + "bindings":[ + { + "addressFamily":"ipv4", + "prefix":"1.1.1.1/32", + "neighborId":"0.0.0.0", + "localLabel":"imp-null", + "remoteLabel":"-", + "inUse":0 + }, + { + "addressFamily":"ipv4", + "prefix":"2.2.2.2/32", + "neighborId":"2.2.2.2", + "remoteLabel":"imp-null", + "inUse":1 + }, + { + "addressFamily":"ipv4", + "prefix":"3.3.3.3/32", + "neighborId":"2.2.2.2", + "inUse":1 + }, + { + "addressFamily":"ipv4", + "prefix":"4.4.4.4/32", + "neighborId":"0.0.0.0", + "remoteLabel":"-", + "inUse":0 + }, + { + "addressFamily":"ipv4", + "prefix":"10.0.1.0/24", + "neighborId":"2.2.2.2", + "localLabel":"imp-null", + "remoteLabel":"imp-null", + "inUse":0 + }, + { + "addressFamily":"ipv4", + "prefix":"10.0.2.0/24", + "neighborId":"2.2.2.2", + "remoteLabel":"imp-null", + "inUse":1 + }, + { + "addressFamily":"ipv4", + "prefix":"10.0.3.0/24", + "neighborId":"2.2.2.2", + "inUse":1 + }, + { + "addressFamily":"ipv4", + "prefix":"123.0.1.0/24", + "neighborId":"0.0.0.0", + "localLabel":"imp-null", + "remoteLabel":"-", + "inUse":0 + } + ] +} diff --git a/tests/topotests/ldp-oc-acl-topo1/r1/show_ldp_binding.ref b/tests/topotests/ldp-oc-acl-topo1/r1/show_ldp_binding.ref new file mode 100644 index 0000000000..ccc8413646 --- /dev/null +++ b/tests/topotests/ldp-oc-acl-topo1/r1/show_ldp_binding.ref @@ -0,0 +1,55 @@ +{ + "bindings":[ + { + "addressFamily":"ipv4", + "prefix":"1.1.1.1/32", + "neighborId":"0.0.0.0", + "localLabel":"imp-null", + "remoteLabel":"-", + "inUse":0 + }, + { + "addressFamily":"ipv4", + "prefix":"2.2.2.2/32", + "neighborId":"2.2.2.2", + "remoteLabel":"imp-null", + "inUse":1 + }, + { + "addressFamily":"ipv4", + "prefix":"3.3.3.3/32", + "neighborId":"2.2.2.2", + "inUse":1 + }, + { + "addressFamily":"ipv4", + "prefix":"4.4.4.4/32", + "neighborId":"0.0.0.0", + "remoteLabel":"-", + "inUse":0 + }, + { + "addressFamily":"ipv4", + "prefix":"10.0.1.0/24", + "neighborId":"2.2.2.2", + "localLabel":"-", + "remoteLabel":"imp-null", + "inUse":0 + }, + { + "addressFamily":"ipv4", + "prefix":"10.0.2.0/24", + "neighborId":"2.2.2.2", + "localLabel":"-", + "remoteLabel":"imp-null", + "inUse":1 + }, + { + "addressFamily":"ipv4", + "prefix":"10.0.3.0/24", + "neighborId":"2.2.2.2", + "localLabel":"-", + "inUse":1 + } + ] +} diff --git a/tests/topotests/ldp-oc-acl-topo1/r1/show_ldp_discovery.ref b/tests/topotests/ldp-oc-acl-topo1/r1/show_ldp_discovery.ref new file mode 100644 index 0000000000..b349f4418f --- /dev/null +++ b/tests/topotests/ldp-oc-acl-topo1/r1/show_ldp_discovery.ref @@ -0,0 +1,11 @@ +{ + "adjacencies":[ + { + "addressFamily":"ipv4", + "neighborId":"2.2.2.2", + "type":"link", + "interface":"r1-eth0", + "helloHoldtime":15 + } + ] +} diff --git a/tests/topotests/ldp-oc-acl-topo1/r1/show_ldp_neighbor.ref b/tests/topotests/ldp-oc-acl-topo1/r1/show_ldp_neighbor.ref new file mode 100644 index 0000000000..4bff444a46 --- /dev/null +++ b/tests/topotests/ldp-oc-acl-topo1/r1/show_ldp_neighbor.ref @@ -0,0 +1,10 @@ +{ + "neighbors":[ + { + "addressFamily":"ipv4", + "neighborId":"2.2.2.2", + "state":"OPERATIONAL", + "transportAddress":"2.2.2.2" + } + ] +} diff --git a/tests/topotests/ldp-oc-acl-topo1/r1/zebra.conf b/tests/topotests/ldp-oc-acl-topo1/r1/zebra.conf new file mode 100644 index 0000000000..83aea46e64 --- /dev/null +++ b/tests/topotests/ldp-oc-acl-topo1/r1/zebra.conf @@ -0,0 +1,17 @@ +log file zebra.log +! +hostname r1 +! +interface lo + ip address 1.1.1.1/32 +! +interface r1-eth0 + description to sw0 + ip address 10.0.1.1/24 + ip address 123.0.1.1/24 +! +ip forwarding +! +! +line vty +! diff --git a/tests/topotests/ldp-oc-acl-topo1/r2/ldpd.conf b/tests/topotests/ldp-oc-acl-topo1/r2/ldpd.conf new file mode 100644 index 0000000000..e1a552c701 --- /dev/null +++ b/tests/topotests/ldp-oc-acl-topo1/r2/ldpd.conf @@ -0,0 +1,28 @@ +hostname r2 +log file ldpd.log +! +debug mpls ldp zebra +debug mpls ldp event +debug mpls ldp errors +debug mpls ldp messages recv +debug mpls ldp messages sent +debug mpls ldp discovery hello recv +debug mpls ldp discovery hello sent +! +mpls ldp + router-id 2.2.2.2 + ordered-control + ! + address-family ipv4 + discovery transport-address 2.2.2.2 + ! + interface r2-eth0 + ! + interface r2-eth1 + ! + interface r2-eth2 + ! + ! +! +line vty +! diff --git a/tests/topotests/ldp-oc-acl-topo1/r2/ospfd.conf b/tests/topotests/ldp-oc-acl-topo1/r2/ospfd.conf new file mode 100644 index 0000000000..8678813665 --- /dev/null +++ b/tests/topotests/ldp-oc-acl-topo1/r2/ospfd.conf @@ -0,0 +1,7 @@ +hostname r2 +log file ospfd.log +! +router ospf + router-id 2.2.2.2 + network 0.0.0.0/0 area 0 +! diff --git a/tests/topotests/ldp-oc-acl-topo1/r2/show_ip_ospf_neighbor.json b/tests/topotests/ldp-oc-acl-topo1/r2/show_ip_ospf_neighbor.json new file mode 100644 index 0000000000..55f12359e5 --- /dev/null +++ b/tests/topotests/ldp-oc-acl-topo1/r2/show_ip_ospf_neighbor.json @@ -0,0 +1,31 @@ +{ + "neighbors":{ + "1.1.1.1":[ + { + "priority":1, + "state":"Full\/Backup", + "address":"10.0.1.1", + "ifaceName":"r2-eth0:10.0.1.2", + "retransmitCounter":0, + "requestCounter":0, + "dbSummaryCounter":0 + } + ], + "3.3.3.3":[ + { + "priority":1, + "state":"Full\/Backup", + "address":"10.0.2.3", + "ifaceName":"r2-eth1:10.0.2.2" + } + ], + "4.4.4.4":[ + { + "priority":1, + "state":"Full\/DR", + "address":"10.0.2.4", + "ifaceName":"r2-eth1:10.0.2.2" + } + ] + } +} diff --git a/tests/topotests/ldp-oc-acl-topo1/r2/show_ip_route.ref b/tests/topotests/ldp-oc-acl-topo1/r2/show_ip_route.ref new file mode 100644 index 0000000000..060c0b429d --- /dev/null +++ b/tests/topotests/ldp-oc-acl-topo1/r2/show_ip_route.ref @@ -0,0 +1,209 @@ +{ + "1.1.1.1/32":[ + { + "prefix":"1.1.1.1/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceIndex":2, + "interfaceName":"r2-eth0", + "active":true + } + ] + } + ], + "2.2.2.2/32":[ + { + "prefix":"2.2.2.2/32", + "protocol":"ospf", + "distance":110, + "metric":0, + "nexthops":[ + { + "directlyConnected":true, + "interfaceIndex":1, + "interfaceName":"lo", + "active":true + } + ] + }, + { + "prefix":"2.2.2.2/32", + "protocol":"connected", + "selected":true, + "destSelected":true, + "distance":0, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceIndex":1, + "interfaceName":"lo", + "active":true + } + ] + } + ], + "3.3.3.3/32":[ + { + "prefix":"3.3.3.3/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.3", + "afi":"ipv4", + "interfaceIndex":3, + "interfaceName":"r2-eth1", + "active":true + } + ] + } + ], + "4.4.4.4/32":[ + { + "prefix":"4.4.4.4/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceIndex":3, + "interfaceName":"r2-eth1", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceIndex":2, + "interfaceName":"r2-eth0", + "active":true + } + ] + }, + { + "prefix":"10.0.1.0\/24", + "protocol":"connected", + "selected":true, + "destSelected":true, + "distance":0, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceIndex":2, + "interfaceName":"r2-eth0", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceIndex":3, + "interfaceName":"r2-eth1", + "active":true + } + ] + }, + { + "prefix":"10.0.2.0\/24", + "protocol":"connected", + "selected":true, + "destSelected":true, + "distance":0, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceIndex":3, + "interfaceName":"r2-eth1", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.3", + "afi":"ipv4", + "interfaceIndex":3, + "interfaceName":"r2-eth1", + "active":true + } + ] + } + ], + "123.0.1.0\/24":[ + { + "prefix":"123.0.1.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceIndex":2, + "interfaceName":"r2-eth0", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/ldp-oc-acl-topo1/r2/show_ldp_all_binding.ref b/tests/topotests/ldp-oc-acl-topo1/r2/show_ldp_all_binding.ref new file mode 100644 index 0000000000..95fb847c1e --- /dev/null +++ b/tests/topotests/ldp-oc-acl-topo1/r2/show_ldp_all_binding.ref @@ -0,0 +1,63 @@ +{ + "bindings":[ + { + "addressFamily":"ipv4", + "prefix":"1.1.1.1/32", + "neighborId":"1.1.1.1", + "remoteLabel":"imp-null", + "inUse":1 + }, + { + "addressFamily":"ipv4", + "prefix":"2.2.2.2/32", + "neighborId":"0.0.0.0", + "localLabel":"imp-null", + "remoteLabel":"-", + "inUse":0 + }, + { + "addressFamily":"ipv4", + "prefix":"3.3.3.3/32", + "neighborId":"3.3.3.3", + "remoteLabel":"imp-null", + "inUse":1 + }, + { + "addressFamily":"ipv4", + "prefix":"4.4.4.4/32", + "neighborId":"0.0.0.0", + "remoteLabel":"-", + "inUse":0 + }, + { + "addressFamily":"ipv4", + "prefix":"10.0.1.0/24", + "neighborId":"1.1.1.1", + "localLabel":"imp-null", + "remoteLabel":"imp-null", + "inUse":0 + }, + { + "addressFamily":"ipv4", + "prefix":"10.0.2.0/24", + "neighborId":"3.3.3.3", + "localLabel":"imp-null", + "remoteLabel":"imp-null", + "inUse":0 + }, + { + "addressFamily":"ipv4", + "prefix":"10.0.3.0/24", + "neighborId":"3.3.3.3", + "remoteLabel":"imp-null", + "inUse":1 + }, + { + "addressFamily":"ipv4", + "prefix":"123.0.1.0/24", + "neighborId":"1.1.1.1", + "remoteLabel":"imp-null", + "inUse":1 + } + ] +} diff --git a/tests/topotests/ldp-oc-acl-topo1/r2/show_ldp_binding.ref b/tests/topotests/ldp-oc-acl-topo1/r2/show_ldp_binding.ref new file mode 100644 index 0000000000..ea32de3eda --- /dev/null +++ b/tests/topotests/ldp-oc-acl-topo1/r2/show_ldp_binding.ref @@ -0,0 +1,63 @@ +{ + "bindings":[ + { + "addressFamily":"ipv4", + "prefix":"1.1.1.1/32", + "neighborId":"1.1.1.1", + "remoteLabel":"imp-null", + "inUse":1 + }, + { + "addressFamily":"ipv4", + "prefix":"2.2.2.2/32", + "neighborId":"0.0.0.0", + "localLabel":"imp-null", + "remoteLabel":"-", + "inUse":0 + }, + { + "addressFamily":"ipv4", + "prefix":"3.3.3.3/32", + "neighborId":"3.3.3.3", + "remoteLabel":"imp-null", + "inUse":1 + }, + { + "addressFamily":"ipv4", + "prefix":"4.4.4.4/32", + "neighborId":"0.0.0.0", + "remoteLabel":"-", + "inUse":0 + }, + { + "addressFamily":"ipv4", + "prefix":"10.0.1.0/24", + "neighborId":"0.0.0.0", + "localLabel":"imp-null", + "remoteLabel":"-", + "inUse":0 + }, + { + "addressFamily":"ipv4", + "prefix":"10.0.2.0/24", + "neighborId":"3.3.3.3", + "localLabel":"imp-null", + "remoteLabel":"imp-null", + "inUse":0 + }, + { + "addressFamily":"ipv4", + "prefix":"10.0.3.0/24", + "neighborId":"3.3.3.3", + "remoteLabel":"imp-null", + "inUse":1 + }, + { + "addressFamily":"ipv4", + "prefix":"123.0.1.0/24", + "neighborId":"0.0.0.0", + "remoteLabel":"-", + "inUse":0 + } + ] +} diff --git a/tests/topotests/ldp-oc-acl-topo1/r2/show_ldp_discovery.ref b/tests/topotests/ldp-oc-acl-topo1/r2/show_ldp_discovery.ref new file mode 100644 index 0000000000..8129570082 --- /dev/null +++ b/tests/topotests/ldp-oc-acl-topo1/r2/show_ldp_discovery.ref @@ -0,0 +1,18 @@ +{ + "adjacencies":[ + { + "addressFamily":"ipv4", + "neighborId":"1.1.1.1", + "type":"link", + "interface":"r2-eth0", + "helloHoldtime":15 + }, + { + "addressFamily":"ipv4", + "neighborId":"3.3.3.3", + "type":"link", + "interface":"r2-eth1", + "helloHoldtime":15 + } + ] +} diff --git a/tests/topotests/ldp-oc-acl-topo1/r2/show_ldp_neighbor.ref b/tests/topotests/ldp-oc-acl-topo1/r2/show_ldp_neighbor.ref new file mode 100644 index 0000000000..eed35289ea --- /dev/null +++ b/tests/topotests/ldp-oc-acl-topo1/r2/show_ldp_neighbor.ref @@ -0,0 +1,16 @@ +{ + "neighbors":[ + { + "addressFamily":"ipv4", + "neighborId":"1.1.1.1", + "state":"OPERATIONAL", + "transportAddress":"1.1.1.1" + }, + { + "addressFamily":"ipv4", + "neighborId":"3.3.3.3", + "state":"OPERATIONAL", + "transportAddress":"3.3.3.3" + } + ] +} diff --git a/tests/topotests/ldp-oc-acl-topo1/r2/zebra.conf b/tests/topotests/ldp-oc-acl-topo1/r2/zebra.conf new file mode 100644 index 0000000000..1f1e3e391a --- /dev/null +++ b/tests/topotests/ldp-oc-acl-topo1/r2/zebra.conf @@ -0,0 +1,27 @@ +log file zebra.log +! +hostname r2 +! +interface lo + ip address 2.2.2.2/32 +! +interface r2-eth0 + description to sw0 + ip address 10.0.1.2/24 +! no link-detect +! +interface r2-eth1 + description to sw1 + ip address 10.0.2.2/24 +! no link-detect +! +interface r2-eths2 + description to sw2 + ip address 10.0.3.2/24 +! no link-detect +! +ip forwarding +! +! +line vty +! diff --git a/tests/topotests/ldp-oc-acl-topo1/r3/ldpd.conf b/tests/topotests/ldp-oc-acl-topo1/r3/ldpd.conf new file mode 100644 index 0000000000..4e66b140ac --- /dev/null +++ b/tests/topotests/ldp-oc-acl-topo1/r3/ldpd.conf @@ -0,0 +1,24 @@ +hostname r3 +log file ldpd.log +! +debug mpls ldp zebra +debug mpls ldp event +debug mpls ldp errors +debug mpls ldp messages recv +debug mpls ldp messages sent +debug mpls ldp discovery hello recv +debug mpls ldp discovery hello sent +! +mpls ldp + router-id 3.3.3.3 + ordered-control + ! + address-family ipv4 + discovery transport-address 3.3.3.3 + ! + interface r3-eth0 + ! + ! +! +line vty +! diff --git a/tests/topotests/ldp-oc-acl-topo1/r3/ospfd.conf b/tests/topotests/ldp-oc-acl-topo1/r3/ospfd.conf new file mode 100644 index 0000000000..202be238ec --- /dev/null +++ b/tests/topotests/ldp-oc-acl-topo1/r3/ospfd.conf @@ -0,0 +1,8 @@ +hostname r3 +password 1 +log file ospfd.log +! +router ospf + router-id 3.3.3.3 + network 0.0.0.0/0 area 0 +! diff --git a/tests/topotests/ldp-oc-acl-topo1/r3/show_ip_ospf_neighbor.json b/tests/topotests/ldp-oc-acl-topo1/r3/show_ip_ospf_neighbor.json new file mode 100644 index 0000000000..24502ed813 --- /dev/null +++ b/tests/topotests/ldp-oc-acl-topo1/r3/show_ip_ospf_neighbor.json @@ -0,0 +1,20 @@ +{ + "neighbors":{ + "2.2.2.2":[ + { + "priority":1, + "state":"Full\/DROther", + "address":"10.0.2.2", + "ifaceName":"r3-eth0:10.0.2.3" + } + ], + "4.4.4.4":[ + { + "priority":1, + "state":"Full\/DR", + "address":"10.0.2.4", + "ifaceName":"r3-eth0:10.0.2.3" + } + ] + } +} diff --git a/tests/topotests/ldp-oc-acl-topo1/r3/show_ip_route.ref b/tests/topotests/ldp-oc-acl-topo1/r3/show_ip_route.ref new file mode 100644 index 0000000000..40800762ba --- /dev/null +++ b/tests/topotests/ldp-oc-acl-topo1/r3/show_ip_route.ref @@ -0,0 +1,209 @@ +{ + "1.1.1.1/32":[ + { + "prefix":"1.1.1.1/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceIndex":2, + "interfaceName":"r3-eth0", + "active":true + } + ] + } + ], + "2.2.2.2/32":[ + { + "prefix":"2.2.2.2/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceIndex":2, + "interfaceName":"r3-eth0", + "active":true + } + ] + } + ], + "3.3.3.3/32":[ + { + "prefix":"3.3.3.3/32", + "protocol":"ospf", + "distance":110, + "metric":0, + "nexthops":[ + { + "directlyConnected":true, + "interfaceIndex":1, + "interfaceName":"lo", + "active":true + } + ] + }, + { + "prefix":"3.3.3.3/32", + "protocol":"connected", + "selected":true, + "destSelected":true, + "distance":0, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceIndex":1, + "interfaceName":"lo", + "active":true + } + ] + } + ], + "4.4.4.4/32":[ + { + "prefix":"4.4.4.4/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceIndex":2, + "interfaceName":"r3-eth0", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceIndex":2, + "interfaceName":"r3-eth0", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceIndex":2, + "interfaceName":"r3-eth0", + "active":true + } + ] + }, + { + "prefix":"10.0.2.0\/24", + "protocol":"connected", + "selected":true, + "destSelected":true, + "distance":0, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceIndex":2, + "interfaceName":"r3-eth0", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceIndex":3, + "interfaceName":"r3-eth1", + "active":true + } + ] + }, + { + "prefix":"10.0.3.0\/24", + "protocol":"connected", + "selected":true, + "destSelected":true, + "distance":0, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceIndex":3, + "interfaceName":"r3-eth1", + "active":true + } + ] + } + ], + "123.0.1.0\/24":[ + { + "prefix":"123.0.1.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceIndex":2, + "interfaceName":"r3-eth0", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/ldp-oc-acl-topo1/r3/show_ldp_all_binding.ref b/tests/topotests/ldp-oc-acl-topo1/r3/show_ldp_all_binding.ref new file mode 100644 index 0000000000..100dd307ea --- /dev/null +++ b/tests/topotests/ldp-oc-acl-topo1/r3/show_ldp_all_binding.ref @@ -0,0 +1,61 @@ +{ + "bindings":[ + { + "addressFamily":"ipv4", + "prefix":"1.1.1.1/32", + "neighborId":"2.2.2.2", + "inUse":1 + }, + { + "addressFamily":"ipv4", + "prefix":"2.2.2.2/32", + "neighborId":"2.2.2.2", + "remoteLabel":"imp-null", + "inUse":1 + }, + { + "addressFamily":"ipv4", + "prefix":"3.3.3.3/32", + "neighborId":"0.0.0.0", + "localLabel":"imp-null", + "remoteLabel":"-", + "inUse":0 + }, + { + "addressFamily":"ipv4", + "prefix":"4.4.4.4/32", + "neighborId":"0.0.0.0", + "remoteLabel":"-", + "inUse":0 + }, + { + "addressFamily":"ipv4", + "prefix":"10.0.1.0/24", + "neighborId":"2.2.2.2", + "remoteLabel":"imp-null", + "inUse":1 + }, + { + "addressFamily":"ipv4", + "prefix":"10.0.2.0/24", + "neighborId":"2.2.2.2", + "localLabel":"imp-null", + "remoteLabel":"imp-null", + "inUse":0 + }, + { + "addressFamily":"ipv4", + "prefix":"10.0.3.0/24", + "neighborId":"0.0.0.0", + "localLabel":"imp-null", + "remoteLabel":"-", + "inUse":0 + }, + { + "addressFamily":"ipv4", + "prefix":"123.0.1.0/24", + "neighborId":"2.2.2.2", + "inUse":1 + } + ] +} diff --git a/tests/topotests/ldp-oc-acl-topo1/r3/show_ldp_binding.ref b/tests/topotests/ldp-oc-acl-topo1/r3/show_ldp_binding.ref new file mode 100644 index 0000000000..bb1b2b3023 --- /dev/null +++ b/tests/topotests/ldp-oc-acl-topo1/r3/show_ldp_binding.ref @@ -0,0 +1,62 @@ +{ + "bindings":[ + { + "addressFamily":"ipv4", + "prefix":"1.1.1.1/32", + "neighborId":"2.2.2.2", + "inUse":1 + }, + { + "addressFamily":"ipv4", + "prefix":"2.2.2.2/32", + "neighborId":"2.2.2.2", + "remoteLabel":"imp-null", + "inUse":1 + }, + { + "addressFamily":"ipv4", + "prefix":"3.3.3.3/32", + "neighborId":"0.0.0.0", + "localLabel":"imp-null", + "remoteLabel":"-", + "inUse":0 + }, + { + "addressFamily":"ipv4", + "prefix":"4.4.4.4/32", + "neighborId":"0.0.0.0", + "remoteLabel":"-", + "inUse":0 + }, + { + "addressFamily":"ipv4", + "prefix":"10.0.1.0/24", + "neighborId":"2.2.2.2", + "remoteLabel":"imp-null", + "inUse":1 + }, + { + "addressFamily":"ipv4", + "prefix":"10.0.2.0/24", + "neighborId":"2.2.2.2", + "localLabel":"imp-null", + "remoteLabel":"imp-null", + "inUse":0 + }, + { + "addressFamily":"ipv4", + "prefix":"10.0.3.0/24", + "neighborId":"0.0.0.0", + "localLabel":"imp-null", + "remoteLabel":"-", + "inUse":0 + }, + { + "addressFamily":"ipv4", + "prefix":"123.0.1.0/24", + "neighborId":"0.0.0.0", + "remoteLabel":"-", + "inUse":0 + } + ] +} diff --git a/tests/topotests/ldp-oc-acl-topo1/r3/show_ldp_discovery.ref b/tests/topotests/ldp-oc-acl-topo1/r3/show_ldp_discovery.ref new file mode 100644 index 0000000000..c3a07e7e38 --- /dev/null +++ b/tests/topotests/ldp-oc-acl-topo1/r3/show_ldp_discovery.ref @@ -0,0 +1,11 @@ +{ + "adjacencies":[ + { + "addressFamily":"ipv4", + "neighborId":"2.2.2.2", + "type":"link", + "interface":"r3-eth0", + "helloHoldtime":15 + } + ] +} diff --git a/tests/topotests/ldp-oc-acl-topo1/r3/show_ldp_neighbor.ref b/tests/topotests/ldp-oc-acl-topo1/r3/show_ldp_neighbor.ref new file mode 100644 index 0000000000..4bff444a46 --- /dev/null +++ b/tests/topotests/ldp-oc-acl-topo1/r3/show_ldp_neighbor.ref @@ -0,0 +1,10 @@ +{ + "neighbors":[ + { + "addressFamily":"ipv4", + "neighborId":"2.2.2.2", + "state":"OPERATIONAL", + "transportAddress":"2.2.2.2" + } + ] +} diff --git a/tests/topotests/ldp-oc-acl-topo1/r3/zebra.conf b/tests/topotests/ldp-oc-acl-topo1/r3/zebra.conf new file mode 100644 index 0000000000..234c215ddf --- /dev/null +++ b/tests/topotests/ldp-oc-acl-topo1/r3/zebra.conf @@ -0,0 +1,22 @@ +log file zebra.log +! +hostname r3 +! +interface lo + ip address 3.3.3.3/32 +! +interface r3-eth0 + description to sw1 + ip address 10.0.2.3/24 +! no link-detect +! +interface r3-eth1 + description to sw2 + ip address 10.0.3.3/24 +! no link-detect +! +ip forwarding +! +! +line vty +! diff --git a/tests/topotests/ldp-oc-acl-topo1/r4/ldpd.conf b/tests/topotests/ldp-oc-acl-topo1/r4/ldpd.conf new file mode 100644 index 0000000000..6b7d28f983 --- /dev/null +++ b/tests/topotests/ldp-oc-acl-topo1/r4/ldpd.conf @@ -0,0 +1,24 @@ +hostname r4 +log file ldpd.log +! +debug mpls ldp zebra +debug mpls ldp event +debug mpls ldp errors +debug mpls ldp messages recv +debug mpls ldp messages sent +debug mpls ldp discovery hello recv +debug mpls ldp discovery hello sent +! +mpls ldp + router-id 4.4.4.4 + ordered-control + ! + address-family ipv4 + discovery transport-address 4.4.4.4 + ! + !interface r4-eth0 + ! + ! +! +line vty +! diff --git a/tests/topotests/ldp-oc-acl-topo1/r4/ospfd.conf b/tests/topotests/ldp-oc-acl-topo1/r4/ospfd.conf new file mode 100644 index 0000000000..569dbc54e2 --- /dev/null +++ b/tests/topotests/ldp-oc-acl-topo1/r4/ospfd.conf @@ -0,0 +1,7 @@ +hostname r4 +log file ospfd.log +! +router ospf + router-id 4.4.4.4 + network 0.0.0.0/0 area 0 +! diff --git a/tests/topotests/ldp-oc-acl-topo1/r4/show_ip_ospf_neighbor.json b/tests/topotests/ldp-oc-acl-topo1/r4/show_ip_ospf_neighbor.json new file mode 100644 index 0000000000..794410522d --- /dev/null +++ b/tests/topotests/ldp-oc-acl-topo1/r4/show_ip_ospf_neighbor.json @@ -0,0 +1,21 @@ + +{ + "neighbors":{ + "2.2.2.2":[ + { + "priority":1, + "state":"Full\/DROther", + "address":"10.0.2.2", + "ifaceName":"r4-eth0:10.0.2.4" + } + ], + "3.3.3.3":[ + { + "priority":1, + "state":"Full\/Backup", + "address":"10.0.2.3", + "ifaceName":"r4-eth0:10.0.2.4" + } + ] + } +} diff --git a/tests/topotests/ldp-oc-acl-topo1/r4/show_ip_route.ref b/tests/topotests/ldp-oc-acl-topo1/r4/show_ip_route.ref new file mode 100644 index 0000000000..c9b83a1c73 --- /dev/null +++ b/tests/topotests/ldp-oc-acl-topo1/r4/show_ip_route.ref @@ -0,0 +1,196 @@ +{ + "1.1.1.1/32":[ + { + "prefix":"1.1.1.1/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceIndex":2, + "interfaceName":"r4-eth0", + "active":true + } + ] + } + ], + "2.2.2.2/32":[ + { + "prefix":"2.2.2.2/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceIndex":2, + "interfaceName":"r4-eth0", + "active":true + } + ] + } + ], + "3.3.3.3/32":[ + { + "prefix":"3.3.3.3/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.3", + "afi":"ipv4", + "interfaceIndex":2, + "interfaceName":"r4-eth0", + "active":true + } + ] + } + ], + "4.4.4.4/32":[ + { + "prefix":"4.4.4.4/32", + "protocol":"ospf", + "distance":110, + "metric":0, + "nexthops":[ + { + "directlyConnected":true, + "interfaceIndex":1, + "interfaceName":"lo", + "active":true + } + ] + }, + { + "prefix":"4.4.4.4/32", + "protocol":"connected", + "selected":true, + "destSelected":true, + "distance":0, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceIndex":1, + "interfaceName":"lo", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceIndex":2, + "interfaceName":"r4-eth0", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceIndex":2, + "interfaceName":"r4-eth0", + "active":true + } + ] + }, + { + "prefix":"10.0.2.0\/24", + "protocol":"connected", + "selected":true, + "destSelected":true, + "distance":0, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceIndex":2, + "interfaceName":"r4-eth0", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.3", + "afi":"ipv4", + "interfaceIndex":2, + "interfaceName":"r4-eth0", + "active":true + } + ] + } + ], + "123.0.1.0\/24":[ + { + "prefix":"123.0.1.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceIndex":2, + "interfaceName":"r4-eth0", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/ldp-oc-acl-topo1/r4/show_ldp_all_binding.ref b/tests/topotests/ldp-oc-acl-topo1/r4/show_ldp_all_binding.ref new file mode 100644 index 0000000000..2a46c40346 --- /dev/null +++ b/tests/topotests/ldp-oc-acl-topo1/r4/show_ldp_all_binding.ref @@ -0,0 +1,68 @@ +{ + "bindings":[ + { + "addressFamily":"ipv4", + "prefix":"1.1.1.1/32", + "neighborId":"0.0.0.0", + "localLabel":"imp-null", + "remoteLabel":"-", + "inUse":0 + }, + { + "addressFamily":"ipv4", + "prefix":"2.2.2.2/32", + "neighborId":"0.0.0.0", + "localLabel":"imp-null", + "remoteLabel":"-", + "inUse":0 + }, + { + "addressFamily":"ipv4", + "prefix":"3.3.3.3/32", + "neighborId":"0.0.0.0", + "localLabel":"imp-null", + "remoteLabel":"-", + "inUse":0 + }, + { + "addressFamily":"ipv4", + "prefix":"4.4.4.4/32", + "neighborId":"0.0.0.0", + "localLabel":"imp-null", + "remoteLabel":"-", + "inUse":0 + }, + { + "addressFamily":"ipv4", + "prefix":"10.0.1.0/24", + "neighborId":"0.0.0.0", + "localLabel":"imp-null", + "remoteLabel":"-", + "inUse":0 + }, + { + "addressFamily":"ipv4", + "prefix":"10.0.2.0/24", + "neighborId":"0.0.0.0", + "localLabel":"imp-null", + "remoteLabel":"-", + "inUse":0 + }, + { + "addressFamily":"ipv4", + "prefix":"10.0.3.0/24", + "neighborId":"0.0.0.0", + "localLabel":"imp-null", + "remoteLabel":"-", + "inUse":0 + }, + { + "addressFamily":"ipv4", + "prefix":"123.0.1.0/24", + "neighborId":"0.0.0.0", + "localLabel":"imp-null", + "remoteLabel":"-", + "inUse":0 + } + ] +} diff --git a/tests/topotests/ldp-oc-acl-topo1/r4/show_ldp_binding.ref b/tests/topotests/ldp-oc-acl-topo1/r4/show_ldp_binding.ref new file mode 100644 index 0000000000..2a46c40346 --- /dev/null +++ b/tests/topotests/ldp-oc-acl-topo1/r4/show_ldp_binding.ref @@ -0,0 +1,68 @@ +{ + "bindings":[ + { + "addressFamily":"ipv4", + "prefix":"1.1.1.1/32", + "neighborId":"0.0.0.0", + "localLabel":"imp-null", + "remoteLabel":"-", + "inUse":0 + }, + { + "addressFamily":"ipv4", + "prefix":"2.2.2.2/32", + "neighborId":"0.0.0.0", + "localLabel":"imp-null", + "remoteLabel":"-", + "inUse":0 + }, + { + "addressFamily":"ipv4", + "prefix":"3.3.3.3/32", + "neighborId":"0.0.0.0", + "localLabel":"imp-null", + "remoteLabel":"-", + "inUse":0 + }, + { + "addressFamily":"ipv4", + "prefix":"4.4.4.4/32", + "neighborId":"0.0.0.0", + "localLabel":"imp-null", + "remoteLabel":"-", + "inUse":0 + }, + { + "addressFamily":"ipv4", + "prefix":"10.0.1.0/24", + "neighborId":"0.0.0.0", + "localLabel":"imp-null", + "remoteLabel":"-", + "inUse":0 + }, + { + "addressFamily":"ipv4", + "prefix":"10.0.2.0/24", + "neighborId":"0.0.0.0", + "localLabel":"imp-null", + "remoteLabel":"-", + "inUse":0 + }, + { + "addressFamily":"ipv4", + "prefix":"10.0.3.0/24", + "neighborId":"0.0.0.0", + "localLabel":"imp-null", + "remoteLabel":"-", + "inUse":0 + }, + { + "addressFamily":"ipv4", + "prefix":"123.0.1.0/24", + "neighborId":"0.0.0.0", + "localLabel":"imp-null", + "remoteLabel":"-", + "inUse":0 + } + ] +} diff --git a/tests/topotests/ldp-oc-acl-topo1/r4/show_ldp_discovery.ref b/tests/topotests/ldp-oc-acl-topo1/r4/show_ldp_discovery.ref new file mode 100644 index 0000000000..2c63c08510 --- /dev/null +++ b/tests/topotests/ldp-oc-acl-topo1/r4/show_ldp_discovery.ref @@ -0,0 +1,2 @@ +{ +} diff --git a/tests/topotests/ldp-oc-acl-topo1/r4/show_ldp_neighbor.ref b/tests/topotests/ldp-oc-acl-topo1/r4/show_ldp_neighbor.ref new file mode 100644 index 0000000000..2c63c08510 --- /dev/null +++ b/tests/topotests/ldp-oc-acl-topo1/r4/show_ldp_neighbor.ref @@ -0,0 +1,2 @@ +{ +} diff --git a/tests/topotests/ldp-oc-acl-topo1/r4/zebra.conf b/tests/topotests/ldp-oc-acl-topo1/r4/zebra.conf new file mode 100644 index 0000000000..7e291053e5 --- /dev/null +++ b/tests/topotests/ldp-oc-acl-topo1/r4/zebra.conf @@ -0,0 +1,17 @@ +log file zebra.log +! +hostname r4 +! +interface lo + ip address 4.4.4.4/32 +! +interface r4-eth0 + description to sw1 + ip address 10.0.2.4/24 +! no link-detect +! +ip forwarding +! +! +line vty +! diff --git a/tests/topotests/ldp-oc-acl-topo1/test_ldp_oc_acl_topo1.dot b/tests/topotests/ldp-oc-acl-topo1/test_ldp_oc_acl_topo1.dot new file mode 100644 index 0000000000..62058e3cb1 --- /dev/null +++ b/tests/topotests/ldp-oc-acl-topo1/test_ldp_oc_acl_topo1.dot @@ -0,0 +1,76 @@ +## Color coding: +######################### +## Main FRR: #f08080 red +## Switches: #d0e0d0 gray +## RIP: #19e3d9 Cyan +## RIPng: #fcb314 dark yellow +## OSPFv2: #32b835 Green +## OSPFv3: #19e3d9 Cyan +## ISIS IPv4 #fcb314 dark yellow +## ISIS IPv6 #9a81ec purple +## BGP IPv4 #eee3d3 beige +## BGP IPv6 #fdff00 yellow +##### Colors (see http://www.color-hex.com/) + +graph template { + label="Test Topology - LDP-OC 1"; + + # Routers + r1 [ + shape=doubleoctagon, + label="r1", + fillcolor="#f08080", + style=filled, + ]; + r2 [ + shape=doubleoctagon + label="r2", + fillcolor="#f08080", + style=filled, + ]; + r3 [ + shape=doubleoctagon + label="r3", + fillcolor="#f08080", + style=filled, + ]; + r4 [ + shape=doubleoctagon + label="r4", + fillcolor="#f08080", + style=filled, + ]; + + + # Switches + s0 [ + shape=oval, + label="10.0.1.0/24", + fillcolor="#d0e0d0", + style=filled, + ]; + s1 [ + shape=oval, + label="10.0.2.0/24", + fillcolor="#d0e0d0", + style=filled, + ]; + s2 [ + shape=oval, + label="10.0.3.0/24", + fillcolor="#d0e0d0", + style=filled, + ]; + + # Connections + + r1 -- s0 [label="eth0"]; + r2 -- s0 [label="eth0"]; + + r2 -- s1 [label="eth1"]; + r3 -- s1 [label="eth0"]; + r4 -- s1 [label="eth0"]; + + r2 -- s2 [label="eth2"]; + r3 -- s2 [label="eth1"]; +} diff --git a/tests/topotests/ldp-oc-acl-topo1/test_ldp_oc_acl_topo1.py b/tests/topotests/ldp-oc-acl-topo1/test_ldp_oc_acl_topo1.py new file mode 100755 index 0000000000..9695c0d345 --- /dev/null +++ b/tests/topotests/ldp-oc-acl-topo1/test_ldp_oc_acl_topo1.py @@ -0,0 +1,243 @@ +#!/usr/bin/env python + +# +# test_ldp_oc_acl_topo1.py +# Part of NetDEF Topology Tests +# +# Copyright (c) 2020 by Volta Networks +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +""" +test_ldp_oc_acl_topo1.py: Simple FRR/Quagga LDP Test + + +---------+ + | r1 | + | 1.1.1.1 | + +----+----+ + | .1 r1-eth0 + | + ~~~~~~~~~~~~~ + ~~ sw0 ~~ + ~~ 10.0.1.0/24 ~~ + ~~~~~~~~~~~~~ + |10.0.1.0/24 + | + | .2 r2-eth0 + +----+----+ + | r2 | + | 2.2.2.2 | + +--+---+--+ + r2-eth2 .2 | | .2 r2-eth1 + ______/ \______ + / \ + ~~~~~~~~~~~~~ ~~~~~~~~~~~~~ +~~ sw2 ~~ ~~ sw1 ~~ +~~ 10.0.3.0/24 ~~ ~~ 10.0.2.0/24 ~~ + ~~~~~~~~~~~~~ ~~~~~~~~~~~~~ + | / | + \ _________/ | + \ / \ +r3-eth1 .3 | | .3 r3-eth0 | .4 r4-eth0 + +----+--+---+ +----+----+ + | r3 | | r4 | + | 3.3.3.3 | | 4.4.4.4 | + +-----------+ +---------+ +""" + +import os +import sys +import pytest +import json +from time import sleep +from functools import partial + +# Save the Current Working Directory to find configuration files. +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, '../')) + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger + +# Required to instantiate the topology builder class. +from mininet.topo import Topo + +class TemplateTopo(Topo): + "Test topology builder" + def build(self, *_args, **_opts): + "Build function" + tgen = get_topogen(self) + + # + # Define FRR Routers + # + for router in ['r1', 'r2', 'r3', 'r4']: + tgen.add_router(router) + + # + # Define connections + # + switch = tgen.add_switch('s0') + switch.add_link(tgen.gears['r1']) + switch.add_link(tgen.gears['r2']) + + switch = tgen.add_switch('s1') + switch.add_link(tgen.gears['r2']) + switch.add_link(tgen.gears['r3']) + switch.add_link(tgen.gears['r4']) + + switch = tgen.add_switch('s2') + switch.add_link(tgen.gears['r2']) + switch.add_link(tgen.gears['r3']) + +def setup_module(mod): + "Sets up the pytest environment" + tgen = Topogen(TemplateTopo, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + # For all registered routers, load the zebra configuration file + for rname, router in router_list.iteritems(): + router.load_config( + TopoRouter.RD_ZEBRA, + os.path.join(CWD, '{}/zebra.conf'.format(rname)) + ) + # Don't start ospfd and ldpd in the CE nodes + if router.name[0] == 'r': + router.load_config( + TopoRouter.RD_OSPF, + os.path.join(CWD, '{}/ospfd.conf'.format(rname)) + ) + router.load_config( + TopoRouter.RD_LDP, + os.path.join(CWD, '{}/ldpd.conf'.format(rname)) + ) + + tgen.start_router() + +def teardown_module(mod): + "Teardown the pytest environment" + tgen = get_topogen() + + # This function tears down the whole topology. + tgen.stop_topology() + + +def router_compare_json_output(rname, command, reference): + "Compare router JSON output" + + logger.info('Comparing router "%s" "%s" output', rname, command) + + tgen = get_topogen() + filename = '{}/{}/{}'.format(CWD, rname, reference) + expected = json.loads(open(filename).read()) + + # Run test function until we get an result. Wait at most 80 seconds. + test_func = partial(topotest.router_json_cmp, + tgen.gears[rname], command, expected) + _, diff = topotest.run_and_expect(test_func, None, count=160, wait=0.5) + + assertmsg = '"{}" JSON output mismatches the expected result'.format(rname) + assert diff is None, assertmsg + +def test_ospf_convergence(): + logger.info("Test: check OSPF adjacencies") + + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + for rname in ['r1', 'r2', 'r3', 'r4']: + router_compare_json_output(rname, "show ip ospf neighbor json", "show_ip_ospf_neighbor.json") + +def test_rib(): + logger.info("Test: verify RIB") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + for rname in ['r1', 'r2', 'r3', 'r4']: + router_compare_json_output(rname, "show ip route json", "show_ip_route.ref") + +def test_ldp_adjacencies(): + logger.info("Test: verify LDP adjacencies") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + for rname in ['r1', 'r2', 'r3', 'r4']: + router_compare_json_output(rname, "show mpls ldp discovery json", "show_ldp_discovery.ref") + +def test_ldp_neighbors(): + logger.info("Test: verify LDP neighbors") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + for rname in ['r1', 'r2', 'r3', 'r4']: + router_compare_json_output(rname, "show mpls ldp neighbor json", "show_ldp_neighbor.ref") + +def test_ldp_bindings(): + logger.info("Test: verify LDP bindings") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + for rname in ['r1', 'r2', 'r3', 'r4']: + router_compare_json_output(rname, "show mpls ldp binding json", "show_ldp_binding.ref") + +def test_ldp_bindings_all_routes(): + logger.info("Test: verify LDP bindings after host filter removed") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # remove ACL that blocks advertising everything but host routes */ + cmd = 'vtysh -c \"configure terminal\" -c \"mpls ldp\" -c \"address-family ipv4\" -c \"no label local allocate host-routes\"' + tgen.net['r1'].cmd(cmd) + sleep(2) + + for rname in ['r1', 'r2', 'r3', 'r4']: + router_compare_json_output(rname, "show mpls ldp binding json", "show_ldp_all_binding.ref") + +# Memory leak test template +def test_memory_leak(): + "Run the memory leak test and report results." + tgen = get_topogen() + if not tgen.is_memleak_enabled(): + pytest.skip('Memory leak test/report is disabled') + + tgen.report_memory_leaks() + +if __name__ == '__main__': + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/ldp-oc-topo1/r1/ldpd.conf b/tests/topotests/ldp-oc-topo1/r1/ldpd.conf new file mode 100644 index 0000000000..2a8e023832 --- /dev/null +++ b/tests/topotests/ldp-oc-topo1/r1/ldpd.conf @@ -0,0 +1,24 @@ +hostname r1 +log file ldpd.log +! +debug mpls ldp zebra +debug mpls ldp event +debug mpls ldp errors +debug mpls ldp messages recv +debug mpls ldp messages sent +debug mpls ldp discovery hello recv +debug mpls ldp discovery hello sent +! +mpls ldp + router-id 1.1.1.1 + ordered-control + ! + address-family ipv4 + discovery transport-address 1.1.1.1 + ! + interface r1-eth0 + ! + ! +! +line vty +! diff --git a/tests/topotests/ldp-oc-topo1/r1/ospfd.conf b/tests/topotests/ldp-oc-topo1/r1/ospfd.conf new file mode 100644 index 0000000000..6daf034d18 --- /dev/null +++ b/tests/topotests/ldp-oc-topo1/r1/ospfd.conf @@ -0,0 +1,7 @@ +hostname r1 +log file ospfd.log +! +router ospf + router-id 1.1.1.1 + network 0.0.0.0/0 area 0 +! diff --git a/tests/topotests/ldp-oc-topo1/r1/show_ip_ospf_neighbor.json b/tests/topotests/ldp-oc-topo1/r1/show_ip_ospf_neighbor.json new file mode 100644 index 0000000000..2c493173f5 --- /dev/null +++ b/tests/topotests/ldp-oc-topo1/r1/show_ip_ospf_neighbor.json @@ -0,0 +1,12 @@ +{ + "neighbors":{ + "2.2.2.2":[ + { + "priority":1, + "state":"Full\/DR", + "address":"10.0.1.2", + "ifaceName":"r1-eth0:10.0.1.1" + } + ] + } +} diff --git a/tests/topotests/ldp-oc-topo1/r1/show_ip_route.ref b/tests/topotests/ldp-oc-topo1/r1/show_ip_route.ref new file mode 100644 index 0000000000..d75b8f21db --- /dev/null +++ b/tests/topotests/ldp-oc-topo1/r1/show_ip_route.ref @@ -0,0 +1,171 @@ +{ + "1.1.1.1/32":[ + { + "prefix":"1.1.1.1/32", + "protocol":"ospf", + "nexthops":[ + { + "directlyConnected":true, + "interfaceIndex":1, + "interfaceName":"lo", + "active":true + } + ] + }, + { + "prefix":"1.1.1.1/32", + "protocol":"connected", + "selected":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceIndex":1, + "interfaceName":"lo", + "active":true + } + ] + } + ], + "2.2.2.2/32":[ + { + "prefix":"2.2.2.2/32", + "protocol":"ospf", + "selected":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceIndex":2, + "interfaceName":"r1-eth0", + "active":true + } + ] + } + ], + "3.3.3.3/32":[ + { + "prefix":"3.3.3.3/32", + "protocol":"ospf", + "selected":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceIndex":2, + "interfaceName":"r1-eth0", + "active":true + } + ] + } + ], + "4.4.4.4/32":[ + { + "prefix":"4.4.4.4/32", + "protocol":"ospf", + "selected":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceIndex":2, + "interfaceName":"r1-eth0", + "active":true + } + ] + } + ], + "10.0.1.0/24":[ + { + "prefix":"10.0.1.0/24", + "protocol":"ospf", + "nexthops":[ + { + "directlyConnected":true, + "interfaceIndex":2, + "interfaceName":"r1-eth0", + "active":true + } + ] + }, + { + "prefix":"10.0.1.0/24", + "protocol":"connected", + "selected":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceIndex":2, + "interfaceName":"r1-eth0", + "active":true + } + ] + } + ], + "10.0.2.0/24":[ + { + "prefix":"10.0.2.0/24", + "protocol":"ospf", + "selected":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceIndex":2, + "interfaceName":"r1-eth0", + "active":true + } + ] + } + ], + "10.0.3.0/24":[ + { + "prefix":"10.0.3.0/24", + "protocol":"ospf", + "selected":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceIndex":2, + "interfaceName":"r1-eth0", + "active":true + } + ] + } + ], + "123.0.1.0/24":[ + { + "prefix":"123.0.1.0/24", + "protocol":"ospf", + "nexthops":[ + { + "directlyConnected":true, + "interfaceIndex":2, + "interfaceName":"r1-eth0", + "active":true + } + ] + }, + { + "prefix":"123.0.1.0/24", + "protocol":"connected", + "selected":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceIndex":2, + "interfaceName":"r1-eth0", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/ldp-oc-topo1/r1/show_ldp_binding.ref b/tests/topotests/ldp-oc-topo1/r1/show_ldp_binding.ref new file mode 100644 index 0000000000..99a59668f8 --- /dev/null +++ b/tests/topotests/ldp-oc-topo1/r1/show_ldp_binding.ref @@ -0,0 +1,61 @@ +{ + "bindings":[ + { + "addressFamily":"ipv4", + "prefix":"1.1.1.1/32", + "neighborId":"0.0.0.0", + "localLabel":"imp-null", + "remoteLabel":"-", + "inUse":0 + }, + { + "addressFamily":"ipv4", + "prefix":"2.2.2.2/32", + "neighborId":"2.2.2.2", + "remoteLabel":"imp-null", + "inUse":1 + }, + { + "addressFamily":"ipv4", + "prefix":"3.3.3.3/32", + "neighborId":"2.2.2.2", + "inUse":1 + }, + { + "addressFamily":"ipv4", + "prefix":"4.4.4.4/32", + "neighborId":"0.0.0.0", + "remoteLabel":"-", + "inUse":0 + }, + { + "addressFamily":"ipv4", + "prefix":"10.0.1.0/24", + "neighborId":"2.2.2.2", + "localLabel":"imp-null", + "remoteLabel":"imp-null", + "inUse":0 + }, + { + "addressFamily":"ipv4", + "prefix":"10.0.2.0/24", + "neighborId":"2.2.2.2", + "remoteLabel":"imp-null", + "inUse":1 + }, + { + "addressFamily":"ipv4", + "prefix":"10.0.3.0/24", + "neighborId":"2.2.2.2", + "inUse":1 + }, + { + "addressFamily":"ipv4", + "prefix":"123.0.1.0/24", + "neighborId":"0.0.0.0", + "localLabel":"imp-null", + "remoteLabel":"-", + "inUse":0 + } + ] +} diff --git a/tests/topotests/ldp-oc-topo1/r1/show_ldp_discovery.ref b/tests/topotests/ldp-oc-topo1/r1/show_ldp_discovery.ref new file mode 100644 index 0000000000..b349f4418f --- /dev/null +++ b/tests/topotests/ldp-oc-topo1/r1/show_ldp_discovery.ref @@ -0,0 +1,11 @@ +{ + "adjacencies":[ + { + "addressFamily":"ipv4", + "neighborId":"2.2.2.2", + "type":"link", + "interface":"r1-eth0", + "helloHoldtime":15 + } + ] +} diff --git a/tests/topotests/ldp-oc-topo1/r1/show_ldp_neighbor.ref b/tests/topotests/ldp-oc-topo1/r1/show_ldp_neighbor.ref new file mode 100644 index 0000000000..4bff444a46 --- /dev/null +++ b/tests/topotests/ldp-oc-topo1/r1/show_ldp_neighbor.ref @@ -0,0 +1,10 @@ +{ + "neighbors":[ + { + "addressFamily":"ipv4", + "neighborId":"2.2.2.2", + "state":"OPERATIONAL", + "transportAddress":"2.2.2.2" + } + ] +} diff --git a/tests/topotests/ldp-oc-topo1/r1/zebra.conf b/tests/topotests/ldp-oc-topo1/r1/zebra.conf new file mode 100644 index 0000000000..83aea46e64 --- /dev/null +++ b/tests/topotests/ldp-oc-topo1/r1/zebra.conf @@ -0,0 +1,17 @@ +log file zebra.log +! +hostname r1 +! +interface lo + ip address 1.1.1.1/32 +! +interface r1-eth0 + description to sw0 + ip address 10.0.1.1/24 + ip address 123.0.1.1/24 +! +ip forwarding +! +! +line vty +! diff --git a/tests/topotests/ldp-oc-topo1/r2/ldpd.conf b/tests/topotests/ldp-oc-topo1/r2/ldpd.conf new file mode 100644 index 0000000000..e1a552c701 --- /dev/null +++ b/tests/topotests/ldp-oc-topo1/r2/ldpd.conf @@ -0,0 +1,28 @@ +hostname r2 +log file ldpd.log +! +debug mpls ldp zebra +debug mpls ldp event +debug mpls ldp errors +debug mpls ldp messages recv +debug mpls ldp messages sent +debug mpls ldp discovery hello recv +debug mpls ldp discovery hello sent +! +mpls ldp + router-id 2.2.2.2 + ordered-control + ! + address-family ipv4 + discovery transport-address 2.2.2.2 + ! + interface r2-eth0 + ! + interface r2-eth1 + ! + interface r2-eth2 + ! + ! +! +line vty +! diff --git a/tests/topotests/ldp-oc-topo1/r2/ospfd.conf b/tests/topotests/ldp-oc-topo1/r2/ospfd.conf new file mode 100644 index 0000000000..8678813665 --- /dev/null +++ b/tests/topotests/ldp-oc-topo1/r2/ospfd.conf @@ -0,0 +1,7 @@ +hostname r2 +log file ospfd.log +! +router ospf + router-id 2.2.2.2 + network 0.0.0.0/0 area 0 +! diff --git a/tests/topotests/ldp-oc-topo1/r2/show_ip_ospf_neighbor.json b/tests/topotests/ldp-oc-topo1/r2/show_ip_ospf_neighbor.json new file mode 100644 index 0000000000..55f12359e5 --- /dev/null +++ b/tests/topotests/ldp-oc-topo1/r2/show_ip_ospf_neighbor.json @@ -0,0 +1,31 @@ +{ + "neighbors":{ + "1.1.1.1":[ + { + "priority":1, + "state":"Full\/Backup", + "address":"10.0.1.1", + "ifaceName":"r2-eth0:10.0.1.2", + "retransmitCounter":0, + "requestCounter":0, + "dbSummaryCounter":0 + } + ], + "3.3.3.3":[ + { + "priority":1, + "state":"Full\/Backup", + "address":"10.0.2.3", + "ifaceName":"r2-eth1:10.0.2.2" + } + ], + "4.4.4.4":[ + { + "priority":1, + "state":"Full\/DR", + "address":"10.0.2.4", + "ifaceName":"r2-eth1:10.0.2.2" + } + ] + } +} diff --git a/tests/topotests/ldp-oc-topo1/r2/show_ip_route.ref b/tests/topotests/ldp-oc-topo1/r2/show_ip_route.ref new file mode 100644 index 0000000000..060c0b429d --- /dev/null +++ b/tests/topotests/ldp-oc-topo1/r2/show_ip_route.ref @@ -0,0 +1,209 @@ +{ + "1.1.1.1/32":[ + { + "prefix":"1.1.1.1/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceIndex":2, + "interfaceName":"r2-eth0", + "active":true + } + ] + } + ], + "2.2.2.2/32":[ + { + "prefix":"2.2.2.2/32", + "protocol":"ospf", + "distance":110, + "metric":0, + "nexthops":[ + { + "directlyConnected":true, + "interfaceIndex":1, + "interfaceName":"lo", + "active":true + } + ] + }, + { + "prefix":"2.2.2.2/32", + "protocol":"connected", + "selected":true, + "destSelected":true, + "distance":0, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceIndex":1, + "interfaceName":"lo", + "active":true + } + ] + } + ], + "3.3.3.3/32":[ + { + "prefix":"3.3.3.3/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.3", + "afi":"ipv4", + "interfaceIndex":3, + "interfaceName":"r2-eth1", + "active":true + } + ] + } + ], + "4.4.4.4/32":[ + { + "prefix":"4.4.4.4/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceIndex":3, + "interfaceName":"r2-eth1", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceIndex":2, + "interfaceName":"r2-eth0", + "active":true + } + ] + }, + { + "prefix":"10.0.1.0\/24", + "protocol":"connected", + "selected":true, + "destSelected":true, + "distance":0, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceIndex":2, + "interfaceName":"r2-eth0", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceIndex":3, + "interfaceName":"r2-eth1", + "active":true + } + ] + }, + { + "prefix":"10.0.2.0\/24", + "protocol":"connected", + "selected":true, + "destSelected":true, + "distance":0, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceIndex":3, + "interfaceName":"r2-eth1", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.3", + "afi":"ipv4", + "interfaceIndex":3, + "interfaceName":"r2-eth1", + "active":true + } + ] + } + ], + "123.0.1.0\/24":[ + { + "prefix":"123.0.1.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceIndex":2, + "interfaceName":"r2-eth0", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/ldp-oc-topo1/r2/show_ldp_binding.ref b/tests/topotests/ldp-oc-topo1/r2/show_ldp_binding.ref new file mode 100644 index 0000000000..95fb847c1e --- /dev/null +++ b/tests/topotests/ldp-oc-topo1/r2/show_ldp_binding.ref @@ -0,0 +1,63 @@ +{ + "bindings":[ + { + "addressFamily":"ipv4", + "prefix":"1.1.1.1/32", + "neighborId":"1.1.1.1", + "remoteLabel":"imp-null", + "inUse":1 + }, + { + "addressFamily":"ipv4", + "prefix":"2.2.2.2/32", + "neighborId":"0.0.0.0", + "localLabel":"imp-null", + "remoteLabel":"-", + "inUse":0 + }, + { + "addressFamily":"ipv4", + "prefix":"3.3.3.3/32", + "neighborId":"3.3.3.3", + "remoteLabel":"imp-null", + "inUse":1 + }, + { + "addressFamily":"ipv4", + "prefix":"4.4.4.4/32", + "neighborId":"0.0.0.0", + "remoteLabel":"-", + "inUse":0 + }, + { + "addressFamily":"ipv4", + "prefix":"10.0.1.0/24", + "neighborId":"1.1.1.1", + "localLabel":"imp-null", + "remoteLabel":"imp-null", + "inUse":0 + }, + { + "addressFamily":"ipv4", + "prefix":"10.0.2.0/24", + "neighborId":"3.3.3.3", + "localLabel":"imp-null", + "remoteLabel":"imp-null", + "inUse":0 + }, + { + "addressFamily":"ipv4", + "prefix":"10.0.3.0/24", + "neighborId":"3.3.3.3", + "remoteLabel":"imp-null", + "inUse":1 + }, + { + "addressFamily":"ipv4", + "prefix":"123.0.1.0/24", + "neighborId":"1.1.1.1", + "remoteLabel":"imp-null", + "inUse":1 + } + ] +} diff --git a/tests/topotests/ldp-oc-topo1/r2/show_ldp_discovery.ref b/tests/topotests/ldp-oc-topo1/r2/show_ldp_discovery.ref new file mode 100644 index 0000000000..8129570082 --- /dev/null +++ b/tests/topotests/ldp-oc-topo1/r2/show_ldp_discovery.ref @@ -0,0 +1,18 @@ +{ + "adjacencies":[ + { + "addressFamily":"ipv4", + "neighborId":"1.1.1.1", + "type":"link", + "interface":"r2-eth0", + "helloHoldtime":15 + }, + { + "addressFamily":"ipv4", + "neighborId":"3.3.3.3", + "type":"link", + "interface":"r2-eth1", + "helloHoldtime":15 + } + ] +} diff --git a/tests/topotests/ldp-oc-topo1/r2/show_ldp_neighbor.ref b/tests/topotests/ldp-oc-topo1/r2/show_ldp_neighbor.ref new file mode 100644 index 0000000000..eed35289ea --- /dev/null +++ b/tests/topotests/ldp-oc-topo1/r2/show_ldp_neighbor.ref @@ -0,0 +1,16 @@ +{ + "neighbors":[ + { + "addressFamily":"ipv4", + "neighborId":"1.1.1.1", + "state":"OPERATIONAL", + "transportAddress":"1.1.1.1" + }, + { + "addressFamily":"ipv4", + "neighborId":"3.3.3.3", + "state":"OPERATIONAL", + "transportAddress":"3.3.3.3" + } + ] +} diff --git a/tests/topotests/ldp-oc-topo1/r2/zebra.conf b/tests/topotests/ldp-oc-topo1/r2/zebra.conf new file mode 100644 index 0000000000..1f1e3e391a --- /dev/null +++ b/tests/topotests/ldp-oc-topo1/r2/zebra.conf @@ -0,0 +1,27 @@ +log file zebra.log +! +hostname r2 +! +interface lo + ip address 2.2.2.2/32 +! +interface r2-eth0 + description to sw0 + ip address 10.0.1.2/24 +! no link-detect +! +interface r2-eth1 + description to sw1 + ip address 10.0.2.2/24 +! no link-detect +! +interface r2-eths2 + description to sw2 + ip address 10.0.3.2/24 +! no link-detect +! +ip forwarding +! +! +line vty +! diff --git a/tests/topotests/ldp-oc-topo1/r3/ldpd.conf b/tests/topotests/ldp-oc-topo1/r3/ldpd.conf new file mode 100644 index 0000000000..4e66b140ac --- /dev/null +++ b/tests/topotests/ldp-oc-topo1/r3/ldpd.conf @@ -0,0 +1,24 @@ +hostname r3 +log file ldpd.log +! +debug mpls ldp zebra +debug mpls ldp event +debug mpls ldp errors +debug mpls ldp messages recv +debug mpls ldp messages sent +debug mpls ldp discovery hello recv +debug mpls ldp discovery hello sent +! +mpls ldp + router-id 3.3.3.3 + ordered-control + ! + address-family ipv4 + discovery transport-address 3.3.3.3 + ! + interface r3-eth0 + ! + ! +! +line vty +! diff --git a/tests/topotests/ldp-oc-topo1/r3/ospfd.conf b/tests/topotests/ldp-oc-topo1/r3/ospfd.conf new file mode 100644 index 0000000000..202be238ec --- /dev/null +++ b/tests/topotests/ldp-oc-topo1/r3/ospfd.conf @@ -0,0 +1,8 @@ +hostname r3 +password 1 +log file ospfd.log +! +router ospf + router-id 3.3.3.3 + network 0.0.0.0/0 area 0 +! diff --git a/tests/topotests/ldp-oc-topo1/r3/show_ip_ospf_neighbor.json b/tests/topotests/ldp-oc-topo1/r3/show_ip_ospf_neighbor.json new file mode 100644 index 0000000000..24502ed813 --- /dev/null +++ b/tests/topotests/ldp-oc-topo1/r3/show_ip_ospf_neighbor.json @@ -0,0 +1,20 @@ +{ + "neighbors":{ + "2.2.2.2":[ + { + "priority":1, + "state":"Full\/DROther", + "address":"10.0.2.2", + "ifaceName":"r3-eth0:10.0.2.3" + } + ], + "4.4.4.4":[ + { + "priority":1, + "state":"Full\/DR", + "address":"10.0.2.4", + "ifaceName":"r3-eth0:10.0.2.3" + } + ] + } +} diff --git a/tests/topotests/ldp-oc-topo1/r3/show_ip_route.ref b/tests/topotests/ldp-oc-topo1/r3/show_ip_route.ref new file mode 100644 index 0000000000..40800762ba --- /dev/null +++ b/tests/topotests/ldp-oc-topo1/r3/show_ip_route.ref @@ -0,0 +1,209 @@ +{ + "1.1.1.1/32":[ + { + "prefix":"1.1.1.1/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceIndex":2, + "interfaceName":"r3-eth0", + "active":true + } + ] + } + ], + "2.2.2.2/32":[ + { + "prefix":"2.2.2.2/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceIndex":2, + "interfaceName":"r3-eth0", + "active":true + } + ] + } + ], + "3.3.3.3/32":[ + { + "prefix":"3.3.3.3/32", + "protocol":"ospf", + "distance":110, + "metric":0, + "nexthops":[ + { + "directlyConnected":true, + "interfaceIndex":1, + "interfaceName":"lo", + "active":true + } + ] + }, + { + "prefix":"3.3.3.3/32", + "protocol":"connected", + "selected":true, + "destSelected":true, + "distance":0, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceIndex":1, + "interfaceName":"lo", + "active":true + } + ] + } + ], + "4.4.4.4/32":[ + { + "prefix":"4.4.4.4/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceIndex":2, + "interfaceName":"r3-eth0", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceIndex":2, + "interfaceName":"r3-eth0", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceIndex":2, + "interfaceName":"r3-eth0", + "active":true + } + ] + }, + { + "prefix":"10.0.2.0\/24", + "protocol":"connected", + "selected":true, + "destSelected":true, + "distance":0, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceIndex":2, + "interfaceName":"r3-eth0", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceIndex":3, + "interfaceName":"r3-eth1", + "active":true + } + ] + }, + { + "prefix":"10.0.3.0\/24", + "protocol":"connected", + "selected":true, + "destSelected":true, + "distance":0, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceIndex":3, + "interfaceName":"r3-eth1", + "active":true + } + ] + } + ], + "123.0.1.0\/24":[ + { + "prefix":"123.0.1.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceIndex":2, + "interfaceName":"r3-eth0", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/ldp-oc-topo1/r3/show_ldp_binding.ref b/tests/topotests/ldp-oc-topo1/r3/show_ldp_binding.ref new file mode 100644 index 0000000000..100dd307ea --- /dev/null +++ b/tests/topotests/ldp-oc-topo1/r3/show_ldp_binding.ref @@ -0,0 +1,61 @@ +{ + "bindings":[ + { + "addressFamily":"ipv4", + "prefix":"1.1.1.1/32", + "neighborId":"2.2.2.2", + "inUse":1 + }, + { + "addressFamily":"ipv4", + "prefix":"2.2.2.2/32", + "neighborId":"2.2.2.2", + "remoteLabel":"imp-null", + "inUse":1 + }, + { + "addressFamily":"ipv4", + "prefix":"3.3.3.3/32", + "neighborId":"0.0.0.0", + "localLabel":"imp-null", + "remoteLabel":"-", + "inUse":0 + }, + { + "addressFamily":"ipv4", + "prefix":"4.4.4.4/32", + "neighborId":"0.0.0.0", + "remoteLabel":"-", + "inUse":0 + }, + { + "addressFamily":"ipv4", + "prefix":"10.0.1.0/24", + "neighborId":"2.2.2.2", + "remoteLabel":"imp-null", + "inUse":1 + }, + { + "addressFamily":"ipv4", + "prefix":"10.0.2.0/24", + "neighborId":"2.2.2.2", + "localLabel":"imp-null", + "remoteLabel":"imp-null", + "inUse":0 + }, + { + "addressFamily":"ipv4", + "prefix":"10.0.3.0/24", + "neighborId":"0.0.0.0", + "localLabel":"imp-null", + "remoteLabel":"-", + "inUse":0 + }, + { + "addressFamily":"ipv4", + "prefix":"123.0.1.0/24", + "neighborId":"2.2.2.2", + "inUse":1 + } + ] +} diff --git a/tests/topotests/ldp-oc-topo1/r3/show_ldp_discovery.ref b/tests/topotests/ldp-oc-topo1/r3/show_ldp_discovery.ref new file mode 100644 index 0000000000..c3a07e7e38 --- /dev/null +++ b/tests/topotests/ldp-oc-topo1/r3/show_ldp_discovery.ref @@ -0,0 +1,11 @@ +{ + "adjacencies":[ + { + "addressFamily":"ipv4", + "neighborId":"2.2.2.2", + "type":"link", + "interface":"r3-eth0", + "helloHoldtime":15 + } + ] +} diff --git a/tests/topotests/ldp-oc-topo1/r3/show_ldp_neighbor.ref b/tests/topotests/ldp-oc-topo1/r3/show_ldp_neighbor.ref new file mode 100644 index 0000000000..4bff444a46 --- /dev/null +++ b/tests/topotests/ldp-oc-topo1/r3/show_ldp_neighbor.ref @@ -0,0 +1,10 @@ +{ + "neighbors":[ + { + "addressFamily":"ipv4", + "neighborId":"2.2.2.2", + "state":"OPERATIONAL", + "transportAddress":"2.2.2.2" + } + ] +} diff --git a/tests/topotests/ldp-oc-topo1/r3/zebra.conf b/tests/topotests/ldp-oc-topo1/r3/zebra.conf new file mode 100644 index 0000000000..234c215ddf --- /dev/null +++ b/tests/topotests/ldp-oc-topo1/r3/zebra.conf @@ -0,0 +1,22 @@ +log file zebra.log +! +hostname r3 +! +interface lo + ip address 3.3.3.3/32 +! +interface r3-eth0 + description to sw1 + ip address 10.0.2.3/24 +! no link-detect +! +interface r3-eth1 + description to sw2 + ip address 10.0.3.3/24 +! no link-detect +! +ip forwarding +! +! +line vty +! diff --git a/tests/topotests/ldp-oc-topo1/r4/ldpd.conf b/tests/topotests/ldp-oc-topo1/r4/ldpd.conf new file mode 100644 index 0000000000..6b7d28f983 --- /dev/null +++ b/tests/topotests/ldp-oc-topo1/r4/ldpd.conf @@ -0,0 +1,24 @@ +hostname r4 +log file ldpd.log +! +debug mpls ldp zebra +debug mpls ldp event +debug mpls ldp errors +debug mpls ldp messages recv +debug mpls ldp messages sent +debug mpls ldp discovery hello recv +debug mpls ldp discovery hello sent +! +mpls ldp + router-id 4.4.4.4 + ordered-control + ! + address-family ipv4 + discovery transport-address 4.4.4.4 + ! + !interface r4-eth0 + ! + ! +! +line vty +! diff --git a/tests/topotests/ldp-oc-topo1/r4/ospfd.conf b/tests/topotests/ldp-oc-topo1/r4/ospfd.conf new file mode 100644 index 0000000000..569dbc54e2 --- /dev/null +++ b/tests/topotests/ldp-oc-topo1/r4/ospfd.conf @@ -0,0 +1,7 @@ +hostname r4 +log file ospfd.log +! +router ospf + router-id 4.4.4.4 + network 0.0.0.0/0 area 0 +! diff --git a/tests/topotests/ldp-oc-topo1/r4/show_ip_ospf_neighbor.json b/tests/topotests/ldp-oc-topo1/r4/show_ip_ospf_neighbor.json new file mode 100644 index 0000000000..794410522d --- /dev/null +++ b/tests/topotests/ldp-oc-topo1/r4/show_ip_ospf_neighbor.json @@ -0,0 +1,21 @@ + +{ + "neighbors":{ + "2.2.2.2":[ + { + "priority":1, + "state":"Full\/DROther", + "address":"10.0.2.2", + "ifaceName":"r4-eth0:10.0.2.4" + } + ], + "3.3.3.3":[ + { + "priority":1, + "state":"Full\/Backup", + "address":"10.0.2.3", + "ifaceName":"r4-eth0:10.0.2.4" + } + ] + } +} diff --git a/tests/topotests/ldp-oc-topo1/r4/show_ip_route.ref b/tests/topotests/ldp-oc-topo1/r4/show_ip_route.ref new file mode 100644 index 0000000000..c9b83a1c73 --- /dev/null +++ b/tests/topotests/ldp-oc-topo1/r4/show_ip_route.ref @@ -0,0 +1,196 @@ +{ + "1.1.1.1/32":[ + { + "prefix":"1.1.1.1/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceIndex":2, + "interfaceName":"r4-eth0", + "active":true + } + ] + } + ], + "2.2.2.2/32":[ + { + "prefix":"2.2.2.2/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceIndex":2, + "interfaceName":"r4-eth0", + "active":true + } + ] + } + ], + "3.3.3.3/32":[ + { + "prefix":"3.3.3.3/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":10, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.3", + "afi":"ipv4", + "interfaceIndex":2, + "interfaceName":"r4-eth0", + "active":true + } + ] + } + ], + "4.4.4.4/32":[ + { + "prefix":"4.4.4.4/32", + "protocol":"ospf", + "distance":110, + "metric":0, + "nexthops":[ + { + "directlyConnected":true, + "interfaceIndex":1, + "interfaceName":"lo", + "active":true + } + ] + }, + { + "prefix":"4.4.4.4/32", + "protocol":"connected", + "selected":true, + "destSelected":true, + "distance":0, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceIndex":1, + "interfaceName":"lo", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceIndex":2, + "interfaceName":"r4-eth0", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"ospf", + "distance":110, + "metric":10, + "nexthops":[ + { + "directlyConnected":true, + "interfaceIndex":2, + "interfaceName":"r4-eth0", + "active":true + } + ] + }, + { + "prefix":"10.0.2.0\/24", + "protocol":"connected", + "selected":true, + "destSelected":true, + "distance":0, + "metric":0, + "installed":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceIndex":2, + "interfaceName":"r4-eth0", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.3", + "afi":"ipv4", + "interfaceIndex":2, + "interfaceName":"r4-eth0", + "active":true + } + ] + } + ], + "123.0.1.0\/24":[ + { + "prefix":"123.0.1.0\/24", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "distance":110, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceIndex":2, + "interfaceName":"r4-eth0", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/ldp-oc-topo1/r4/show_ldp_binding.ref b/tests/topotests/ldp-oc-topo1/r4/show_ldp_binding.ref new file mode 100644 index 0000000000..2a46c40346 --- /dev/null +++ b/tests/topotests/ldp-oc-topo1/r4/show_ldp_binding.ref @@ -0,0 +1,68 @@ +{ + "bindings":[ + { + "addressFamily":"ipv4", + "prefix":"1.1.1.1/32", + "neighborId":"0.0.0.0", + "localLabel":"imp-null", + "remoteLabel":"-", + "inUse":0 + }, + { + "addressFamily":"ipv4", + "prefix":"2.2.2.2/32", + "neighborId":"0.0.0.0", + "localLabel":"imp-null", + "remoteLabel":"-", + "inUse":0 + }, + { + "addressFamily":"ipv4", + "prefix":"3.3.3.3/32", + "neighborId":"0.0.0.0", + "localLabel":"imp-null", + "remoteLabel":"-", + "inUse":0 + }, + { + "addressFamily":"ipv4", + "prefix":"4.4.4.4/32", + "neighborId":"0.0.0.0", + "localLabel":"imp-null", + "remoteLabel":"-", + "inUse":0 + }, + { + "addressFamily":"ipv4", + "prefix":"10.0.1.0/24", + "neighborId":"0.0.0.0", + "localLabel":"imp-null", + "remoteLabel":"-", + "inUse":0 + }, + { + "addressFamily":"ipv4", + "prefix":"10.0.2.0/24", + "neighborId":"0.0.0.0", + "localLabel":"imp-null", + "remoteLabel":"-", + "inUse":0 + }, + { + "addressFamily":"ipv4", + "prefix":"10.0.3.0/24", + "neighborId":"0.0.0.0", + "localLabel":"imp-null", + "remoteLabel":"-", + "inUse":0 + }, + { + "addressFamily":"ipv4", + "prefix":"123.0.1.0/24", + "neighborId":"0.0.0.0", + "localLabel":"imp-null", + "remoteLabel":"-", + "inUse":0 + } + ] +} diff --git a/tests/topotests/ldp-oc-topo1/r4/show_ldp_discovery.ref b/tests/topotests/ldp-oc-topo1/r4/show_ldp_discovery.ref new file mode 100644 index 0000000000..2c63c08510 --- /dev/null +++ b/tests/topotests/ldp-oc-topo1/r4/show_ldp_discovery.ref @@ -0,0 +1,2 @@ +{ +} diff --git a/tests/topotests/ldp-oc-topo1/r4/show_ldp_neighbor.ref b/tests/topotests/ldp-oc-topo1/r4/show_ldp_neighbor.ref new file mode 100644 index 0000000000..2c63c08510 --- /dev/null +++ b/tests/topotests/ldp-oc-topo1/r4/show_ldp_neighbor.ref @@ -0,0 +1,2 @@ +{ +} diff --git a/tests/topotests/ldp-oc-topo1/r4/zebra.conf b/tests/topotests/ldp-oc-topo1/r4/zebra.conf new file mode 100644 index 0000000000..7e291053e5 --- /dev/null +++ b/tests/topotests/ldp-oc-topo1/r4/zebra.conf @@ -0,0 +1,17 @@ +log file zebra.log +! +hostname r4 +! +interface lo + ip address 4.4.4.4/32 +! +interface r4-eth0 + description to sw1 + ip address 10.0.2.4/24 +! no link-detect +! +ip forwarding +! +! +line vty +! diff --git a/tests/topotests/ldp-oc-topo1/test_ldp_oc_topo1.dot b/tests/topotests/ldp-oc-topo1/test_ldp_oc_topo1.dot new file mode 100644 index 0000000000..62058e3cb1 --- /dev/null +++ b/tests/topotests/ldp-oc-topo1/test_ldp_oc_topo1.dot @@ -0,0 +1,76 @@ +## Color coding: +######################### +## Main FRR: #f08080 red +## Switches: #d0e0d0 gray +## RIP: #19e3d9 Cyan +## RIPng: #fcb314 dark yellow +## OSPFv2: #32b835 Green +## OSPFv3: #19e3d9 Cyan +## ISIS IPv4 #fcb314 dark yellow +## ISIS IPv6 #9a81ec purple +## BGP IPv4 #eee3d3 beige +## BGP IPv6 #fdff00 yellow +##### Colors (see http://www.color-hex.com/) + +graph template { + label="Test Topology - LDP-OC 1"; + + # Routers + r1 [ + shape=doubleoctagon, + label="r1", + fillcolor="#f08080", + style=filled, + ]; + r2 [ + shape=doubleoctagon + label="r2", + fillcolor="#f08080", + style=filled, + ]; + r3 [ + shape=doubleoctagon + label="r3", + fillcolor="#f08080", + style=filled, + ]; + r4 [ + shape=doubleoctagon + label="r4", + fillcolor="#f08080", + style=filled, + ]; + + + # Switches + s0 [ + shape=oval, + label="10.0.1.0/24", + fillcolor="#d0e0d0", + style=filled, + ]; + s1 [ + shape=oval, + label="10.0.2.0/24", + fillcolor="#d0e0d0", + style=filled, + ]; + s2 [ + shape=oval, + label="10.0.3.0/24", + fillcolor="#d0e0d0", + style=filled, + ]; + + # Connections + + r1 -- s0 [label="eth0"]; + r2 -- s0 [label="eth0"]; + + r2 -- s1 [label="eth1"]; + r3 -- s1 [label="eth0"]; + r4 -- s1 [label="eth0"]; + + r2 -- s2 [label="eth2"]; + r3 -- s2 [label="eth1"]; +} diff --git a/tests/topotests/ldp-oc-topo1/test_ldp_oc_topo1.py b/tests/topotests/ldp-oc-topo1/test_ldp_oc_topo1.py new file mode 100755 index 0000000000..eda1b37e52 --- /dev/null +++ b/tests/topotests/ldp-oc-topo1/test_ldp_oc_topo1.py @@ -0,0 +1,227 @@ +#!/usr/bin/env python + +# +# test_ldp_oc_topo1.py +# Part of NetDEF Topology Tests +# +# Copyright (c) 2020 by by Volta Networks +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +""" +test_ldp_oc_topo1.py: Simple FRR/Quagga LDP Test + + +---------+ + | r1 | + | 1.1.1.1 | + +----+----+ + | .1 r1-eth0 + | + ~~~~~~~~~~~~~ + ~~ sw0 ~~ + ~~ 10.0.1.0/24 ~~ + ~~~~~~~~~~~~~ + |10.0.1.0/24 + | + | .2 r2-eth0 + +----+----+ + | r2 | + | 2.2.2.2 | + +--+---+--+ + r2-eth2 .2 | | .2 r2-eth1 + ______/ \______ + / \ + ~~~~~~~~~~~~~ ~~~~~~~~~~~~~ +~~ sw2 ~~ ~~ sw1 ~~ +~~ 10.0.3.0/24 ~~ ~~ 10.0.2.0/24 ~~ + ~~~~~~~~~~~~~ ~~~~~~~~~~~~~ + | / | + \ _________/ | + \ / \ +r3-eth1 .3 | | .3 r3-eth0 | .4 r4-eth0 + +----+--+---+ +----+----+ + | r3 | | r4 | + | 3.3.3.3 | | 4.4.4.4 | + +-----------+ +---------+ +""" + +import os +import sys +import pytest +import json +from time import sleep +from functools import partial + +# Save the Current Working Directory to find configuration files. +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, '../')) + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger + +# Required to instantiate the topology builder class. +from mininet.topo import Topo + +class TemplateTopo(Topo): + "Test topology builder" + def build(self, *_args, **_opts): + "Build function" + tgen = get_topogen(self) + + # + # Define FRR Routers + # + for router in ['r1', 'r2', 'r3', 'r4']: + tgen.add_router(router) + + # + # Define connections + # + switch = tgen.add_switch('s0') + switch.add_link(tgen.gears['r1']) + switch.add_link(tgen.gears['r2']) + + switch = tgen.add_switch('s1') + switch.add_link(tgen.gears['r2']) + switch.add_link(tgen.gears['r3']) + switch.add_link(tgen.gears['r4']) + + switch = tgen.add_switch('s2') + switch.add_link(tgen.gears['r2']) + switch.add_link(tgen.gears['r3']) + +def setup_module(mod): + "Sets up the pytest environment" + tgen = Topogen(TemplateTopo, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + # For all registered routers, load the zebra configuration file + for rname, router in router_list.iteritems(): + router.load_config( + TopoRouter.RD_ZEBRA, + os.path.join(CWD, '{}/zebra.conf'.format(rname)) + ) + # Don't start ospfd and ldpd in the CE nodes + if router.name[0] == 'r': + router.load_config( + TopoRouter.RD_OSPF, + os.path.join(CWD, '{}/ospfd.conf'.format(rname)) + ) + router.load_config( + TopoRouter.RD_LDP, + os.path.join(CWD, '{}/ldpd.conf'.format(rname)) + ) + + tgen.start_router() + +def teardown_module(mod): + "Teardown the pytest environment" + tgen = get_topogen() + + # This function tears down the whole topology. + tgen.stop_topology() + + +def router_compare_json_output(rname, command, reference): + "Compare router JSON output" + + logger.info('Comparing router "%s" "%s" output', rname, command) + + tgen = get_topogen() + filename = '{}/{}/{}'.format(CWD, rname, reference) + expected = json.loads(open(filename).read()) + + # Run test function until we get an result. Wait at most 80 seconds. + test_func = partial(topotest.router_json_cmp, + tgen.gears[rname], command, expected) + _, diff = topotest.run_and_expect(test_func, None, count=160, wait=0.5) + + assertmsg = '"{}" JSON output mismatches the expected result'.format(rname) + assert diff is None, assertmsg + +def test_ospf_convergence(): + logger.info("Test: check OSPF adjacencies") + + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + for rname in ['r1', 'r2', 'r3', 'r4']: + router_compare_json_output(rname, "show ip ospf neighbor json", "show_ip_ospf_neighbor.json") + +def test_rib(): + logger.info("Test: verify RIB") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + for rname in ['r1', 'r2', 'r3', 'r4']: + router_compare_json_output(rname, "show ip route json", "show_ip_route.ref") + +def test_ldp_adjacencies(): + logger.info("Test: verify LDP adjacencies") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + for rname in ['r1', 'r2', 'r3', 'r4']: + router_compare_json_output(rname, "show mpls ldp discovery json", "show_ldp_discovery.ref") + +def test_ldp_neighbors(): + logger.info("Test: verify LDP neighbors") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + for rname in ['r1', 'r2', 'r3', 'r4']: + router_compare_json_output(rname, "show mpls ldp neighbor json", "show_ldp_neighbor.ref") + +def test_ldp_bindings(): + logger.info("Test: verify LDP bindings") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + for rname in ['r1', 'r2', 'r3', 'r4']: + router_compare_json_output(rname, "show mpls ldp binding json", "show_ldp_binding.ref") + +# Memory leak test template +def test_memory_leak(): + "Run the memory leak test and report results." + tgen = get_topogen() + if not tgen.is_memleak_enabled(): + pytest.skip('Memory leak test/report is disabled') + + tgen.report_memory_leaks() + +if __name__ == '__main__': + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/ldp-topo1/r1/ip_mpls_route.ref b/tests/topotests/ldp-topo1/r1/ip_mpls_route.ref index f244122f1a..a13c1d459b 100644 --- a/tests/topotests/ldp-topo1/r1/ip_mpls_route.ref +++ b/tests/topotests/ldp-topo1/r1/ip_mpls_route.ref @@ -3,3 +3,4 @@ xx as to xx via inet 10.0.1.2 dev r1-eth0 proto xx xx via inet 10.0.1.2 dev r1-eth0 proto xx xx via inet 10.0.1.2 dev r1-eth0 proto xx xx via inet 10.0.1.2 dev r1-eth0 proto xx + diff --git a/tests/topotests/lib/bgp.py b/tests/topotests/lib/bgp.py index 997b72d691..15f970ba75 100644 --- a/tests/topotests/lib/bgp.py +++ b/tests/topotests/lib/bgp.py @@ -1256,7 +1256,7 @@ def verify_bgp_attributes(tgen, addr_type, dut, static_routes, rmap_name, } }, "set": { - "localpref": 150, + "locPrf": 150, "weight": 100 } }], @@ -1269,7 +1269,7 @@ def verify_bgp_attributes(tgen, addr_type, dut, static_routes, rmap_name, } }, "set": { - "med": 50 + "metric": 50 } }] } @@ -1406,7 +1406,7 @@ def verify_best_path_as_per_bgp_attribute(tgen, addr_type, router, input_dict, } } } - attribute = "localpref" + attribute = "locPrf" result = verify_best_path_as_per_bgp_attribute(tgen, "ipv4", dut, \ input_dict, attribute) Returns @@ -1443,14 +1443,14 @@ def verify_best_path_as_per_bgp_attribute(tgen, addr_type, router, input_dict, attribute_dict[next_hop_ip] = route_attribute[attribute] # AS_PATH attribute - if attribute == "aspath": + if attribute == "path": # Find next_hop for the route have minimum as_path _next_hop = min(attribute_dict, key=lambda x: len(set( attribute_dict[x]))) compare = "SHORTEST" # LOCAL_PREF attribute - elif attribute == "localpref": + elif attribute == "locPrf": # Find next_hop for the route have highest local preference _next_hop = max(attribute_dict, key=(lambda k: attribute_dict[k])) @@ -1473,7 +1473,7 @@ def verify_best_path_as_per_bgp_attribute(tgen, addr_type, router, input_dict, compare = "" # MED attribute - elif attribute == "med": + elif attribute == "metric": # Find next_hop for the route have LOWEST MED _next_hop = min(attribute_dict, key=(lambda k: attribute_dict[k])) @@ -1548,7 +1548,7 @@ def verify_best_path_as_per_admin_distance(tgen, addr_type, router, input_dict, {"network": "200.50.2.0/32", \ "admin_distance": 60, "next_hop": "10.0.0.18"}] }} - attribute = "localpref" + attribute = "locPrf" result = verify_best_path_as_per_admin_distance(tgen, "ipv4", dut, \ input_dict, attribute): Returns diff --git a/tests/topotests/lib/common_config.py b/tests/topotests/lib/common_config.py index fc7581b1f2..8a9d2d64c9 100644 --- a/tests/topotests/lib/common_config.py +++ b/tests/topotests/lib/common_config.py @@ -1101,9 +1101,9 @@ def create_route_maps(tgen, input_dict, build=False): "tag": "tag_id" }, "set": { - "localpref": 150, - "med": 30, - "aspath": { + "locPrf": 150, + "metric": 30, + "path": { "num": 20000, "action": "prepend", }, @@ -1199,10 +1199,10 @@ def create_route_maps(tgen, input_dict, build=False): set_data = rmap_dict["set"] ipv4_data = set_data.setdefault("ipv4", {}) ipv6_data = set_data.setdefault("ipv6", {}) - local_preference = set_data.setdefault("localpref", + local_preference = set_data.setdefault("locPrf", None) - metric = set_data.setdefault("med", None) - as_path = set_data.setdefault("aspath", {}) + metric = set_data.setdefault("metric", None) + as_path = set_data.setdefault("path", {}) weight = set_data.setdefault("weight", None) community = set_data.setdefault("community", {}) large_community = set_data.setdefault( diff --git a/tests/topotests/pytest.ini b/tests/topotests/pytest.ini index 62c825341f..ade5bfd501 100644 --- a/tests/topotests/pytest.ini +++ b/tests/topotests/pytest.ini @@ -1,6 +1,6 @@ # Skip pytests example directory [pytest] -norecursedirs = .git example-test example-topojson-test lib docker bgp_rr_ibgp +norecursedirs = .git example-test example-topojson-test lib docker [topogen] # Default configuration values diff --git a/tools/gcc-plugins/.gitignore b/tools/gcc-plugins/.gitignore new file mode 100644 index 0000000000..dd8d0cb7ee --- /dev/null +++ b/tools/gcc-plugins/.gitignore @@ -0,0 +1,7 @@ +*.so +*.o +debian/.debhelper +debian/files +debian/*.substvars +debian/gcc-9-frr-plugin +!gcc-retain-typeinfo.patch diff --git a/tools/gcc-plugins/COPYING.GPLv3 b/tools/gcc-plugins/COPYING.GPLv3 new file mode 100644 index 0000000000..94a9ed024d --- /dev/null +++ b/tools/gcc-plugins/COPYING.GPLv3 @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + <program> Copyright (C) <year> <name of author> + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +<http://www.gnu.org/licenses/>. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +<http://www.gnu.org/philosophy/why-not-lgpl.html>. diff --git a/tools/gcc-plugins/Makefile b/tools/gcc-plugins/Makefile new file mode 100644 index 0000000000..d6edd745ce --- /dev/null +++ b/tools/gcc-plugins/Makefile @@ -0,0 +1,19 @@ +all: frr-format.so + +CXX=g++-9 + +PLUGBASE=`$(CXX) -print-file-name=plugin` +CPPFLAGS=-I$(PLUGBASE)/include -I$(PLUGBASE)/include/c-family + +frr-format.so: frr-format.o + $(CXX) -g -shared -o $@ $^ + +frr-format.o: frr-format.c gcc-common.h + $(CXX) -g $(CPPFLAGS) -fPIC -Wall -Wextra -Wno-unused-parameter -c -o $@ $< + +install: + install -d $(DESTDIR)$(PLUGBASE) + install frr-format.so $(DESTDIR)$(PLUGBASE) + +clean: + rm -f frr-format.so frr-format.o diff --git a/tools/gcc-plugins/README.md b/tools/gcc-plugins/README.md new file mode 100644 index 0000000000..94a9635e76 --- /dev/null +++ b/tools/gcc-plugins/README.md @@ -0,0 +1,99 @@ +frr-format GCC plugin +===================== + +Context +------- + +This plugin provides improved type checking for Linux kernel style printf +extensions (i.e. `%pI4` printing `struct in_addr *` as `1.2.3.4`.) + +Other than additional warnings, (non-)usage of this plugin should not affect +the build outcome. It is perfectly fine to build FRR without this plugin. + + +Binary Debian packages +---------------------- + +Can be found at [https://deb.nox.tf/devel/]. + + +GCC requirements +---------------- + +To use this plugin, you need a **patched 9.3.0** version of GCC using the +[gcc-retain-typeinfo.patch] provided in this repo. Without this patch, GCC +strips type information too early during compilation, leaving to the plugin +being unable to perform more meaningful type checks. (Specifically, all +`typedef` types will be "cooked down" to their final type.) + +(@eqvinox has discussed this one-line diff with some GCC people on their +IRC channel around mid 2019, the consensus was that the line is an "early +optimization" and removing it should not be harmful. However, doing so is +likely to break GCC's unit tests since warnings would print different types.) + +Other versions of gcc are not supported. gcc 8 previously did work but isn't +actively tested/maintained. gcc 10 is not supported yet but may work. + + +Usage +----- + +First, all plugin-specific statements should be wrapped by an ifdef: + +``` +#ifdef _FRR_ATTRIBUTE_PRINTFRR +... +#endif +``` + +`_FRR_ATTRIBUTE_PRINTFRR` will be defined to the plugin's version (currently +0x10000) whenever the plugin is loaded. + +Then, annotate extended printf functions with the `frr_format` attribute. +This works exactly like the `format` attribute: + +``` +int printfn(const char *fmt, ...) __attribute__((frr_format("frr_printf", 1, 2))); +``` + +In the FRR codebase, use the `PRINTFRR` macro provided in +[../../lib/compiler.h]. + +Lastly, "declare" extensions with `#pragma FRR printfrr_ext`: +``` +#ifdef _FRR_ATTRIBUTE_PRINTFRR +#pragma FRR printfrr_ext "%pI4" (struct in_addr *) +#pragma FRR printfrr_ext "%pI4" (in_addr_t *) +#endif +``` + +Note that you can use multiple such lines if a particular extended printer +works for more than one type (as seen above.) + +The pragma type "parameter" looks like a C cast but unfortunately due to GCC +not exporting a good interface to proper type parsing, it is "ghetto parsed", +with only `struct`, `union`, `enum` being properly supported. `const` is +ignored if it occurs as the first token. (The plugin always accepts `const` +parameters for printf since printf shouldn't change the passed data it's +printing.) The last token may be zero or more counts of `*`, note that +qualifiers on the intermediate pointers (e.g. `const char * const *`) are not +supported. + + +TODOs and future direction +-------------------------- + +* support two-parameter extension printers that use the precision field + (e.g. `"%.*pI5" (int af, void *addr)` to print an IP address with the + address family in the "precision". + +* port to future GCC versions + +* get the one-liner patch upstreamed + + +License +------- + +This plugin is **derivative of GCC 9.x**. It was created by copying off +`c-format.c`. It must therefore adhere to GCC's GPLv3+ license. diff --git a/tools/gcc-plugins/debian/changelog b/tools/gcc-plugins/debian/changelog new file mode 100644 index 0000000000..62bbbcd46f --- /dev/null +++ b/tools/gcc-plugins/debian/changelog @@ -0,0 +1,5 @@ +gcc-frr-plugin (9.3.0d8+equi2) unstable; urgency=medium + + * package created (+equi1 used during development, never released.) + + -- David Lamparter <equinox-debian@diac24.net> Sun, 29 Mar 2020 08:32:24 +0200 diff --git a/tools/gcc-plugins/debian/compat b/tools/gcc-plugins/debian/compat new file mode 100644 index 0000000000..48082f72f0 --- /dev/null +++ b/tools/gcc-plugins/debian/compat @@ -0,0 +1 @@ +12 diff --git a/tools/gcc-plugins/debian/control b/tools/gcc-plugins/debian/control new file mode 100644 index 0000000000..6a9b886bef --- /dev/null +++ b/tools/gcc-plugins/debian/control @@ -0,0 +1,19 @@ +Source: gcc-frr-plugin +Section: devel +Priority: optional +Maintainer: David Lamparter <equinox-debian@diac24.net> +Build-Depends: + gcc-9-plugin-dev (=9.3.0-8+equi1), + debhelper (>= 12) +Standards-Version: 4.4.1 +Homepage: https://www.frrouting.org/ +Vcs-Browser: https://github.com/FRRouting/frr/ +Vcs-Git: https://github.com/FRRouting/frr.git + +Package: gcc-9-frr-plugin +Architecture: linux-any +Depends: + gcc-9 (=9.3.0-8+equi1), + ${misc:Depends}, + ${shlibs:Depends} +Description: GCC plugin for FRRouting diff --git a/tools/gcc-plugins/debian/copyright b/tools/gcc-plugins/debian/copyright new file mode 100644 index 0000000000..dcd9fa1770 --- /dev/null +++ b/tools/gcc-plugins/debian/copyright @@ -0,0 +1,9 @@ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: FRR +Upstream-Contact: maintainers@frrouting.org, security@frrouting.org +Source: https://www.frrouting.org/ + +Files: * +Copyright: + 2019-2020 by David Lamparter + Code derived from GCC, please refer to gcc package copyright. diff --git a/tools/gcc-plugins/debian/rules b/tools/gcc-plugins/debian/rules new file mode 100755 index 0000000000..f8f42ad337 --- /dev/null +++ b/tools/gcc-plugins/debian/rules @@ -0,0 +1,11 @@ +#!/usr/bin/make -f + +# standard Debian options & profiles + +export DEB_BUILD_MAINT_OPTIONS = hardening=+all + +%: + dh $@ + +override_dh_auto_test: + true diff --git a/tools/gcc-plugins/debian/source/format b/tools/gcc-plugins/debian/source/format new file mode 100644 index 0000000000..af745b310b --- /dev/null +++ b/tools/gcc-plugins/debian/source/format @@ -0,0 +1 @@ +3.0 (git) diff --git a/tools/gcc-plugins/format-test.c b/tools/gcc-plugins/format-test.c new file mode 100644 index 0000000000..b031ca5ece --- /dev/null +++ b/tools/gcc-plugins/format-test.c @@ -0,0 +1,107 @@ +#include <stddef.h> +#include <stdlib.h> +#include <netinet/in.h> +#include <sys/types.h> +#include <unistd.h> + +typedef unsigned long mytype; +typedef size_t mysize; + +typedef unsigned int not_in_addr_t; +typedef in_addr_t yes_in_addr_t; +typedef struct in_addr in_addr_s; + +struct other { + int x; +}; + +int testfn(const char *fmt, ...) __attribute__((frr_format("frr_printf", 1, 2))); + +#ifndef _FRR_ATTRIBUTE_PRINTFRR +#error please load the frr-format plugin +#endif + +#pragma FRR printfrr_ext "%pI4" (struct in_addr *) +#pragma FRR printfrr_ext "%pI4" (in_addr_t *) + +int test(unsigned long long ay) +{ + size_t v_size_t = 0; + long v_long = 0; + int v_int = 0; + uint64_t v_uint64_t = 0; + mytype v_mytype = 0; + mysize v_mysize = 0; + pid_t v_pid_t = 0; + + testfn("%zu", v_size_t); // NOWARN + testfn("%zu", v_long); // WARN + testfn("%zu", v_int); // WARN + testfn("%zu", sizeof(v_int)); // NOWARN + testfn("%zu", v_mytype); // WARN + testfn("%zu", v_mysize); // NOWARN + testfn("%zu", v_uint64_t); // WARN + testfn("%zu", v_pid_t); // WARN + + testfn("%lu", v_long); // NOWARN PEDANTIC + testfn("%lu", v_int); // WARN + testfn("%lu", v_size_t); // WARN + testfn("%lu", sizeof(v_int)); // NOWARN (integer constant) + testfn("%lu", v_uint64_t); // WARN + testfn("%lu", v_pid_t); // WARN + + testfn("%ld", v_long); // NOWARN + testfn("%ld", v_int); // WARN + testfn("%ld", v_size_t); // WARN + testfn("%ld", sizeof(v_int)); // NOWARN (integer constant) + testfn("%ld", v_uint64_t); // WARN + testfn("%ld", v_pid_t); // WARN + + testfn("%d", v_int); // NOWARN + testfn("%d", v_long); // WARN + testfn("%d", v_size_t); // WARN + testfn("%d", sizeof(v_int)); // WARN + testfn("%d", v_uint64_t); // WARN + testfn("%d", v_pid_t); // WARN + + testfn("%Lu", v_size_t); // WARN + testfn("%Lu", v_long); // WARN + testfn("%Lu", v_int); // WARN + testfn("%Lu", sizeof(v_int)); // NOWARN (integer constant) + testfn("%Lu", v_mytype); // WARN + testfn("%Lu", v_mysize); // WARN + testfn("%Lu", v_pid_t); // WARN + testfn("%Lu", v_uint64_t); // NOWARN + + testfn("%Ld", v_size_t); // WARN + testfn("%Ld", v_long); // WARN + testfn("%Ld", v_int); // WARN + testfn("%Ld", sizeof(v_int)); // NOWARN (integer constant) + testfn("%Ld", v_mytype); // WARN + testfn("%Ld", v_mysize); // WARN + testfn("%Ld", v_pid_t); // WARN + testfn("%Ld", v_uint64_t); // NOWARN + + testfn("%pI4", &v_long); // WARN + + in_addr_t v_in_addr_t; + yes_in_addr_t v_yes_in_addr_t; + not_in_addr_t v_not_in_addr_t; + void *v_voidp = &v_in_addr_t; + + testfn("%pI4", &v_in_addr_t); // NOWARN + testfn("%pI4", &v_yes_in_addr_t); // NOWARN + testfn("%pI4", &v_not_in_addr_t); // WARN + testfn("%pI4", v_voidp); // WARN + + struct in_addr v_in_addr; + in_addr_s v_in_addr_s; + struct other v_other; + const struct in_addr *v_in_addr_const = &v_in_addr; + + testfn("%pI4", &v_in_addr); // NOWARN + testfn("%pI4", &v_in_addr_s); // NOWARN + testfn("%pI4", &v_other); // WARN + testfn("%pI4", v_in_addr_const); // NOWARN + return 0; +} diff --git a/tools/gcc-plugins/format-test.py b/tools/gcc-plugins/format-test.py new file mode 100644 index 0000000000..cc6ca6100e --- /dev/null +++ b/tools/gcc-plugins/format-test.py @@ -0,0 +1,57 @@ +import subprocess +import sys +import shlex +import os +import re + +os.environ['LC_ALL'] = 'C' +os.environ['LANG'] = 'C' +for k in list(os.environ.keys()): + if k.startswith('LC_'): + os.environ.pop(k) + +c_re = re.compile(r'//\s+(NO)?WARN') +expect = {} +lines = {} + +with open('format-test.c', 'r') as fd: + for lno, line in enumerate(fd.readlines(), 1): + lines[lno] = line.strip() + m = c_re.search(line) + if m is None: + continue + if m.group(1) is None: + expect[lno] = 'warn' + else: + expect[lno] = 'nowarn' + +cmd = shlex.split('gcc -Wall -Wextra -Wno-unused -fplugin=./frr-format.so -fno-diagnostics-show-caret -c -o format-test.o format-test.c') + +gcc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) +sout, serr = gcc.communicate() +gcc.wait() + +gcclines = serr.decode('UTF-8').splitlines() +line_re = re.compile(r'^format-test\.c:(\d+):(.*)$') +gcc_warns = {} + +for line in gcclines: + if line.find('In function') >= 0: + continue + m = line_re.match(line) + if m is None: + sys.stderr.write('cannot process GCC output: %s\n' % line) + continue + + lno = int(m.group(1)) + gcc_warns.setdefault(lno, []).append(line) + +for lno, val in expect.items(): + if val == 'nowarn' and lno in gcc_warns: + sys.stderr.write('unexpected gcc warning on line %d:\n\t%s\n\t%s\n' % (lno, lines[lno], '\n\t'.join(gcc_warns[lno]))) + if val == 'warn' and lno not in gcc_warns: + sys.stderr.write('expected warning on line %d but did not get one\n\t%s\n' % (lno, lines[lno])) + +leftover = set(gcc_warns.keys()) - set(expect.keys()) +for lno in sorted(leftover): + sys.stderr.write('unmarked gcc warning on line %d:\n\t%s\n\t%s\n' % (lno, lines[lno], '\n\t'.join(gcc_warns[lno]))) diff --git a/tools/gcc-plugins/frr-format.c b/tools/gcc-plugins/frr-format.c new file mode 100644 index 0000000000..174f403d48 --- /dev/null +++ b/tools/gcc-plugins/frr-format.c @@ -0,0 +1,4457 @@ +/* Check calls to formatted I/O functions (-Wformat). + Copyright (C) 1992-2019 Free Software Foundation, Inc. + + Extended for FRR's printfrr() with Linux kernel style extensions + Copyright (C) 2019-2020 David Lamparter, for NetDEF, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING.GPLv3. If not see +<http://www.gnu.org/licenses/>. */ + +#include "gcc-common.h" + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +//include "c-target.h" +#include "c-common.h" +#include "alloc-pool.h" +#include "stringpool.h" +#include "c-tree.h" +#include "c-objc.h" +#include "intl.h" +#include "langhooks.h" +#include "frr-format.h" +#include "diagnostic.h" +#include "substring-locations.h" +#include "selftest.h" +#include "selftest-diagnostic.h" +#ifndef FIRST_PSEUDO_REGISTER +#define FIRST_PSEUDO_REGISTER 0 +#endif +#include "builtins.h" +#include "attribs.h" +#include "gcc-rich-location.h" +#include "c-pretty-print.h" +#include "c-pragma.h" + +extern struct cpp_reader *parse_in; + +#pragma GCC visibility push(hidden) + +/* Handle attributes associated with format checking. */ + +/* This must be in the same order as format_types, except for + format_type_error. Target-specific format types do not have + matching enum values. */ +enum format_type { frr_printf_format_type, + format_type_error = -1}; + +struct function_format_info +{ + int format_type; /* type of format (printf, scanf, etc.) */ + unsigned HOST_WIDE_INT format_num; /* number of format argument */ + unsigned HOST_WIDE_INT first_arg_num; /* number of first arg (zero for varargs) */ +}; + +static GTY(()) tree local_uint64_t_node; +static GTY(()) tree local_int64_t_node; + +static GTY(()) tree local_size_t_node; +static GTY(()) tree local_ssize_t_node; +static GTY(()) tree local_atomic_size_t_node; +static GTY(()) tree local_atomic_ssize_t_node; +static GTY(()) tree local_ptrdiff_t_node; + +static GTY(()) tree local_pid_t_node; +static GTY(()) tree local_uid_t_node; +static GTY(()) tree local_gid_t_node; +static GTY(()) tree local_time_t_node; + +static GTY(()) tree local_socklen_t_node; +static GTY(()) tree local_in_addr_t_node; + +static struct type_special { + tree *match; + tree *replace; + tree *cousin; +} special_types[] = { + { &local_atomic_size_t_node, &local_size_t_node, &local_ssize_t_node, }, + { &local_atomic_ssize_t_node, &local_ssize_t_node, &local_size_t_node, }, + { &local_size_t_node, NULL, &local_ssize_t_node, }, + { &local_ssize_t_node, NULL, &local_size_t_node, }, + { &local_uint64_t_node, NULL, &local_int64_t_node, }, + { &local_int64_t_node, NULL, &local_uint64_t_node, }, + { &local_pid_t_node, NULL, &local_pid_t_node, }, + { &local_uid_t_node, NULL, &local_uid_t_node, }, + { &local_gid_t_node, NULL, &local_gid_t_node, }, + { &local_time_t_node, NULL, &local_time_t_node, }, + { NULL, NULL, NULL, } +}; + +static bool decode_format_attr (tree, function_format_info *, int); +static int decode_format_type (const char *); + +static bool check_format_string (tree argument, + unsigned HOST_WIDE_INT format_num, + int flags, bool *no_add_attrs, + int expected_format_type); +static bool get_constant (tree expr, unsigned HOST_WIDE_INT *value, + int validated_p); +static const char *convert_format_name_to_system_name (const char *attr_name); + +static int first_target_format_type; +static const char *format_name (int format_num); +static int format_flags (int format_num); + +/* Emit a warning as per format_warning_va, but construct the substring_loc + for the character at offset (CHAR_IDX - 1) within a string constant + FORMAT_STRING_CST at FMT_STRING_LOC. */ + +ATTRIBUTE_GCC_DIAG (5,6) +static bool +format_warning_at_char (location_t fmt_string_loc, tree format_string_cst, + int char_idx, int opt, const char *gmsgid, ...) +{ + va_list ap; + va_start (ap, gmsgid); + tree string_type = TREE_TYPE (format_string_cst); + + /* The callers are of the form: + format_warning (format_string_loc, format_string_cst, + format_chars - orig_format_chars, + where format_chars has already been incremented, so that + CHAR_IDX is one character beyond where the warning should + be emitted. Fix it. */ + char_idx -= 1; + + substring_loc fmt_loc (fmt_string_loc, string_type, char_idx, char_idx, + char_idx); +#if BUILDING_GCC_VERSION >= 9000 + format_string_diagnostic_t diag (fmt_loc, NULL, UNKNOWN_LOCATION, NULL, + NULL); + bool warned = diag.emit_warning_va (opt, gmsgid, &ap); +#else + bool warned = format_warning_va (fmt_loc, UNKNOWN_LOCATION, NULL, + opt, gmsgid, &ap); +#endif + va_end (ap); + + return warned; +} + +/* Check that we have a pointer to a string suitable for use as a format. + The default is to check for a char type. + For objective-c dialects, this is extended to include references to string + objects validated by objc_string_ref_type_p (). + Targets may also provide a string object type that can be used within c and + c++ and shared with their respective objective-c dialects. In this case the + reference to a format string is checked for validity via a hook. + + The function returns true if strref points to any string type valid for the + language dialect and target. */ + +static bool +valid_stringptr_type_p (tree strref) +{ + return (strref != NULL + && TREE_CODE (strref) == POINTER_TYPE + && (TYPE_MAIN_VARIANT (TREE_TYPE (strref)) == char_type_node + || objc_string_ref_type_p (strref))); +// || (*targetcm.string_object_ref_type_p) ((const_tree) strref))); +} + +/* Handle a "format_arg" attribute; arguments as in + struct attribute_spec.handler. */ +tree +handle_frr_format_arg_attribute (tree *node, tree ARG_UNUSED (name), + tree args, int flags, bool *no_add_attrs) +{ + tree type = *node; + tree format_num_expr = TREE_VALUE (args); + unsigned HOST_WIDE_INT format_num = 0; + + if (!get_constant (format_num_expr, &format_num, 0)) + { + error ("format string has invalid operand number"); + *no_add_attrs = true; + return NULL_TREE; + } + + if (prototype_p (type)) + { + /* The format arg can be any string reference valid for the language and + target. We cannot be more specific in this case. */ + if (!check_format_string (type, format_num, flags, no_add_attrs, -1)) + return NULL_TREE; + } + + if (!valid_stringptr_type_p (TREE_TYPE (type))) + { + if (!(flags & (int) ATTR_FLAG_BUILT_IN)) + error ("function does not return string type"); + *no_add_attrs = true; + return NULL_TREE; + } + + return NULL_TREE; +} + +/* Verify that the format_num argument is actually a string reference suitable, + for the language dialect and target (in case the format attribute is in + error). When we know the specific reference type expected, this is also + checked. */ +static bool +check_format_string (tree fntype, unsigned HOST_WIDE_INT format_num, + int flags, bool *no_add_attrs, int expected_format_type) +{ + unsigned HOST_WIDE_INT i; + bool is_target_sref, is_char_ref; + tree ref; + int fmt_flags; + function_args_iterator iter; + + i = 1; + FOREACH_FUNCTION_ARGS (fntype, ref, iter) + { + if (i == format_num) + break; + i++; + } + + if (!ref + || !valid_stringptr_type_p (ref)) + { + if (!(flags & (int) ATTR_FLAG_BUILT_IN)) + error ("format string argument is not a string type"); + *no_add_attrs = true; + return false; + } + + /* We only know that we want a suitable string reference. */ + if (expected_format_type < 0) + return true; + + /* Now check that the arg matches the expected type. */ + is_char_ref = + (TYPE_MAIN_VARIANT (TREE_TYPE (ref)) == char_type_node); + + fmt_flags = format_flags (expected_format_type); + is_target_sref = false; + + if (!(fmt_flags & FMT_FLAG_PARSE_ARG_CONVERT_EXTERNAL)) + { + if (is_char_ref) + return true; /* OK, we expected a char and found one. */ + else + { + error ("found a %qT but the format argument should be a string", + ref); + *no_add_attrs = true; + return false; + } + } + + /* We expect a string object type as the format arg. */ + if (is_char_ref) + { + error ("format argument should be a %qs reference but" + " a string was found", format_name (expected_format_type)); + *no_add_attrs = true; + return false; + } + + /* We will allow a target string ref to match only itself. */ + if (first_target_format_type + && expected_format_type >= first_target_format_type + && is_target_sref) + return true; + else + { + error ("format argument should be a %qs reference", + format_name (expected_format_type)); + *no_add_attrs = true; + return false; + } + + gcc_unreachable (); +} + +/* Verify EXPR is a constant, and store its value. + If validated_p is true there should be no errors. + Returns true on success, false otherwise. */ +static bool +get_constant (tree expr, unsigned HOST_WIDE_INT *value, int validated_p) +{ + if (!tree_fits_uhwi_p (expr)) + { + gcc_assert (!validated_p); + return false; + } + + *value = TREE_INT_CST_LOW (expr); + + return true; +} + +/* Decode the arguments to a "format" attribute into a + function_format_info structure. It is already known that the list + is of the right length. If VALIDATED_P is true, then these + attributes have already been validated and must not be erroneous; + if false, it will give an error message. Returns true if the + attributes are successfully decoded, false otherwise. */ + +static bool +decode_format_attr (tree args, function_format_info *info, int validated_p) +{ + tree format_type_id = TREE_VALUE (args); + tree format_num_expr = TREE_VALUE (TREE_CHAIN (args)); + tree first_arg_num_expr + = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args))); + + if (TREE_CODE (format_type_id) != STRING_CST) + { + gcc_assert (!validated_p); + error ("unrecognized format specifier"); + return false; + } + else + { + const char *p = TREE_STRING_POINTER (format_type_id); + + p = convert_format_name_to_system_name (p); + + info->format_type = decode_format_type (p); + + if (info->format_type == format_type_error) + { + gcc_assert (!validated_p); + warning (OPT_Wformat_, "%qE is an unrecognized format function type", + format_type_id); + return false; + } + } + + if (!get_constant (format_num_expr, &info->format_num, validated_p)) + { + error ("format string has invalid operand number"); + return false; + } + + if (!get_constant (first_arg_num_expr, &info->first_arg_num, validated_p)) + { + error ("%<...%> has invalid operand number"); + return false; + } + + if (info->first_arg_num != 0 && info->first_arg_num <= info->format_num) + { + gcc_assert (!validated_p); + error ("format string argument follows the args to be formatted"); + return false; + } + + return true; +} + +/* Check a call to a format function against a parameter list. */ + +/* The C standard version C++ is treated as equivalent to + or inheriting from, for the purpose of format features supported. */ +#define CPLUSPLUS_STD_VER (cxx_dialect < cxx11 ? STD_C94 : STD_C99) +/* The C standard version we are checking formats against when pedantic. */ +#define C_STD_VER ((int) (c_dialect_cxx () \ + ? CPLUSPLUS_STD_VER \ + : (flag_isoc99 \ + ? STD_C99 \ + : (flag_isoc94 ? STD_C94 : STD_C89)))) +/* The name to give to the standard version we are warning about when + pedantic. FEATURE_VER is the version in which the feature warned out + appeared, which is higher than C_STD_VER. */ +#define C_STD_NAME(FEATURE_VER) (c_dialect_cxx () \ + ? (cxx_dialect < cxx11 ? "ISO C++98" \ + : "ISO C++11") \ + : ((FEATURE_VER) == STD_EXT \ + ? "ISO C" \ + : "ISO C90")) +/* Adjust a C standard version, which may be STD_C9L, to account for + -Wno-long-long. Returns other standard versions unchanged. */ +#define ADJ_STD(VER) ((int) ((VER) == STD_C9L \ + ? (warn_long_long ? STD_C99 : STD_C89) \ + : (VER))) + +/* Enum describing the kind of specifiers present in the format and + requiring an argument. */ +enum format_specifier_kind { + CF_KIND_FORMAT, + CF_KIND_FIELD_WIDTH, + CF_KIND_FIELD_PRECISION +}; + +static const char *kind_descriptions[] = { + N_("format"), + N_("field width specifier"), + N_("field precision specifier") +}; + +/* Structure describing details of a type expected in format checking, + and the type to check against it. */ +struct format_wanted_type +{ + /* The type wanted. */ + tree wanted_type; + /* The name of this type to use in diagnostics. */ + const char *wanted_type_name; + /* Should be type checked just for scalar width identity. */ + int scalar_identity_flag; + /* The level of indirection through pointers at which this type occurs. */ + int pointer_count; + /* Whether, when pointer_count is 1, to allow any character type when + pedantic, rather than just the character or void type specified. */ + int char_lenient_flag; + /* Whether the argument, dereferenced once, is written into and so the + argument must not be a pointer to a const-qualified type. */ + int writing_in_flag; + /* Whether the argument, dereferenced once, is read from and so + must not be a NULL pointer. */ + int reading_from_flag; + /* The kind of specifier that this type is used for. */ + enum format_specifier_kind kind; + /* The starting character of the specifier. This never includes the + initial percent sign. */ + const char *format_start; + /* The length of the specifier. */ + int format_length; + /* The actual parameter to check against the wanted type. */ + tree param; + /* The argument number of that parameter. */ + int arg_num; + /* The offset location of this argument with respect to the format + string location. */ + unsigned int offset_loc; + /* The next type to check for this format conversion, or NULL if none. */ + struct format_wanted_type *next; +}; + +/* Convenience macro for format_length_info meaning unused. */ +#define NO_FMT NULL, FMT_LEN_none, STD_C89 + +static const format_length_info printf_length_specs[] = +{ + { "h", FMT_LEN_h, STD_C89, "hh", FMT_LEN_hh, STD_C99, 0 }, + { "l", FMT_LEN_l, STD_C89, "ll", FMT_LEN_ll, STD_C9L, 0 }, + { "q", FMT_LEN_ll, STD_EXT, NO_FMT, 0 }, + { "L", FMT_LEN_L, STD_C89, NO_FMT, 0 }, + { "z", FMT_LEN_z, STD_C99, NO_FMT, 0 }, + { "Z", FMT_LEN_z, STD_EXT, NO_FMT, 0 }, + { "t", FMT_LEN_t, STD_C99, NO_FMT, 0 }, + { "j", FMT_LEN_j, STD_C99, NO_FMT, 0 }, + { "H", FMT_LEN_H, STD_EXT, NO_FMT, 0 }, + { "D", FMT_LEN_D, STD_EXT, "DD", FMT_LEN_DD, STD_EXT, 0 }, + { NO_FMT, NO_FMT, 0 } +}; + +static const format_flag_spec printf_flag_specs[] = +{ + { ' ', 0, 0, 0, N_("' ' flag"), N_("the ' ' printf flag"), STD_C89 }, + { '+', 0, 0, 0, N_("'+' flag"), N_("the '+' printf flag"), STD_C89 }, + { '#', 0, 0, 0, N_("'#' flag"), N_("the '#' printf flag"), STD_C89 }, + { '0', 0, 0, 0, N_("'0' flag"), N_("the '0' printf flag"), STD_C89 }, + { '-', 0, 0, 0, N_("'-' flag"), N_("the '-' printf flag"), STD_C89 }, + { '\'', 0, 0, 0, N_("''' flag"), N_("the ''' printf flag"), STD_EXT }, + { 'I', 0, 0, 0, N_("'I' flag"), N_("the 'I' printf flag"), STD_EXT }, + { 'w', 0, 0, 0, N_("field width"), N_("field width in printf format"), STD_C89 }, + { 'p', 0, 0, 0, N_("precision"), N_("precision in printf format"), STD_C89 }, + { 'L', 0, 0, 0, N_("length modifier"), N_("length modifier in printf format"), STD_C89 }, + { 0, 0, 0, 0, NULL, NULL, STD_C89 } +}; + + +static const format_flag_pair printf_flag_pairs[] = +{ + { ' ', '+', 1, 0 }, + { '0', '-', 1, 0 }, + { '0', 'p', 1, 'i' }, + { 0, 0, 0, 0 } +}; + +#define ETAB_SZ 128 +static kernel_ext_fmt ext_p[ETAB_SZ] = { + { NULL } +}; +static kernel_ext_fmt ext_d[ETAB_SZ] = { + { NULL } +}; + +static const format_char_info print_char_table[] = +{ + /* C89 conversion specifiers. */ + /* none, hh, h, l, ll, L, z, t, j, H, D, DD */ + { "di", 0, STD_C89, { T89_I, T99_SC, T89_S, T89_L, T9L_LL, TEX_S64, T99_SST, T99_PD, T99_IM, BADLEN, BADLEN, BADLEN }, "-wp0 +'I", "i", NULL, ext_d }, + { "oxX", 0, STD_C89, { T89_UI, T99_UC, T89_US, T89_UL, T9L_ULL, TEX_U64, T99_ST, T99_UPD, T99_UIM, BADLEN, BADLEN, BADLEN }, "-wp0#", "i", NULL, NULL }, + { "u", 0, STD_C89, { T89_UI, T99_UC, T89_US, T89_UL, T9L_ULL, TEX_U64, T99_ST, T99_UPD, T99_UIM, BADLEN, BADLEN, BADLEN }, "-wp0'I", "i", NULL, NULL }, + { "fgG", 0, STD_C89, { T89_D, BADLEN, BADLEN, T99_D, BADLEN, T89_LD, BADLEN, BADLEN, BADLEN, TEX_D32, TEX_D64, TEX_D128 }, "-wp0 +#'I", "", NULL, NULL }, + { "eE", 0, STD_C89, { T89_D, BADLEN, BADLEN, T99_D, BADLEN, T89_LD, BADLEN, BADLEN, BADLEN, TEX_D32, TEX_D64, TEX_D128 }, "-wp0 +#I", "", NULL, NULL }, + { "c", 0, STD_C89, { T89_I, BADLEN, BADLEN, T94_WI, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-w", "", NULL, NULL }, + { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, T94_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp", "cR", NULL, NULL }, + { "p", 1, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp", "c", NULL, ext_p }, + { "n", 1, STD_C89, { T89_I, T99_SC, T89_S, T89_L, T9L_LL, BADLEN, T99_SST, T99_PD, T99_IM, BADLEN, BADLEN, BADLEN }, "", "W", NULL, NULL }, + /* C99 conversion specifiers. */ + { "F", 0, STD_C99, { T99_D, BADLEN, BADLEN, T99_D, BADLEN, T99_LD, BADLEN, BADLEN, BADLEN, TEX_D32, TEX_D64, TEX_D128 }, "-wp0 +#'I", "", NULL, NULL }, + { "aA", 0, STD_C99, { T99_D, BADLEN, BADLEN, T99_D, BADLEN, T99_LD, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp0 +#", "", NULL, NULL }, + /* X/Open conversion specifiers. */ + { "C", 0, STD_EXT, { TEX_WI, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-w", "", NULL, NULL }, + { "S", 1, STD_EXT, { TEX_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp", "R", NULL, NULL }, + /* GNU conversion specifiers. */ + { "m", 0, STD_EXT, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp", "", NULL, NULL }, + { NULL, 0, STD_C89, NOLENGTHS, NULL, NULL, NULL, NULL } +}; + +/* This must be in the same order as enum format_type. */ +static const format_kind_info format_types_orig[] = +{ + { "frr_printf", printf_length_specs, print_char_table, " +#0-'I", NULL, + printf_flag_specs, printf_flag_pairs, + FMT_FLAG_ARG_CONVERT|FMT_FLAG_DOLLAR_MULTIPLE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_EMPTY_PREC_OK, + 'w', 0, 'p', 0, 'L', 0, + &integer_type_node, &integer_type_node + }, +}; + +/* This layer of indirection allows GCC to reassign format_types with + new data if necessary, while still allowing the original data to be + const. */ +static const format_kind_info *format_types = format_types_orig; + +static int n_format_types = ARRAY_SIZE (format_types_orig); + +/* Structure detailing the results of checking a format function call + where the format expression may be a conditional expression with + many leaves resulting from nested conditional expressions. */ +struct format_check_results +{ + /* Number of leaves of the format argument that could not be checked + as they were not string literals. */ + int number_non_literal; + /* Number of leaves of the format argument that were null pointers or + string literals, but had extra format arguments. */ + int number_extra_args; + location_t extra_arg_loc; + /* Number of leaves of the format argument that were null pointers or + string literals, but had extra format arguments and used $ operand + numbers. */ + int number_dollar_extra_args; + /* Number of leaves of the format argument that were wide string + literals. */ + int number_wide; + /* Number of leaves of the format argument that are not array of "char". */ + int number_non_char; + /* Number of leaves of the format argument that were empty strings. */ + int number_empty; + /* Number of leaves of the format argument that were unterminated + strings. */ + int number_unterminated; + /* Number of leaves of the format argument that were not counted above. */ + int number_other; + /* Location of the format string. */ + location_t format_string_loc; +}; + +struct format_check_context +{ + format_check_results *res; + function_format_info *info; + tree params; + vec<location_t> *arglocs; +}; + +/* Return the format name (as specified in the original table) for the format + type indicated by format_num. */ +static const char * +format_name (int format_num) +{ + if (format_num >= 0 && format_num < n_format_types) + return format_types[format_num].name; + gcc_unreachable (); +} + +/* Return the format flags (as specified in the original table) for the format + type indicated by format_num. */ +static int +format_flags (int format_num) +{ + if (format_num >= 0 && format_num < n_format_types) + return format_types[format_num].flags; + gcc_unreachable (); +} + +static void check_format_info (function_format_info *, tree, + vec<location_t> *); +static void check_format_arg (void *, tree, unsigned HOST_WIDE_INT); +static void check_format_info_main (format_check_results *, + function_format_info *, const char *, + location_t, tree, + int, tree, + unsigned HOST_WIDE_INT, + object_allocator<format_wanted_type> &, + vec<location_t> *); + +static void init_dollar_format_checking (int, tree); +static int maybe_read_dollar_number (const char **, int, + tree, tree *, const format_kind_info *); +static bool avoid_dollar_number (const char *); +static void finish_dollar_format_checking (format_check_results *, int); + +static const format_flag_spec *get_flag_spec (const format_flag_spec *, + int, const char *); + +static void check_format_types (const substring_loc &fmt_loc, + format_wanted_type *, + const format_kind_info *fki, + int offset_to_type_start, + char conversion_char, + vec<location_t> *arglocs); +static void format_type_warning (const substring_loc &fmt_loc, + location_t param_loc, + format_wanted_type *, tree, + tree, + const format_kind_info *fki, + int offset_to_type_start, + char conversion_char, + const char *extra = NULL); + +static bool check_kef_type (const substring_loc &fmt_loc, + const struct kernel_ext_fmt *kef, + unsigned arg_num, + tree cur_param, + tree wanted_type, + const format_kind_info *fki, + int offset_to_type_start, + char conversion_char, + vec<location_t> *arglocs); + +/* Decode a format type from a string, returning the type, or + format_type_error if not valid, in which case the caller should print an + error message. */ +static int +decode_format_type (const char *s) +{ + int i; + int slen; + + s = convert_format_name_to_system_name (s); + slen = strlen (s); + for (i = 0; i < n_format_types; i++) + { + int alen; + if (!strcmp (s, format_types[i].name)) + return i; + alen = strlen (format_types[i].name); + if (slen == alen + 4 && s[0] == '_' && s[1] == '_' + && s[slen - 1] == '_' && s[slen - 2] == '_' + && !strncmp (s + 2, format_types[i].name, alen)) + return i; + } + return format_type_error; +} + + +/* Check the argument list of a call to printf, scanf, etc. + ATTRS are the attributes on the function type. There are NARGS argument + values in the array ARGARRAY. + Also, if -Wsuggest-attribute=format, + warn for calls to vprintf or vscanf in functions with no such format + attribute themselves. */ + +void +check_function_format (tree attrs, int nargs, tree *argarray, + vec<location_t> *arglocs) +{ + tree a; + + /* See if this function has any format attributes. */ + for (a = attrs; a; a = TREE_CHAIN (a)) + { + if (is_attribute_p ("frr_format", TREE_PURPOSE (a))) + { + /* Yup; check it. */ + function_format_info info; + decode_format_attr (TREE_VALUE (a), &info, /*validated=*/true); + if (warn_format) + { + /* FIXME: Rewrite all the internal functions in this file + to use the ARGARRAY directly instead of constructing this + temporary list. */ + tree params = NULL_TREE; + int i; + for (i = nargs - 1; i >= 0; i--) + params = tree_cons (NULL_TREE, argarray[i], params); + check_format_info (&info, params, arglocs); + } + + /* Attempt to detect whether the current function might benefit + from the format attribute if the called function is decorated + with it. Avoid using calls with string literal formats for + guidance since those are unlikely to be viable candidates. */ + if (warn_suggest_attribute_format + && current_function_decl != NULL_TREE + && info.first_arg_num == 0 + && (format_types[info.format_type].flags + & (int) FMT_FLAG_ARG_CONVERT) + /* c_strlen will fail for a function parameter but succeed + for a literal or constant array. */ + && !c_strlen (argarray[info.format_num - 1], 1)) + { + tree c; + for (c = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl)); + c; + c = TREE_CHAIN (c)) + if (is_attribute_p ("frr_format", TREE_PURPOSE (c)) + && (decode_format_type (IDENTIFIER_POINTER + (TREE_VALUE (TREE_VALUE (c)))) + == info.format_type)) + break; + if (c == NULL_TREE) + { + /* Check if the current function has a parameter to which + the format attribute could be attached; if not, it + can't be a candidate for a format attribute, despite + the vprintf-like or vscanf-like call. */ + tree args; + for (args = DECL_ARGUMENTS (current_function_decl); + args != 0; + args = DECL_CHAIN (args)) + { + if (TREE_CODE (TREE_TYPE (args)) == POINTER_TYPE + && (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (args))) + == char_type_node)) + break; + } + if (args != 0) + warning (OPT_Wsuggest_attribute_format, "function %qD " + "might be a candidate for %qs frr_format attribute", + current_function_decl, + format_types[info.format_type].name); + } + } + } + } +} + + +/* Variables used by the checking of $ operand number formats. */ +static char *dollar_arguments_used = NULL; +static char *dollar_arguments_pointer_p = NULL; +static int dollar_arguments_alloc = 0; +static int dollar_arguments_count; +static int dollar_first_arg_num; +static int dollar_max_arg_used; +static int dollar_format_warned; + +/* Initialize the checking for a format string that may contain $ + parameter number specifications; we will need to keep track of whether + each parameter has been used. FIRST_ARG_NUM is the number of the first + argument that is a parameter to the format, or 0 for a vprintf-style + function; PARAMS is the list of arguments starting at this argument. */ + +static void +init_dollar_format_checking (int first_arg_num, tree params) +{ + tree oparams = params; + + dollar_first_arg_num = first_arg_num; + dollar_arguments_count = 0; + dollar_max_arg_used = 0; + dollar_format_warned = 0; + if (first_arg_num > 0) + { + while (params) + { + dollar_arguments_count++; + params = TREE_CHAIN (params); + } + } + if (dollar_arguments_alloc < dollar_arguments_count) + { + free (dollar_arguments_used); + free (dollar_arguments_pointer_p); + dollar_arguments_alloc = dollar_arguments_count; + dollar_arguments_used = XNEWVEC (char, dollar_arguments_alloc); + dollar_arguments_pointer_p = XNEWVEC (char, dollar_arguments_alloc); + } + if (dollar_arguments_alloc) + { + memset (dollar_arguments_used, 0, dollar_arguments_alloc); + if (first_arg_num > 0) + { + int i = 0; + params = oparams; + while (params) + { + dollar_arguments_pointer_p[i] = (TREE_CODE (TREE_TYPE (TREE_VALUE (params))) + == POINTER_TYPE); + params = TREE_CHAIN (params); + i++; + } + } + } +} + + +/* Look for a decimal number followed by a $ in *FORMAT. If DOLLAR_NEEDED + is set, it is an error if one is not found; otherwise, it is OK. If + such a number is found, check whether it is within range and mark that + numbered operand as being used for later checking. Returns the operand + number if found and within range, zero if no such number was found and + this is OK, or -1 on error. PARAMS points to the first operand of the + format; PARAM_PTR is made to point to the parameter referred to. If + a $ format is found, *FORMAT is updated to point just after it. */ + +static int +maybe_read_dollar_number (const char **format, + int dollar_needed, tree params, tree *param_ptr, + const format_kind_info *fki) +{ + int argnum; + int overflow_flag; + const char *fcp = *format; + if (!ISDIGIT (*fcp)) + { + if (dollar_needed) + { + warning (OPT_Wformat_, "missing $ operand number in format"); + return -1; + } + else + return 0; + } + argnum = 0; + overflow_flag = 0; + while (ISDIGIT (*fcp)) + { + int nargnum; + nargnum = 10 * argnum + (*fcp - '0'); + if (nargnum < 0 || nargnum / 10 != argnum) + overflow_flag = 1; + argnum = nargnum; + fcp++; + } + if (*fcp != '$') + { + if (dollar_needed) + { + warning (OPT_Wformat_, "missing $ operand number in format"); + return -1; + } + else + return 0; + } + *format = fcp + 1; + if (pedantic && !dollar_format_warned) + { + warning (OPT_Wformat_, "%s does not support %%n$ operand number formats", + C_STD_NAME (STD_EXT)); + dollar_format_warned = 1; + } + if (overflow_flag || argnum == 0 + || (dollar_first_arg_num && argnum > dollar_arguments_count)) + { + warning (OPT_Wformat_, "operand number out of range in format"); + return -1; + } + if (argnum > dollar_max_arg_used) + dollar_max_arg_used = argnum; + /* For vprintf-style functions we may need to allocate more memory to + track which arguments are used. */ + while (dollar_arguments_alloc < dollar_max_arg_used) + { + int nalloc; + nalloc = 2 * dollar_arguments_alloc + 16; + dollar_arguments_used = XRESIZEVEC (char, dollar_arguments_used, + nalloc); + dollar_arguments_pointer_p = XRESIZEVEC (char, dollar_arguments_pointer_p, + nalloc); + memset (dollar_arguments_used + dollar_arguments_alloc, 0, + nalloc - dollar_arguments_alloc); + dollar_arguments_alloc = nalloc; + } + if (!(fki->flags & (int) FMT_FLAG_DOLLAR_MULTIPLE) + && dollar_arguments_used[argnum - 1] == 1) + { + dollar_arguments_used[argnum - 1] = 2; + warning (OPT_Wformat_, "format argument %d used more than once in %s format", + argnum, fki->name); + } + else + dollar_arguments_used[argnum - 1] = 1; + if (dollar_first_arg_num) + { + int i; + *param_ptr = params; + for (i = 1; i < argnum && *param_ptr != 0; i++) + *param_ptr = TREE_CHAIN (*param_ptr); + + /* This case shouldn't be caught here. */ + gcc_assert (*param_ptr); + } + else + *param_ptr = 0; + return argnum; +} + +/* Ensure that FORMAT does not start with a decimal number followed by + a $; give a diagnostic and return true if it does, false otherwise. */ + +static bool +avoid_dollar_number (const char *format) +{ + if (!ISDIGIT (*format)) + return false; + while (ISDIGIT (*format)) + format++; + if (*format == '$') + { + warning (OPT_Wformat_, "$ operand number used after format without operand number"); + return true; + } + return false; +} + + +/* Finish the checking for a format string that used $ operand number formats + instead of non-$ formats. We check for unused operands before used ones + (a serious error, since the implementation of the format function + can't know what types to pass to va_arg to find the later arguments). + and for unused operands at the end of the format (if we know how many + arguments the format had, so not for vprintf). If there were operand + numbers out of range on a non-vprintf-style format, we won't have reached + here. If POINTER_GAP_OK, unused arguments are OK if all arguments are + pointers. */ + +static void +finish_dollar_format_checking (format_check_results *res, int pointer_gap_ok) +{ + int i; + bool found_pointer_gap = false; + for (i = 0; i < dollar_max_arg_used; i++) + { + if (!dollar_arguments_used[i]) + { + if (pointer_gap_ok && (dollar_first_arg_num == 0 + || dollar_arguments_pointer_p[i])) + found_pointer_gap = true; + else + warning_at (res->format_string_loc, OPT_Wformat_, + "format argument %d unused before used argument %d in $-style format", + i + 1, dollar_max_arg_used); + } + } + if (found_pointer_gap + || (dollar_first_arg_num + && dollar_max_arg_used < dollar_arguments_count)) + { + res->number_other--; + res->number_dollar_extra_args++; + } +} + + +/* Retrieve the specification for a format flag. SPEC contains the + specifications for format flags for the applicable kind of format. + FLAG is the flag in question. If PREDICATES is NULL, the basic + spec for that flag must be retrieved and must exist. If + PREDICATES is not NULL, it is a string listing possible predicates + for the spec entry; if an entry predicated on any of these is + found, it is returned, otherwise NULL is returned. */ + +static const format_flag_spec * +get_flag_spec (const format_flag_spec *spec, int flag, const char *predicates) +{ + int i; + for (i = 0; spec[i].flag_char != 0; i++) + { + if (spec[i].flag_char != flag) + continue; + if (predicates != NULL) + { + if (spec[i].predicate != 0 + && strchr (predicates, spec[i].predicate) != 0) + return &spec[i]; + } + else if (spec[i].predicate == 0) + return &spec[i]; + } + gcc_assert (predicates); + return NULL; +} + + +/* Check the argument list of a call to printf, scanf, etc. + INFO points to the function_format_info structure. + PARAMS is the list of argument values. */ + +static void +check_format_info (function_format_info *info, tree params, + vec<location_t> *arglocs) +{ + format_check_context format_ctx; + unsigned HOST_WIDE_INT arg_num; + tree format_tree; + format_check_results res; + /* Skip to format argument. If the argument isn't available, there's + no work for us to do; prototype checking will catch the problem. */ + for (arg_num = 1; ; ++arg_num) + { + if (params == 0) + return; + if (arg_num == info->format_num) + break; + params = TREE_CHAIN (params); + } + format_tree = TREE_VALUE (params); + params = TREE_CHAIN (params); + if (format_tree == 0) + return; + + res.number_non_literal = 0; + res.number_extra_args = 0; + res.extra_arg_loc = UNKNOWN_LOCATION; + res.number_dollar_extra_args = 0; + res.number_wide = 0; + res.number_non_char = 0; + res.number_empty = 0; + res.number_unterminated = 0; + res.number_other = 0; + res.format_string_loc = input_location; + + format_ctx.res = &res; + format_ctx.info = info; + format_ctx.params = params; + format_ctx.arglocs = arglocs; + + check_function_arguments_recurse (check_format_arg, &format_ctx, + format_tree, arg_num); + + location_t loc = format_ctx.res->format_string_loc; + + if (res.number_non_literal > 0) + { + /* Functions taking a va_list normally pass a non-literal format + string. These functions typically are declared with + first_arg_num == 0, so avoid warning in those cases. */ + if (!(format_types[info->format_type].flags & (int) FMT_FLAG_ARG_CONVERT)) + { + /* For strftime-like formats, warn for not checking the format + string; but there are no arguments to check. */ + warning_at (loc, OPT_Wformat_nonliteral, + "format not a string literal, format string not checked"); + } + else if (info->first_arg_num != 0) + { + /* If there are no arguments for the format at all, we may have + printf (foo) which is likely to be a security hole. */ + while (arg_num + 1 < info->first_arg_num) + { + if (params == 0) + break; + params = TREE_CHAIN (params); + ++arg_num; + } + if (params == 0 && warn_format_security) + warning_at (loc, OPT_Wformat_security, + "format not a string literal and no format arguments"); + else if (params == 0 && warn_format_nonliteral) + warning_at (loc, OPT_Wformat_nonliteral, + "format not a string literal and no format arguments"); + else + warning_at (loc, OPT_Wformat_nonliteral, + "format not a string literal, argument types not checked"); + } + } + + /* If there were extra arguments to the format, normally warn. However, + the standard does say extra arguments are ignored, so in the specific + case where we have multiple leaves (conditional expressions or + ngettext) allow extra arguments if at least one leaf didn't have extra + arguments, but was otherwise OK (either non-literal or checked OK). + If the format is an empty string, this should be counted similarly to the + case of extra format arguments. */ + if (res.number_extra_args > 0 && res.number_non_literal == 0 + && res.number_other == 0) + { + if (res.extra_arg_loc == UNKNOWN_LOCATION) + res.extra_arg_loc = loc; + warning_at (res.extra_arg_loc, OPT_Wformat_extra_args, + "too many arguments for format"); + } + if (res.number_dollar_extra_args > 0 && res.number_non_literal == 0 + && res.number_other == 0) + warning_at (loc, OPT_Wformat_extra_args, "unused arguments in $-style format"); + if (res.number_empty > 0 && res.number_non_literal == 0 + && res.number_other == 0) + warning_at (loc, OPT_Wformat_zero_length, "zero-length %s format string", + format_types[info->format_type].name); + + if (res.number_wide > 0) + warning_at (loc, OPT_Wformat_, "format is a wide character string"); + + if (res.number_non_char > 0) + warning_at (loc, OPT_Wformat_, + "format string is not an array of type %qs", "char"); + + if (res.number_unterminated > 0) + warning_at (loc, OPT_Wformat_, "unterminated format string"); +} + +/* Callback from check_function_arguments_recurse to check a + format string. FORMAT_TREE is the format parameter. ARG_NUM + is the number of the format argument. CTX points to a + format_check_context. */ + +static void +check_format_arg (void *ctx, tree format_tree, + unsigned HOST_WIDE_INT arg_num) +{ + format_check_context *format_ctx = (format_check_context *) ctx; + format_check_results *res = format_ctx->res; + function_format_info *info = format_ctx->info; + tree params = format_ctx->params; + vec<location_t> *arglocs = format_ctx->arglocs; + + int format_length; + HOST_WIDE_INT offset; + const char *format_chars; + tree array_size = 0; + tree array_init; + + location_t fmt_param_loc = EXPR_LOC_OR_LOC (format_tree, input_location); + + /* Pull out a constant value if the front end didn't, and handle location + wrappers. */ + format_tree = fold_for_warn (format_tree); + STRIP_NOPS (format_tree); + + if (integer_zerop (format_tree)) + { + /* Skip to first argument to check, so we can see if this format + has any arguments (it shouldn't). */ + while (arg_num + 1 < info->first_arg_num) + { + if (params == 0) + return; + params = TREE_CHAIN (params); + ++arg_num; + } + + if (params == 0) + res->number_other++; + else + { + if (res->number_extra_args == 0) + res->extra_arg_loc = EXPR_LOC_OR_LOC (TREE_VALUE (params), + input_location); + res->number_extra_args++; + } + return; + } + + offset = 0; + if (TREE_CODE (format_tree) == POINTER_PLUS_EXPR) + { + tree arg0, arg1; + + arg0 = TREE_OPERAND (format_tree, 0); + arg1 = TREE_OPERAND (format_tree, 1); + STRIP_NOPS (arg0); + STRIP_NOPS (arg1); + if (TREE_CODE (arg1) == INTEGER_CST) + format_tree = arg0; + else + { + res->number_non_literal++; + return; + } + /* POINTER_PLUS_EXPR offsets are to be interpreted signed. */ + if (!cst_and_fits_in_hwi (arg1)) + { + res->number_non_literal++; + return; + } + offset = int_cst_value (arg1); + } + if (TREE_CODE (format_tree) != ADDR_EXPR) + { + res->number_non_literal++; + return; + } + res->format_string_loc = EXPR_LOC_OR_LOC (format_tree, input_location); + format_tree = TREE_OPERAND (format_tree, 0); + if (format_types[info->format_type].flags + & (int) FMT_FLAG_PARSE_ARG_CONVERT_EXTERNAL) + { + /* We cannot examine this string here - but we can check that it is + a valid type. */ + if (TREE_CODE (format_tree) != CONST_DECL) + { + res->number_non_literal++; + return; + } + /* Skip to first argument to check. */ + while (arg_num + 1 < info->first_arg_num) + { + if (params == 0) + return; + params = TREE_CHAIN (params); + ++arg_num; + } + return; + } + if (TREE_CODE (format_tree) == ARRAY_REF + && tree_fits_shwi_p (TREE_OPERAND (format_tree, 1)) + && (offset += tree_to_shwi (TREE_OPERAND (format_tree, 1))) >= 0) + format_tree = TREE_OPERAND (format_tree, 0); + if (offset < 0) + { + res->number_non_literal++; + return; + } + if (VAR_P (format_tree) + && TREE_CODE (TREE_TYPE (format_tree)) == ARRAY_TYPE + && (array_init = decl_constant_value (format_tree)) != format_tree + && TREE_CODE (array_init) == STRING_CST) + { + /* Extract the string constant initializer. Note that this may include + a trailing NUL character that is not in the array (e.g. + const char a[3] = "foo";). */ + array_size = DECL_SIZE_UNIT (format_tree); + format_tree = array_init; + } + if (TREE_CODE (format_tree) != STRING_CST) + { + res->number_non_literal++; + return; + } + tree underlying_type + = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (format_tree))); + if (underlying_type != char_type_node) + { + if (underlying_type == char16_type_node + || underlying_type == char32_type_node + || underlying_type == wchar_type_node) + res->number_wide++; + else + res->number_non_char++; + return; + } + format_chars = TREE_STRING_POINTER (format_tree); + format_length = TREE_STRING_LENGTH (format_tree); + if (array_size != 0) + { + /* Variable length arrays can't be initialized. */ + gcc_assert (TREE_CODE (array_size) == INTEGER_CST); + + if (tree_fits_shwi_p (array_size)) + { + HOST_WIDE_INT array_size_value = tree_to_shwi (array_size); + if (array_size_value > 0 + && array_size_value == (int) array_size_value + && format_length > array_size_value) + format_length = array_size_value; + } + } + if (offset) + { + if (offset >= format_length) + { + res->number_non_literal++; + return; + } + format_chars += offset; + format_length -= offset; + } + if (format_length < 1 || format_chars[--format_length] != 0) + { + res->number_unterminated++; + return; + } + if (format_length == 0) + { + res->number_empty++; + return; + } + + /* Skip to first argument to check. */ + while (arg_num + 1 < info->first_arg_num) + { + if (params == 0) + return; + params = TREE_CHAIN (params); + ++arg_num; + } + /* Provisionally increment res->number_other; check_format_info_main + will decrement it if it finds there are extra arguments, but this way + need not adjust it for every return. */ + res->number_other++; + object_allocator <format_wanted_type> fwt_pool ("format_wanted_type pool"); + check_format_info_main (res, info, format_chars, fmt_param_loc, format_tree, + format_length, params, arg_num, fwt_pool, arglocs); +} + +/* Support class for argument_parser and check_format_info_main. + Tracks any flag characters that have been applied to the + current argument. */ + +class flag_chars_t +{ + public: + flag_chars_t (); + bool has_char_p (char ch) const; + void add_char (char ch); + void validate (const format_kind_info *fki, + const format_char_info *fci, + const format_flag_spec *flag_specs, + const char * const format_chars, + tree format_string_cst, + location_t format_string_loc, + const char * const orig_format_chars, + char format_char, + bool quoted); + int get_alloc_flag (const format_kind_info *fki); + int assignment_suppression_p (const format_kind_info *fki); + + private: + char m_flag_chars[256]; +}; + +/* Support struct for argument_parser and check_format_info_main. + Encapsulates any length modifier applied to the current argument. */ + +struct length_modifier +{ + length_modifier () + : chars (NULL), val (FMT_LEN_none), std (STD_C89), + scalar_identity_flag (0) + { + } + + length_modifier (const char *chars_, + enum format_lengths val_, + enum format_std_version std_, + int scalar_identity_flag_) + : chars (chars_), val (val_), std (std_), + scalar_identity_flag (scalar_identity_flag_) + { + } + + const char *chars; + enum format_lengths val; + enum format_std_version std; + int scalar_identity_flag; +}; + +/* Parsing one argument within a format string. */ + +class argument_parser +{ + public: + argument_parser (function_format_info *info, const char *&format_chars, + tree format_string_cst, + const char * const orig_format_chars, + location_t format_string_loc, flag_chars_t &flag_chars, + int &has_operand_number, tree first_fillin_param, + object_allocator <format_wanted_type> &fwt_pool_, + vec<location_t> *arglocs); + + bool read_any_dollar (); + + bool read_format_flags (); + + bool + read_any_format_width (tree ¶ms, + unsigned HOST_WIDE_INT &arg_num); + + void + read_any_format_left_precision (); + + bool + read_any_format_precision (tree ¶ms, + unsigned HOST_WIDE_INT &arg_num); + + void handle_alloc_chars (); + + length_modifier read_any_length_modifier (); + + void read_any_other_modifier (); + + const format_char_info *find_format_char_info (char format_char); + + void + validate_flag_pairs (const format_char_info *fci, + char format_char); + + void + give_y2k_warnings (const format_char_info *fci, + char format_char); + + void parse_any_scan_set (const format_char_info *fci); + + bool handle_conversions (const format_char_info *fci, + const length_modifier &len_modifier, + tree &wanted_type, + const char *&wanted_type_name, + unsigned HOST_WIDE_INT &arg_num, + tree ¶ms, + char format_char); + + bool + check_argument_type (const format_char_info *fci, + const struct kernel_ext_fmt *kef, + const length_modifier &len_modifier, + tree &wanted_type, + const char *&wanted_type_name, + const bool suppressed, + unsigned HOST_WIDE_INT &arg_num, + tree ¶ms, + const int alloc_flag, + const char * const format_start, + const char * const type_start, + location_t fmt_param_loc, + char conversion_char); + + private: + const function_format_info *const info; + const format_kind_info * const fki; + const format_flag_spec * const flag_specs; + const char *start_of_this_format; + const char *&format_chars; + const tree format_string_cst; + const char * const orig_format_chars; + const location_t format_string_loc; + object_allocator <format_wanted_type> &fwt_pool; + flag_chars_t &flag_chars; + int main_arg_num; + tree main_arg_params; + int &has_operand_number; + const tree first_fillin_param; + format_wanted_type width_wanted_type; + format_wanted_type precision_wanted_type; + public: + format_wanted_type main_wanted_type; + private: + format_wanted_type *first_wanted_type; + format_wanted_type *last_wanted_type; + vec<location_t> *arglocs; +}; + +/* flag_chars_t's constructor. */ + +flag_chars_t::flag_chars_t () +{ + m_flag_chars[0] = 0; +} + +/* Has CH been seen as a flag within the current argument? */ + +bool +flag_chars_t::has_char_p (char ch) const +{ + return strchr (m_flag_chars, ch) != 0; +} + +/* Add CH to the flags seen within the current argument. */ + +void +flag_chars_t::add_char (char ch) +{ + int i = strlen (m_flag_chars); + m_flag_chars[i++] = ch; + m_flag_chars[i] = 0; +} + +/* Validate the individual flags used, removing any that are invalid. */ + +void +flag_chars_t::validate (const format_kind_info *fki, + const format_char_info *fci, + const format_flag_spec *flag_specs, + const char * const format_chars, + tree format_string_cst, + location_t format_string_loc, + const char * const orig_format_chars, + char format_char, + bool quoted) +{ + int i; + int d = 0; + bool quotflag = false; + + for (i = 0; m_flag_chars[i] != 0; i++) + { + const format_flag_spec *s = get_flag_spec (flag_specs, + m_flag_chars[i], NULL); + m_flag_chars[i - d] = m_flag_chars[i]; + if (m_flag_chars[i] == fki->length_code_char) + continue; + + /* Remember if a quoting flag is seen. */ + quotflag |= s->quoting; + + if (strchr (fci->flag_chars, m_flag_chars[i]) == 0) + { + format_warning_at_char (format_string_loc, format_string_cst, + format_chars - orig_format_chars, + OPT_Wformat_, + "%s used with %<%%%c%> %s format", + _(s->name), format_char, fki->name); + d++; + continue; + } + if (pedantic) + { + const format_flag_spec *t; + if (ADJ_STD (s->std) > C_STD_VER) + warning_at (format_string_loc, OPT_Wformat_, + "%s does not support %s", + C_STD_NAME (s->std), _(s->long_name)); + t = get_flag_spec (flag_specs, m_flag_chars[i], fci->flags2); + if (t != NULL && ADJ_STD (t->std) > ADJ_STD (s->std)) + { + const char *long_name = (t->long_name != NULL + ? t->long_name + : s->long_name); + if (ADJ_STD (t->std) > C_STD_VER) + warning_at (format_string_loc, OPT_Wformat_, + "%s does not support %s with" + " the %<%%%c%> %s format", + C_STD_NAME (t->std), _(long_name), + format_char, fki->name); + } + } + + /* Detect quoting directives used within a quoted sequence, such + as GCC's "%<...%qE". */ + if (quoted && s->quoting) + { + format_warning_at_char (format_string_loc, format_string_cst, + format_chars - orig_format_chars - 1, + OPT_Wformat_, + "%s used within a quoted sequence", + _(s->name)); + } + } + m_flag_chars[i - d] = 0; + + if (!quoted + && !quotflag + && strchr (fci->flags2, '\'')) + { + format_warning_at_char (format_string_loc, format_string_cst, + format_chars - orig_format_chars, + OPT_Wformat_, + "%qc conversion used unquoted", + format_char); + } +} + +/* Determine if an assignment-allocation has been set, requiring + an extra char ** for writing back a dynamically-allocated char *. + This is for handling the optional 'm' character in scanf. */ + +int +flag_chars_t::get_alloc_flag (const format_kind_info *fki) +{ + if ((fki->flags & (int) FMT_FLAG_SCANF_A_KLUDGE) + && has_char_p ('a')) + return 1; + if (fki->alloc_char && has_char_p (fki->alloc_char)) + return 1; + return 0; +} + +/* Determine if an assignment-suppression character was seen. + ('*' in scanf, for discarding the converted input). */ + +int +flag_chars_t::assignment_suppression_p (const format_kind_info *fki) +{ + if (fki->suppression_char + && has_char_p (fki->suppression_char)) + return 1; + return 0; +} + +/* Constructor for argument_parser. Initialize for parsing one + argument within a format string. */ + +argument_parser:: +argument_parser (function_format_info *info_, const char *&format_chars_, + tree format_string_cst_, + const char * const orig_format_chars_, + location_t format_string_loc_, + flag_chars_t &flag_chars_, + int &has_operand_number_, + tree first_fillin_param_, + object_allocator <format_wanted_type> &fwt_pool_, + vec<location_t> *arglocs_) +: info (info_), + fki (&format_types[info->format_type]), + flag_specs (fki->flag_specs), + start_of_this_format (format_chars_), + format_chars (format_chars_), + format_string_cst (format_string_cst_), + orig_format_chars (orig_format_chars_), + format_string_loc (format_string_loc_), + fwt_pool (fwt_pool_), + flag_chars (flag_chars_), + main_arg_num (0), + main_arg_params (NULL), + has_operand_number (has_operand_number_), + first_fillin_param (first_fillin_param_), + first_wanted_type (NULL), + last_wanted_type (NULL), + arglocs (arglocs_) +{ +} + +/* Handle dollars at the start of format arguments, setting up main_arg_params + and main_arg_num. + + Return true if format parsing is to continue, false otherwise. */ + +bool +argument_parser::read_any_dollar () +{ + if ((fki->flags & (int) FMT_FLAG_USE_DOLLAR) && has_operand_number != 0) + { + /* Possibly read a $ operand number at the start of the format. + If one was previously used, one is required here. If one + is not used here, we can't immediately conclude this is a + format without them, since it could be printf %m or scanf %*. */ + int opnum; + opnum = maybe_read_dollar_number (&format_chars, 0, + first_fillin_param, + &main_arg_params, fki); + if (opnum == -1) + return false; + else if (opnum > 0) + { + has_operand_number = 1; + main_arg_num = opnum + info->first_arg_num - 1; + } + } + else if (fki->flags & FMT_FLAG_USE_DOLLAR) + { + if (avoid_dollar_number (format_chars)) + return false; + } + return true; +} + +/* Read any format flags, but do not yet validate them beyond removing + duplicates, since in general validation depends on the rest of + the format. + + Return true if format parsing is to continue, false otherwise. */ + +bool +argument_parser::read_format_flags () +{ + while (*format_chars != 0 + && strchr (fki->flag_chars, *format_chars) != 0) + { + const format_flag_spec *s = get_flag_spec (flag_specs, + *format_chars, NULL); + if (flag_chars.has_char_p (*format_chars)) + { + format_warning_at_char (format_string_loc, format_string_cst, + format_chars + 1 - orig_format_chars, + OPT_Wformat_, + "repeated %s in format", _(s->name)); + } + else + flag_chars.add_char (*format_chars); + + if (s->skip_next_char) + { + ++format_chars; + if (*format_chars == 0) + { + warning_at (format_string_loc, OPT_Wformat_, + "missing fill character at end of strfmon format"); + return false; + } + } + ++format_chars; + } + + return true; +} + +/* Read any format width, possibly * or *m$. + + Return true if format parsing is to continue, false otherwise. */ + +bool +argument_parser:: +read_any_format_width (tree ¶ms, + unsigned HOST_WIDE_INT &arg_num) +{ + if (!fki->width_char) + return true; + + if (fki->width_type != NULL && *format_chars == '*') + { + flag_chars.add_char (fki->width_char); + /* "...a field width...may be indicated by an asterisk. + In this case, an int argument supplies the field width..." */ + ++format_chars; + if (has_operand_number != 0) + { + int opnum; + opnum = maybe_read_dollar_number (&format_chars, + has_operand_number == 1, + first_fillin_param, + ¶ms, fki); + if (opnum == -1) + return false; + else if (opnum > 0) + { + has_operand_number = 1; + arg_num = opnum + info->first_arg_num - 1; + } + else + has_operand_number = 0; + } + else + { + if (avoid_dollar_number (format_chars)) + return false; + } + if (info->first_arg_num != 0) + { + tree cur_param; + if (params == 0) + cur_param = NULL; + else + { + cur_param = TREE_VALUE (params); + if (has_operand_number <= 0) + { + params = TREE_CHAIN (params); + ++arg_num; + } + } + width_wanted_type.wanted_type = *fki->width_type; + width_wanted_type.wanted_type_name = NULL; + width_wanted_type.pointer_count = 0; + width_wanted_type.char_lenient_flag = 0; + width_wanted_type.scalar_identity_flag = 0; + width_wanted_type.writing_in_flag = 0; + width_wanted_type.reading_from_flag = 0; + width_wanted_type.kind = CF_KIND_FIELD_WIDTH; + width_wanted_type.format_start = format_chars - 1; + width_wanted_type.format_length = 1; + width_wanted_type.param = cur_param; + width_wanted_type.arg_num = arg_num; + width_wanted_type.offset_loc = + format_chars - orig_format_chars; + width_wanted_type.next = NULL; + if (last_wanted_type != 0) + last_wanted_type->next = &width_wanted_type; + if (first_wanted_type == 0) + first_wanted_type = &width_wanted_type; + last_wanted_type = &width_wanted_type; + } + } + else + { + /* Possibly read a numeric width. If the width is zero, + we complain if appropriate. */ + int non_zero_width_char = FALSE; + int found_width = FALSE; + while (ISDIGIT (*format_chars)) + { + found_width = TRUE; + if (*format_chars != '0') + non_zero_width_char = TRUE; + ++format_chars; + } + if (found_width && !non_zero_width_char && + (fki->flags & (int) FMT_FLAG_ZERO_WIDTH_BAD)) + warning_at (format_string_loc, OPT_Wformat_, + "zero width in %s format", fki->name); + if (found_width) + flag_chars.add_char (fki->width_char); + } + + return true; +} + +/* Read any format left precision (must be a number, not *). */ +void +argument_parser::read_any_format_left_precision () +{ + if (fki->left_precision_char == 0) + return; + if (*format_chars != '#') + return; + + ++format_chars; + flag_chars.add_char (fki->left_precision_char); + if (!ISDIGIT (*format_chars)) + format_warning_at_char (format_string_loc, format_string_cst, + format_chars - orig_format_chars, + OPT_Wformat_, + "empty left precision in %s format", fki->name); + while (ISDIGIT (*format_chars)) + ++format_chars; +} + +/* Read any format precision, possibly * or *m$. + + Return true if format parsing is to continue, false otherwise. */ + +bool +argument_parser:: +read_any_format_precision (tree ¶ms, + unsigned HOST_WIDE_INT &arg_num) +{ + if (fki->precision_char == 0) + return true; + if (*format_chars != '.') + return true; + + ++format_chars; + flag_chars.add_char (fki->precision_char); + if (fki->precision_type != NULL && *format_chars == '*') + { + /* "...a...precision...may be indicated by an asterisk. + In this case, an int argument supplies the...precision." */ + ++format_chars; + if (has_operand_number != 0) + { + int opnum; + opnum = maybe_read_dollar_number (&format_chars, + has_operand_number == 1, + first_fillin_param, + ¶ms, fki); + if (opnum == -1) + return false; + else if (opnum > 0) + { + has_operand_number = 1; + arg_num = opnum + info->first_arg_num - 1; + } + else + has_operand_number = 0; + } + else + { + if (avoid_dollar_number (format_chars)) + return false; + } + if (info->first_arg_num != 0) + { + tree cur_param; + if (params == 0) + cur_param = NULL; + else + { + cur_param = TREE_VALUE (params); + if (has_operand_number <= 0) + { + params = TREE_CHAIN (params); + ++arg_num; + } + } + precision_wanted_type.wanted_type = *fki->precision_type; + precision_wanted_type.wanted_type_name = NULL; + precision_wanted_type.pointer_count = 0; + precision_wanted_type.char_lenient_flag = 0; + precision_wanted_type.scalar_identity_flag = 0; + precision_wanted_type.writing_in_flag = 0; + precision_wanted_type.reading_from_flag = 0; + precision_wanted_type.kind = CF_KIND_FIELD_PRECISION; + precision_wanted_type.param = cur_param; + precision_wanted_type.format_start = format_chars - 2; + precision_wanted_type.format_length = 2; + precision_wanted_type.arg_num = arg_num; + precision_wanted_type.offset_loc = + format_chars - orig_format_chars; + precision_wanted_type.next = NULL; + if (last_wanted_type != 0) + last_wanted_type->next = &precision_wanted_type; + if (first_wanted_type == 0) + first_wanted_type = &precision_wanted_type; + last_wanted_type = &precision_wanted_type; + } + } + else + { + if (!(fki->flags & (int) FMT_FLAG_EMPTY_PREC_OK) + && !ISDIGIT (*format_chars)) + format_warning_at_char (format_string_loc, format_string_cst, + format_chars - orig_format_chars, + OPT_Wformat_, + "empty precision in %s format", fki->name); + while (ISDIGIT (*format_chars)) + ++format_chars; + } + + return true; +} + +/* Parse any assignment-allocation flags, which request an extra + char ** for writing back a dynamically-allocated char *. + This is for handling the optional 'm' character in scanf, + and, before C99, 'a' (for compatibility with a non-standard + GNU libc extension). */ + +void +argument_parser::handle_alloc_chars () +{ + if (fki->alloc_char && fki->alloc_char == *format_chars) + { + flag_chars.add_char (fki->alloc_char); + format_chars++; + } + + /* Handle the scanf allocation kludge. */ + if (fki->flags & (int) FMT_FLAG_SCANF_A_KLUDGE) + { + if (*format_chars == 'a' && !flag_isoc99) + { + if (format_chars[1] == 's' || format_chars[1] == 'S' + || format_chars[1] == '[') + { + /* 'a' is used as a flag. */ + flag_chars.add_char ('a'); + format_chars++; + } + } + } +} + +/* Look for length modifiers within the current format argument, + returning a length_modifier instance describing it (or the + default if one is not found). + + Issue warnings about non-standard modifiers. */ + +length_modifier +argument_parser::read_any_length_modifier () +{ + length_modifier result; + + const format_length_info *fli = fki->length_char_specs; + if (!fli) + return result; + + while (fli->name != 0 + && strncmp (fli->name, format_chars, strlen (fli->name))) + fli++; + if (fli->name != 0) + { + format_chars += strlen (fli->name); + if (fli->double_name != 0 && fli->name[0] == *format_chars) + { + format_chars++; + result = length_modifier (fli->double_name, fli->double_index, + fli->double_std, 0); + } + else + { + result = length_modifier (fli->name, fli->index, fli->std, + fli->scalar_identity_flag); + } + flag_chars.add_char (fki->length_code_char); + } + if (pedantic) + { + /* Warn if the length modifier is non-standard. */ + if (ADJ_STD (result.std) > C_STD_VER) + warning_at (format_string_loc, OPT_Wformat_, + "%s does not support the %qs %s length modifier", + C_STD_NAME (result.std), result.chars, + fki->name); + } + + return result; +} + +/* Read any other modifier (strftime E/O). */ + +void +argument_parser::read_any_other_modifier () +{ + if (fki->modifier_chars == NULL) + return; + + while (*format_chars != 0 + && strchr (fki->modifier_chars, *format_chars) != 0) + { + if (flag_chars.has_char_p (*format_chars)) + { + const format_flag_spec *s = get_flag_spec (flag_specs, + *format_chars, NULL); + format_warning_at_char (format_string_loc, format_string_cst, + format_chars - orig_format_chars, + OPT_Wformat_, + "repeated %s in format", _(s->name)); + } + else + flag_chars.add_char (*format_chars); + ++format_chars; + } +} + +/* Return the format_char_info corresponding to FORMAT_CHAR, + potentially issuing a warning if the format char is + not supported in the C standard version we are checking + against. + + Issue a warning and return NULL if it is not found. + + Issue warnings about non-standard modifiers. */ + +const format_char_info * +argument_parser::find_format_char_info (char format_char) +{ + const format_char_info *fci = fki->conversion_specs; + + while (fci->format_chars != 0 + && strchr (fci->format_chars, format_char) == 0) + ++fci; + if (fci->format_chars == 0) + { + format_warning_at_char (format_string_loc, format_string_cst, + format_chars - orig_format_chars, + OPT_Wformat_, + "unknown conversion type character" + " %qc in format", + format_char); + return NULL; + } + + if (pedantic) + { + if (ADJ_STD (fci->std) > C_STD_VER) + format_warning_at_char (format_string_loc, format_string_cst, + format_chars - orig_format_chars, + OPT_Wformat_, + "%s does not support the %<%%%c%> %s format", + C_STD_NAME (fci->std), format_char, fki->name); + } + + return fci; +} + +/* Validate the pairs of flags used. + Issue warnings about incompatible combinations of flags. */ + +void +argument_parser::validate_flag_pairs (const format_char_info *fci, + char format_char) +{ + const format_flag_pair * const bad_flag_pairs = fki->bad_flag_pairs; + + for (int i = 0; bad_flag_pairs[i].flag_char1 != 0; i++) + { + const format_flag_spec *s, *t; + if (!flag_chars.has_char_p (bad_flag_pairs[i].flag_char1)) + continue; + if (!flag_chars.has_char_p (bad_flag_pairs[i].flag_char2)) + continue; + if (bad_flag_pairs[i].predicate != 0 + && strchr (fci->flags2, bad_flag_pairs[i].predicate) == 0) + continue; + s = get_flag_spec (flag_specs, bad_flag_pairs[i].flag_char1, NULL); + t = get_flag_spec (flag_specs, bad_flag_pairs[i].flag_char2, NULL); + if (bad_flag_pairs[i].ignored) + { + if (bad_flag_pairs[i].predicate != 0) + warning_at (format_string_loc, OPT_Wformat_, + "%s ignored with %s and %<%%%c%> %s format", + _(s->name), _(t->name), format_char, + fki->name); + else + warning_at (format_string_loc, OPT_Wformat_, + "%s ignored with %s in %s format", + _(s->name), _(t->name), fki->name); + } + else + { + if (bad_flag_pairs[i].predicate != 0) + warning_at (format_string_loc, OPT_Wformat_, + "use of %s and %s together with %<%%%c%> %s format", + _(s->name), _(t->name), format_char, + fki->name); + else + warning_at (format_string_loc, OPT_Wformat_, + "use of %s and %s together in %s format", + _(s->name), _(t->name), fki->name); + } + } +} + +/* Give Y2K warnings. */ + +void +argument_parser::give_y2k_warnings (const format_char_info *fci, + char format_char) +{ + if (!warn_format_y2k) + return; + + int y2k_level = 0; + if (strchr (fci->flags2, '4') != 0) + if (flag_chars.has_char_p ('E')) + y2k_level = 3; + else + y2k_level = 2; + else if (strchr (fci->flags2, '3') != 0) + y2k_level = 3; + else if (strchr (fci->flags2, '2') != 0) + y2k_level = 2; + if (y2k_level == 3) + warning_at (format_string_loc, OPT_Wformat_y2k, + "%<%%%c%> yields only last 2 digits of " + "year in some locales", format_char); + else if (y2k_level == 2) + warning_at (format_string_loc, OPT_Wformat_y2k, + "%<%%%c%> yields only last 2 digits of year", + format_char); +} + +/* Parse any "scan sets" enclosed in square brackets, e.g. + for scanf-style calls. */ + +void +argument_parser::parse_any_scan_set (const format_char_info *fci) +{ + if (strchr (fci->flags2, '[') == NULL) + return; + + /* Skip over scan set, in case it happens to have '%' in it. */ + if (*format_chars == '^') + ++format_chars; + /* Find closing bracket; if one is hit immediately, then + it's part of the scan set rather than a terminator. */ + if (*format_chars == ']') + ++format_chars; + while (*format_chars && *format_chars != ']') + ++format_chars; + if (*format_chars != ']') + /* The end of the format string was reached. */ + format_warning_at_char (format_string_loc, format_string_cst, + format_chars - orig_format_chars, + OPT_Wformat_, + "no closing %<]%> for %<%%[%> format"); +} + +/* Return true if this argument is to be continued to be parsed, + false to skip to next argument. */ + +bool +argument_parser::handle_conversions (const format_char_info *fci, + const length_modifier &len_modifier, + tree &wanted_type, + const char *&wanted_type_name, + unsigned HOST_WIDE_INT &arg_num, + tree ¶ms, + char format_char) +{ + enum format_std_version wanted_type_std; + + if (!(fki->flags & (int) FMT_FLAG_ARG_CONVERT)) + return true; + + wanted_type = (fci->types[len_modifier.val].type + ? *fci->types[len_modifier.val].type : 0); + wanted_type_name = fci->types[len_modifier.val].name; + wanted_type_std = fci->types[len_modifier.val].std; + if (wanted_type == 0) + { + format_warning_at_char (format_string_loc, format_string_cst, + format_chars - orig_format_chars, + OPT_Wformat_, + "use of %qs length modifier with %qc type" + " character has either no effect" + " or undefined behavior", + len_modifier.chars, format_char); + /* Heuristic: skip one argument when an invalid length/type + combination is encountered. */ + arg_num++; + if (params != 0) + params = TREE_CHAIN (params); + return false; + } + else if (pedantic + /* Warn if non-standard, provided it is more non-standard + than the length and type characters that may already + have been warned for. */ + && ADJ_STD (wanted_type_std) > ADJ_STD (len_modifier.std) + && ADJ_STD (wanted_type_std) > ADJ_STD (fci->std)) + { + if (ADJ_STD (wanted_type_std) > C_STD_VER) + format_warning_at_char (format_string_loc, format_string_cst, + format_chars - orig_format_chars, + OPT_Wformat_, + "%s does not support the %<%%%s%c%> %s format", + C_STD_NAME (wanted_type_std), + len_modifier.chars, + format_char, fki->name); + } + + return true; +} + +/* Check type of argument against desired type. + + Return true if format parsing is to continue, false otherwise. */ + +bool +argument_parser:: +check_argument_type (const format_char_info *fci, + const struct kernel_ext_fmt *kef, + const length_modifier &len_modifier, + tree &wanted_type, + const char *&wanted_type_name, + const bool suppressed, + unsigned HOST_WIDE_INT &arg_num, + tree ¶ms, + const int alloc_flag, + const char * const format_start, + const char * const type_start, + location_t fmt_param_loc, + char conversion_char) +{ + if (info->first_arg_num == 0) + return true; + + if ((fci->pointer_count == 0 && wanted_type == void_type_node) + || suppressed) + { + if (main_arg_num != 0) + { + if (suppressed) + warning_at (format_string_loc, OPT_Wformat_, + "operand number specified with " + "suppressed assignment"); + else + warning_at (format_string_loc, OPT_Wformat_, + "operand number specified for format " + "taking no argument"); + } + } + else + { + format_wanted_type *wanted_type_ptr; + + if (main_arg_num != 0) + { + arg_num = main_arg_num; + params = main_arg_params; + } + else + { + ++arg_num; + if (has_operand_number > 0) + { + warning_at (format_string_loc, OPT_Wformat_, + "missing $ operand number in format"); + return false; + } + else + has_operand_number = 0; + } + + wanted_type_ptr = &main_wanted_type; + while (fci) + { + tree cur_param; + if (params == 0) + cur_param = NULL; + else + { + cur_param = TREE_VALUE (params); + params = TREE_CHAIN (params); + } + + wanted_type_ptr->wanted_type = wanted_type; + wanted_type_ptr->wanted_type_name = wanted_type_name; + wanted_type_ptr->pointer_count = fci->pointer_count + alloc_flag; + wanted_type_ptr->char_lenient_flag = 0; + if (strchr (fci->flags2, 'c') != 0) + wanted_type_ptr->char_lenient_flag = 1; + wanted_type_ptr->scalar_identity_flag = 0; + if (len_modifier.scalar_identity_flag) + wanted_type_ptr->scalar_identity_flag = 1; + wanted_type_ptr->writing_in_flag = 0; + wanted_type_ptr->reading_from_flag = 0; + if (alloc_flag) + wanted_type_ptr->writing_in_flag = 1; + else + { + if (strchr (fci->flags2, 'W') != 0) + wanted_type_ptr->writing_in_flag = 1; + if (strchr (fci->flags2, 'R') != 0) + wanted_type_ptr->reading_from_flag = 1; + } + wanted_type_ptr->kind = CF_KIND_FORMAT; + wanted_type_ptr->param = cur_param; + wanted_type_ptr->arg_num = arg_num; + wanted_type_ptr->format_start = format_start; + wanted_type_ptr->format_length = format_chars - format_start; + wanted_type_ptr->offset_loc = format_chars - orig_format_chars; + wanted_type_ptr->next = NULL; + if (last_wanted_type != 0) + last_wanted_type->next = wanted_type_ptr; + if (first_wanted_type == 0) + first_wanted_type = wanted_type_ptr; + last_wanted_type = wanted_type_ptr; + + fci = fci->chain; + if (fci) + { + wanted_type_ptr = fwt_pool.allocate (); + arg_num++; + wanted_type = *fci->types[len_modifier.val].type; + wanted_type_name = fci->types[len_modifier.val].name; + } + } + } + + if (first_wanted_type != 0) + { + ptrdiff_t offset_to_format_start = (start_of_this_format - 1) - orig_format_chars; + ptrdiff_t offset_to_format_end = (format_chars - 1) - orig_format_chars; + /* By default, use the end of the range for the caret location. */ + substring_loc fmt_loc (fmt_param_loc, TREE_TYPE (format_string_cst), + offset_to_format_end, + offset_to_format_start, offset_to_format_end); + ptrdiff_t offset_to_type_start = type_start - orig_format_chars; + check_format_types (fmt_loc, first_wanted_type, fki, + offset_to_type_start, + conversion_char, arglocs); + + /* note printf extension type checks are *additional* - %p must always + * be pointer compatible, %d always int compatible. + */ + if (!kef) + return true; + + const struct kernel_ext_fmt *kef_now; + bool success; + + for (kef_now = kef; kef_now->suffix && !strcmp (kef->suffix, kef_now->suffix); kef_now++) + { + success = check_kef_type (fmt_loc, kef_now, + first_wanted_type->arg_num, + first_wanted_type->param, + kef_now->type, fki, offset_to_type_start, conversion_char, arglocs); + + if (success) + return true; + } + + location_t param_loc; + + if (EXPR_HAS_LOCATION (first_wanted_type->param)) + param_loc = EXPR_LOCATION (first_wanted_type->param); + else if (arglocs) + { + /* arg_num is 1-based. */ + gcc_assert (first_wanted_type->arg_num > 0); + param_loc = (*arglocs)[first_wanted_type->arg_num - 1]; + } + + format_type_warning (fmt_loc, param_loc, first_wanted_type, + kef->type, TREE_TYPE (first_wanted_type->param), + fki, offset_to_type_start, conversion_char); + } + + return true; +} + +/* Do the main part of checking a call to a format function. FORMAT_CHARS + is the NUL-terminated format string (which at this point may contain + internal NUL characters); FORMAT_LENGTH is its length (excluding the + terminating NUL character). ARG_NUM is one less than the number of + the first format argument to check; PARAMS points to that format + argument in the list of arguments. */ + +static void +check_format_info_main (format_check_results *res, + function_format_info *info, const char *format_chars, + location_t fmt_param_loc, tree format_string_cst, + int format_length, tree params, + unsigned HOST_WIDE_INT arg_num, + object_allocator <format_wanted_type> &fwt_pool, + vec<location_t> *arglocs) +{ + const char * const orig_format_chars = format_chars; + const tree first_fillin_param = params; + + const format_kind_info * const fki = &format_types[info->format_type]; + const format_flag_spec * const flag_specs = fki->flag_specs; + const location_t format_string_loc = res->format_string_loc; + + /* -1 if no conversions taking an operand have been found; 0 if one has + and it didn't use $; 1 if $ formats are in use. */ + int has_operand_number = -1; + + /* Vector of pointers to opening quoting directives (like GCC "%<"). */ + auto_vec<const char*> quotdirs; + + /* Pointers to the most recent color directives (like GCC's "%r or %R"). + A starting color directive much be terminated before the end of + the format string. A terminating directive makes no sense without + a prior starting directive. */ + const char *color_begin = NULL; + const char *color_end = NULL; + + init_dollar_format_checking (info->first_arg_num, first_fillin_param); + + while (*format_chars != 0) + { + if (*format_chars++ != '%') + continue; + if (*format_chars == 0) + { + format_warning_at_char (format_string_loc, format_string_cst, + format_chars - orig_format_chars, + OPT_Wformat_, + "spurious trailing %<%%%> in format"); + continue; + } + if (*format_chars == '%') + { + ++format_chars; + continue; + } + + flag_chars_t flag_chars; + argument_parser arg_parser (info, format_chars, format_string_cst, + orig_format_chars, format_string_loc, + flag_chars, has_operand_number, + first_fillin_param, fwt_pool, arglocs); + + if (!arg_parser.read_any_dollar ()) + return; + + if (!arg_parser.read_format_flags ()) + return; + + /* Read any format width, possibly * or *m$. */ + if (!arg_parser.read_any_format_width (params, arg_num)) + return; + + /* Read any format left precision (must be a number, not *). */ + arg_parser.read_any_format_left_precision (); + + /* Read any format precision, possibly * or *m$. */ + if (!arg_parser.read_any_format_precision (params, arg_num)) + return; + + const char *format_start = format_chars; + + arg_parser.handle_alloc_chars (); + + /* The rest of the conversion specification is the length modifier + (if any), and the conversion specifier, so this is where the + type information starts. If we need to issue a suggestion + about a type mismatch, then we should preserve everything up + to here. */ + const char *type_start = format_chars; + + /* Read any length modifier, if this kind of format has them. */ + const length_modifier len_modifier + = arg_parser.read_any_length_modifier (); + + /* Read any modifier (strftime E/O). */ + arg_parser.read_any_other_modifier (); + + char format_char = *format_chars; + if (format_char == 0 + || (!(fki->flags & (int) FMT_FLAG_FANCY_PERCENT_OK) + && format_char == '%')) + { + format_warning_at_char (format_string_loc, format_string_cst, + format_chars - orig_format_chars, + OPT_Wformat_, + "conversion lacks type at end of format"); + continue; + } + format_chars++; + + const format_char_info * const fci + = arg_parser.find_format_char_info (format_char); + if (!fci) + continue; + + struct kernel_ext_fmt *etab = fci->kernel_ext; + + if (etab && format_chars[0] >= 'A' && format_chars[0] <= 'Z') + { + struct kernel_ext_fmt *etab_end = etab + ETAB_SZ; + + for (; etab < etab_end && etab->suffix; etab++) + { + if (!strncmp (etab->suffix, format_chars, strlen (etab->suffix))) + break; + } + + if (!etab->suffix || etab == etab_end) + { + format_warning_at_char (format_string_loc, format_string_cst, + format_chars - orig_format_chars + 1, + OPT_Wformat_, + "unrecognized printf extension suffix"); + etab = NULL; + } + else + { + format_chars += strlen (etab->suffix); + } + } + else + etab = NULL; + + flag_chars.validate (fki, fci, flag_specs, format_chars, + format_string_cst, + format_string_loc, orig_format_chars, format_char, + quotdirs.length () > 0); + + const int alloc_flag = flag_chars.get_alloc_flag (fki); + const bool suppressed = flag_chars.assignment_suppression_p (fki); + + /* Diagnose nested or unmatched quoting directives such as GCC's + "%<...%<" and "%>...%>". */ + bool quot_begin_p = strchr (fci->flags2, '<'); + bool quot_end_p = strchr (fci->flags2, '>'); + + if (quot_begin_p && !quot_end_p) + { + if (quotdirs.length ()) + format_warning_at_char (format_string_loc, format_string_cst, + format_chars - orig_format_chars, + OPT_Wformat_, + "nested quoting directive"); + quotdirs.safe_push (format_chars); + } + else if (!quot_begin_p && quot_end_p) + { + if (quotdirs.length ()) + quotdirs.pop (); + else + format_warning_at_char (format_string_loc, format_string_cst, + format_chars - orig_format_chars, + OPT_Wformat_, + "unmatched quoting directive"); + } + + bool color_begin_p = strchr (fci->flags2, '/'); + if (color_begin_p) + { + color_begin = format_chars; + color_end = NULL; + } + else if (strchr (fci->flags2, '\\')) + { + if (color_end) + format_warning_at_char (format_string_loc, format_string_cst, + format_chars - orig_format_chars, + OPT_Wformat_, + "%qc directive redundant after prior " + "occurence of the same", format_char); + else if (!color_begin) + format_warning_at_char (format_string_loc, format_string_cst, + format_chars - orig_format_chars, + OPT_Wformat_, + "unmatched color reset directive"); + color_end = format_chars; + } + + /* Diagnose directives that shouldn't appear in a quoted sequence. + (They are denoted by a double quote in FLAGS2.) */ + if (quotdirs.length ()) + { + if (strchr (fci->flags2, '"')) + format_warning_at_char (format_string_loc, format_string_cst, + format_chars - orig_format_chars, + OPT_Wformat_, + "%qc conversion used within a quoted " + "sequence", + format_char); + } + + /* Validate the pairs of flags used. */ + arg_parser.validate_flag_pairs (fci, format_char); + + arg_parser.give_y2k_warnings (fci, format_char); + + arg_parser.parse_any_scan_set (fci); + + tree wanted_type = NULL; + const char *wanted_type_name = NULL; + + if (!arg_parser.handle_conversions (fci, len_modifier, + wanted_type, wanted_type_name, + arg_num, + params, + format_char)) + continue; + + arg_parser.main_wanted_type.next = NULL; + + /* Finally. . .check type of argument against desired type! */ + if (!arg_parser.check_argument_type (fci, etab, len_modifier, + wanted_type, wanted_type_name, + suppressed, + arg_num, params, + alloc_flag, + format_start, type_start, + fmt_param_loc, + format_char)) + return; + } + + if (format_chars - orig_format_chars != format_length) + format_warning_at_char (format_string_loc, format_string_cst, + format_chars + 1 - orig_format_chars, + OPT_Wformat_contains_nul, + "embedded %<\\0%> in format"); + if (info->first_arg_num != 0 && params != 0 + && has_operand_number <= 0) + { + res->number_other--; + res->number_extra_args++; + } + if (has_operand_number > 0) + finish_dollar_format_checking (res, fki->flags & (int) FMT_FLAG_DOLLAR_GAP_POINTER_OK); + + if (quotdirs.length ()) + format_warning_at_char (format_string_loc, format_string_cst, + quotdirs.pop () - orig_format_chars, + OPT_Wformat_, "unterminated quoting directive"); + if (color_begin && !color_end) + format_warning_at_char (format_string_loc, format_string_cst, + color_begin - orig_format_chars, + OPT_Wformat_, "unterminated color directive"); +} + +/* Check the argument types from a single format conversion (possibly + including width and precision arguments). + + FMT_LOC is the location of the format conversion. + + TYPES is a singly-linked list expressing the parts of the format + conversion that expect argument types, and the arguments they + correspond to. + + OFFSET_TO_TYPE_START is the offset within the execution-charset encoded + format string to where type information begins for the conversion + (the length modifier and conversion specifier). + + CONVERSION_CHAR is the user-provided conversion specifier. + + For example, given: + + sprintf (d, "before %-+*.*lld after", arg3, arg4, arg5); + + then FMT_LOC covers this range: + + sprintf (d, "before %-+*.*lld after", arg3, arg4, arg5); + ^^^^^^^^^ + + and TYPES in this case is a three-entry singly-linked list consisting of: + (1) the check for the field width here: + sprintf (d, "before %-+*.*lld after", arg3, arg4, arg5); + ^ ^^^^ + against arg3, and + (2) the check for the field precision here: + sprintf (d, "before %-+*.*lld after", arg3, arg4, arg5); + ^^ ^^^^ + against arg4, and + (3) the check for the length modifier and conversion char here: + sprintf (d, "before %-+*.*lld after", arg3, arg4, arg5); + ^^^ ^^^^ + against arg5. + + OFFSET_TO_TYPE_START is 13, the offset to the "lld" within the + STRING_CST: + + 0000000000111111111122 + 0123456789012345678901 + sprintf (d, "before %-+*.*lld after", arg3, arg4, arg5); + ^ ^ + | ` CONVERSION_CHAR: 'd' + type starts here. */ +tree type_normalize (tree type, tree *cousin, tree target = NULL) +{ + while (1) + { + if (TREE_CODE (type) == FUNCTION_TYPE || TREE_CODE (type) == POINTER_TYPE) + return type; + if (target) + /* Strip off any "const" etc. */ + type = build_qualified_type (type, 0); + if (TREE_CODE (TYPE_NAME (type)) != TYPE_DECL) + return type; + + if (target && (type == target || TYPE_NAME (type) == target)) + return target; + + struct type_special *t; + for (t = special_types; t->match; t++) + { + if (!*t->match) + continue; + if (TYPE_NAME (type) != *t->match) + continue; + if (t->cousin && *t->cousin) + *cousin = *t->cousin; + if (t->replace) + return *t->replace ? *t->replace : type; + return type; + } + + tree orig = DECL_ORIGINAL_TYPE (TYPE_NAME (type)); + if (!orig) + return type; + + type = orig; + } + return type; +} + +static void +check_format_types (const substring_loc &fmt_loc, + format_wanted_type *types, const format_kind_info *fki, + int offset_to_type_start, + char conversion_char, + vec<location_t> *arglocs) +{ + for (; types != 0; types = types->next) + { + tree cur_param; + tree cur_type; + tree cur_type_cousin = NULL; + tree orig_cur_type; + tree wanted_type; + int arg_num; + int i; + int char_type_flag; + + wanted_type = types->wanted_type; + arg_num = types->arg_num; + + /* The following should not occur here. */ + gcc_assert (wanted_type); + gcc_assert (wanted_type != void_type_node || types->pointer_count); + + if (types->pointer_count == 0) + wanted_type = lang_hooks.types.type_promotes_to (wanted_type); + + switch (TREE_CODE (wanted_type)) + { + case IDENTIFIER_NODE: + break; + case TYPE_DECL: + wanted_type = TYPE_MAIN_VARIANT (DECL_ORIGINAL_TYPE (wanted_type)); + break; + default: + wanted_type = TYPE_MAIN_VARIANT (wanted_type); + break; + } + + cur_param = types->param; + if (!cur_param) + { + format_type_warning (fmt_loc, UNKNOWN_LOCATION, types, wanted_type, + NULL, fki, offset_to_type_start, + conversion_char); + continue; + } + + cur_type = TREE_TYPE (cur_param); + if (cur_type == error_mark_node) + continue; + orig_cur_type = cur_type; + char_type_flag = 0; + + location_t param_loc = UNKNOWN_LOCATION; + if (EXPR_HAS_LOCATION (cur_param)) + param_loc = EXPR_LOCATION (cur_param); + else if (arglocs) + { + /* arg_num is 1-based. */ + gcc_assert (types->arg_num > 0); + param_loc = (*arglocs)[types->arg_num - 1]; + } + + STRIP_NOPS (cur_param); + + /* Check the types of any additional pointer arguments + that precede the "real" argument. */ + for (i = 0; i < types->pointer_count; ++i) + { + if (TREE_CODE (cur_type) == POINTER_TYPE) + { + cur_type = TREE_TYPE (cur_type); + if (cur_type == error_mark_node) + break; + + /* Check for writing through a NULL pointer. */ + if (types->writing_in_flag + && i == 0 + && cur_param != 0 + && integer_zerop (cur_param)) + warning (OPT_Wformat_, "writing through null pointer " + "(argument %d)", arg_num); + + /* Check for reading through a NULL pointer. */ + if (types->reading_from_flag + && i == 0 + && cur_param != 0 + && integer_zerop (cur_param)) + warning (OPT_Wformat_, "reading through null pointer " + "(argument %d)", arg_num); + + if (cur_param != 0 && TREE_CODE (cur_param) == ADDR_EXPR) + cur_param = TREE_OPERAND (cur_param, 0); + else + cur_param = 0; + + /* See if this is an attempt to write into a const type with + scanf or with printf "%n". Note: the writing in happens + at the first indirection only, if for example + void * const * is passed to scanf %p; passing + const void ** is simply passing an incompatible type. */ + if (types->writing_in_flag + && i == 0 + && (TYPE_READONLY (cur_type) + || (cur_param != 0 + && (CONSTANT_CLASS_P (cur_param) + || (DECL_P (cur_param) + && TREE_READONLY (cur_param)))))) + warning (OPT_Wformat_, "writing into constant object " + "(argument %d)", arg_num); + + /* If there are extra type qualifiers beyond the first + indirection, then this makes the types technically + incompatible. */ + if (i > 0 + && pedantic + && (TYPE_READONLY (cur_type) + || TYPE_VOLATILE (cur_type) + || TYPE_ATOMIC (cur_type) + || TYPE_RESTRICT (cur_type))) + warning (OPT_Wformat_, "extra type qualifiers in format " + "argument (argument %d)", + arg_num); + + } + else + { + format_type_warning (fmt_loc, param_loc, + types, wanted_type, orig_cur_type, fki, + offset_to_type_start, conversion_char); + break; + } + } + + if (i < types->pointer_count) + continue; + + cur_type = type_normalize (cur_type, &cur_type_cousin); + + /* Check whether the argument type is a character type. This leniency + only applies to certain formats, flagged with 'c'. */ + if (types->char_lenient_flag) + char_type_flag = (cur_type == char_type_node + || cur_type == signed_char_type_node + || cur_type == unsigned_char_type_node); + + int compat = lang_hooks.types_compatible_p (wanted_type, cur_type); + /* Check the type of the "real" argument, if there's a type we want. */ + if ((TREE_CODE (wanted_type) != INTEGER_TYPE || types->pointer_count) + && compat) + continue; + if (TREE_CODE (wanted_type) == INTEGER_TYPE && !types->pointer_count + && compat) + { +compat_inner: + if (TREE_CODE (cur_param) == INTEGER_CST) + continue; + + if (TREE_CODE (types->wanted_type) == TYPE_DECL + && TREE_CODE (cur_type) == TYPE_DECL) + { + if (types->wanted_type == cur_type) + continue; + format_type_warning (fmt_loc, param_loc, types, + wanted_type, orig_cur_type, fki, + offset_to_type_start, conversion_char, + " (strict match required [A])"); + continue; + } + else if (TREE_CODE (types->wanted_type) == TYPE_DECL) + { + if (types->wanted_type == TYPE_NAME(cur_type)) + continue; + format_type_warning (fmt_loc, param_loc, types, + wanted_type, orig_cur_type, fki, + offset_to_type_start, conversion_char, + " (strict match required [B])"); + continue; + } + else if (wanted_type == cur_type) + continue; + else if (cur_type_cousin) + { + format_type_warning (fmt_loc, param_loc, types, + wanted_type, orig_cur_type, fki, + offset_to_type_start, conversion_char, + " (strict match required [C])"); + } + + /* + format_type_warning (fmt_loc, param_loc, types, + wanted_type, orig_cur_type, fki, + offset_to_type_start, conversion_char, + " (ultra-pedantic mode)"); + */ + continue; + } + + /* If we want 'void *', allow any pointer type. + (Anything else would already have got a warning.) + With -Wpedantic, only allow pointers to void and to character + types. */ + if (wanted_type == void_type_node + && (!pedantic || (i == 1 && char_type_flag))) + continue; + /* Don't warn about differences merely in signedness, unless + -Wpedantic. With -Wpedantic, warn if the type is a pointer + target and not a character type, and for character types at + a second level of indirection. */ + if (TREE_CODE (wanted_type) == INTEGER_TYPE + && TREE_CODE (cur_type) == INTEGER_TYPE + && ((!pedantic && !warn_format_signedness) + || (i == 0 && !warn_format_signedness) + || (i == 1 && char_type_flag)) + && (TYPE_UNSIGNED (wanted_type) + ? wanted_type == c_common_unsigned_type (cur_type) + : wanted_type == c_common_signed_type (cur_type))) + { + if (cur_type_cousin) + { + if (TREE_CODE (types->wanted_type) == TYPE_DECL + && TREE_CODE (cur_type_cousin) == TYPE_DECL) + { + if (types->wanted_type == cur_type_cousin) + continue; + format_type_warning (fmt_loc, param_loc, types, + wanted_type, orig_cur_type, fki, + offset_to_type_start, conversion_char, + " (strict match required [X])"); + continue; + } + else if (TREE_CODE (types->wanted_type) == TYPE_DECL) + { + if (types->wanted_type == TYPE_NAME(cur_type_cousin)) + continue; + format_type_warning (fmt_loc, param_loc, types, + wanted_type, orig_cur_type, fki, + offset_to_type_start, conversion_char, + " (strict match required [Y])"); + continue; + } + else if (wanted_type == cur_type_cousin) + continue; + else + { + format_type_warning (fmt_loc, param_loc, types, + wanted_type, orig_cur_type, fki, + offset_to_type_start, conversion_char, + " (strict match required [Z])"); + } + } + + goto compat_inner; + } + /* Don't warn about differences merely in signedness if we know + that the current type is integer-promoted and its original type + was unsigned such as that it is in the range of WANTED_TYPE. */ + if (TREE_CODE (wanted_type) == INTEGER_TYPE + && TREE_CODE (cur_type) == INTEGER_TYPE + && warn_format_signedness + && TYPE_UNSIGNED (wanted_type) + && cur_param != NULL_TREE + && TREE_CODE (cur_param) == NOP_EXPR) + { + tree t = TREE_TYPE (TREE_OPERAND (cur_param, 0)); + if (TYPE_UNSIGNED (t) + && cur_type == lang_hooks.types.type_promotes_to (t)) + continue; + } + /* Likewise, "signed char", "unsigned char" and "char" are + equivalent but the above test won't consider them equivalent. */ + if (wanted_type == char_type_node + && (!pedantic || i < 2) + && char_type_flag) + continue; + if (types->scalar_identity_flag + && (TREE_CODE (cur_type) == TREE_CODE (wanted_type) + || (INTEGRAL_TYPE_P (cur_type) + && INTEGRAL_TYPE_P (wanted_type))) + && TYPE_PRECISION (cur_type) == TYPE_PRECISION (wanted_type)) + continue; + /* Now we have a type mismatch. */ + format_type_warning (fmt_loc, param_loc, types, + wanted_type, orig_cur_type, fki, + offset_to_type_start, conversion_char); + } +} + +static bool +check_kef_type (const substring_loc &fmt_loc, + const struct kernel_ext_fmt *kef, + unsigned arg_num, + tree cur_param, + tree wanted_type, + const format_kind_info *fki, + int offset_to_type_start, + char conversion_char, + vec<location_t> *arglocs) +{ + tree cur_type; + bool ok = true; + int i; + + /* The following should not occur here. */ + gcc_assert (wanted_type); + gcc_assert (wanted_type != void_type_node || kef->ptrlevel); + + if (TREE_CODE (wanted_type) == TYPE_DECL) + wanted_type = DECL_ORIGINAL_TYPE (wanted_type); + + if (!cur_param) + return false; + + cur_type = TREE_TYPE (cur_param); + if (cur_type == error_mark_node) + return false; + + location_t param_loc = UNKNOWN_LOCATION; + if (EXPR_HAS_LOCATION (cur_param)) + param_loc = EXPR_LOCATION (cur_param); + else if (arglocs) + { + /* arg_num is 1-based. */ + gcc_assert (arg_num > 0); + param_loc = (*arglocs)[arg_num - 1]; + } + (void)param_loc; + + STRIP_NOPS (cur_param); + + /* Check the types of any additional pointer arguments + that precede the "real" argument. */ + for (i = 0; i < kef->ptrlevel; ++i) + { + if (TREE_CODE (cur_type) == POINTER_TYPE) + { + cur_type = TREE_TYPE (cur_type); + if (cur_type == error_mark_node) + break; + + if (cur_param != 0 && TREE_CODE (cur_param) == ADDR_EXPR) + cur_param = TREE_OPERAND (cur_param, 0); + else + cur_param = 0; + + /* If there are extra type qualifiers beyond the first + indirection, then this makes the types technically + incompatible. */ + if (i > 0 + && pedantic + && (TYPE_READONLY (cur_type) + || TYPE_VOLATILE (cur_type) + || TYPE_ATOMIC (cur_type) + || TYPE_RESTRICT (cur_type))) + warning (OPT_Wformat_, "extra type qualifiers in format " + "argument (argument %d)", + arg_num); + + } + else + { + ok = false; + break; + } + } + + if (i < kef->ptrlevel) + return ok; + + int compat = lang_hooks.types_compatible_p (wanted_type, cur_type); + + if (!compat) + return false; + + tree cousin; + tree normal_type; + + normal_type = type_normalize (cur_type, &cousin, wanted_type); + + return normal_type == wanted_type; +} + + +/* Given type TYPE, attempt to dereference the type N times + (e.g. from ("int ***", 2) to "int *") + + Return the derefenced type, with any qualifiers + such as "const" stripped from the result, or + NULL if unsuccessful (e.g. TYPE is not a pointer type). */ + +static tree +deref_n_times (tree type, int n) +{ + gcc_assert (type); + + for (int i = n; i > 0; i--) + { + if (TREE_CODE (type) != POINTER_TYPE) + return NULL_TREE; + type = TREE_TYPE (type); + } + /* Strip off any "const" etc. */ + return build_qualified_type (type, 0); +} + +/* Lookup the format code for FORMAT_LEN within FLI, + returning the string code for expressing it, or NULL + if it is not found. */ + +static const char * +get_modifier_for_format_len (const format_length_info *fli, + enum format_lengths format_len) +{ + for (; fli->name; fli++) + { + if (fli->index == format_len) + return fli->name; + if (fli->double_index == format_len) + return fli->double_name; + } + return NULL; +} + +#if CHECKING_P + +namespace selftest { + +static void +test_get_modifier_for_format_len () +{ + ASSERT_STREQ ("h", + get_modifier_for_format_len (printf_length_specs, FMT_LEN_h)); + ASSERT_STREQ ("hh", + get_modifier_for_format_len (printf_length_specs, FMT_LEN_hh)); + ASSERT_STREQ ("L", + get_modifier_for_format_len (printf_length_specs, FMT_LEN_L)); + ASSERT_EQ (NULL, + get_modifier_for_format_len (printf_length_specs, FMT_LEN_none)); +} + +} // namespace selftest + +#endif /* CHECKING_P */ + +/* Determine if SPEC_TYPE and ARG_TYPE are sufficiently similar for a + format_type_detail using SPEC_TYPE to be offered as a suggestion for + Wformat type errors where the argument has type ARG_TYPE. */ + +static bool +matching_type_p (tree spec_type, tree arg_type) +{ + gcc_assert (spec_type); + gcc_assert (arg_type); + + /* If any of the types requires structural equality, we can't compare + their canonical types. */ + if (TYPE_STRUCTURAL_EQUALITY_P (spec_type) + || TYPE_STRUCTURAL_EQUALITY_P (arg_type)) + return false; + + spec_type = TYPE_CANONICAL (spec_type); + arg_type = TYPE_CANONICAL (arg_type); + + if (TREE_CODE (spec_type) == INTEGER_TYPE + && TREE_CODE (arg_type) == INTEGER_TYPE + && (TYPE_UNSIGNED (spec_type) + ? spec_type == c_common_unsigned_type (arg_type) + : spec_type == c_common_signed_type (arg_type))) + return true; + + return spec_type == arg_type; +} + +/* Subroutine of get_format_for_type. + + Generate a string containing the length modifier and conversion specifier + that should be used to format arguments of type ARG_TYPE within FKI + (effectively the inverse of the checking code). + + If CONVERSION_CHAR is not zero (the first pass), the resulting suggestion + is required to use it, for correcting bogus length modifiers. + If CONVERSION_CHAR is zero (the second pass), then allow any suggestion + that matches ARG_TYPE. + + If successful, returns a non-NULL string which should be freed + by the caller. + Otherwise, returns NULL. */ + +static char * +get_format_for_type_1 (const format_kind_info *fki, tree arg_type, + char conversion_char) +{ + gcc_assert (arg_type); + + const format_char_info *spec; + for (spec = &fki->conversion_specs[0]; + spec->format_chars; + spec++) + { + if (conversion_char) + if (!strchr (spec->format_chars, conversion_char)) + continue; + + tree effective_arg_type = deref_n_times (arg_type, + spec->pointer_count); + if (!effective_arg_type) + continue; + for (int i = 0; i < FMT_LEN_MAX; i++) + { + const format_type_detail *ftd = &spec->types[i]; + if (!ftd->type) + continue; + if (matching_type_p (*ftd->type, effective_arg_type)) + { + const char *len_modifier + = get_modifier_for_format_len (fki->length_char_specs, + (enum format_lengths)i); + if (!len_modifier) + len_modifier = ""; + + if (conversion_char) + /* We found a match, using the given conversion char - the + length modifier was incorrect (or absent). + Provide a suggestion using the conversion char with the + correct length modifier for the type. */ + return xasprintf ("%s%c", len_modifier, conversion_char); + else + /* 2nd pass: no match was possible using the user-provided + conversion char, but we do have a match without using it. + Provide a suggestion using the first conversion char + listed for the given type. */ + return xasprintf ("%s%c", len_modifier, spec->format_chars[0]); + } + } + } + + return NULL; +} + +/* Generate a string containing the length modifier and conversion specifier + that should be used to format arguments of type ARG_TYPE within FKI + (effectively the inverse of the checking code). + + If successful, returns a non-NULL string which should be freed + by the caller. + Otherwise, returns NULL. */ + +static char * +get_format_for_type (const format_kind_info *fki, tree arg_type, + char conversion_char) +{ + gcc_assert (arg_type); + gcc_assert (conversion_char); + + /* First pass: look for a format_char_info containing CONVERSION_CHAR + If we find one, then presumably the length modifier was incorrect + (or absent). */ + char *result = get_format_for_type_1 (fki, arg_type, conversion_char); + if (result) + return result; + + /* Second pass: we didn't find a match for CONVERSION_CHAR, so try + matching just on the type. */ + return get_format_for_type_1 (fki, arg_type, '\0'); +} + +/* Attempt to get a string for use as a replacement fix-it hint for the + source range in FMT_LOC. + + Preserve all of the text within the range of FMT_LOC up to + OFFSET_TO_TYPE_START, replacing the rest with an appropriate + length modifier and conversion specifier for ARG_TYPE, attempting + to keep the user-provided CONVERSION_CHAR if possible. + + For example, given a long vs long long mismatch for arg5 here: + + 000000000111111111122222222223333333333| + 123456789012345678901234567890123456789` column numbers + 0000000000111111111122| + 0123456789012345678901` string offsets + V~~~~~~~~ : range of FMT_LOC, from cols 23-31 + sprintf (d, "before %-+*.*lld after", arg3, arg4, arg5); + ^ ^ + | ` CONVERSION_CHAR: 'd' + type starts here + + where OFFSET_TO_TYPE_START is 13 (the offset to the "lld" within the + STRING_CST), where the user provided: + %-+*.*lld + the result (assuming "long" argument 5) should be: + %-+*.*ld + + If successful, returns a non-NULL string which should be freed + by the caller. + Otherwise, returns NULL. */ + +static char * +get_corrected_substring (const substring_loc &fmt_loc, + format_wanted_type *type, tree arg_type, + const format_kind_info *fki, + int offset_to_type_start, char conversion_char) +{ + /* Attempt to provide hints for argument types, but not for field widths + and precisions. */ + if (!arg_type) + return NULL; + if (type->kind != CF_KIND_FORMAT) + return NULL; + + /* Locate the current code within the source range, rejecting + any awkward cases where the format string occupies more than + one line. + Lookup the place where the type starts (including any length + modifiers), getting it as the caret location. */ + substring_loc type_loc (fmt_loc); + type_loc.set_caret_index (offset_to_type_start); + + location_t fmt_substring_loc; + const char *err = type_loc.get_location (&fmt_substring_loc); + if (err) + return NULL; + + source_range fmt_substring_range + = get_range_from_loc (line_table, fmt_substring_loc); + + expanded_location caret + = expand_location_to_spelling_point (fmt_substring_loc); + expanded_location start + = expand_location_to_spelling_point (fmt_substring_range.m_start); + expanded_location finish + = expand_location_to_spelling_point (fmt_substring_range.m_finish); + if (caret.file != start.file) + return NULL; + if (start.file != finish.file) + return NULL; + if (caret.line != start.line) + return NULL; + if (start.line != finish.line) + return NULL; + if (start.column > caret.column) + return NULL; + if (start.column > finish.column) + return NULL; + if (caret.column > finish.column) + return NULL; + +#if BUILDING_GCC_VERSION >= 9000 + char_span line = location_get_source_line (start.file, start.line); + if (!line) + return NULL; + + /* If we got this far, then we have the line containing the + existing conversion specification. + + Generate a trimmed copy, containing the prefix part of the conversion + specification, up to the (but not including) the length modifier. + In the above example, this would be "%-+*.*". */ + int length_up_to_type = caret.column - start.column; + char_span prefix_span = line.subspan (start.column - 1, length_up_to_type); + char *prefix = prefix_span.xstrdup (); +#else + char *prefix = NULL; +#endif + + /* Now attempt to generate a suggestion for the rest of the specification + (length modifier and conversion char), based on ARG_TYPE and + CONVERSION_CHAR. + In the above example, this would be "ld". */ + char *format_for_type = get_format_for_type (fki, arg_type, conversion_char); + if (!format_for_type) + { + free (prefix); + return NULL; + } + + /* Success. Generate the resulting suggestion for the whole range of + FMT_LOC by concatenating the two strings. + In the above example, this would be "%-+*.*ld". */ + char *result = concat (prefix, format_for_type, NULL); + free (format_for_type); + free (prefix); + return result; +} + +/* Helper class for adding zero or more trailing '*' to types. + + The format type and name exclude any '*' for pointers, so those + must be formatted manually. For all the types we currently have, + this is adequate, but formats taking pointers to functions or + arrays would require the full type to be built up in order to + print it with %T. */ + +class indirection_suffix +{ + public: + indirection_suffix (int pointer_count) : m_pointer_count (pointer_count) {} + + /* Determine the size of the buffer (including NUL-terminator). */ + + size_t get_buffer_size () const + { + return m_pointer_count + 2; + } + + /* Write the '*' to DST and add a NUL-terminator. */ + + void fill_buffer (char *dst) const + { + if (m_pointer_count == 0) + dst[0] = 0; + else if (c_dialect_cxx ()) + { + memset (dst, '*', m_pointer_count); + dst[m_pointer_count] = 0; + } + else + { + dst[0] = ' '; + memset (dst + 1, '*', m_pointer_count); + dst[m_pointer_count + 1] = 0; + } + } + + private: + int m_pointer_count; +}; + +#if BUILDING_GCC_VERSION >= 9000 +/* not exported by GCC... need a local copy :( */ +class frr_range_label_for_type_mismatch : public range_label +{ + public: + frr_range_label_for_type_mismatch (tree labelled_type, tree other_type) + : m_labelled_type (labelled_type), m_other_type (other_type) + { + } + + label_text get_text (unsigned range_idx) const OVERRIDE; + + protected: + tree m_labelled_type; + tree m_other_type; +}; + +/* Print T to CPP. */ + +static void +print_type (c_pretty_printer *cpp, tree t, bool *quoted) +{ + gcc_assert (TYPE_P (t)); + struct obstack *ob = pp_buffer (cpp)->obstack; + char *p = (char *) obstack_base (ob); + /* Remember the end of the initial dump. */ + int len = obstack_object_size (ob); + + tree name = TYPE_NAME (t); + if (name && TREE_CODE (name) == TYPE_DECL && DECL_NAME (name)) + pp_identifier (cpp, lang_hooks.decl_printable_name (name, 2)); + else + cpp->type_id (t); + + /* If we're printing a type that involves typedefs, also print the + stripped version. But sometimes the stripped version looks + exactly the same, so we don't want it after all. To avoid + printing it in that case, we play ugly obstack games. */ + if (TYPE_CANONICAL (t) && t != TYPE_CANONICAL (t)) + { + c_pretty_printer cpp2; + /* Print the stripped version into a temporary printer. */ + cpp2.type_id (TYPE_CANONICAL (t)); + struct obstack *ob2 = cpp2.buffer->obstack; + /* Get the stripped version from the temporary printer. */ + const char *aka = (char *) obstack_base (ob2); + int aka_len = obstack_object_size (ob2); + int type1_len = obstack_object_size (ob) - len; + + /* If they are identical, bail out. */ + if (aka_len == type1_len && memcmp (p + len, aka, aka_len) == 0) + return; + + /* They're not, print the stripped version now. */ + if (*quoted) + pp_end_quote (cpp, pp_show_color (cpp)); + pp_c_whitespace (cpp); + pp_left_brace (cpp); + pp_c_ws_string (cpp, _("aka")); + pp_c_whitespace (cpp); + if (*quoted) + pp_begin_quote (cpp, pp_show_color (cpp)); + cpp->type_id (TYPE_CANONICAL (t)); + if (*quoted) + pp_end_quote (cpp, pp_show_color (cpp)); + pp_right_brace (cpp); + /* No further closing quotes are needed. */ + *quoted = false; + } +} + +/* C-specific implementation of range_label::get_text () vfunc for + range_label_for_type_mismatch. */ + +label_text +frr_range_label_for_type_mismatch::get_text (unsigned /*range_idx*/) const +{ + if (m_labelled_type == NULL_TREE) + return label_text (NULL, false); + + c_pretty_printer cpp; + bool quoted = false; + print_type (&cpp, m_labelled_type, "ed); + return label_text (xstrdup (pp_formatted_text (&cpp)), true); +} + +#define range_label_for_type_mismatch frr_range_label_for_type_mismatch +#endif + +/* Subclass of range_label for labelling the range in the format string + with the type in question, adding trailing '*' for pointer_count. */ + +class range_label_for_format_type_mismatch + : public range_label_for_type_mismatch +{ + public: + range_label_for_format_type_mismatch (tree labelled_type, tree other_type, + int pointer_count) + : range_label_for_type_mismatch (labelled_type, other_type), + m_pointer_count (pointer_count) + { + } + + label_text get_text (unsigned range_idx) const FINAL OVERRIDE + { + label_text text = range_label_for_type_mismatch::get_text (range_idx); + if (text.m_buffer == NULL) + return text; + + indirection_suffix suffix (m_pointer_count); + char *p = (char *) alloca (suffix.get_buffer_size ()); + suffix.fill_buffer (p); + + char *result = concat (text.m_buffer, p, NULL); + text.maybe_free (); + return label_text (result, true); + } + + private: + int m_pointer_count; +}; + +/* Give a warning about a format argument of different type from that expected. + The range of the diagnostic is taken from WHOLE_FMT_LOC; the caret location + is based on the location of the char at TYPE->offset_loc. + PARAM_LOC is the location of the relevant argument, or UNKNOWN_LOCATION + if this is unavailable. + WANTED_TYPE is the type the argument should have, + possibly stripped of pointer dereferences. The description (such as "field + precision"), the placement in the format string, a possibly more + friendly name of WANTED_TYPE, and the number of pointer dereferences + are taken from TYPE. ARG_TYPE is the type of the actual argument, + or NULL if it is missing. + + OFFSET_TO_TYPE_START is the offset within the execution-charset encoded + format string to where type information begins for the conversion + (the length modifier and conversion specifier). + CONVERSION_CHAR is the user-provided conversion specifier. + + For example, given a type mismatch for argument 5 here: + + 00000000011111111112222222222333333333344444444445555555555| + 12345678901234567890123456789012345678901234567890123456789` column numbers + 0000000000111111111122| + 0123456789012345678901` offsets within STRING_CST + V~~~~~~~~ : range of WHOLE_FMT_LOC, from cols 23-31 + sprintf (d, "before %-+*.*lld after", int_expr, int_expr, long_expr); + ^ ^ ^~~~~~~~~ + | ` CONVERSION_CHAR: 'd' PARAM_LOC + type starts here + + OFFSET_TO_TYPE_START is 13, the offset to the "lld" within the + STRING_CST. */ + +static void +format_type_warning (const substring_loc &whole_fmt_loc, + location_t param_loc, + format_wanted_type *type, + tree wanted_type, tree arg_type, + const format_kind_info *fki, + int offset_to_type_start, + char conversion_char, + const char *extra) +{ + enum format_specifier_kind kind = type->kind; + const char *wanted_type_name = type->wanted_type_name; + const char *format_start = type->format_start; + int format_length = type->format_length; + int pointer_count = type->pointer_count; + int arg_num = type->arg_num; + + if (!extra) + extra = ""; + + /* If ARG_TYPE is a typedef with a misleading name (for example, + size_t but not the standard size_t expected by printf %zu), avoid + printing the typedef name. */ + if (wanted_type_name + && arg_type + && TYPE_NAME (arg_type) + && TREE_CODE (TYPE_NAME (arg_type)) == TYPE_DECL + && DECL_NAME (TYPE_NAME (arg_type)) + && !strcmp (wanted_type_name, + lang_hooks.decl_printable_name (TYPE_NAME (arg_type), 2))) + arg_type = TYPE_MAIN_VARIANT (arg_type); + + indirection_suffix suffix (pointer_count); + char *p = (char *) alloca (suffix.get_buffer_size ()); + suffix.fill_buffer (p); + + /* WHOLE_FMT_LOC has the caret at the end of the range. + Set the caret to be at the offset from TYPE. Subtract one + from the offset for the same reason as in format_warning_at_char. */ + substring_loc fmt_loc (whole_fmt_loc); + fmt_loc.set_caret_index (type->offset_loc - 1); + +#if BUILDING_GCC_VERSION >= 9000 + range_label_for_format_type_mismatch fmt_label (wanted_type, arg_type, + pointer_count); + range_label_for_type_mismatch param_label (arg_type, wanted_type); + + /* Get a string for use as a replacement fix-it hint for the range in + fmt_loc, or NULL. */ + char *corrected_substring + = get_corrected_substring (fmt_loc, type, arg_type, fki, + offset_to_type_start, conversion_char); + format_string_diagnostic_t diag (fmt_loc, &fmt_label, param_loc, ¶m_label, + corrected_substring); +# define format_warning_at_substring(a,b,c,d,e,...) \ + diag.emit_warning(__VA_ARGS__) +#else +# define format_warning_at_substring(a,b,c,d,...) \ + format_warning_at_substring(a,c,__VA_ARGS__) + /* Get a string for use as a replacement fix-it hint for the range in + fmt_loc, or NULL. */ + char *corrected_substring + = get_corrected_substring (fmt_loc, type, arg_type, fki, + offset_to_type_start, conversion_char); + +#endif + + if (wanted_type_name) + { + if (arg_type) + format_warning_at_substring + (fmt_loc, &fmt_label, param_loc, ¶m_label, + corrected_substring, OPT_Wformat_, + "%s %<%s%.*s%> expects argument of type %<%s%s%>, " + "but argument %d has type %qT%s", + gettext (kind_descriptions[kind]), + (kind == CF_KIND_FORMAT ? "%" : ""), + format_length, format_start, + wanted_type_name, p, arg_num, arg_type, extra); + else + format_warning_at_substring + (fmt_loc, &fmt_label, param_loc, ¶m_label, + corrected_substring, OPT_Wformat_, + "%s %<%s%.*s%> expects a matching %<%s%s%> argument%s", + gettext (kind_descriptions[kind]), + (kind == CF_KIND_FORMAT ? "%" : ""), + format_length, format_start, wanted_type_name, p, extra); + } + else + { + if (arg_type) + format_warning_at_substring + (fmt_loc, &fmt_label, param_loc, ¶m_label, + corrected_substring, OPT_Wformat_, + "%s %<%s%.*s%> expects argument of type %<%T%s%>, " + "but argument %d has type %qT%s", + gettext (kind_descriptions[kind]), + (kind == CF_KIND_FORMAT ? "%" : ""), + format_length, format_start, + wanted_type, p, arg_num, arg_type, extra); + else + format_warning_at_substring + (fmt_loc, &fmt_label, param_loc, ¶m_label, + corrected_substring, OPT_Wformat_, + "%s %<%s%.*s%> expects a matching %<%T%s%> argument%s", + gettext (kind_descriptions[kind]), + (kind == CF_KIND_FORMAT ? "%" : ""), + format_length, format_start, wanted_type, p, extra); + } + + free (corrected_substring); +} + + +#if 0 +/* Given a format_char_info array FCI, and a character C, this function + returns the index into the conversion_specs where that specifier's + data is located. The character must exist. */ +static unsigned int +find_char_info_specifier_index (const format_char_info *fci, int c) +{ + unsigned i; + + for (i = 0; fci->format_chars; i++, fci++) + if (strchr (fci->format_chars, c)) + return i; + + /* We shouldn't be looking for a non-existent specifier. */ + gcc_unreachable (); +} + +/* Given a format_length_info array FLI, and a character C, this + function returns the index into the conversion_specs where that + modifier's data is located. The character must exist. */ +static unsigned int +find_length_info_modifier_index (const format_length_info *fli, int c) +{ + unsigned i; + + for (i = 0; fli->name; i++, fli++) + if (strchr (fli->name, c)) + return i; + + /* We shouldn't be looking for a non-existent modifier. */ + gcc_unreachable (); +} +#endif + +#ifdef TARGET_FORMAT_TYPES +extern const format_kind_info TARGET_FORMAT_TYPES[]; +#endif + +#ifdef TARGET_OVERRIDES_FORMAT_ATTRIBUTES +extern const target_ovr_attr TARGET_OVERRIDES_FORMAT_ATTRIBUTES[]; +#endif +#ifdef TARGET_OVERRIDES_FORMAT_INIT + extern void TARGET_OVERRIDES_FORMAT_INIT (void); +#endif + +/* Attributes such as "printf" are equivalent to those such as + "gnu_printf" unless this is overridden by a target. */ +static const target_ovr_attr gnu_target_overrides_format_attributes[] = +{ + { NULL, NULL } +}; + +/* Translate to unified attribute name. This is used in decode_format_type and + decode_format_attr. In attr_name the user specified argument is passed. It + returns the unified format name from TARGET_OVERRIDES_FORMAT_ATTRIBUTES + or the attr_name passed to this function, if there is no matching entry. */ +static const char * +convert_format_name_to_system_name (const char *attr_name) +{ + int i; + + if (attr_name == NULL || *attr_name == 0 + || strncmp (attr_name, "gcc_", 4) == 0) + return attr_name; +#ifdef TARGET_OVERRIDES_FORMAT_INIT + TARGET_OVERRIDES_FORMAT_INIT (); +#endif + +#ifdef TARGET_OVERRIDES_FORMAT_ATTRIBUTES + /* Check if format attribute is overridden by target. */ + if (TARGET_OVERRIDES_FORMAT_ATTRIBUTES != NULL + && TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT > 0) + { + for (i = 0; i < TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT; ++i) + { + if (cmp_attribs (TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_src, + attr_name)) + return attr_name; + if (cmp_attribs (TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_dst, + attr_name)) + return TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_src; + } + } +#endif + /* Otherwise default to gnu format. */ + for (i = 0; + gnu_target_overrides_format_attributes[i].named_attr_src != NULL; + ++i) + { + if (cmp_attribs (gnu_target_overrides_format_attributes[i].named_attr_src, + attr_name)) + return attr_name; + if (cmp_attribs (gnu_target_overrides_format_attributes[i].named_attr_dst, + attr_name)) + return gnu_target_overrides_format_attributes[i].named_attr_src; + } + + return attr_name; +} + +/* Handle a "format" attribute; arguments as in + struct attribute_spec.handler. */ +tree +handle_frr_format_attribute (tree *node, tree ARG_UNUSED (name), tree args, + int flags, bool *no_add_attrs) +{ + tree type = *node; + function_format_info info; + + /* Canonicalize name of format function. */ + if (TREE_CODE (TREE_VALUE (args)) == IDENTIFIER_NODE) + TREE_VALUE (args) = canonicalize_attr_name (TREE_VALUE (args)); + + if (!decode_format_attr (args, &info, 0)) + { + *no_add_attrs = true; + return NULL_TREE; + } + + if (prototype_p (type)) + { + if (!check_format_string (type, info.format_num, flags, + no_add_attrs, info.format_type)) + return NULL_TREE; + + if (info.first_arg_num != 0) + { + unsigned HOST_WIDE_INT arg_num = 1; + function_args_iterator iter; + tree arg_type; + + /* Verify that first_arg_num points to the last arg, + the ... */ + FOREACH_FUNCTION_ARGS (type, arg_type, iter) + arg_num++; + + if (arg_num != info.first_arg_num) + { + if (!(flags & (int) ATTR_FLAG_BUILT_IN)) + error ("args to be formatted is not %<...%>"); + *no_add_attrs = true; + return NULL_TREE; + } + } + } + + /* Check if this is a strftime variant. Just for this variant + FMT_FLAG_ARG_CONVERT is not set. */ + if ((format_types[info.format_type].flags & (int) FMT_FLAG_ARG_CONVERT) == 0 + && info.first_arg_num != 0) + { + error ("strftime formats cannot format arguments"); + *no_add_attrs = true; + return NULL_TREE; + } + + return NULL_TREE; +} + +#if CHECKING_P + +namespace selftest { + +/* Selftests of location handling. */ + +/* Get the format_kind_info with the given name. */ + +static const format_kind_info * +get_info (const char *name) +{ + int idx = decode_format_type (name); + const format_kind_info *fki = &format_types[idx]; + ASSERT_STREQ (fki->name, name); + return fki; +} + +/* Verify that get_format_for_type (FKI, TYPE, CONVERSION_CHAR) + is EXPECTED_FORMAT. */ + +static void +assert_format_for_type_streq (const location &loc, const format_kind_info *fki, + const char *expected_format, tree type, + char conversion_char) +{ + gcc_assert (fki); + gcc_assert (expected_format); + gcc_assert (type); + + char *actual_format = get_format_for_type (fki, type, conversion_char); + ASSERT_STREQ_AT (loc, expected_format, actual_format); + free (actual_format); +} + +/* Selftests for get_format_for_type. */ + +#define ASSERT_FORMAT_FOR_TYPE_STREQ(EXPECTED_FORMAT, TYPE, CONVERSION_CHAR) \ + assert_format_for_type_streq (SELFTEST_LOCATION, (fki), (EXPECTED_FORMAT), \ + (TYPE), (CONVERSION_CHAR)) + +/* Selftest for get_format_for_type for "printf"-style functions. */ + +static void +test_get_format_for_type_printf () +{ + const format_kind_info *fki = get_info ("gnu_printf"); + ASSERT_NE (fki, NULL); + + ASSERT_FORMAT_FOR_TYPE_STREQ ("f", double_type_node, 'i'); + ASSERT_FORMAT_FOR_TYPE_STREQ ("Lf", long_double_type_node, 'i'); + ASSERT_FORMAT_FOR_TYPE_STREQ ("f", double_type_node, 'o'); + ASSERT_FORMAT_FOR_TYPE_STREQ ("Lf", long_double_type_node, 'o'); + ASSERT_FORMAT_FOR_TYPE_STREQ ("f", double_type_node, 'x'); + ASSERT_FORMAT_FOR_TYPE_STREQ ("Lf", long_double_type_node, 'x'); + ASSERT_FORMAT_FOR_TYPE_STREQ ("f", double_type_node, 'X'); + ASSERT_FORMAT_FOR_TYPE_STREQ ("Lf", long_double_type_node, 'X'); + ASSERT_FORMAT_FOR_TYPE_STREQ ("d", integer_type_node, 'd'); + ASSERT_FORMAT_FOR_TYPE_STREQ ("i", integer_type_node, 'i'); + ASSERT_FORMAT_FOR_TYPE_STREQ ("o", integer_type_node, 'o'); + ASSERT_FORMAT_FOR_TYPE_STREQ ("x", integer_type_node, 'x'); + ASSERT_FORMAT_FOR_TYPE_STREQ ("X", integer_type_node, 'X'); + ASSERT_FORMAT_FOR_TYPE_STREQ ("d", unsigned_type_node, 'd'); + ASSERT_FORMAT_FOR_TYPE_STREQ ("i", unsigned_type_node, 'i'); + ASSERT_FORMAT_FOR_TYPE_STREQ ("o", unsigned_type_node, 'o'); + ASSERT_FORMAT_FOR_TYPE_STREQ ("x", unsigned_type_node, 'x'); + ASSERT_FORMAT_FOR_TYPE_STREQ ("X", unsigned_type_node, 'X'); + ASSERT_FORMAT_FOR_TYPE_STREQ ("ld", long_integer_type_node, 'd'); + ASSERT_FORMAT_FOR_TYPE_STREQ ("li", long_integer_type_node, 'i'); + ASSERT_FORMAT_FOR_TYPE_STREQ ("lx", long_integer_type_node, 'x'); + ASSERT_FORMAT_FOR_TYPE_STREQ ("lo", long_unsigned_type_node, 'o'); + ASSERT_FORMAT_FOR_TYPE_STREQ ("lx", long_unsigned_type_node, 'x'); + ASSERT_FORMAT_FOR_TYPE_STREQ ("lld", long_long_integer_type_node, 'd'); + ASSERT_FORMAT_FOR_TYPE_STREQ ("lli", long_long_integer_type_node, 'i'); + ASSERT_FORMAT_FOR_TYPE_STREQ ("llo", long_long_unsigned_type_node, 'o'); + ASSERT_FORMAT_FOR_TYPE_STREQ ("llx", long_long_unsigned_type_node, 'x'); + ASSERT_FORMAT_FOR_TYPE_STREQ ("s", build_pointer_type (char_type_node), 'i'); +} + +/* Selftest for get_format_for_type for "scanf"-style functions. */ + +static void +test_get_format_for_type_scanf () +{ + const format_kind_info *fki = get_info ("gnu_scanf"); + ASSERT_NE (fki, NULL); + ASSERT_FORMAT_FOR_TYPE_STREQ ("d", build_pointer_type (integer_type_node), 'd'); + ASSERT_FORMAT_FOR_TYPE_STREQ ("u", build_pointer_type (unsigned_type_node), 'u'); + ASSERT_FORMAT_FOR_TYPE_STREQ ("ld", + build_pointer_type (long_integer_type_node), 'd'); + ASSERT_FORMAT_FOR_TYPE_STREQ ("lu", + build_pointer_type (long_unsigned_type_node), 'u'); + ASSERT_FORMAT_FOR_TYPE_STREQ + ("lld", build_pointer_type (long_long_integer_type_node), 'd'); + ASSERT_FORMAT_FOR_TYPE_STREQ + ("llu", build_pointer_type (long_long_unsigned_type_node), 'u'); + ASSERT_FORMAT_FOR_TYPE_STREQ ("e", build_pointer_type (float_type_node), 'e'); + ASSERT_FORMAT_FOR_TYPE_STREQ ("le", build_pointer_type (double_type_node), 'e'); +} + +#undef ASSERT_FORMAT_FOR_TYPE_STREQ + +/* Exercise the type-printing label code, to give some coverage + under "make selftest-valgrind" (in particular, to ensure that + the label-printing machinery doesn't leak). */ + +static void +test_type_mismatch_range_labels () +{ + /* Create a tempfile and write some text to it. + ....................0000000001 11111111 12 22222222 + ....................1234567890 12345678 90 12345678. */ + const char *content = " printf (\"msg: %i\\n\", msg);\n"; + temp_source_file tmp (SELFTEST_LOCATION, ".c", content); + line_table_test ltt; + + linemap_add (line_table, LC_ENTER, false, tmp.get_filename (), 1); + + location_t c17 = linemap_position_for_column (line_table, 17); + ASSERT_EQ (LOCATION_COLUMN (c17), 17); + location_t c18 = linemap_position_for_column (line_table, 18); + location_t c24 = linemap_position_for_column (line_table, 24); + location_t c26 = linemap_position_for_column (line_table, 26); + + /* Don't attempt to run the tests if column data might be unavailable. */ + if (c26 > LINE_MAP_MAX_LOCATION_WITH_COLS) + return; + + location_t fmt = make_location (c18, c17, c18); + ASSERT_EQ (LOCATION_COLUMN (fmt), 18); + + location_t param = make_location (c24, c24, c26); + ASSERT_EQ (LOCATION_COLUMN (param), 24); + + range_label_for_format_type_mismatch fmt_label (char_type_node, + integer_type_node, 1); + range_label_for_type_mismatch param_label (integer_type_node, + char_type_node); + gcc_rich_location richloc (fmt, &fmt_label); + richloc.add_range (param, SHOW_RANGE_WITHOUT_CARET, ¶m_label); + + test_diagnostic_context dc; + diagnostic_show_locus (&dc, &richloc, DK_ERROR); + if (c_dialect_cxx ()) + /* "char*", without a space. */ + ASSERT_STREQ ("\n" + " printf (\"msg: %i\\n\", msg);\n" + " ~^ ~~~\n" + " | |\n" + " char* int\n", + pp_formatted_text (dc.printer)); + else + /* "char *", with a space. */ + ASSERT_STREQ ("\n" + " printf (\"msg: %i\\n\", msg);\n" + " ~^ ~~~\n" + " | |\n" + " | int\n" + " char *\n", + pp_formatted_text (dc.printer)); +} + +/* Run all of the selftests within this file. */ + +void +c_format_c_tests () +{ + test_get_modifier_for_format_len (); + test_get_format_for_type_printf (); + test_get_format_for_type_scanf (); + test_type_mismatch_range_labels (); +} + +} // namespace selftest + +#endif /* CHECKING_P */ + +// include "gt-c-family-c-format.h" + +static const struct attribute_spec frr_format_attribute_table[] = +{ + /* { name, min_len, max_len, decl_req, type_req, fn_type_req, + affects_type_identity, handler, exclude } */ + { "frr_format", 3, 3, false, true, true, false, + handle_frr_format_attribute, NULL }, + { "frr_format_arg", 1, 1, false, true, true, false, + handle_frr_format_arg_attribute, NULL }, + { NULL, 0, 0, false, false, false, false, NULL, NULL } +}; + +static void +register_attributes (void *event_data, void *data) +{ + // warning (0, G_("Callback to register attributes")); + register_attribute (frr_format_attribute_table); +} + +tree +cb_walk_tree_fn (tree * tp, int * walk_subtrees, void * data ATTRIBUTE_UNUSED) +{ + if (TREE_CODE (*tp) != CALL_EXPR) + return NULL_TREE; + + tree call_expr = *tp; + + int nargs = call_expr_nargs(call_expr); + tree fn = CALL_EXPR_FN(call_expr); + + if (!fn || TREE_CODE (fn) != ADDR_EXPR) + return NULL_TREE; + + tree fndecl = TREE_OPERAND (fn, 0); + if (TREE_CODE (fndecl) != FUNCTION_DECL) + return NULL_TREE; + +#if 0 + warning (0, G_("function call to %s, %d args"), + IDENTIFIER_POINTER (DECL_NAME (fndecl)), + nargs); +#endif + + tree *fargs = (tree *) alloca (nargs * sizeof (tree)); + + for (int j = 0; j < nargs; j++) + { + tree arg = CALL_EXPR_ARG(call_expr, j); + + /* For -Wformat undo the implicit passing by hidden reference + done by convert_arg_to_ellipsis. */ + if (TREE_CODE (arg) == ADDR_EXPR + && TREE_CODE (TREE_TYPE (arg)) == REFERENCE_TYPE) + fargs[j] = TREE_OPERAND (arg, 0); + else + fargs[j] = arg; + } + + check_function_format (TYPE_ATTRIBUTES (TREE_TYPE (fndecl)), nargs, fargs, NULL); + return NULL_TREE; +} + +static void +setup_type (const char *name, tree *dst) +{ + tree tmp; + + if (*dst && *dst != void_type_node) + return; + + *dst = maybe_get_identifier (name); + if (!*dst) + return; + + tmp = identifier_global_value (*dst); + if (tmp && TREE_CODE (tmp) != TYPE_DECL) + { + warning (0, "%<%s%> is not defined as a type", name); + *dst = NULL; + return; + } + if (tmp && TREE_CODE (tmp) == TYPE_DECL) + *dst = tmp; + else + *dst = NULL; +} + +static void +handle_finish_parse (void *event_data, void *data) +{ + tree fndecl = (tree) event_data; + gcc_assert (TREE_CODE (fndecl) == FUNCTION_DECL); + + setup_type ("uint64_t", &local_uint64_t_node); + setup_type ("int64_t", &local_int64_t_node); + + setup_type ("size_t", &local_size_t_node); + setup_type ("ssize_t", &local_ssize_t_node); + setup_type ("atomic_size_t", &local_atomic_size_t_node); + setup_type ("atomic_ssize_t", &local_atomic_ssize_t_node); + setup_type ("ptrdiff_t", &local_ptrdiff_t_node); + + setup_type ("pid_t", &local_pid_t_node); + setup_type ("uid_t", &local_uid_t_node); + setup_type ("gid_t", &local_gid_t_node); + setup_type ("time_t", &local_time_t_node); + + setup_type ("socklen_t", &local_socklen_t_node); + setup_type ("in_addr_t", &local_in_addr_t_node); + + const format_char_info *fci; + + for (fci = print_char_table; fci->format_chars; fci++) + { + if (!fci->kernel_ext) + continue; + + struct kernel_ext_fmt *etab = fci->kernel_ext; + struct kernel_ext_fmt *etab_end = etab + ETAB_SZ; + + for (; etab->suffix && etab < etab_end; etab++) + { + tree identifier, node; + + if (etab->type && etab->type != void_type_node) + continue; + + identifier = maybe_get_identifier (etab->type_str); + + if (!identifier || identifier == error_mark_node) + continue; + + if (etab->type_code) + { + node = identifier_global_tag (identifier); + if (!node) + continue; + + if (node->base.code != etab->type_code) + { + if (!etab->warned) + { + warning (0, "%qs tag category (struct/union/enum) mismatch", etab->type_str); + etab->warned = true; + } + continue; + } + } + else + { + node = identifier_global_value (identifier); + if (!node) + continue; + + if (TREE_CODE (node) != TYPE_DECL) + { + if (!etab->warned) + { + warning (0, "%qs is defined as a non-type", etab->type_str); + etab->warned = true; + } + continue; + } + node = TREE_TYPE (node); + } + + etab->type = node; + } + } + + walk_tree (&DECL_SAVED_TREE (fndecl), cb_walk_tree_fn, NULL, NULL); +} + +static void +handle_pragma_printfrr_ext (cpp_reader *dummy) +{ + tree token = 0; + location_t loc; + enum cpp_ttype ttype; + + ttype = pragma_lex (&token, &loc); + if (ttype != CPP_STRING) + { + error_at (loc, "%<#pragma FRR printfrr_ext%> requires string argument"); + return; + } + + const char *s = TREE_STRING_POINTER (token); + + if (s[0] != '%') + { + error_at (loc, "%<#pragma FRR printfrr_ext%>: invalid format string, needs to start with '%%'"); + return; + } + + switch (s[1]) + { + case 'p': + case 'd': + case 'i': + break; + default: + error_at (loc, "%<#pragma FRR printfrr_ext%>: invalid format string, needs to be %%p, %%d or %%i"); + return; + } + + const format_char_info *fci; + + for (fci = print_char_table; fci->format_chars; fci++) + if (strchr (fci->format_chars, s[1])) + break; + + gcc_assert (fci->format_chars); + gcc_assert (fci->kernel_ext); + + struct kernel_ext_fmt *etab = fci->kernel_ext; + struct kernel_ext_fmt *etab_end = etab + ETAB_SZ; + + switch (s[2]) + { + case 'A' ... 'Z': + break; + + default: + error_at (loc, "%<#pragma FRR printfrr_ext%>: invalid format string, suffix must start with an uppercase letter"); + return; + } + + /* -2 -- need to keep the sentinel at the end */ + if (etab[ETAB_SZ - 2].suffix) + { + error_at (loc, "%<#pragma FRR printfrr_ext%>: out of space for format suffixes"); + return; + } + + for (; etab->suffix && etab < etab_end; etab++) + { + if (!strcmp(s + 2, etab->suffix)) + { + memmove (etab + 1, etab, (etab_end - etab - 1) * sizeof (*etab)); + + if (0) + { + warning_at (loc, OPT_Wformat_, + "%<#pragma FRR printfrr_ext%>: duplicate printf format suffix \"%s\"", s); + warning_at (etab->origin_loc, OPT_Wformat_, + "%<#pragma FRR printfrr_ext%>: previous definition was here"); + return; + } + + break; + } + + if (!strncmp(s + 2, etab->suffix, MIN(strlen(s + 2), strlen(etab->suffix)))) + { + warning_at (loc, OPT_Wformat_, + "%<#pragma FRR printfrr_ext%>: overlapping printf format suffix \"%s\"", s); + warning_at (etab->origin_loc, OPT_Wformat_, + "%<#pragma FRR printfrr_ext%>: previous definition for \"%%%c%s\" was here", s[1], etab->suffix); + return; + } + } + + gcc_assert (etab < etab_end); + + memset (etab, 0, sizeof (*etab)); + etab->suffix = xstrdup(s + 2); + etab->origin_loc = loc; + etab->type = void_type_node; + + ttype = pragma_lex (&token, &loc); + if (ttype != CPP_OPEN_PAREN) + { + error_at (loc, "%<#pragma FRR printfrr_ext%> expected %<(%>"); + goto out_drop; + } + + ttype = pragma_lex (&token, &loc); + + /* qualifiers */ + if (ttype == CPP_NAME && !strcmp (IDENTIFIER_POINTER (token), "const")) + { + etab->t_const = true; + ttype = pragma_lex (&token, &loc); + } + + /* tagged types */ + if (ttype == CPP_NAME && !strcmp (IDENTIFIER_POINTER (token), "struct")) + { + etab->type_code = RECORD_TYPE; + ttype = pragma_lex (&token, &loc); + } + else if (ttype == CPP_NAME && !strcmp (IDENTIFIER_POINTER (token), "union")) + { + etab->type_code = UNION_TYPE; + ttype = pragma_lex (&token, &loc); + } + else if (ttype == CPP_NAME && !strcmp (IDENTIFIER_POINTER (token), "enum")) + { + etab->type_code = ENUMERAL_TYPE; + ttype = pragma_lex (&token, &loc); + } + + /* type name */ + if (ttype != CPP_NAME) + { + error_at (loc, "%<#pragma FRR printfrr_ext%>: expected typename identifier"); + goto out_drop; + } + + etab->type_str = xstrdup (IDENTIFIER_POINTER (token)); + + while ((ttype = pragma_lex (&token, &loc)) != CPP_CLOSE_PAREN) + { + switch (ttype) { + case CPP_NAME: + error_at (loc, "%<#pragma FRR printfrr_ext%>: unexpected identifier. Note the only supported qualifier is \"const\"."); + goto out_drop; + + case CPP_MULT: + etab->ptrlevel++; + break; + + case CPP_EOF: + error_at (loc, "%<#pragma FRR printfrr_ext%>: premature end of line, missing %<)%>"); + goto out_drop; + + default: + error_at (loc, "%<#pragma FRR printfrr_ext%>: unsupported token"); + goto out_drop; + } + } + + ttype = pragma_lex (&token, &loc); + if (ttype != CPP_EOF) + warning_at (loc, OPT_Wformat_, + "%<#pragma FRR printfrr_ext%>: garbage at end of line"); + + return; + +out_drop: + memset (etab, 0, sizeof (*etab)); +} + +static void +register_pragma_printfrr_ext (void *event_data, void *data) +{ + c_register_pragma_with_expansion ("FRR", "printfrr_ext", handle_pragma_printfrr_ext); +} + +static void +define_vars (void *gcc_data, void *user_data) +{ + cpp_define (parse_in, "_FRR_ATTRIBUTE_PRINTFRR=0x10000"); +} + +#ifndef __visible +#define __visible __attribute__((visibility("default"))) +#endif + +__visible int plugin_is_GPL_compatible; + +__visible int +plugin_init (struct plugin_name_args *plugin_info, + struct plugin_gcc_version *version) +{ + const char *plugin_name = plugin_info->base_name; + + if (!plugin_default_version_check(version, &gcc_version)) + { + error(G_("incompatible gcc/plugin versions")); + return 1; + } + + memset (ext_p, 0, sizeof (ext_p)); + memset (ext_d, 0, sizeof (ext_d)); + + register_callback (plugin_name, PLUGIN_FINISH_PARSE_FUNCTION, handle_finish_parse, NULL); + register_callback (plugin_name, PLUGIN_ATTRIBUTES, register_attributes, NULL); + register_callback (plugin_name, PLUGIN_START_UNIT, define_vars, NULL); + register_callback (plugin_name, PLUGIN_PRAGMAS, register_pragma_printfrr_ext, NULL); + return 0; +} diff --git a/tools/gcc-plugins/frr-format.h b/tools/gcc-plugins/frr-format.h new file mode 100644 index 0000000000..87d2049ed4 --- /dev/null +++ b/tools/gcc-plugins/frr-format.h @@ -0,0 +1,364 @@ +/* Check calls to formatted I/O functions (-Wformat). + Copyright (C) 1992-2018 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + +#ifndef GCC_C_FORMAT_H +#define GCC_C_FORMAT_H + +/* The meaningfully distinct length modifiers for format checking recognized + by GCC. */ +enum format_lengths +{ + FMT_LEN_none, + FMT_LEN_hh, + FMT_LEN_h, + FMT_LEN_l, + FMT_LEN_ll, + FMT_LEN_L, + FMT_LEN_z, + FMT_LEN_t, + FMT_LEN_j, + FMT_LEN_H, + FMT_LEN_D, + FMT_LEN_DD, + FMT_LEN_MAX +}; + + +/* The standard versions in which various format features appeared. */ +enum format_std_version +{ + STD_C89, + STD_C94, + STD_C9L, /* C99, but treat as C89 if -Wno-long-long. */ + STD_C99, + STD_EXT +}; + +/* Flags that may apply to a particular kind of format checked by GCC. */ +enum +{ + /* This format converts arguments of types determined by the + format string. */ + FMT_FLAG_ARG_CONVERT = 1, + /* The scanf allocation 'a' kludge applies to this format kind. */ + FMT_FLAG_SCANF_A_KLUDGE = 2, + /* A % during parsing a specifier is allowed to be a modified % rather + that indicating the format is broken and we are out-of-sync. */ + FMT_FLAG_FANCY_PERCENT_OK = 4, + /* With $ operand numbers, it is OK to reference the same argument more + than once. */ + FMT_FLAG_DOLLAR_MULTIPLE = 8, + /* This format type uses $ operand numbers (strfmon doesn't). */ + FMT_FLAG_USE_DOLLAR = 16, + /* Zero width is bad in this type of format (scanf). */ + FMT_FLAG_ZERO_WIDTH_BAD = 32, + /* Empty precision specification is OK in this type of format (printf). */ + FMT_FLAG_EMPTY_PREC_OK = 64, + /* Gaps are allowed in the arguments with $ operand numbers if all + arguments are pointers (scanf). */ + FMT_FLAG_DOLLAR_GAP_POINTER_OK = 128, + /* The format arg is an opaque object that will be parsed by an external + facility. */ + FMT_FLAG_PARSE_ARG_CONVERT_EXTERNAL = 256 + /* Not included here: details of whether width or precision may occur + (controlled by width_char and precision_char); details of whether + '*' can be used for these (width_type and precision_type); details + of whether length modifiers can occur (length_char_specs). */ +}; + +/* Structure describing a length modifier supported in format checking, and + possibly a doubled version such as "hh". */ +struct format_length_info +{ + /* Name of the single-character length modifier. If prefixed by + a zero character, it describes a multi character length + modifier, like I64, I32, etc. */ + const char *name; + /* Index into a format_char_info.types array. */ + enum format_lengths index; + /* Standard version this length appears in. */ + enum format_std_version std; + /* Same, if the modifier can be repeated, or NULL if it can't. */ + const char *double_name; + enum format_lengths double_index; + enum format_std_version double_std; + + /* If this flag is set, just scalar width identity is checked, and + not the type identity itself. */ + int scalar_identity_flag; +}; + + +struct kernel_ext_fmt +{ + const char *suffix; + + /* RECORD_TYPE, UNION_TYPE, ENUMERAL_TYPE, or NULL for typedef */ + tree_code type_code; + int ptrlevel; + bool t_const; + bool warned; + + const char *type_str; + GTY(()) tree type; + + location_t origin_loc; +}; + + +/* Structure describing the combination of a conversion specifier + (or a set of specifiers which act identically) and a length modifier. */ +struct format_type_detail +{ + /* The standard version this combination of length and type appeared in. + This is only relevant if greater than those for length and type + individually; otherwise it is ignored. */ + enum format_std_version std; + /* The name to use for the type, if different from that generated internally + (e.g., "signed size_t"). */ + const char *name; + /* The type itself. */ + tree *type; +}; + + +/* Macros to fill out tables of these. */ +#define NOARGUMENTS { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN } +#define BADLEN { STD_C89, NULL, NULL } +#define NOLENGTHS { BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN } + + +/* Structure describing a format conversion specifier (or a set of specifiers + which act identically), and the length modifiers used with it. */ +struct format_char_info +{ + const char *format_chars; + int pointer_count; + enum format_std_version std; + /* Types accepted for each length modifier. */ + format_type_detail types[FMT_LEN_MAX]; + /* List of other modifier characters allowed with these specifiers. + This lists flags, and additionally "w" for width, "p" for precision + (right precision, for strfmon), "#" for left precision (strfmon), + "a" for scanf "a" allocation extension (not applicable in C99 mode), + "*" for scanf suppression, and "E" and "O" for those strftime + modifiers. */ + const char *flag_chars; + /* List of additional flags describing these conversion specifiers. + "c" for generic character pointers being allowed, "2" for strftime + two digit year formats, "3" for strftime formats giving two digit + years in some locales, "4" for "2" which becomes "3" with an "E" modifier, + "o" if use of strftime "O" is a GNU extension beyond C99, + "W" if the argument is a pointer which is dereferenced and written into, + "R" if the argument is a pointer which is dereferenced and read from, + "i" for printf integer formats where the '0' flag is ignored with + precision, and "[" for the starting character of a scanf scanset, + "<" if the specifier introduces a quoted sequence (such as "%<"), + ">" if the specifier terminates a quoted sequence (such as "%>"), + "[" if the specifier introduces a color sequence (such as "%r"), + "]" if the specifier terminates a color sequence (such as "%R"), + "'" (single quote) if the specifier is expected to be quoted when + it appears outside a quoted sequence and unquoted otherwise (such + as the GCC internal printf format directive "%T"), and + "\"" (double quote) if the specifier is not expected to appear in + a quoted sequence (such as the GCC internal format directive "%K". */ + const char *flags2; + /* If this format conversion character consumes more than one argument, + CHAIN points to information about the next argument. For later + arguments, only POINTER_COUNT, TYPES, and the "c", "R", and "W" flags + in FLAGS2 are used. */ + const struct format_char_info *chain; + + struct kernel_ext_fmt *kernel_ext; +}; + + +/* Structure describing a flag accepted by some kind of format. */ +struct format_flag_spec +{ + /* The flag character in question (0 for end of array). */ + int flag_char; + /* Zero if this entry describes the flag character in general, or a + nonzero character that may be found in flags2 if it describes the + flag when used with certain formats only. If the latter, only + the first such entry found that applies to the current conversion + specifier is used; the values of 'name' and 'long_name' it supplies + will be used, if non-NULL and the standard version is higher than + the unpredicated one, for any pedantic warning. For example, 'o' + for strftime formats (meaning 'O' is an extension over C99). */ + int predicate; + /* Nonzero if the next character after this flag in the format should + be skipped ('=' in strfmon), zero otherwise. */ + int skip_next_char; + /* True if the flag introduces quoting (as in GCC's %qE). */ + bool quoting; + /* The name to use for this flag in diagnostic messages. For example, + N_("'0' flag"), N_("field width"). */ + const char *name; + /* Long name for this flag in diagnostic messages; currently only used for + "ISO C does not support ...". For example, N_("the 'I' printf flag"). */ + const char *long_name; + /* The standard version in which it appeared. */ + enum format_std_version std; +}; + + +/* Structure describing a combination of flags that is bad for some kind + of format. */ +struct format_flag_pair +{ + /* The first flag character in question (0 for end of array). */ + int flag_char1; + /* The second flag character. */ + int flag_char2; + /* Nonzero if the message should say that the first flag is ignored with + the second, zero if the combination should simply be objected to. */ + int ignored; + /* Zero if this entry applies whenever this flag combination occurs, + a nonzero character from flags2 if it only applies in some + circumstances (e.g. 'i' for printf formats ignoring 0 with precision). */ + int predicate; +}; + + +/* Structure describing a particular kind of format processed by GCC. */ +struct format_kind_info +{ + /* The name of this kind of format, for use in diagnostics. Also + the name of the attribute (without preceding and following __). */ + const char *name; + /* Specifications of the length modifiers accepted; possibly NULL. */ + const format_length_info *length_char_specs; + /* Details of the conversion specification characters accepted. */ + const format_char_info *conversion_specs; + /* String listing the flag characters that are accepted. */ + const char *flag_chars; + /* String listing modifier characters (strftime) accepted. May be NULL. */ + const char *modifier_chars; + /* Details of the flag characters, including pseudo-flags. */ + const format_flag_spec *flag_specs; + /* Details of bad combinations of flags. */ + const format_flag_pair *bad_flag_pairs; + /* Flags applicable to this kind of format. */ + int flags; + /* Flag character to treat a width as, or 0 if width not used. */ + int width_char; + /* Flag character to treat a left precision (strfmon) as, + or 0 if left precision not used. */ + int left_precision_char; + /* Flag character to treat a precision (for strfmon, right precision) as, + or 0 if precision not used. */ + int precision_char; + /* If a flag character has the effect of suppressing the conversion of + an argument ('*' in scanf), that flag character, otherwise 0. */ + int suppression_char; + /* Flag character to treat a length modifier as (ignored if length + modifiers not used). Need not be placed in flag_chars for conversion + specifiers, but is used to check for bad combinations such as length + modifier with assignment suppression in scanf. */ + int length_code_char; + /* Assignment-allocation flag character ('m' in scanf), otherwise 0. */ + int alloc_char; + /* Pointer to type of argument expected if '*' is used for a width, + or NULL if '*' not used for widths. */ + tree *width_type; + /* Pointer to type of argument expected if '*' is used for a precision, + or NULL if '*' not used for precisions. */ + tree *precision_type; +}; + +#define T_I &integer_type_node +#define T89_I { STD_C89, NULL, T_I } +#define T_L &long_integer_type_node +#define T89_L { STD_C89, NULL, T_L } +#define T_LL &long_long_integer_type_node +#define T9L_LL { STD_C9L, NULL, T_LL } +#define TEX_LL { STD_EXT, NULL, T_LL } +#define T_U64 &local_uint64_t_node +#define TEX_U64 { STD_EXT, "uint64_t", T_U64 } +#define T_S64 &local_int64_t_node +#define TEX_S64 { STD_EXT, "int64_t", T_S64 } +#define T_S &short_integer_type_node +#define T89_S { STD_C89, NULL, T_S } +#define T_UI &unsigned_type_node +#define T89_UI { STD_C89, NULL, T_UI } +#define T_UL &long_unsigned_type_node +#define T89_UL { STD_C89, NULL, T_UL } +#define T_ULL &long_long_unsigned_type_node +#define T9L_ULL { STD_C9L, NULL, T_ULL } +#define TEX_ULL { STD_EXT, NULL, T_ULL } +#define T_US &short_unsigned_type_node +#define T89_US { STD_C89, NULL, T_US } +#define T_F &float_type_node +#define T89_F { STD_C89, NULL, T_F } +#define T99_F { STD_C99, NULL, T_F } +#define T_D &double_type_node +#define T89_D { STD_C89, NULL, T_D } +#define T99_D { STD_C99, NULL, T_D } +#define T_LD &long_double_type_node +#define T89_LD { STD_C89, NULL, T_LD } +#define T99_LD { STD_C99, NULL, T_LD } +#define T_C &char_type_node +#define T89_C { STD_C89, NULL, T_C } +#define T_SC &signed_char_type_node +#define T99_SC { STD_C99, NULL, T_SC } +#define T_UC &unsigned_char_type_node +#define T99_UC { STD_C99, NULL, T_UC } +#define T_V &void_type_node +#define T89_G { STD_C89, NULL, &local_gimple_ptr_node } +#define T89_T { STD_C89, NULL, &local_tree_type_node } +#define T89_V { STD_C89, NULL, T_V } +#define T_W &wchar_type_node +#define T94_W { STD_C94, "wchar_t", T_W } +#define TEX_W { STD_EXT, "wchar_t", T_W } +#define T_WI &wint_type_node +#define T94_WI { STD_C94, "wint_t", T_WI } +#define TEX_WI { STD_EXT, "wint_t", T_WI } +#define T_ST &local_size_t_node +#define T99_ST { STD_C99, "size_t", T_ST } +#define T_SST &local_ssize_t_node +#define T99_SST { STD_C99, "ssize_t", T_SST } +#define T_PD &ptrdiff_type_node +#define T99_PD { STD_C99, "ptrdiff_t", T_PD } +#define T_UPD &unsigned_ptrdiff_type_node +#define T99_UPD { STD_C99, "unsigned ptrdiff_t", T_UPD } +#define T_IM &intmax_type_node +#define T99_IM { STD_C99, "intmax_t", T_IM } +#define T_UIM &uintmax_type_node +#define T99_UIM { STD_C99, "uintmax_t", T_UIM } +#define T_D32 &dfloat32_type_node +#define TEX_D32 { STD_EXT, "_Decimal32", T_D32 } +#define T_D64 &dfloat64_type_node +#define TEX_D64 { STD_EXT, "_Decimal64", T_D64 } +#define T_D128 &dfloat128_type_node +#define TEX_D128 { STD_EXT, "_Decimal128", T_D128 } + +/* Structure describing how format attributes such as "printf" are + interpreted as "gnu_printf" or "ms_printf" on a particular system. + TARGET_OVERRIDES_FORMAT_ATTRIBUTES is used to specify target-specific + defaults. */ +struct target_ovr_attr +{ + /* The name of the to be copied format attribute. */ + const char *named_attr_src; + /* The name of the to be overridden format attribute. */ + const char *named_attr_dst; +}; + +#endif /* GCC_C_FORMAT_H */ diff --git a/tools/gcc-plugins/gcc-common.h b/tools/gcc-plugins/gcc-common.h new file mode 100644 index 0000000000..6b6c17231a --- /dev/null +++ b/tools/gcc-plugins/gcc-common.h @@ -0,0 +1,981 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/* FRR: imported from Linux kernel on 2019-07-29 */ + +#ifndef GCC_COMMON_H_INCLUDED +#define GCC_COMMON_H_INCLUDED + +#include "bversion.h" +#if BUILDING_GCC_VERSION >= 6000 +#include "gcc-plugin.h" +#else +#include "plugin.h" +#endif +#include "plugin-version.h" +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "line-map.h" +#include "input.h" +#include "tree.h" + +#include "tree-inline.h" +#include "version.h" +#include "rtl.h" +#include "tm_p.h" +#include "flags.h" +#include "hard-reg-set.h" +#include "output.h" +#include "except.h" +#include "function.h" +#include "toplev.h" +#if BUILDING_GCC_VERSION >= 5000 +#include "expr.h" +#endif +#include "basic-block.h" +#include "intl.h" +#include "ggc.h" +#include "timevar.h" + +#include "params.h" + +#if BUILDING_GCC_VERSION <= 4009 +#include "pointer-set.h" +#else +#include "hash-map.h" +#endif + +#if BUILDING_GCC_VERSION >= 7000 +#include "memmodel.h" +#endif +#include "emit-rtl.h" +#include "debug.h" +#include "target.h" +#include "langhooks.h" +#include "cfgloop.h" +#include "cgraph.h" +#include "opts.h" + +#if BUILDING_GCC_VERSION == 4005 +#include <sys/mman.h> +#endif + +#if BUILDING_GCC_VERSION >= 4007 +#include "tree-pretty-print.h" +#include "gimple-pretty-print.h" +#endif + +#if BUILDING_GCC_VERSION >= 4006 +/* + * The c-family headers were moved into a subdirectory in GCC version + * 4.7, but most plugin-building users of GCC 4.6 are using the Debian + * or Ubuntu package, which has an out-of-tree patch to move this to the + * same location as found in 4.7 and later: + * https://sources.debian.net/src/gcc-4.6/4.6.3-14/debian/patches/pr45078.diff/ + */ +#include "c-family/c-common.h" +#else +#include "c-common.h" +#endif + +#if BUILDING_GCC_VERSION <= 4008 +#include "tree-flow.h" +#else +#include "tree-cfgcleanup.h" +#include "tree-ssa-operands.h" +#include "tree-into-ssa.h" +#endif + +#if BUILDING_GCC_VERSION >= 4008 +#include "is-a.h" +#endif + +#include "diagnostic.h" +#include "tree-dump.h" +#include "tree-pass.h" +#if BUILDING_GCC_VERSION >= 4009 +#include "pass_manager.h" +#endif +#include "predict.h" +#include "ipa-utils.h" + +#if BUILDING_GCC_VERSION >= 8000 +#include "stringpool.h" +#endif + +#if BUILDING_GCC_VERSION >= 4009 +#include "attribs.h" +#include "varasm.h" +#include "stor-layout.h" +#include "internal-fn.h" +#include "gimple-expr.h" +#include "gimple-fold.h" +#include "context.h" +#include "tree-ssa-alias.h" +#include "tree-ssa.h" +#include "stringpool.h" +#if BUILDING_GCC_VERSION >= 7000 +#include "tree-vrp.h" +#endif +#include "tree-ssanames.h" +#include "print-tree.h" +#include "tree-eh.h" +#include "stmt.h" +#include "gimplify.h" +#endif + +#include "gimple.h" + +#if BUILDING_GCC_VERSION >= 4009 +#include "tree-ssa-operands.h" +#include "tree-phinodes.h" +#include "tree-cfg.h" +#include "gimple-iterator.h" +#include "gimple-ssa.h" +#include "ssa-iterators.h" +#endif + +#if BUILDING_GCC_VERSION >= 5000 +#include "builtins.h" +#endif + +/* missing from basic_block.h... */ +void debug_dominance_info(enum cdi_direction dir); +void debug_dominance_tree(enum cdi_direction dir, basic_block root); + +#if BUILDING_GCC_VERSION == 4006 +void debug_gimple_stmt(gimple); +void debug_gimple_seq(gimple_seq); +void print_gimple_seq(FILE *, gimple_seq, int, int); +void print_gimple_stmt(FILE *, gimple, int, int); +void print_gimple_expr(FILE *, gimple, int, int); +void dump_gimple_stmt(pretty_printer *, gimple, int, int); +#endif + +#ifndef __unused +#define __unused __attribute__((__unused__)) +#endif +#ifndef __visible +#define __visible __attribute__((visibility("default"))) +#endif + +#define DECL_NAME_POINTER(node) IDENTIFIER_POINTER(DECL_NAME(node)) +#define DECL_NAME_LENGTH(node) IDENTIFIER_LENGTH(DECL_NAME(node)) +#define TYPE_NAME_POINTER(node) IDENTIFIER_POINTER(TYPE_NAME(node)) +#define TYPE_NAME_LENGTH(node) IDENTIFIER_LENGTH(TYPE_NAME(node)) + +#if BUILDING_GCC_VERSION < 9000 +/* should come from c-tree.h if only it were installed for gcc 4.5... */ +#define C_TYPE_FIELDS_READONLY(TYPE) TREE_LANG_FLAG_1(TYPE) +#endif + +static inline tree build_const_char_string(int len, const char *str) +{ + tree cstr, elem, index, type; + + cstr = build_string(len, str); + elem = build_type_variant(char_type_node, 1, 0); + index = build_index_type(size_int(len - 1)); + type = build_array_type(elem, index); + TREE_TYPE(cstr) = type; + TREE_CONSTANT(cstr) = 1; + TREE_READONLY(cstr) = 1; + TREE_STATIC(cstr) = 1; + return cstr; +} + +#define PASS_INFO(NAME, REF, ID, POS) \ +struct register_pass_info NAME##_pass_info = { \ + .pass = make_##NAME##_pass(), \ + .reference_pass_name = REF, \ + .ref_pass_instance_number = ID, \ + .pos_op = POS, \ +} + +#if BUILDING_GCC_VERSION == 4005 +#define FOR_EACH_LOCAL_DECL(FUN, I, D) \ + for (tree vars = (FUN)->local_decls, (I) = 0; \ + vars && ((D) = TREE_VALUE(vars)); \ + vars = TREE_CHAIN(vars), (I)++) +#define DECL_CHAIN(NODE) (TREE_CHAIN(DECL_MINIMAL_CHECK(NODE))) +#define FOR_EACH_VEC_ELT(T, V, I, P) \ + for (I = 0; VEC_iterate(T, (V), (I), (P)); ++(I)) +#define TODO_rebuild_cgraph_edges 0 +#define SCOPE_FILE_SCOPE_P(EXP) (!(EXP)) + +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +typedef struct varpool_node *varpool_node_ptr; + +static inline bool gimple_call_builtin_p(gimple stmt, enum built_in_function code) +{ + tree fndecl; + + if (!is_gimple_call(stmt)) + return false; + fndecl = gimple_call_fndecl(stmt); + if (!fndecl || DECL_BUILT_IN_CLASS(fndecl) != BUILT_IN_NORMAL) + return false; + return DECL_FUNCTION_CODE(fndecl) == code; +} + +static inline bool is_simple_builtin(tree decl) +{ + if (decl && DECL_BUILT_IN_CLASS(decl) != BUILT_IN_NORMAL) + return false; + + switch (DECL_FUNCTION_CODE(decl)) { + /* Builtins that expand to constants. */ + case BUILT_IN_CONSTANT_P: + case BUILT_IN_EXPECT: + case BUILT_IN_OBJECT_SIZE: + case BUILT_IN_UNREACHABLE: + /* Simple register moves or loads from stack. */ + case BUILT_IN_RETURN_ADDRESS: + case BUILT_IN_EXTRACT_RETURN_ADDR: + case BUILT_IN_FROB_RETURN_ADDR: + case BUILT_IN_RETURN: + case BUILT_IN_AGGREGATE_INCOMING_ADDRESS: + case BUILT_IN_FRAME_ADDRESS: + case BUILT_IN_VA_END: + case BUILT_IN_STACK_SAVE: + case BUILT_IN_STACK_RESTORE: + /* Exception state returns or moves registers around. */ + case BUILT_IN_EH_FILTER: + case BUILT_IN_EH_POINTER: + case BUILT_IN_EH_COPY_VALUES: + return true; + + default: + return false; + } +} + +static inline void add_local_decl(struct function *fun, tree d) +{ + gcc_assert(TREE_CODE(d) == VAR_DECL); + fun->local_decls = tree_cons(NULL_TREE, d, fun->local_decls); +} +#endif + +#if BUILDING_GCC_VERSION <= 4006 +#define ANY_RETURN_P(rtx) (GET_CODE(rtx) == RETURN) +#define C_DECL_REGISTER(EXP) DECL_LANG_FLAG_4(EXP) +#define EDGE_PRESERVE 0ULL +#define HOST_WIDE_INT_PRINT_HEX_PURE "%" HOST_WIDE_INT_PRINT "x" +#define flag_fat_lto_objects true + +#define get_random_seed(noinit) ({ \ + unsigned HOST_WIDE_INT seed; \ + sscanf(get_random_seed(noinit), "%" HOST_WIDE_INT_PRINT "x", &seed); \ + seed * seed; }) + +#define int_const_binop(code, arg1, arg2) \ + int_const_binop((code), (arg1), (arg2), 0) + +static inline bool gimple_clobber_p(gimple s __unused) +{ + return false; +} + +static inline bool gimple_asm_clobbers_memory_p(const_gimple stmt) +{ + unsigned i; + + for (i = 0; i < gimple_asm_nclobbers(stmt); i++) { + tree op = gimple_asm_clobber_op(stmt, i); + + if (!strcmp(TREE_STRING_POINTER(TREE_VALUE(op)), "memory")) + return true; + } + + return false; +} + +static inline tree builtin_decl_implicit(enum built_in_function fncode) +{ + return implicit_built_in_decls[fncode]; +} + +static inline int ipa_reverse_postorder(struct cgraph_node **order) +{ + return cgraph_postorder(order); +} + +static inline struct cgraph_node *cgraph_create_node(tree decl) +{ + return cgraph_node(decl); +} + +static inline struct cgraph_node *cgraph_get_create_node(tree decl) +{ + struct cgraph_node *node = cgraph_get_node(decl); + + return node ? node : cgraph_node(decl); +} + +static inline bool cgraph_function_with_gimple_body_p(struct cgraph_node *node) +{ + return node->analyzed && !node->thunk.thunk_p && !node->alias; +} + +static inline struct cgraph_node *cgraph_first_function_with_gimple_body(void) +{ + struct cgraph_node *node; + + for (node = cgraph_nodes; node; node = node->next) + if (cgraph_function_with_gimple_body_p(node)) + return node; + return NULL; +} + +static inline struct cgraph_node *cgraph_next_function_with_gimple_body(struct cgraph_node *node) +{ + for (node = node->next; node; node = node->next) + if (cgraph_function_with_gimple_body_p(node)) + return node; + return NULL; +} + +static inline bool cgraph_for_node_and_aliases(cgraph_node_ptr node, bool (*callback)(cgraph_node_ptr, void *), void *data, bool include_overwritable) +{ + cgraph_node_ptr alias; + + if (callback(node, data)) + return true; + + for (alias = node->same_body; alias; alias = alias->next) { + if (include_overwritable || cgraph_function_body_availability(alias) > AVAIL_OVERWRITABLE) + if (cgraph_for_node_and_aliases(alias, callback, data, include_overwritable)) + return true; + } + + return false; +} + +#define FOR_EACH_FUNCTION_WITH_GIMPLE_BODY(node) \ + for ((node) = cgraph_first_function_with_gimple_body(); (node); \ + (node) = cgraph_next_function_with_gimple_body(node)) + +static inline void varpool_add_new_variable(tree decl) +{ + varpool_finalize_decl(decl); +} +#endif + +#if BUILDING_GCC_VERSION <= 4007 +#define FOR_EACH_FUNCTION(node) \ + for (node = cgraph_nodes; node; node = node->next) +#define FOR_EACH_VARIABLE(node) \ + for (node = varpool_nodes; node; node = node->next) +#define PROP_loops 0 +#define NODE_SYMBOL(node) (node) +#define NODE_DECL(node) (node)->decl +#define INSN_LOCATION(INSN) RTL_LOCATION(INSN) +#define vNULL NULL + +static inline int bb_loop_depth(const_basic_block bb) +{ + return bb->loop_father ? loop_depth(bb->loop_father) : 0; +} + +static inline bool gimple_store_p(gimple gs) +{ + tree lhs = gimple_get_lhs(gs); + + return lhs && !is_gimple_reg(lhs); +} + +static inline void gimple_init_singleton(gimple g __unused) +{ +} +#endif + +#if BUILDING_GCC_VERSION == 4007 || BUILDING_GCC_VERSION == 4008 +static inline struct cgraph_node *cgraph_alias_target(struct cgraph_node *n) +{ + return cgraph_alias_aliased_node(n); +} +#endif + +#if BUILDING_GCC_VERSION <= 4008 +#define ENTRY_BLOCK_PTR_FOR_FN(FN) ENTRY_BLOCK_PTR_FOR_FUNCTION(FN) +#define EXIT_BLOCK_PTR_FOR_FN(FN) EXIT_BLOCK_PTR_FOR_FUNCTION(FN) +#define basic_block_info_for_fn(FN) ((FN)->cfg->x_basic_block_info) +#define n_basic_blocks_for_fn(FN) ((FN)->cfg->x_n_basic_blocks) +#define n_edges_for_fn(FN) ((FN)->cfg->x_n_edges) +#define last_basic_block_for_fn(FN) ((FN)->cfg->x_last_basic_block) +#define label_to_block_map_for_fn(FN) ((FN)->cfg->x_label_to_block_map) +#define profile_status_for_fn(FN) ((FN)->cfg->x_profile_status) +#define BASIC_BLOCK_FOR_FN(FN, N) BASIC_BLOCK_FOR_FUNCTION((FN), (N)) +#define NODE_IMPLICIT_ALIAS(node) (node)->same_body_alias +#define VAR_P(NODE) (TREE_CODE(NODE) == VAR_DECL) + +static inline bool tree_fits_shwi_p(const_tree t) +{ + if (t == NULL_TREE || TREE_CODE(t) != INTEGER_CST) + return false; + + if (TREE_INT_CST_HIGH(t) == 0 && (HOST_WIDE_INT)TREE_INT_CST_LOW(t) >= 0) + return true; + + if (TREE_INT_CST_HIGH(t) == -1 && (HOST_WIDE_INT)TREE_INT_CST_LOW(t) < 0 && !TYPE_UNSIGNED(TREE_TYPE(t))) + return true; + + return false; +} + +static inline bool tree_fits_uhwi_p(const_tree t) +{ + if (t == NULL_TREE || TREE_CODE(t) != INTEGER_CST) + return false; + + return TREE_INT_CST_HIGH(t) == 0; +} + +static inline HOST_WIDE_INT tree_to_shwi(const_tree t) +{ + gcc_assert(tree_fits_shwi_p(t)); + return TREE_INT_CST_LOW(t); +} + +static inline unsigned HOST_WIDE_INT tree_to_uhwi(const_tree t) +{ + gcc_assert(tree_fits_uhwi_p(t)); + return TREE_INT_CST_LOW(t); +} + +static inline const char *get_tree_code_name(enum tree_code code) +{ + gcc_assert(code < MAX_TREE_CODES); + return tree_code_name[code]; +} + +#define ipa_remove_stmt_references(cnode, stmt) + +typedef union gimple_statement_d gasm; +typedef union gimple_statement_d gassign; +typedef union gimple_statement_d gcall; +typedef union gimple_statement_d gcond; +typedef union gimple_statement_d gdebug; +typedef union gimple_statement_d ggoto; +typedef union gimple_statement_d gphi; +typedef union gimple_statement_d greturn; + +static inline gasm *as_a_gasm(gimple stmt) +{ + return stmt; +} + +static inline const gasm *as_a_const_gasm(const_gimple stmt) +{ + return stmt; +} + +static inline gassign *as_a_gassign(gimple stmt) +{ + return stmt; +} + +static inline const gassign *as_a_const_gassign(const_gimple stmt) +{ + return stmt; +} + +static inline gcall *as_a_gcall(gimple stmt) +{ + return stmt; +} + +static inline const gcall *as_a_const_gcall(const_gimple stmt) +{ + return stmt; +} + +static inline gcond *as_a_gcond(gimple stmt) +{ + return stmt; +} + +static inline const gcond *as_a_const_gcond(const_gimple stmt) +{ + return stmt; +} + +static inline gdebug *as_a_gdebug(gimple stmt) +{ + return stmt; +} + +static inline const gdebug *as_a_const_gdebug(const_gimple stmt) +{ + return stmt; +} + +static inline ggoto *as_a_ggoto(gimple stmt) +{ + return stmt; +} + +static inline const ggoto *as_a_const_ggoto(const_gimple stmt) +{ + return stmt; +} + +static inline gphi *as_a_gphi(gimple stmt) +{ + return stmt; +} + +static inline const gphi *as_a_const_gphi(const_gimple stmt) +{ + return stmt; +} + +static inline greturn *as_a_greturn(gimple stmt) +{ + return stmt; +} + +static inline const greturn *as_a_const_greturn(const_gimple stmt) +{ + return stmt; +} +#endif + +#if BUILDING_GCC_VERSION == 4008 +#define NODE_SYMBOL(node) (&(node)->symbol) +#define NODE_DECL(node) (node)->symbol.decl +#endif + +#if BUILDING_GCC_VERSION >= 4008 +#define add_referenced_var(var) +#define mark_sym_for_renaming(var) +#define varpool_mark_needed_node(node) +#define create_var_ann(var) +#define TODO_dump_func 0 +#define TODO_dump_cgraph 0 +#endif + +#if BUILDING_GCC_VERSION <= 4009 +#define TODO_verify_il 0 +#define AVAIL_INTERPOSABLE AVAIL_OVERWRITABLE + +#define section_name_prefix LTO_SECTION_NAME_PREFIX +#define fatal_error(loc, gmsgid, ...) fatal_error((gmsgid), __VA_ARGS__) + +rtx emit_move_insn(rtx x, rtx y); + +typedef struct rtx_def rtx_insn; + +static inline const char *get_decl_section_name(const_tree decl) +{ + if (DECL_SECTION_NAME(decl) == NULL_TREE) + return NULL; + + return TREE_STRING_POINTER(DECL_SECTION_NAME(decl)); +} + +static inline void set_decl_section_name(tree node, const char *value) +{ + if (value) + DECL_SECTION_NAME(node) = build_string(strlen(value) + 1, value); + else + DECL_SECTION_NAME(node) = NULL; +} +#endif + +#if BUILDING_GCC_VERSION == 4009 +typedef struct gimple_statement_asm gasm; +typedef struct gimple_statement_base gassign; +typedef struct gimple_statement_call gcall; +typedef struct gimple_statement_base gcond; +typedef struct gimple_statement_base gdebug; +typedef struct gimple_statement_base ggoto; +typedef struct gimple_statement_phi gphi; +typedef struct gimple_statement_base greturn; + +static inline gasm *as_a_gasm(gimple stmt) +{ + return as_a<gasm>(stmt); +} + +static inline const gasm *as_a_const_gasm(const_gimple stmt) +{ + return as_a<const gasm>(stmt); +} + +static inline gassign *as_a_gassign(gimple stmt) +{ + return stmt; +} + +static inline const gassign *as_a_const_gassign(const_gimple stmt) +{ + return stmt; +} + +static inline gcall *as_a_gcall(gimple stmt) +{ + return as_a<gcall>(stmt); +} + +static inline const gcall *as_a_const_gcall(const_gimple stmt) +{ + return as_a<const gcall>(stmt); +} + +static inline gcond *as_a_gcond(gimple stmt) +{ + return stmt; +} + +static inline const gcond *as_a_const_gcond(const_gimple stmt) +{ + return stmt; +} + +static inline gdebug *as_a_gdebug(gimple stmt) +{ + return stmt; +} + +static inline const gdebug *as_a_const_gdebug(const_gimple stmt) +{ + return stmt; +} + +static inline ggoto *as_a_ggoto(gimple stmt) +{ + return stmt; +} + +static inline const ggoto *as_a_const_ggoto(const_gimple stmt) +{ + return stmt; +} + +static inline gphi *as_a_gphi(gimple stmt) +{ + return as_a<gphi>(stmt); +} + +static inline const gphi *as_a_const_gphi(const_gimple stmt) +{ + return as_a<const gphi>(stmt); +} + +static inline greturn *as_a_greturn(gimple stmt) +{ + return stmt; +} + +static inline const greturn *as_a_const_greturn(const_gimple stmt) +{ + return stmt; +} +#endif + +#if BUILDING_GCC_VERSION >= 4009 +#define TODO_ggc_collect 0 +#define NODE_SYMBOL(node) (node) +#define NODE_DECL(node) (node)->decl +#define cgraph_node_name(node) (node)->name() +#define NODE_IMPLICIT_ALIAS(node) (node)->cpp_implicit_alias + +static inline opt_pass *get_pass_for_id(int id) +{ + return g->get_passes()->get_pass_for_id(id); +} +#endif + +#if BUILDING_GCC_VERSION >= 5000 && BUILDING_GCC_VERSION < 6000 +/* gimple related */ +template <> +template <> +inline bool is_a_helper<const gassign *>::test(const_gimple gs) +{ + return gs->code == GIMPLE_ASSIGN; +} +#endif + +#if BUILDING_GCC_VERSION >= 5000 +#define TODO_verify_ssa TODO_verify_il +#define TODO_verify_flow TODO_verify_il +#define TODO_verify_stmts TODO_verify_il +#define TODO_verify_rtl_sharing TODO_verify_il + +#define INSN_DELETED_P(insn) (insn)->deleted() + +static inline const char *get_decl_section_name(const_tree decl) +{ + return DECL_SECTION_NAME(decl); +} + +/* symtab/cgraph related */ +#define debug_cgraph_node(node) (node)->debug() +#define cgraph_get_node(decl) cgraph_node::get(decl) +#define cgraph_get_create_node(decl) cgraph_node::get_create(decl) +#define cgraph_create_node(decl) cgraph_node::create(decl) +#define cgraph_n_nodes symtab->cgraph_count +#define cgraph_max_uid symtab->cgraph_max_uid +#define varpool_get_node(decl) varpool_node::get(decl) +#define dump_varpool_node(file, node) (node)->dump(file) + +#if BUILDING_GCC_VERSION >= 8000 +#define cgraph_create_edge(caller, callee, call_stmt, count, freq) \ + (caller)->create_edge((callee), (call_stmt), (count)) + +#define cgraph_create_edge_including_clones(caller, callee, \ + old_call_stmt, call_stmt, count, freq, reason) \ + (caller)->create_edge_including_clones((callee), \ + (old_call_stmt), (call_stmt), (count), (reason)) +#else +#define cgraph_create_edge(caller, callee, call_stmt, count, freq) \ + (caller)->create_edge((callee), (call_stmt), (count), (freq)) + +#define cgraph_create_edge_including_clones(caller, callee, \ + old_call_stmt, call_stmt, count, freq, reason) \ + (caller)->create_edge_including_clones((callee), \ + (old_call_stmt), (call_stmt), (count), (freq), (reason)) +#endif + +typedef struct cgraph_node *cgraph_node_ptr; +typedef struct cgraph_edge *cgraph_edge_p; +typedef struct varpool_node *varpool_node_ptr; + +static inline void change_decl_assembler_name(tree decl, tree name) +{ + symtab->change_decl_assembler_name(decl, name); +} + +static inline void varpool_finalize_decl(tree decl) +{ + varpool_node::finalize_decl(decl); +} + +static inline void varpool_add_new_variable(tree decl) +{ + varpool_node::add(decl); +} + +static inline unsigned int rebuild_cgraph_edges(void) +{ + return cgraph_edge::rebuild_edges(); +} + +static inline cgraph_node_ptr cgraph_function_node(cgraph_node_ptr node, enum availability *availability) +{ + return node->function_symbol(availability); +} + +static inline cgraph_node_ptr cgraph_function_or_thunk_node(cgraph_node_ptr node, enum availability *availability = NULL) +{ + return node->ultimate_alias_target(availability); +} + +static inline bool cgraph_only_called_directly_p(cgraph_node_ptr node) +{ + return node->only_called_directly_p(); +} + +static inline enum availability cgraph_function_body_availability(cgraph_node_ptr node) +{ + return node->get_availability(); +} + +static inline cgraph_node_ptr cgraph_alias_target(cgraph_node_ptr node) +{ + return node->get_alias_target(); +} + +static inline bool cgraph_for_node_and_aliases(cgraph_node_ptr node, bool (*callback)(cgraph_node_ptr, void *), void *data, bool include_overwritable) +{ + return node->call_for_symbol_thunks_and_aliases(callback, data, include_overwritable); +} + +static inline struct cgraph_node_hook_list *cgraph_add_function_insertion_hook(cgraph_node_hook hook, void *data) +{ + return symtab->add_cgraph_insertion_hook(hook, data); +} + +static inline void cgraph_remove_function_insertion_hook(struct cgraph_node_hook_list *entry) +{ + symtab->remove_cgraph_insertion_hook(entry); +} + +static inline struct cgraph_node_hook_list *cgraph_add_node_removal_hook(cgraph_node_hook hook, void *data) +{ + return symtab->add_cgraph_removal_hook(hook, data); +} + +static inline void cgraph_remove_node_removal_hook(struct cgraph_node_hook_list *entry) +{ + symtab->remove_cgraph_removal_hook(entry); +} + +static inline struct cgraph_2node_hook_list *cgraph_add_node_duplication_hook(cgraph_2node_hook hook, void *data) +{ + return symtab->add_cgraph_duplication_hook(hook, data); +} + +static inline void cgraph_remove_node_duplication_hook(struct cgraph_2node_hook_list *entry) +{ + symtab->remove_cgraph_duplication_hook(entry); +} + +static inline void cgraph_call_node_duplication_hooks(cgraph_node_ptr node, cgraph_node_ptr node2) +{ + symtab->call_cgraph_duplication_hooks(node, node2); +} + +static inline void cgraph_call_edge_duplication_hooks(cgraph_edge *cs1, cgraph_edge *cs2) +{ + symtab->call_edge_duplication_hooks(cs1, cs2); +} + +#if BUILDING_GCC_VERSION >= 6000 +typedef gimple *gimple_ptr; +typedef const gimple *const_gimple_ptr; +#define gimple gimple_ptr +#define const_gimple const_gimple_ptr +#undef CONST_CAST_GIMPLE +#define CONST_CAST_GIMPLE(X) CONST_CAST(gimple, (X)) +#endif + +/* gimple related */ +static inline gimple gimple_build_assign_with_ops(enum tree_code subcode, tree lhs, tree op1, tree op2 MEM_STAT_DECL) +{ + return gimple_build_assign(lhs, subcode, op1, op2 PASS_MEM_STAT); +} + +template <> +template <> +inline bool is_a_helper<const ggoto *>::test(const_gimple gs) +{ + return gs->code == GIMPLE_GOTO; +} + +template <> +template <> +inline bool is_a_helper<const greturn *>::test(const_gimple gs) +{ + return gs->code == GIMPLE_RETURN; +} + +static inline gasm *as_a_gasm(gimple stmt) +{ + return as_a<gasm *>(stmt); +} + +static inline const gasm *as_a_const_gasm(const_gimple stmt) +{ + return as_a<const gasm *>(stmt); +} + +static inline gassign *as_a_gassign(gimple stmt) +{ + return as_a<gassign *>(stmt); +} + +static inline const gassign *as_a_const_gassign(const_gimple stmt) +{ + return as_a<const gassign *>(stmt); +} + +static inline gcall *as_a_gcall(gimple stmt) +{ + return as_a<gcall *>(stmt); +} + +static inline const gcall *as_a_const_gcall(const_gimple stmt) +{ + return as_a<const gcall *>(stmt); +} + +static inline ggoto *as_a_ggoto(gimple stmt) +{ + return as_a<ggoto *>(stmt); +} + +static inline const ggoto *as_a_const_ggoto(const_gimple stmt) +{ + return as_a<const ggoto *>(stmt); +} + +static inline gphi *as_a_gphi(gimple stmt) +{ + return as_a<gphi *>(stmt); +} + +static inline const gphi *as_a_const_gphi(const_gimple stmt) +{ + return as_a<const gphi *>(stmt); +} + +static inline greturn *as_a_greturn(gimple stmt) +{ + return as_a<greturn *>(stmt); +} + +static inline const greturn *as_a_const_greturn(const_gimple stmt) +{ + return as_a<const greturn *>(stmt); +} + +/* IPA/LTO related */ +#define ipa_ref_list_referring_iterate(L, I, P) \ + (L)->referring.iterate((I), &(P)) +#define ipa_ref_list_reference_iterate(L, I, P) \ + (L)->reference.iterate((I), &(P)) + +static inline cgraph_node_ptr ipa_ref_referring_node(struct ipa_ref *ref) +{ + return dyn_cast<cgraph_node_ptr>(ref->referring); +} + +static inline void ipa_remove_stmt_references(symtab_node *referring_node, gimple stmt) +{ + referring_node->remove_stmt_references(stmt); +} +#endif + +#if BUILDING_GCC_VERSION < 6000 +#define get_inner_reference(exp, pbitsize, pbitpos, poffset, pmode, punsignedp, preversep, pvolatilep, keep_aligning) \ + get_inner_reference(exp, pbitsize, pbitpos, poffset, pmode, punsignedp, pvolatilep, keep_aligning) +#define gen_rtx_set(ARG0, ARG1) gen_rtx_SET(VOIDmode, (ARG0), (ARG1)) +#endif + +#if BUILDING_GCC_VERSION >= 6000 +#define gen_rtx_set(ARG0, ARG1) gen_rtx_SET((ARG0), (ARG1)) +#endif + +#ifdef __cplusplus +static inline void debug_tree(const_tree t) +{ + debug_tree(CONST_CAST_TREE(t)); +} + +static inline void debug_gimple_stmt(const_gimple s) +{ + debug_gimple_stmt(CONST_CAST_GIMPLE(s)); +} +#else +#define debug_tree(t) debug_tree(CONST_CAST_TREE(t)) +#define debug_gimple_stmt(s) debug_gimple_stmt(CONST_CAST_GIMPLE(s)) +#endif + +#if BUILDING_GCC_VERSION >= 7000 +#define get_inner_reference(exp, pbitsize, pbitpos, poffset, pmode, punsignedp, preversep, pvolatilep, keep_aligning) \ + get_inner_reference(exp, pbitsize, pbitpos, poffset, pmode, punsignedp, preversep, pvolatilep) +#endif + +#if BUILDING_GCC_VERSION < 7000 +#define SET_DECL_ALIGN(decl, align) DECL_ALIGN(decl) = (align) +#define SET_DECL_MODE(decl, mode) DECL_MODE(decl) = (mode) +#endif + +#endif diff --git a/tools/gcc-plugins/gcc-retain-typeinfo.patch b/tools/gcc-plugins/gcc-retain-typeinfo.patch new file mode 100644 index 0000000000..ec51f0be6f --- /dev/null +++ b/tools/gcc-plugins/gcc-retain-typeinfo.patch @@ -0,0 +1,11 @@ +--- a/src/gcc/c/c-typeck.c ++++ b/src/gcc/c/c-typeck.c +@@ -5716,8 +5716,6 @@ build_c_cast (location_t loc, tree type, tree expr) + if (objc_is_object_ptr (type) && objc_is_object_ptr (TREE_TYPE (expr))) + return build1 (NOP_EXPR, type, expr); + +- type = TYPE_MAIN_VARIANT (type); +- + if (TREE_CODE (type) == ARRAY_TYPE) + { + error_at (loc, "cast specifies array type"); diff --git a/watchfrr/watchfrr.c b/watchfrr/watchfrr.c index ed9616963d..05e6651229 100644 --- a/watchfrr/watchfrr.c +++ b/watchfrr/watchfrr.c @@ -318,9 +318,8 @@ static pid_t run_background(char *shell_cmd) } default: /* Parent process: we will reap the child later. */ - flog_err_sys(EC_LIB_SYSTEM_CALL, - "Forked background command [pid %d]: %s", - (int)child, shell_cmd); + zlog_info("Forked background command [pid %d]: %s", (int)child, + shell_cmd); return child; } } @@ -559,9 +558,9 @@ static int wakeup_init(struct thread *t_wakeup) dmn->t_wakeup = NULL; if (try_connect(dmn) < 0) { - flog_err(EC_WATCHFRR_CONNECTION, - "%s state -> down : initial connection attempt failed", - dmn->name); + zlog_info( + "%s state -> down : initial connection attempt failed", + dmn->name); dmn->state = DAEMON_DOWN; } phase_check(); diff --git a/yang/frr-bfdd.yang b/yang/frr-bfdd.yang index f9ac2e43b0..b870bfd0c8 100644 --- a/yang/frr-bfdd.yang +++ b/yang/frr-bfdd.yang @@ -16,7 +16,7 @@ module frr-bfdd { prefix frr-route-types; } - organization "Free Range Routing"; + organization "FRRouting"; contact "FRR Users List: <mailto:frog@lists.frrouting.org> FRR Development List: <mailto:dev@lists.frrouting.org>"; diff --git a/yang/frr-eigrpd.yang b/yang/frr-eigrpd.yang index 0c62954570..e02f888b0e 100644 --- a/yang/frr-eigrpd.yang +++ b/yang/frr-eigrpd.yang @@ -16,7 +16,7 @@ module frr-eigrpd { prefix frr-route-types; } - organization "Free Range Routing"; + organization "FRRouting"; contact "FRR Users List: <mailto:frog@lists.frrouting.org> FRR Development List: <mailto:dev@lists.frrouting.org>"; diff --git a/yang/frr-filter.yang b/yang/frr-filter.yang index e79ede87b7..61ffa51552 100644 --- a/yang/frr-filter.yang +++ b/yang/frr-filter.yang @@ -10,7 +10,7 @@ module frr-filter { prefix yang; } - organization "Free Range Routing"; + organization "FRRouting"; contact "FRR Users List: <mailto:frog@lists.frrouting.org> FRR Development List: <mailto:dev@lists.frrouting.org>"; diff --git a/yang/frr-interface.yang b/yang/frr-interface.yang index 4f7f3beebd..1f3eebb2ab 100644 --- a/yang/frr-interface.yang +++ b/yang/frr-interface.yang @@ -4,7 +4,7 @@ module frr-interface { prefix frr-interface; organization - "Free Range Routing"; + "FRRouting"; contact "FRR Users List: <mailto:frog@lists.frrouting.org> FRR Development List: <mailto:dev@lists.frrouting.org>"; diff --git a/yang/frr-isisd.yang b/yang/frr-isisd.yang index faab1e55b2..8dcc0f97a3 100644 --- a/yang/frr-isisd.yang +++ b/yang/frr-isisd.yang @@ -20,7 +20,7 @@ module frr-isisd { } organization - "Free Range Routing"; + "FRRouting"; contact "FRR Users List: <mailto:frog@lists.frrouting.org> FRR Development List: <mailto:dev@lists.frrouting.org>"; diff --git a/yang/frr-module-translator.yang b/yang/frr-module-translator.yang index 3d64ec5399..6713eae76e 100644 --- a/yang/frr-module-translator.yang +++ b/yang/frr-module-translator.yang @@ -4,7 +4,7 @@ module frr-module-translator { prefix frr-module-translator; organization - "Free Range Routing"; + "FRRouting"; contact "FRR Users List: <mailto:frog@lists.frrouting.org> FRR Development List: <mailto:dev@lists.frrouting.org>"; diff --git a/yang/frr-nexthop.yang b/yang/frr-nexthop.yang index 7d8ce1b8ed..3657ecbd75 100644 --- a/yang/frr-nexthop.yang +++ b/yang/frr-nexthop.yang @@ -15,7 +15,7 @@ module frr-nexthop { } organization - "Free Range Routing"; + "FRRouting"; contact "FRR Users List: <mailto:frog@lists.frrouting.org> FRR Development List: <mailto:dev@lists.frrouting.org>"; diff --git a/yang/frr-ripd.yang b/yang/frr-ripd.yang index 94a9ebf3e1..7318eb18d7 100644 --- a/yang/frr-ripd.yang +++ b/yang/frr-ripd.yang @@ -17,7 +17,7 @@ module frr-ripd { } organization - "Free Range Routing"; + "FRRouting"; contact "FRR Users List: <mailto:frog@lists.frrouting.org> FRR Development List: <mailto:dev@lists.frrouting.org>"; diff --git a/yang/frr-ripngd.yang b/yang/frr-ripngd.yang index 831758af86..732f32ea50 100644 --- a/yang/frr-ripngd.yang +++ b/yang/frr-ripngd.yang @@ -17,7 +17,7 @@ module frr-ripngd { } organization - "Free Range Routing"; + "FRRouting"; contact "FRR Users List: <mailto:frog@lists.frrouting.org> FRR Development List: <mailto:dev@lists.frrouting.org>"; diff --git a/yang/frr-route-map.yang b/yang/frr-route-map.yang index 34a7e28a77..eea29733a3 100644 --- a/yang/frr-route-map.yang +++ b/yang/frr-route-map.yang @@ -13,7 +13,7 @@ module frr-route-map { prefix frr-interface; } - organization "Free Range Routing"; + organization "FRRouting"; contact "FRR Users List: <mailto:frog@lists.frrouting.org> FRR Development List: <mailto:dev@lists.frrouting.org>"; @@ -179,17 +179,27 @@ module frr-route-map { description "Match a route tag"; value 10; } - - /* - * Protocol YANG models should augment the parent node to - * contain the routing protocol specific value. The protocol - * must also augment `condition-value` to include its specific - * values or expand the `when` statement on the existing cases. - */ - enum routing-protocol-specific { - description "Match a routing protocol specific type"; + /* zebra specific conditions. */ + enum ipv4-prefix-length { + description "Match IPv4 prefix length"; value 100; } + enum ipv6-prefix-length { + description "Match IPv6 prefix length"; + value 101; + } + enum ipv4-next-hop-prefix-length { + description "Match next-hop prefix length"; + value 102; + } + enum source-protocol { + description "Match source protocol"; + value 103; + } + enum source-instance { + description "Match source protocol instance"; + value 104; + } } } @@ -291,15 +301,9 @@ module frr-route-map { description "Set tag"; value 3; } - - /* - * Protocol YANG models should augment the parent node to - * contain the routing protocol specific value. The protocol - * must also augment `action-value` to include its specific - * values or expand the `when` statement on the existing cases. - */ - enum routing-protocol-specific { - description "Set a routing protocol specific action"; + /* zebra specific conditions. */ + enum source { + description "Set source address for route"; value 100; } } diff --git a/yang/frr-route-types.yang b/yang/frr-route-types.yang index f22c5ef890..8fdd10121e 100644 --- a/yang/frr-route-types.yang +++ b/yang/frr-route-types.yang @@ -4,7 +4,7 @@ module frr-route-types { prefix frr-route-types; organization - "Free Range Routing"; + "FRRouting"; contact "FRR Users List: <mailto:frog@lists.frrouting.org> FRR Development List: <mailto:dev@lists.frrouting.org>"; @@ -106,4 +106,12 @@ module frr-route-types { } } } + + typedef frr-route-types { + description "Route types as enumerated in `lib/route_types.txt`"; + type union { + type frr-route-types-v4; + type frr-route-types-v6; + } + } } diff --git a/yang/frr-vrrpd.yang b/yang/frr-vrrpd.yang index 3d3a4138fa..145387c4b4 100644 --- a/yang/frr-vrrpd.yang +++ b/yang/frr-vrrpd.yang @@ -16,7 +16,7 @@ module frr-vrrpd { } organization - "Free Range Routing"; + "FRRouting"; contact "FRR Users List: <mailto:frog@lists.frrouting.org> FRR Development List: <mailto:dev@lists.frrouting.org>"; diff --git a/yang/frr-zebra.yang b/yang/frr-zebra.yang index 74922a22f7..736bbc2c81 100644 --- a/yang/frr-zebra.yang +++ b/yang/frr-zebra.yang @@ -11,6 +11,10 @@ module frr-zebra { prefix inet; } + import frr-route-map { + prefix frr-route-map; + } + import frr-route-types { prefix frr-route-types; } @@ -28,7 +32,7 @@ module frr-zebra { } organization - "Free Range Routing"; + "FRRouting"; contact "FRR Users List: <mailto:frog@lists.frrouting.org> FRR Development List: <mailto:dev@lists.frrouting.org>"; @@ -1985,4 +1989,63 @@ module frr-zebra { } // End interface model augmentation + + augment "/frr-route-map:lib" + + "/frr-route-map:route-map" + + "/frr-route-map:entry" + + "/frr-route-map:match-condition" + + "/frr-route-map:condition-value" { + case ipv4-prefix-length { + when "./condition = 'ipv4-prefix-length' or + ./condition = 'ipv4-next-hop-prefix-length'"; + leaf ipv4-prefix-length { + type uint8 { + range "0..32"; + } + } + } + case ipv6-prefix-length { + when "./condition = 'ipv6-prefix-length'"; + leaf ipv6-prefix-length { + type uint8 { + range "0..128"; + } + } + } + case source-protocol { + when "./condition = 'source-protocol'"; + leaf source-protocol { + type frr-route-types:frr-route-types; + } + } + case source-instance { + when "./condition = 'source-instance'"; + leaf source-instance { + type uint8 { + range "0..255"; + } + } + } + } + + augment "/frr-route-map:lib" + + "/frr-route-map:route-map" + + "/frr-route-map:entry" + + "/frr-route-map:set-action" + + "/frr-route-map:action-value" { + case source-v4 { + when "./action = 'source'"; + leaf source-v4 { + description "IPv4 address"; + type inet:ipv4-address; + } + } + case source-v6 { + when "./action = 'source'"; + leaf source-v6 { + description "IPv6 address"; + type inet:ipv6-address; + } + } + } } diff --git a/yang/ietf/frr-deviations-ietf-interfaces.yang b/yang/ietf/frr-deviations-ietf-interfaces.yang index 6528d66d22..704839fb60 100644 --- a/yang/ietf/frr-deviations-ietf-interfaces.yang +++ b/yang/ietf/frr-deviations-ietf-interfaces.yang @@ -8,7 +8,7 @@ module frr-deviations-ietf-interfaces { } organization - "Free Range Routing"; + "FRRouting"; contact "FRR Users List: <mailto:frog@lists.frrouting.org> diff --git a/yang/ietf/frr-deviations-ietf-rip.yang b/yang/ietf/frr-deviations-ietf-rip.yang index 42ed8e3c09..39a1d7e71d 100644 --- a/yang/ietf/frr-deviations-ietf-rip.yang +++ b/yang/ietf/frr-deviations-ietf-rip.yang @@ -12,7 +12,7 @@ module frr-deviations-ietf-rip { } organization - "Free Range Routing"; + "FRRouting"; contact "FRR Users List: <mailto:frog@lists.frrouting.org> diff --git a/yang/ietf/frr-deviations-ietf-routing.yang b/yang/ietf/frr-deviations-ietf-routing.yang index 62787e782c..15ceb6b929 100644 --- a/yang/ietf/frr-deviations-ietf-routing.yang +++ b/yang/ietf/frr-deviations-ietf-routing.yang @@ -8,7 +8,7 @@ module frr-deviations-ietf-routing { } organization - "Free Range Routing"; + "FRRouting"; contact "FRR Users List: <mailto:frog@lists.frrouting.org> diff --git a/yang/subdir.am b/yang/subdir.am index c1297dafd5..0e124c5ab0 100644 --- a/yang/subdir.am +++ b/yang/subdir.am @@ -21,10 +21,12 @@ EXTRA_DIST += yang/embedmodel.py dist_yangmodels_DATA += yang/frr-filter.yang dist_yangmodels_DATA += yang/frr-module-translator.yang +dist_yangmodels_DATA += yang/frr-nexthop.yang dist_yangmodels_DATA += yang/frr-test-module.yang dist_yangmodels_DATA += yang/frr-interface.yang dist_yangmodels_DATA += yang/frr-route-map.yang dist_yangmodels_DATA += yang/frr-route-types.yang +dist_yangmodels_DATA += yang/frr-zebra.yang dist_yangmodels_DATA += yang/ietf/ietf-routing-types.yang if BFDD diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c index 5ab5210664..950690b943 100644 --- a/zebra/kernel_socket.c +++ b/zebra/kernel_socket.c @@ -1393,7 +1393,7 @@ static int kernel_read(struct thread *thread) */ if (rtm->rtm_msglen != nbytes) { zlog_debug( - "kernel_read: rtm->rtm_msglen %d, nbytes %d, type %d\n", + "kernel_read: rtm->rtm_msglen %d, nbytes %d, type %d", rtm->rtm_msglen, nbytes, rtm->rtm_type); return -1; } diff --git a/zebra/label_manager.c b/zebra/label_manager.c index caebdc0f08..0825fb55ca 100644 --- a/zebra/label_manager.c +++ b/zebra/label_manager.c @@ -4,7 +4,7 @@ * Copyright (C) 2017 by Bingen Eguzkitza, * Volta Networks Inc. * - * This file is part of FreeRangeRouting (FRR) + * This file is part of FRRouting (FRR) * * FRR is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the diff --git a/zebra/label_manager.h b/zebra/label_manager.h index 74e283e85e..4fee34d301 100644 --- a/zebra/label_manager.h +++ b/zebra/label_manager.h @@ -4,7 +4,7 @@ * Copyright (C) 2017 by Bingen Eguzkitza, * Volta Networks Inc. * - * This file is part of FreeRangeRouting (FRR) + * This file is part of FRRouting (FRR) * * FRR is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the diff --git a/zebra/main.c b/zebra/main.c index dab1449194..306372ccdb 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -174,6 +174,7 @@ static void sigint(void) work_queue_free_and_null(&zrouter.lsp_process_q); vrf_terminate(); + rtadv_terminate(); ns_walk_func(zebra_ns_early_shutdown); zebra_ns_notify_close(); @@ -245,6 +246,7 @@ struct quagga_signal_t zebra_signals[] = { static const struct frr_yang_module_info *const zebra_yang_modules[] = { &frr_interface_info, &frr_route_map_info, + &frr_zebra_info, }; FRR_DAEMON_INFO( diff --git a/zebra/redistribute.c b/zebra/redistribute.c index 80cc18a57d..115a69f2c8 100644 --- a/zebra/redistribute.c +++ b/zebra/redistribute.c @@ -268,7 +268,7 @@ void redistribute_delete(const struct prefix *p, const struct prefix *src_p, /* Add DISTANCE_INFINITY check. */ if (old_re && (old_re->distance == DISTANCE_INFINITY)) { if (IS_ZEBRA_DEBUG_RIB) - zlog_debug("\tSkipping due to Infinite Distance"); + zlog_debug(" Skipping due to Infinite Distance"); return; } @@ -291,6 +291,10 @@ void redistribute_delete(const struct prefix *p, const struct prefix *src_p, } for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) { + /* Do not send unsolicited messages to synchronous clients. */ + if (client->synchronous) + continue; + if (new_re) { /* Skip this client if it will receive an update for the * 'new' re @@ -472,6 +476,12 @@ void zebra_interface_up_update(struct interface *ifp) if (ifp->ptm_status || !ifp->ptm_enable) { for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) { + /* Do not send unsolicited messages to synchronous + * clients. + */ + if (client->synchronous) + continue; + zsend_interface_update(ZEBRA_INTERFACE_UP, client, ifp); zsend_interface_link_params(client, ifp); @@ -490,6 +500,10 @@ void zebra_interface_down_update(struct interface *ifp) ifp->name, ifp->vrf_id); for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) { + /* Do not send unsolicited messages to synchronous clients. */ + if (client->synchronous) + continue; + zsend_interface_update(ZEBRA_INTERFACE_DOWN, client, ifp); } } @@ -505,6 +519,10 @@ void zebra_interface_add_update(struct interface *ifp) ifp->vrf_id); for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) { + /* Do not send unsolicited messages to synchronous clients. */ + if (client->synchronous) + continue; + client->ifadd_cnt++; zsend_interface_add(client, ifp); zsend_interface_link_params(client, ifp); @@ -521,6 +539,10 @@ void zebra_interface_delete_update(struct interface *ifp) ifp->name, ifp->vrf_id); for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) { + /* Do not send unsolicited messages to synchronous clients. */ + if (client->synchronous) + continue; + client->ifdel_cnt++; zsend_interface_delete(client, ifp); } @@ -552,12 +574,17 @@ void zebra_interface_address_add_update(struct interface *ifp, router_id_add_address(ifc); - for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) + for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) { + /* Do not send unsolicited messages to synchronous clients. */ + if (client->synchronous) + continue; + if (CHECK_FLAG(ifc->conf, ZEBRA_IFC_REAL)) { client->connected_rt_add_cnt++; zsend_interface_address(ZEBRA_INTERFACE_ADDRESS_ADD, client, ifp, ifc); } + } } /* Interface address deletion. */ @@ -581,12 +608,17 @@ void zebra_interface_address_delete_update(struct interface *ifp, router_id_del_address(ifc); - for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) + for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) { + /* Do not send unsolicited messages to synchronous clients. */ + if (client->synchronous) + continue; + if (CHECK_FLAG(ifc->conf, ZEBRA_IFC_REAL)) { client->connected_rt_del_cnt++; zsend_interface_address(ZEBRA_INTERFACE_ADDRESS_DELETE, client, ifp, ifc); } + } } /* Interface VRF change. May need to delete from clients not interested in @@ -603,6 +635,10 @@ void zebra_interface_vrf_update_del(struct interface *ifp, vrf_id_t new_vrf_id) ifp->name, ifp->vrf_id, new_vrf_id); for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) { + /* Do not send unsolicited messages to synchronous clients. */ + if (client->synchronous) + continue; + /* Need to delete if the client is not interested in the new * VRF. */ zsend_interface_update(ZEBRA_INTERFACE_DOWN, client, ifp); @@ -626,6 +662,10 @@ void zebra_interface_vrf_update_add(struct interface *ifp, vrf_id_t old_vrf_id) ifp->name, old_vrf_id, ifp->vrf_id); for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) { + /* Do not send unsolicited messages to synchronous clients. */ + if (client->synchronous) + continue; + /* Need to add if the client is interested in the new VRF. */ client->ifadd_cnt++; zsend_interface_add(client, ifp); @@ -913,6 +953,11 @@ void zebra_interface_parameters_update(struct interface *ifp) zlog_debug("MESSAGE: ZEBRA_INTERFACE_LINK_PARAMS %s(%u)", ifp->name, ifp->vrf_id); - for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) + for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) { + /* Do not send unsolicited messages to synchronous clients. */ + if (client->synchronous) + continue; + zsend_interface_link_params(client, ifp); + } } diff --git a/zebra/rib.h b/zebra/rib.h index 931c97638e..3717a12814 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -107,7 +107,7 @@ struct route_entry { /* Uptime. */ time_t uptime; - /* Type fo this route. */ + /* Type of this route. */ int type; /* VRF identifier. */ @@ -347,10 +347,16 @@ extern int rib_add(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, struct prefix_ipv6 *src_p, const struct nexthop *nh, uint32_t nhe_id, uint32_t table_id, uint32_t metric, uint32_t mtu, uint8_t distance, route_tag_t tag); - +/* + * Multipath route apis. + */ extern int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, struct prefix_ipv6 *src_p, struct route_entry *re, struct nexthop_group *ng); +extern int rib_add_multipath_nhe(afi_t afi, safi_t safi, struct prefix *p, + struct prefix_ipv6 *src_p, + struct route_entry *re, + struct nhg_hash_entry *nhe); extern void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, unsigned short instance, int flags, struct prefix *p, diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 2cc520bbce..84c9bd098e 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -1111,7 +1111,8 @@ static int build_label_stack(struct mpls_label_stack *nh_label, * @param nlmsg: nlmsghdr structure to fill in. * @param req_size: The size allocated for the message. */ -static void _netlink_route_build_singlepath(const char *routedesc, int bytelen, +static void _netlink_route_build_singlepath(const struct prefix *p, + const char *routedesc, int bytelen, const struct nexthop *nexthop, struct nlmsghdr *nlmsg, struct rtmsg *rtmsg, @@ -1176,9 +1177,8 @@ static void _netlink_route_build_singlepath(const char *routedesc, int bytelen, if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug( - " 5549: _netlink_route_build_singlepath() (%s): " - "nexthop via %s %s if %u(%u)", - routedesc, ipv4_ll_buf, label_buf, + " 5549: _netlink_route_build_singlepath() (%s): %pFX nexthop via %s %s if %u(%u)", + routedesc, p, ipv4_ll_buf, label_buf, nexthop->ifindex, nexthop->vrf_id); return; } @@ -1202,9 +1202,8 @@ static void _netlink_route_build_singlepath(const char *routedesc, int bytelen, if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug( - "netlink_route_multipath() (%s): " - "nexthop via %s %s if %u(%u)", - routedesc, inet_ntoa(nexthop->gate.ipv4), + "netlink_route_multipath() (%s): %pFX nexthop via %s %s if %u(%u)", + routedesc, p, inet_ntoa(nexthop->gate.ipv4), label_buf, nexthop->ifindex, nexthop->vrf_id); } @@ -1225,9 +1224,8 @@ static void _netlink_route_build_singlepath(const char *routedesc, int bytelen, if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug( - "netlink_route_multipath() (%s): " - "nexthop via %s %s if %u(%u)", - routedesc, inet6_ntoa(nexthop->gate.ipv6), + "netlink_route_multipath() (%s): %pFX nexthop via %s %s if %u(%u)", + routedesc, p, inet6_ntoa(nexthop->gate.ipv6), label_buf, nexthop->ifindex, nexthop->vrf_id); } @@ -1251,9 +1249,9 @@ static void _netlink_route_build_singlepath(const char *routedesc, int bytelen, if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug( - "netlink_route_multipath() (%s): " - "nexthop via if %u(%u)", - routedesc, nexthop->ifindex, nexthop->vrf_id); + "netlink_route_multipath() (%s): %pFX nexthop via if %u(%u)", + routedesc, p, nexthop->ifindex, + nexthop->vrf_id); } } @@ -1273,12 +1271,11 @@ static void _netlink_route_build_singlepath(const char *routedesc, int bytelen, * @param src: pointer pointing to a location where * the prefsrc should be stored. */ -static void _netlink_route_build_multipath(const char *routedesc, int bytelen, - const struct nexthop *nexthop, - struct rtattr *rta, - struct rtnexthop *rtnh, - struct rtmsg *rtmsg, - const union g_addr **src) +static void +_netlink_route_build_multipath(const struct prefix *p, const char *routedesc, + int bytelen, const struct nexthop *nexthop, + struct rtattr *rta, struct rtnexthop *rtnh, + struct rtmsg *rtmsg, const union g_addr **src) { mpls_lse_t out_lse[MPLS_MAX_LABELS]; char label_buf[256]; @@ -1350,9 +1347,8 @@ static void _netlink_route_build_multipath(const char *routedesc, int bytelen, if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug( - " 5549: netlink_route_build_multipath() (%s): " - "nexthop via %s %s if %u", - routedesc, ipv4_ll_buf, label_buf, + " 5549: netlink_route_build_multipath() (%s): %pFX nexthop via %s %s if %u", + routedesc, p, ipv4_ll_buf, label_buf, nexthop->ifindex); return; } @@ -1369,9 +1365,8 @@ static void _netlink_route_build_multipath(const char *routedesc, int bytelen, if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug( - "netlink_route_multipath() (%s): " - "nexthop via %s %s if %u", - routedesc, inet_ntoa(nexthop->gate.ipv4), + "netlink_route_multipath() (%s): %pFX nexthop via %s %s if %u", + routedesc, p, inet_ntoa(nexthop->gate.ipv4), label_buf, nexthop->ifindex); } if (nexthop->type == NEXTHOP_TYPE_IPV6 @@ -1387,9 +1382,8 @@ static void _netlink_route_build_multipath(const char *routedesc, int bytelen, if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug( - "netlink_route_multipath() (%s): " - "nexthop via %s %s if %u", - routedesc, inet6_ntoa(nexthop->gate.ipv6), + "netlink_route_multipath() (%s): %pFX nexthop via %s %s if %u", + routedesc, p, inet6_ntoa(nexthop->gate.ipv6), label_buf, nexthop->ifindex); } @@ -1410,16 +1404,16 @@ static void _netlink_route_build_multipath(const char *routedesc, int bytelen, if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug( - "netlink_route_multipath() (%s): " - "nexthop via if %u", - routedesc, nexthop->ifindex); + "netlink_route_multipath() (%s): %pFX nexthop via if %u", + routedesc, p, nexthop->ifindex); } if (nexthop->weight) rtnh->rtnh_hops = nexthop->weight - 1; } -static inline void _netlink_mpls_build_singlepath(const char *routedesc, +static inline void _netlink_mpls_build_singlepath(const struct prefix *p, + const char *routedesc, const zebra_nhlfe_t *nhlfe, struct nlmsghdr *nlmsg, struct rtmsg *rtmsg, @@ -1430,23 +1424,24 @@ static inline void _netlink_mpls_build_singlepath(const char *routedesc, family = NHLFE_FAMILY(nhlfe); bytelen = (family == AF_INET ? 4 : 16); - _netlink_route_build_singlepath(routedesc, bytelen, nhlfe->nexthop, + _netlink_route_build_singlepath(p, routedesc, bytelen, nhlfe->nexthop, nlmsg, rtmsg, req_size, cmd); } static inline void -_netlink_mpls_build_multipath(const char *routedesc, const zebra_nhlfe_t *nhlfe, - struct rtattr *rta, struct rtnexthop *rtnh, - struct rtmsg *rtmsg, const union g_addr **src) +_netlink_mpls_build_multipath(const struct prefix *p, const char *routedesc, + const zebra_nhlfe_t *nhlfe, struct rtattr *rta, + struct rtnexthop *rtnh, struct rtmsg *rtmsg, + const union g_addr **src) { int bytelen; uint8_t family; family = NHLFE_FAMILY(nhlfe); bytelen = (family == AF_INET ? 4 : 16); - _netlink_route_build_multipath(routedesc, bytelen, nhlfe->nexthop, rta, - rtnh, rtmsg, src); + _netlink_route_build_multipath(p, routedesc, bytelen, nhlfe->nexthop, + rta, rtnh, rtmsg, src); } @@ -1520,6 +1515,30 @@ static int netlink_neigh_update(int cmd, int ifindex, uint32_t addr, char *lla, 0); } +static bool nexthop_set_src(const struct nexthop *nexthop, int family, + union g_addr *src) +{ + if (family == AF_INET) { + if (nexthop->rmap_src.ipv4.s_addr != INADDR_ANY) { + src->ipv4 = nexthop->rmap_src.ipv4; + return true; + } else if (nexthop->src.ipv4.s_addr != INADDR_ANY) { + src->ipv4 = nexthop->src.ipv4; + return true; + } + } else if (family == AF_INET6) { + if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->rmap_src.ipv6)) { + src->ipv6 = nexthop->rmap_src.ipv6; + return true; + } else if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->src.ipv6)) { + src->ipv6 = nexthop->src.ipv6; + return true; + } + } + + return false; +} + /* * Routing table change via netlink interface, using a dataplane context object */ @@ -1530,7 +1549,7 @@ static int netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx) unsigned int nexthop_num; int family; const char *routedesc; - int setsrc = 0; + bool setsrc = false; union g_addr src; const struct prefix *p, *src_p; uint32_t table_id; @@ -1647,8 +1666,29 @@ static int netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx) if (kernel_nexthops_supported()) { /* Kernel supports nexthop objects */ + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug( + "netlink_route_multipath(): %pFX nhg_id is %u", + p, dplane_ctx_get_nhe_id(ctx)); addattr32(&req.n, sizeof(req), RTA_NH_ID, dplane_ctx_get_nhe_id(ctx)); + + /* Have to determine src still */ + for (ALL_NEXTHOPS_PTR(dplane_ctx_get_ng(ctx), nexthop)) { + if (setsrc) + break; + + setsrc = nexthop_set_src(nexthop, family, &src); + } + + if (setsrc) { + if (family == AF_INET) + addattr_l(&req.n, sizeof(req), RTA_PREFSRC, + &src.ipv4, bytelen); + else if (family == AF_INET6) + addattr_l(&req.n, sizeof(req), RTA_PREFSRC, + &src.ipv6, bytelen); + } goto skip; } @@ -1696,32 +1736,8 @@ static int netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx) if (setsrc) continue; - if (family == AF_INET) { - if (nexthop->rmap_src.ipv4.s_addr - != 0) { - src.ipv4 = - nexthop->rmap_src.ipv4; - setsrc = 1; - } else if (nexthop->src.ipv4.s_addr - != 0) { - src.ipv4 = - nexthop->src.ipv4; - setsrc = 1; - } - } else if (family == AF_INET6) { - if (!IN6_IS_ADDR_UNSPECIFIED( - &nexthop->rmap_src.ipv6)) { - src.ipv6 = - nexthop->rmap_src.ipv6; - setsrc = 1; - } else if ( - !IN6_IS_ADDR_UNSPECIFIED( - &nexthop->src.ipv6)) { - src.ipv6 = - nexthop->src.ipv6; - setsrc = 1; - } - } + setsrc = nexthop_set_src(nexthop, family, &src); + continue; } @@ -1732,13 +1748,13 @@ static int netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx) : "single-path"; _netlink_route_build_singlepath( - routedesc, bytelen, nexthop, &req.n, + p, routedesc, bytelen, nexthop, &req.n, &req.r, sizeof(req), cmd); nexthop_num++; break; } } - if (setsrc && (cmd == RTM_NEWROUTE)) { + if (setsrc) { if (family == AF_INET) addattr_l(&req.n, sizeof(req), RTA_PREFSRC, &src.ipv4, bytelen); @@ -1764,32 +1780,7 @@ static int netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx) if (setsrc) continue; - if (family == AF_INET) { - if (nexthop->rmap_src.ipv4.s_addr - != 0) { - src.ipv4 = - nexthop->rmap_src.ipv4; - setsrc = 1; - } else if (nexthop->src.ipv4.s_addr - != 0) { - src.ipv4 = - nexthop->src.ipv4; - setsrc = 1; - } - } else if (family == AF_INET6) { - if (!IN6_IS_ADDR_UNSPECIFIED( - &nexthop->rmap_src.ipv6)) { - src.ipv6 = - nexthop->rmap_src.ipv6; - setsrc = 1; - } else if ( - !IN6_IS_ADDR_UNSPECIFIED( - &nexthop->src.ipv6)) { - src.ipv6 = - nexthop->src.ipv6; - setsrc = 1; - } - } + setsrc = nexthop_set_src(nexthop, family, &src); continue; } @@ -1802,8 +1793,8 @@ static int netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx) nexthop_num++; _netlink_route_build_multipath( - routedesc, bytelen, nexthop, rta, rtnh, - &req.r, &src1); + p, routedesc, bytelen, nexthop, rta, + rtnh, &req.r, &src1); rtnh = RTNH_NEXT(rtnh); if (!setsrc && src1) { @@ -1816,7 +1807,7 @@ static int netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx) } } } - if (setsrc && (cmd == RTM_NEWROUTE)) { + if (setsrc) { if (family == AF_INET) addattr_l(&req.n, sizeof(req), RTA_PREFSRC, &src.ipv4, bytelen); @@ -1991,6 +1982,12 @@ static int netlink_nexthop(int cmd, struct zebra_dplane_ctx *ctx) addattr32(&req.n, req_size, NHA_ID, id); if (cmd == RTM_NEWNEXTHOP) { + /* + * We distinguish between a "group", which is a collection + * of ids, and a singleton nexthop with an id. The + * group is installed as an id that just refers to a list of + * other ids. + */ if (dplane_ctx_get_nhe_nh_grp_count(ctx)) _netlink_nexthop_build_group( &req.n, req_size, id, @@ -2077,14 +2074,13 @@ static int netlink_nexthop(int cmd, struct zebra_dplane_ctx *ctx) } } - nexthop_done: - if (IS_ZEBRA_DEBUG_KERNEL) { - char buf[NEXTHOP_STRLEN]; +nexthop_done: + + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("%s: ID (%u): %pNHv (%u) %s ", + __func__, id, nh, nh->vrf_id, + label_buf); - snprintfrr(buf, sizeof(buf), "%pNHv", nh); - zlog_debug("%s: ID (%u): %s (%u) %s ", __func__, - id, buf, nh->vrf_id, label_buf); - } } req.nhm.nh_protocol = zebra2proto(dplane_ctx_get_nhe_type(ctx)); @@ -2112,43 +2108,19 @@ static int netlink_nexthop(int cmd, struct zebra_dplane_ctx *ctx) */ enum zebra_dplane_result kernel_nexthop_update(struct zebra_dplane_ctx *ctx) { + enum dplane_op_e op; int cmd = 0; int ret = 0; - switch (dplane_ctx_get_op(ctx)) { - case DPLANE_OP_NH_DELETE: - cmd = RTM_DELNEXTHOP; - break; - case DPLANE_OP_NH_INSTALL: - case DPLANE_OP_NH_UPDATE: + op = dplane_ctx_get_op(ctx); + if (op == DPLANE_OP_NH_INSTALL || op == DPLANE_OP_NH_UPDATE) cmd = RTM_NEWNEXTHOP; - break; - case DPLANE_OP_ROUTE_INSTALL: - case DPLANE_OP_ROUTE_UPDATE: - case DPLANE_OP_ROUTE_DELETE: - case DPLANE_OP_ROUTE_NOTIFY: - case DPLANE_OP_LSP_INSTALL: - case DPLANE_OP_LSP_UPDATE: - case DPLANE_OP_LSP_DELETE: - case DPLANE_OP_LSP_NOTIFY: - case DPLANE_OP_PW_INSTALL: - case DPLANE_OP_PW_UNINSTALL: - case DPLANE_OP_SYS_ROUTE_ADD: - case DPLANE_OP_SYS_ROUTE_DELETE: - case DPLANE_OP_ADDR_INSTALL: - case DPLANE_OP_ADDR_UNINSTALL: - case DPLANE_OP_MAC_INSTALL: - case DPLANE_OP_MAC_DELETE: - case DPLANE_OP_NEIGH_INSTALL: - case DPLANE_OP_NEIGH_UPDATE: - case DPLANE_OP_NEIGH_DELETE: - case DPLANE_OP_VTEP_ADD: - case DPLANE_OP_VTEP_DELETE: - case DPLANE_OP_NONE: - flog_err( - EC_ZEBRA_NHG_FIB_UPDATE, - "Context received for kernel nexthop update with incorrect OP code (%u)", - dplane_ctx_get_op(ctx)); + else if (op == DPLANE_OP_NH_DELETE) + cmd = RTM_DELNEXTHOP; + else { + flog_err(EC_ZEBRA_NHG_FIB_UPDATE, + "Context received for kernel nexthop update with incorrect OP code (%u)", + op); return ZEBRA_DPLANE_REQUEST_FAILURE; } @@ -2677,7 +2649,7 @@ static int netlink_macfdb_change(struct nlmsghdr *h, int len, ns_id_t ns_id) if (filter_vlan && vid != filter_vlan) { if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug("\tFiltered due to filter vlan: %d", + zlog_debug(" Filtered due to filter vlan: %d", filter_vlan); return 0; } @@ -2691,8 +2663,9 @@ static int netlink_macfdb_change(struct nlmsghdr *h, int len, ns_id_t ns_id) /* Drop "permanent" entries. */ if (ndm->ndm_state & NUD_PERMANENT) { if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug("\tDropping entry because of NUD_PERMANENT"); - return 0; + zlog_debug( + " Dropping entry because of NUD_PERMANENT"); + return 0; } if (IS_ZEBRA_IF_VXLAN(ifp)) @@ -3466,6 +3439,7 @@ int netlink_mpls_multipath(int cmd, struct zebra_dplane_ctx *ctx) unsigned int nexthop_num; const char *routedesc; int route_type; + struct prefix p = {0}; struct { struct nlmsghdr n; @@ -3552,8 +3526,7 @@ int netlink_mpls_multipath(int cmd, struct zebra_dplane_ctx *ctx) NEXTHOP_FLAG_FIB)))) { /* Add the gateway */ _netlink_mpls_build_singlepath( - routedesc, nhlfe, - &req.n, &req.r, + &p, routedesc, nhlfe, &req.n, &req.r, sizeof(req), cmd); nexthop_num++; @@ -3593,9 +3566,9 @@ int netlink_mpls_multipath(int cmd, struct zebra_dplane_ctx *ctx) nexthop_num++; /* Build the multipath */ - _netlink_mpls_build_multipath(routedesc, nhlfe, - rta, rtnh, &req.r, - &src1); + _netlink_mpls_build_multipath(&p, routedesc, + nhlfe, rta, rtnh, + &req.r, &src1); rtnh = RTNH_NEXT(rtnh); } } diff --git a/zebra/rtadv.c b/zebra/rtadv.c index 60ac471b5a..a22e39dc48 100644 --- a/zebra/rtadv.c +++ b/zebra/rtadv.c @@ -204,9 +204,12 @@ static void rtadv_send_packet(int sock, struct interface *ifp, } /* Logging of packet. */ - if (IS_ZEBRA_DEBUG_PACKET) - zlog_debug("%s(%u): Tx RA, socket %u", ifp->name, ifp->ifindex, - sock); + if (IS_ZEBRA_DEBUG_PACKET) { + struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id); + + zlog_debug("%s(%s:%u): Tx RA, socket %u", ifp->name, + VRF_LOGNAME(vrf), ifp->ifindex, sock); + } /* Fill in sockaddr_in6. */ memset(&addr, 0, sizeof(struct sockaddr_in6)); @@ -333,16 +336,6 @@ static void rtadv_send_packet(int sock, struct interface *ifp, IPV6_ADDR_COPY(&pinfo->nd_opt_pi_prefix, &rprefix->prefix.prefix); -#ifdef DEBUG - { - uint8_t buf[INET6_ADDRSTRLEN]; - - zlog_debug("DEBUG %s", - inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix, - buf, INET6_ADDRSTRLEN)); - } -#endif /* DEBUG */ - len += sizeof(struct nd_opt_prefix_info); } @@ -388,9 +381,11 @@ static void rtadv_send_packet(int sock, struct interface *ifp, sizeof(struct nd_opt_rdnss) + sizeof(struct in6_addr); if (len + opt_len > max_len) { + struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id); + zlog_warn( - "%s(%u): Tx RA: RDNSS option would exceed MTU, omitting it", - ifp->name, ifp->ifindex); + "%s(%s:%u): Tx RA: RDNSS option would exceed MTU, omitting it", + ifp->name, VRF_LOGNAME(vrf), ifp->ifindex); goto no_more_opts; } struct nd_opt_rdnss *opt = (struct nd_opt_rdnss *)(buf + len); @@ -510,10 +505,17 @@ static int rtadv_timer(struct thread *thread) <= 0) zif->rtadv.inFastRexmit = 0; - if (IS_ZEBRA_DEBUG_SEND) + if (IS_ZEBRA_DEBUG_SEND) { + struct vrf *vrf = + vrf_lookup_by_id( + ifp->vrf_id); + zlog_debug( - "Fast RA Rexmit on interface %s", - ifp->name); + "Fast RA Rexmit on interface %s(%s:%u)", + ifp->name, + VRF_LOGNAME(vrf), + ifp->ifindex); + } rtadv_send_packet(rtadv_get_socket(zvrf), ifp, RA_ENABLE); @@ -612,9 +614,14 @@ static void rtadv_process_advert(uint8_t *msg, unsigned int len, inet_ntop(AF_INET6, &addr->sin6_addr, addr_str, INET6_ADDRSTRLEN); if (len < sizeof(struct nd_router_advert)) { - if (IS_ZEBRA_DEBUG_PACKET) - zlog_debug("%s(%u): Rx RA with invalid length %d from %s", - ifp->name, ifp->ifindex, len, addr_str); + if (IS_ZEBRA_DEBUG_PACKET) { + struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id); + + zlog_debug( + "%s(%s:%u): Rx RA with invalid length %d from %s", + ifp->name, VRF_LOGNAME(vrf), ifp->ifindex, len, + addr_str); + } return; } @@ -622,9 +629,14 @@ static void rtadv_process_advert(uint8_t *msg, unsigned int len, rtadv_process_optional(msg + sizeof(struct nd_router_advert), len - sizeof(struct nd_router_advert), ifp, addr); - if (IS_ZEBRA_DEBUG_PACKET) - zlog_debug("%s(%u): Rx RA with non-linklocal source address from %s", - ifp->name, ifp->ifindex, addr_str); + if (IS_ZEBRA_DEBUG_PACKET) { + struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id); + + zlog_debug( + "%s(%s:%u): Rx RA with non-linklocal source address from %s", + ifp->name, VRF_LOGNAME(vrf), ifp->ifindex, + addr_str); + } return; } @@ -703,9 +715,12 @@ static void rtadv_process_packet(uint8_t *buf, unsigned int len, return; } - if (IS_ZEBRA_DEBUG_PACKET) - zlog_debug("%s(%u): Rx RA/RS len %d from %s", ifp->name, - ifp->ifindex, len, addr_str); + if (IS_ZEBRA_DEBUG_PACKET) { + struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id); + + zlog_debug("%s(%s:%u): Rx RA/RS len %d from %s", ifp->name, + VRF_LOGNAME(vrf), ifp->ifindex, len, addr_str); + } if (if_is_loopback(ifp) || CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_VRF_LOOPBACK)) @@ -718,8 +733,11 @@ static void rtadv_process_packet(uint8_t *buf, unsigned int len, /* ICMP message length check. */ if (len < sizeof(struct icmp6_hdr)) { - zlog_debug("%s(%u): Rx RA with Invalid ICMPV6 packet length %d", - ifp->name, ifp->ifindex, len); + struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id); + + zlog_debug( + "%s(%s:%u): Rx RA with Invalid ICMPV6 packet length %d", + ifp->name, VRF_LOGNAME(vrf), ifp->ifindex, len); return; } @@ -728,15 +746,20 @@ static void rtadv_process_packet(uint8_t *buf, unsigned int len, /* ICMP message type check. */ if (icmph->icmp6_type != ND_ROUTER_SOLICIT && icmph->icmp6_type != ND_ROUTER_ADVERT) { - zlog_debug("%s(%u): Rx RA - Unwanted ICMPV6 message type %d", - ifp->name, ifp->ifindex, icmph->icmp6_type); + struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id); + + zlog_debug("%s(%s:%u): Rx RA - Unwanted ICMPV6 message type %d", + ifp->name, VRF_LOGNAME(vrf), ifp->ifindex, + icmph->icmp6_type); return; } /* Hoplimit check. */ if (hoplimit >= 0 && hoplimit != 255) { - zlog_debug("%s(%u): Rx RA - Invalid hoplimit %d", ifp->name, - ifp->ifindex, hoplimit); + struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id); + + zlog_debug("%s(%s:%u): Rx RA - Invalid hoplimit %d", ifp->name, + VRF_LOGNAME(vrf), ifp->ifindex, hoplimit); return; } @@ -1055,25 +1078,34 @@ static void zebra_interface_radv_set(ZAPI_HANDLER_ARGS, int enable) unsigned int ra_interval = ra_interval_rxd; - if (IS_ZEBRA_DEBUG_EVENT) - zlog_debug("%u: IF %u RA %s from client %s, interval %ums", - zvrf_id(zvrf), ifindex, + if (IS_ZEBRA_DEBUG_EVENT) { + struct vrf *vrf = zvrf->vrf; + + zlog_debug("%s:%u: IF %u RA %s from client %s, interval %ums", + VRF_LOGNAME(vrf), zvrf_id(zvrf), ifindex, enable ? "enable" : "disable", zebra_route_string(client->proto), ra_interval); + } /* Locate interface and check VRF match. */ ifp = if_lookup_by_index(ifindex, zvrf->vrf->vrf_id); if (!ifp) { + struct vrf *vrf = zvrf->vrf; + flog_warn(EC_ZEBRA_UNKNOWN_INTERFACE, - "%u: IF %u RA %s client %s - interface unknown", - zvrf_id(zvrf), ifindex, enable ? "enable" : "disable", + "%s:%u: IF %u RA %s client %s - interface unknown", + VRF_LOGNAME(vrf), zvrf_id(zvrf), ifindex, + enable ? "enable" : "disable", zebra_route_string(client->proto)); return; } if (ifp->vrf_id != zvrf_id(zvrf)) { + struct vrf *vrf = zvrf->vrf; + zlog_debug( - "%u: IF %u RA %s client %s - VRF mismatch, IF VRF %u", - zvrf_id(zvrf), ifindex, enable ? "enable" : "disable", + "%s:%u: IF %u RA %s client %s - VRF mismatch, IF VRF %u", + VRF_LOGNAME(vrf), zvrf_id(zvrf), ifindex, + enable ? "enable" : "disable", zebra_route_string(client->proto), ifp->vrf_id); return; } @@ -2329,6 +2361,13 @@ static void rtadv_event(struct zebra_vrf *zvrf, enum rtadv_event event, int val) { struct rtadv *rtadv = &zvrf->rtadv; + if (IS_ZEBRA_DEBUG_EVENT) { + struct vrf *vrf = zvrf->vrf; + + zlog_debug("%s(%s) with event: %d and val: %d", __func__, + VRF_LOGNAME(vrf), event, val); + } + switch (event) { case RTADV_START: thread_add_read(zrouter.master, rtadv_read, zvrf, val, @@ -2371,20 +2410,26 @@ void rtadv_init(struct zebra_vrf *zvrf) } } -void rtadv_terminate(struct zebra_vrf *zvrf) +void rtadv_vrf_terminate(struct zebra_vrf *zvrf) { rtadv_event(zvrf, RTADV_STOP, 0); if (zvrf->rtadv.sock >= 0) { close(zvrf->rtadv.sock); zvrf->rtadv.sock = -1; - } else if (zrouter.rtadv_sock >= 0) { - close(zrouter.rtadv_sock); - zrouter.rtadv_sock = -1; } + zvrf->rtadv.adv_if_count = 0; zvrf->rtadv.adv_msec_if_count = 0; } +void rtadv_terminate(void) +{ + if (zrouter.rtadv_sock >= 0) { + close(zrouter.rtadv_sock); + zrouter.rtadv_sock = -1; + } +} + void rtadv_cmd_init(void) { hook_register(zebra_if_extra_info, nd_dump_vty); @@ -2445,10 +2490,13 @@ static int if_join_all_router(int sock, struct interface *ifp) ifp->name, ifp->ifindex, sock, safe_strerror(errno)); - if (IS_ZEBRA_DEBUG_EVENT) + if (IS_ZEBRA_DEBUG_EVENT) { + struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id); + zlog_debug( - "%s(%u): Join All-Routers multicast group, socket %u", - ifp->name, ifp->ifindex, sock); + "%s(%s:%u): Join All-Routers multicast group, socket %u", + ifp->name, VRF_LOGNAME(vrf), ifp->ifindex, sock); + } return 0; } @@ -2465,17 +2513,22 @@ static int if_leave_all_router(int sock, struct interface *ifp) ret = setsockopt(sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP, (char *)&mreq, sizeof(mreq)); - if (ret < 0) + if (ret < 0) { + struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id); + flog_err_sys( EC_LIB_SOCKET, - "%s(%u): Failed to leave group, socket %u error %s", - ifp->name, ifp->ifindex, sock, safe_strerror(errno)); + "%s(%s:%u): Failed to leave group, socket %u error %s", + ifp->name, VRF_LOGNAME(vrf), ifp->ifindex, sock, + safe_strerror(errno)); + } + if (IS_ZEBRA_DEBUG_EVENT) { + struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id); - if (IS_ZEBRA_DEBUG_EVENT) zlog_debug( - "%s(%u): Leave All-Routers multicast group, socket %u", - ifp->name, ifp->ifindex, sock); - + "%s(%s:%u): Leave All-Routers multicast group, socket %u", + ifp->name, VRF_LOGNAME(vrf), ifp->ifindex, sock); + } return 0; } diff --git a/zebra/rtadv.h b/zebra/rtadv.h index 64b28cbfd6..68a5bbcdbe 100644 --- a/zebra/rtadv.h +++ b/zebra/rtadv.h @@ -153,7 +153,8 @@ typedef enum { } ipv6_nd_suppress_ra_status; extern void rtadv_init(struct zebra_vrf *zvrf); -extern void rtadv_terminate(struct zebra_vrf *zvrf); +extern void rtadv_vrf_terminate(struct zebra_vrf *zvrf); +extern void rtadv_terminate(void); extern void rtadv_stop_ra(struct interface *ifp); extern void rtadv_stop_ra_all(void); extern void rtadv_cmd_init(void); diff --git a/zebra/subdir.am b/zebra/subdir.am index 1d49de5410..f281afce94 100644 --- a/zebra/subdir.am +++ b/zebra/subdir.am @@ -75,6 +75,7 @@ zebra_zebra_SOURCES = \ zebra/zebra_mlag.c \ zebra/zebra_mlag_vty.c \ zebra/zebra_l2.c \ + zebra/zebra_northbound.c \ zebra/zebra_memory.c \ zebra/zebra_dplane.c \ zebra/zebra_mpls.c \ @@ -191,5 +192,10 @@ zebra_zebra_fpm_la_SOURCES += zebra/zebra_fpm_dt.c endif endif +nodist_zebra_zebra_SOURCES = \ + yang/frr-nexthop.yang.c \ + yang/frr-zebra.yang.c \ + # end + zebra_zebra_cumulus_mlag_la_SOURCES = zebra/zebra_mlag_private.c zebra_zebra_cumulus_mlag_la_LDFLAGS = -avoid-version -module -shared -export-dynamic diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index f1c181438e..aabe533ee6 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -383,9 +383,14 @@ static void zebra_interface_nbr_address_add_update(struct interface *ifp, p->prefixlen, ifc->ifp->name); } - for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) + for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) { + /* Do not send unsolicited messages to synchronous clients. */ + if (client->synchronous) + continue; + zsend_interface_nbr_address(ZEBRA_INTERFACE_NBR_ADDRESS_ADD, client, ifp, ifc); + } } /* Interface address deletion. */ @@ -407,9 +412,14 @@ static void zebra_interface_nbr_address_delete_update(struct interface *ifp, p->prefixlen, ifc->ifp->name); } - for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) + for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) { + /* Do not send unsolicited messages to synchronous clients. */ + if (client->synchronous) + continue; + zsend_interface_nbr_address(ZEBRA_INTERFACE_NBR_ADDRESS_DELETE, client, ifp, ifc); + } } /* Send addresses on interface to client */ @@ -1063,7 +1073,7 @@ static void zread_rnh_register(ZAPI_HANDLER_ARGS) if (IS_ZEBRA_DEBUG_NHT) zlog_debug( - "rnh_register msg from client %s: hdr->length=%d, type=%s vrf=%u\n", + "rnh_register msg from client %s: hdr->length=%d, type=%s vrf=%u", zebra_route_string(client->proto), hdr->length, (type == RNH_NEXTHOP_TYPE) ? "nexthop" : "route", zvrf->vrf->vrf_id); @@ -1152,7 +1162,7 @@ static void zread_rnh_unregister(ZAPI_HANDLER_ARGS) if (IS_ZEBRA_DEBUG_NHT) zlog_debug( - "rnh_unregister msg from client %s: hdr->length=%d vrf: %u\n", + "rnh_unregister msg from client %s: hdr->length=%d vrf: %u", zebra_route_string(client->proto), hdr->length, zvrf->vrf->vrf_id); @@ -1403,6 +1413,132 @@ void zserv_nexthop_num_warn(const char *caller, const struct prefix *p, } } +/* + * Create a new nexthop based on a zapi nexthop. + */ +static struct nexthop *nexthop_from_zapi(struct route_entry *re, + const struct zapi_nexthop *api_nh, + const struct zapi_route *api) +{ + struct nexthop *nexthop = NULL; + struct ipaddr vtep_ip; + struct interface *ifp; + char nhbuf[INET6_ADDRSTRLEN] = ""; + + switch (api_nh->type) { + case NEXTHOP_TYPE_IFINDEX: + nexthop = nexthop_from_ifindex(api_nh->ifindex, api_nh->vrf_id); + break; + case NEXTHOP_TYPE_IPV4: + if (IS_ZEBRA_DEBUG_RECV) { + inet_ntop(AF_INET, &api_nh->gate.ipv4, nhbuf, + sizeof(nhbuf)); + zlog_debug("%s: nh=%s, vrf_id=%d", __func__, + nhbuf, api_nh->vrf_id); + } + nexthop = nexthop_from_ipv4(&api_nh->gate.ipv4, NULL, + api_nh->vrf_id); + break; + case NEXTHOP_TYPE_IPV4_IFINDEX: + if (IS_ZEBRA_DEBUG_RECV) { + inet_ntop(AF_INET, &api_nh->gate.ipv4, nhbuf, + sizeof(nhbuf)); + zlog_debug("%s: nh=%s, vrf_id=%d, ifindex=%d", + __func__, nhbuf, api_nh->vrf_id, + api_nh->ifindex); + } + + nexthop = nexthop_from_ipv4_ifindex( + &api_nh->gate.ipv4, NULL, api_nh->ifindex, + api_nh->vrf_id); + + ifp = if_lookup_by_index(api_nh->ifindex, api_nh->vrf_id); + if (ifp && connected_is_unnumbered(ifp)) + SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK); + + /* Special handling for IPv4 routes sourced from EVPN: + * the nexthop and associated MAC need to be installed. + */ + if (CHECK_FLAG(api->flags, ZEBRA_FLAG_EVPN_ROUTE)) { + memset(&vtep_ip, 0, sizeof(struct ipaddr)); + vtep_ip.ipa_type = IPADDR_V4; + memcpy(&(vtep_ip.ipaddr_v4), &(api_nh->gate.ipv4), + sizeof(struct in_addr)); + zebra_vxlan_evpn_vrf_route_add( + api_nh->vrf_id, &api_nh->rmac, + &vtep_ip, &api->prefix); + } + break; + case NEXTHOP_TYPE_IPV6: + if (IS_ZEBRA_DEBUG_RECV) { + inet_ntop(AF_INET6, &api_nh->gate.ipv6, nhbuf, + sizeof(nhbuf)); + zlog_debug("%s: nh=%s, vrf_id=%d", __func__, + nhbuf, api_nh->vrf_id); + } + nexthop = nexthop_from_ipv6(&api_nh->gate.ipv6, api_nh->vrf_id); + break; + case NEXTHOP_TYPE_IPV6_IFINDEX: + if (IS_ZEBRA_DEBUG_RECV) { + inet_ntop(AF_INET6, &api_nh->gate.ipv6, nhbuf, + sizeof(nhbuf)); + zlog_debug("%s: nh=%s, vrf_id=%d, ifindex=%d", + __func__, nhbuf, api_nh->vrf_id, + api_nh->ifindex); + } + nexthop = nexthop_from_ipv6_ifindex(&api_nh->gate.ipv6, + api_nh->ifindex, + api_nh->vrf_id); + + /* Special handling for IPv6 routes sourced from EVPN: + * the nexthop and associated MAC need to be installed. + */ + if (CHECK_FLAG(api->flags, ZEBRA_FLAG_EVPN_ROUTE)) { + memset(&vtep_ip, 0, sizeof(struct ipaddr)); + vtep_ip.ipa_type = IPADDR_V6; + memcpy(&vtep_ip.ipaddr_v6, &(api_nh->gate.ipv6), + sizeof(struct in6_addr)); + zebra_vxlan_evpn_vrf_route_add( + api_nh->vrf_id, &api_nh->rmac, + &vtep_ip, &api->prefix); + } + break; + case NEXTHOP_TYPE_BLACKHOLE: + if (IS_ZEBRA_DEBUG_RECV) + zlog_debug("%s: nh blackhole %d", + __func__, api_nh->bh_type); + + nexthop = nexthop_from_blackhole(api_nh->bh_type); + break; + } + + /* Return early if we couldn't process the zapi nexthop */ + if (nexthop == NULL) { + goto done; + } + + if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_ONLINK)) + SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK); + + if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_WEIGHT)) + nexthop->weight = api_nh->weight; + + if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_HAS_BACKUP)) { + if (api_nh->backup_idx < api->backup_nexthop_num) { + /* Capture backup info */ + SET_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP); + nexthop->backup_idx = api_nh->backup_idx; + } else { + /* Warn about invalid backup index */ + if (IS_ZEBRA_DEBUG_RECV || IS_ZEBRA_DEBUG_EVENT) + zlog_debug("%s: invalid backup nh idx %d", + __func__, api_nh->backup_idx); + } + } +done: + return nexthop; +} + static void zread_route_add(ZAPI_HANDLER_ARGS) { struct stream *s; @@ -1411,12 +1547,15 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) afi_t afi; struct prefix_ipv6 *src_p = NULL; struct route_entry *re; - struct nexthop *nexthop = NULL; + struct nexthop *nexthop = NULL, *last_nh; struct nexthop_group *ng = NULL; + struct nhg_backup_info *bnhg = NULL; int i, ret; vrf_id_t vrf_id; - struct ipaddr vtep_ip; - struct interface *ifp; + struct nhg_hash_entry nhe; + enum lsp_types_t label_type; + char nhbuf[NEXTHOP_STRLEN]; + char labelbuf[MPLS_LABEL_STRLEN]; s = msg; if (zapi_route_decode(s, &api) < 0) { @@ -1430,8 +1569,8 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) char buf_prefix[PREFIX_STRLEN]; prefix2str(&api.prefix, buf_prefix, sizeof(buf_prefix)); - zlog_debug("%s: p=%s, flags=0x%x", - __func__, buf_prefix, api.flags); + zlog_debug("%s: p=%s, msg flags=0x%x, flags=0x%x", + __func__, buf_prefix, (int)api.message, api.flags); } /* Allocate new route. */ @@ -1459,6 +1598,15 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) return; } + /* Report misuse of the backup flag */ + if (CHECK_FLAG(api.message, ZAPI_MESSAGE_BACKUP_NEXTHOPS) && + api.backup_nexthop_num == 0) { + if (IS_ZEBRA_DEBUG_RECV || IS_ZEBRA_DEBUG_EVENT) + zlog_debug("%s: client %s: BACKUP flag set but no backup nexthops, prefix %pFX", + __func__, + zebra_route_string(client->proto), &api.prefix); + } + /* Use temporary list of nexthops */ ng = nexthop_group_new(); @@ -1469,130 +1617,138 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) */ for (i = 0; i < api.nexthop_num; i++) { api_nh = &api.nexthops[i]; - ifindex_t ifindex = 0; - nexthop = NULL; + /* Convert zapi nexthop */ + nexthop = nexthop_from_zapi(re, api_nh, &api); + if (!nexthop) { + flog_warn( + EC_ZEBRA_NEXTHOP_CREATION_FAILED, + "%s: Nexthops Specified: %d but we failed to properly create one", + __func__, api.nexthop_num); + nexthop_group_delete(&ng); + XFREE(MTYPE_RE, re); + return; + } - if (IS_ZEBRA_DEBUG_RECV) - zlog_debug("nh type %d", api_nh->type); + /* MPLS labels for BGP-LU or Segment Routing */ + if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_LABEL) + && api_nh->type != NEXTHOP_TYPE_IFINDEX + && api_nh->type != NEXTHOP_TYPE_BLACKHOLE + && api_nh->label_num > 0) { - switch (api_nh->type) { - case NEXTHOP_TYPE_IFINDEX: - nexthop = nexthop_from_ifindex(api_nh->ifindex, - api_nh->vrf_id); - break; - case NEXTHOP_TYPE_IPV4: - if (IS_ZEBRA_DEBUG_RECV) { - char nhbuf[INET6_ADDRSTRLEN] = {0}; + label_type = lsp_type_from_re_type(client->proto); + nexthop_add_labels(nexthop, label_type, + api_nh->label_num, + &api_nh->labels[0]); + } - inet_ntop(AF_INET, &api_nh->gate.ipv4, nhbuf, - INET6_ADDRSTRLEN); - zlog_debug("%s: nh=%s, vrf_id=%d", __func__, - nhbuf, api_nh->vrf_id); - } - nexthop = nexthop_from_ipv4(&api_nh->gate.ipv4, - NULL, api_nh->vrf_id); - break; - case NEXTHOP_TYPE_IPV4_IFINDEX: + if (IS_ZEBRA_DEBUG_RECV) { + labelbuf[0] = '\0'; + nhbuf[0] = '\0'; - memset(&vtep_ip, 0, sizeof(struct ipaddr)); - ifindex = api_nh->ifindex; - if (IS_ZEBRA_DEBUG_RECV) { - char nhbuf[INET6_ADDRSTRLEN] = {0}; + nexthop2str(nexthop, nhbuf, sizeof(nhbuf)); - inet_ntop(AF_INET, &api_nh->gate.ipv4, nhbuf, - INET6_ADDRSTRLEN); - zlog_debug( - "%s: nh=%s, vrf_id=%d (re->vrf_id=%d), ifindex=%d", - __func__, nhbuf, api_nh->vrf_id, - re->vrf_id, ifindex); + if (nexthop->nh_label && + nexthop->nh_label->num_labels > 0) { + mpls_label2str(nexthop->nh_label->num_labels, + nexthop->nh_label->label, + labelbuf, sizeof(labelbuf), + false); } - nexthop = nexthop_from_ipv4_ifindex( - &api_nh->gate.ipv4, NULL, ifindex, - api_nh->vrf_id); - - ifp = if_lookup_by_index(ifindex, api_nh->vrf_id); - if (ifp && connected_is_unnumbered(ifp)) - SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK); - /* Special handling for IPv4 routes sourced from EVPN: - * the nexthop and associated MAC need to be installed. - */ - if (CHECK_FLAG(api.flags, ZEBRA_FLAG_EVPN_ROUTE)) { - vtep_ip.ipa_type = IPADDR_V4; - memcpy(&(vtep_ip.ipaddr_v4), - &(api_nh->gate.ipv4), - sizeof(struct in_addr)); - zebra_vxlan_evpn_vrf_route_add( - api_nh->vrf_id, &api_nh->rmac, - &vtep_ip, &api.prefix); - } - break; - case NEXTHOP_TYPE_IPV6: - nexthop = nexthop_from_ipv6(&api_nh->gate.ipv6, - api_nh->vrf_id); - break; - case NEXTHOP_TYPE_IPV6_IFINDEX: - memset(&vtep_ip, 0, sizeof(struct ipaddr)); - ifindex = api_nh->ifindex; - nexthop = nexthop_from_ipv6_ifindex(&api_nh->gate.ipv6, - ifindex, - api_nh->vrf_id); - - /* Special handling for IPv6 routes sourced from EVPN: - * the nexthop and associated MAC need to be installed. - */ - if (CHECK_FLAG(api.flags, ZEBRA_FLAG_EVPN_ROUTE)) { - vtep_ip.ipa_type = IPADDR_V6; - memcpy(&vtep_ip.ipaddr_v6, &(api_nh->gate.ipv6), - sizeof(struct in6_addr)); - zebra_vxlan_evpn_vrf_route_add( - api_nh->vrf_id, &api_nh->rmac, - &vtep_ip, &api.prefix); - } - break; - case NEXTHOP_TYPE_BLACKHOLE: - nexthop = nexthop_from_blackhole(api_nh->bh_type); - break; + + zlog_debug("%s: nh=%s, vrf_id=%d %s", + __func__, nhbuf, api_nh->vrf_id, labelbuf); } + /* Add new nexthop to temporary list. This list is + * canonicalized - sorted - so that it can be hashed later + * in route processing. We expect that the sender has sent + * the list sorted, and the zapi client api attempts to enforce + * that, so this should be inexpensive - but it is necessary + * to support shared nexthop-groups. + */ + nexthop_group_add_sorted(ng, nexthop); + } + + /* Allocate temporary list of backup nexthops, if necessary */ + if (api.backup_nexthop_num > 0) { + if (IS_ZEBRA_DEBUG_RECV) + zlog_debug("%s: adding %d backup nexthops", + __func__, api.backup_nexthop_num); + + bnhg = zebra_nhg_backup_alloc(); + nexthop = NULL; + last_nh = NULL; + } + + /* Copy backup nexthops also, if present */ + for (i = 0; i < api.backup_nexthop_num; i++) { + api_nh = &api.backup_nexthops[i]; + + /* Convert zapi backup nexthop */ + nexthop = nexthop_from_zapi(re, api_nh, &api); if (!nexthop) { flog_warn( EC_ZEBRA_NEXTHOP_CREATION_FAILED, - "%s: Nexthops Specified: %d but we failed to properly create one", - __func__, api.nexthop_num); + "%s: Backup Nexthops Specified: %d but we failed to properly create one", + __func__, api.backup_nexthop_num); nexthop_group_delete(&ng); + zebra_nhg_backup_free(&bnhg); XFREE(MTYPE_RE, re); return; } - if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_ONLINK)) - SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK); - - if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_WEIGHT)) - nexthop->weight = api_nh->weight; + /* Backup nexthops can't have backups; that's not valid. */ + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP)) { + if (IS_ZEBRA_DEBUG_RECV) { + nexthop2str(nexthop, nhbuf, sizeof(nhbuf)); + zlog_debug("%s: backup nh %s with BACKUP flag!", + __func__, nhbuf); + } + UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP); + nexthop->backup_idx = 0; + } /* MPLS labels for BGP-LU or Segment Routing */ if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_LABEL) && api_nh->type != NEXTHOP_TYPE_IFINDEX - && api_nh->type != NEXTHOP_TYPE_BLACKHOLE) { - enum lsp_types_t label_type; + && api_nh->type != NEXTHOP_TYPE_BLACKHOLE + && api_nh->label_num > 0) { label_type = lsp_type_from_re_type(client->proto); - - if (IS_ZEBRA_DEBUG_RECV) { - zlog_debug( - "%s: adding %d labels of type %d (1st=%u)", - __func__, api_nh->label_num, label_type, - api_nh->labels[0]); - } - nexthop_add_labels(nexthop, label_type, api_nh->label_num, &api_nh->labels[0]); } - /* Add new nexthop to temporary list */ - nexthop_group_add_sorted(ng, nexthop); + if (IS_ZEBRA_DEBUG_RECV) { + labelbuf[0] = '\0'; + nhbuf[0] = '\0'; + + nexthop2str(nexthop, nhbuf, sizeof(nhbuf)); + + if (nexthop->nh_label && + nexthop->nh_label->num_labels > 0) { + mpls_label2str(nexthop->nh_label->num_labels, + nexthop->nh_label->label, + labelbuf, sizeof(labelbuf), + false); + } + + zlog_debug("%s: backup nh=%s, vrf_id=%d %s", + __func__, nhbuf, api_nh->vrf_id, labelbuf); + } + + /* Note that the order of the backup nexthops is significant, + * so we don't sort this list as we do the primary nexthops, + * we just append. + */ + if (last_nh) + NEXTHOP_APPEND(last_nh, nexthop); + else + bnhg->nhe->nhg.nexthop = nexthop; + + last_nh = nexthop; } if (CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE)) @@ -1610,6 +1766,7 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) "%s: Received SRC Prefix but afi is not v6", __func__); nexthop_group_delete(&ng); + zebra_nhg_backup_free(&bnhg); XFREE(MTYPE_RE, re); return; } @@ -1621,10 +1778,28 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) "%s: Received safi: %d but we can only accept UNICAST or MULTICAST", __func__, api.safi); nexthop_group_delete(&ng); + zebra_nhg_backup_free(&bnhg); XFREE(MTYPE_RE, re); return; } - ret = rib_add_multipath(afi, api.safi, &api.prefix, src_p, re, ng); + + /* Include backup info with the route. We use a temporary nhe here; + * if this is a new/unknown nhe, a new copy will be allocated + * and stored. + */ + zebra_nhe_init(&nhe, afi, ng->nexthop); + nhe.nhg.nexthop = ng->nexthop; + nhe.backup_info = bnhg; + ret = rib_add_multipath_nhe(afi, api.safi, &api.prefix, src_p, + re, &nhe); + + /* At this point, these allocations are not needed: 're' has been + * retained or freed, and if 're' still exists, it is using + * a reference to a shared group object. + */ + nexthop_group_delete(&ng); + if (bnhg) + zebra_nhg_backup_free(&bnhg); /* Stats */ switch (api.prefix.family) { @@ -1740,6 +1915,10 @@ void zsend_capabilities_all_clients(void) zvrf = vrf_info_lookup(VRF_DEFAULT); for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) { + /* Do not send unsolicited messages to synchronous clients. */ + if (client->synchronous) + continue; + zsend_capabilities(client, zvrf); } } @@ -1751,13 +1930,18 @@ static void zread_hello(ZAPI_HANDLER_ARGS) uint8_t proto; unsigned short instance; uint8_t notify; + uint8_t synchronous; STREAM_GETC(msg, proto); STREAM_GETW(msg, instance); STREAM_GETC(msg, notify); + STREAM_GETC(msg, synchronous); if (notify) client->notify_owner = true; + if (synchronous) + client->synchronous = true; + /* accept only dynamic routing protocols */ if ((proto < ZEBRA_ROUTE_MAX) && (proto > ZEBRA_ROUTE_CONNECT)) { zlog_notice( @@ -1774,8 +1958,10 @@ static void zread_hello(ZAPI_HANDLER_ARGS) zebra_gr_client_reconnect(client); } - zsend_capabilities(client, zvrf); - zebra_vrf_update_all(client); + if (!client->synchronous) { + zsend_capabilities(client, zvrf); + zebra_vrf_update_all(client); + } stream_failure: return; } diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index 459d2bc620..a2365ee76b 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -113,10 +113,15 @@ struct dplane_route_info { struct dplane_nexthop_info nhe; /* Nexthops */ + uint32_t zd_nhg_id; struct nexthop_group zd_ng; + /* Backup nexthops (if present) */ + struct nexthop_group backup_ng; + /* "Previous" nexthops, used only in route updates without netlink */ struct nexthop_group zd_old_ng; + struct nexthop_group old_backup_ng; /* TODO -- use fixed array of nexthops, to avoid mallocs? */ @@ -472,6 +477,14 @@ static void dplane_ctx_free(struct zebra_dplane_ctx **pctx) (*pctx)->u.rinfo.zd_ng.nexthop = NULL; } + /* Free backup info also (if present) */ + if ((*pctx)->u.rinfo.backup_ng.nexthop) { + /* This deals with recursive nexthops too */ + nexthops_free((*pctx)->u.rinfo.backup_ng.nexthop); + + (*pctx)->u.rinfo.backup_ng.nexthop = NULL; + } + if ((*pctx)->u.rinfo.zd_old_ng.nexthop) { /* This deals with recursive nexthops too */ nexthops_free((*pctx)->u.rinfo.zd_old_ng.nexthop); @@ -479,6 +492,13 @@ static void dplane_ctx_free(struct zebra_dplane_ctx **pctx) (*pctx)->u.rinfo.zd_old_ng.nexthop = NULL; } + if ((*pctx)->u.rinfo.old_backup_ng.nexthop) { + /* This deals with recursive nexthops too */ + nexthops_free((*pctx)->u.rinfo.old_backup_ng.nexthop); + + (*pctx)->u.rinfo.old_backup_ng.nexthop = NULL; + } + break; case DPLANE_OP_NH_INSTALL: @@ -1038,6 +1058,12 @@ void dplane_ctx_set_nexthops(struct zebra_dplane_ctx *ctx, struct nexthop *nh) nexthop_group_copy_nh_sorted(&(ctx->u.rinfo.zd_ng), nh); } +uint32_t dplane_ctx_get_nhg_id(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + return ctx->u.rinfo.zd_nhg_id; +} + const struct nexthop_group *dplane_ctx_get_ng( const struct zebra_dplane_ctx *ctx) { @@ -1046,14 +1072,30 @@ const struct nexthop_group *dplane_ctx_get_ng( return &(ctx->u.rinfo.zd_ng); } -const struct nexthop_group *dplane_ctx_get_old_ng( - const struct zebra_dplane_ctx *ctx) +const struct nexthop_group * +dplane_ctx_get_backup_ng(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return &(ctx->u.rinfo.backup_ng); +} + +const struct nexthop_group * +dplane_ctx_get_old_ng(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); return &(ctx->u.rinfo.zd_old_ng); } +const struct nexthop_group * +dplane_ctx_get_old_backup_ng(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return &(ctx->u.rinfo.old_backup_ng); +} + const struct zebra_dplane_info *dplane_ctx_get_ns( const struct zebra_dplane_ctx *ctx) { @@ -1514,6 +1556,13 @@ static int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx, /* Copy nexthops; recursive info is included too */ copy_nexthops(&(ctx->u.rinfo.zd_ng.nexthop), re->nhe->nhg.nexthop, NULL); + ctx->u.rinfo.zd_nhg_id = re->nhe->id; + + /* Copy backup nexthop info, if present */ + if (re->nhe->backup_info && re->nhe->backup_info->nhe) { + copy_nexthops(&(ctx->u.rinfo.backup_ng.nexthop), + re->nhe->backup_info->nhe->nhg.nexthop, NULL); + } /* Ensure that the dplane nexthops' flags are clear. */ for (ALL_NEXTHOPS(ctx->u.rinfo.zd_ng, nexthop)) @@ -1532,9 +1581,8 @@ static int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx, dplane_ctx_ns_init(ctx, zns, (op == DPLANE_OP_ROUTE_UPDATE)); #ifdef HAVE_NETLINK - if (re->nhe_id) { - struct nhg_hash_entry *nhe = - zebra_nhg_resolve(zebra_nhg_lookup_id(re->nhe_id)); + if (re->nhe) { + struct nhg_hash_entry *nhe = zebra_nhg_resolve(re->nhe); ctx->u.rinfo.nhe.id = nhe->id; /* @@ -1581,7 +1629,6 @@ static int dplane_ctx_nexthop_init(struct zebra_dplane_ctx *ctx, { struct zebra_vrf *zvrf = NULL; struct zebra_ns *zns = NULL; - int ret = EINVAL; if (!ctx || !nhe) @@ -1850,6 +1897,17 @@ dplane_route_update_internal(struct route_node *rn, */ copy_nexthops(&(ctx->u.rinfo.zd_old_ng.nexthop), old_re->nhe->nhg.nexthop, NULL); + + if (zebra_nhg_get_backup_nhg(old_re->nhe) != NULL) { + struct nexthop_group *nhg; + struct nexthop **nh; + + nhg = zebra_nhg_get_backup_nhg(old_re->nhe); + nh = &(ctx->u.rinfo.old_backup_ng.nexthop); + + if (nhg->nexthop) + copy_nexthops(nh, nhg->nexthop, NULL); + } #endif /* !HAVE_NETLINK */ } diff --git a/zebra/zebra_dplane.h b/zebra/zebra_dplane.h index c0b04e71b0..9ce4df197c 100644 --- a/zebra/zebra_dplane.h +++ b/zebra/zebra_dplane.h @@ -270,11 +270,19 @@ void dplane_ctx_set_distance(struct zebra_dplane_ctx *ctx, uint8_t distance); uint8_t dplane_ctx_get_old_distance(const struct zebra_dplane_ctx *ctx); void dplane_ctx_set_nexthops(struct zebra_dplane_ctx *ctx, struct nexthop *nh); + +uint32_t dplane_ctx_get_nhg_id(const struct zebra_dplane_ctx *ctx); const struct nexthop_group *dplane_ctx_get_ng( const struct zebra_dplane_ctx *ctx); const struct nexthop_group *dplane_ctx_get_old_ng( const struct zebra_dplane_ctx *ctx); +/* Backup nexthop information (list of nexthops) if present. */ +const struct nexthop_group * +dplane_ctx_get_backup_ng(const struct zebra_dplane_ctx *ctx); +const struct nexthop_group * +dplane_ctx_get_old_backup_ng(const struct zebra_dplane_ctx *ctx); + /* Accessors for nexthop information */ uint32_t dplane_ctx_get_nhe_id(const struct zebra_dplane_ctx *ctx); afi_t dplane_ctx_get_nhe_afi(const struct zebra_dplane_ctx *ctx); diff --git a/zebra/zebra_mpls.c b/zebra/zebra_mpls.c index d373fdf370..999e91486d 100644 --- a/zebra/zebra_mpls.c +++ b/zebra/zebra_mpls.c @@ -98,14 +98,14 @@ static void lsp_free(struct hash *lsp_table, zebra_lsp_t **plsp); static char *nhlfe2str(zebra_nhlfe_t *nhlfe, char *buf, int size); static int nhlfe_nhop_match(zebra_nhlfe_t *nhlfe, enum nexthop_types_t gtype, - union g_addr *gate, ifindex_t ifindex); + const union g_addr *gate, ifindex_t ifindex); static zebra_nhlfe_t *nhlfe_find(zebra_lsp_t *lsp, enum lsp_types_t lsp_type, - enum nexthop_types_t gtype, union g_addr *gate, - ifindex_t ifindex); + enum nexthop_types_t gtype, + const union g_addr *gate, ifindex_t ifindex); static zebra_nhlfe_t *nhlfe_add(zebra_lsp_t *lsp, enum lsp_types_t lsp_type, - enum nexthop_types_t gtype, union g_addr *gate, - ifindex_t ifindex, uint8_t num_labels, - mpls_label_t *labels); + enum nexthop_types_t gtype, + const union g_addr *gate, ifindex_t ifindex, + uint8_t num_labels, mpls_label_t *labels); static int nhlfe_del(zebra_nhlfe_t *snhlfe); static void nhlfe_out_label_update(zebra_nhlfe_t *nhlfe, struct mpls_label_stack *nh_label); @@ -117,13 +117,13 @@ static void nhlfe_print(zebra_nhlfe_t *nhlfe, struct vty *vty); static void lsp_print(zebra_lsp_t *lsp, void *ctxt); static void *slsp_alloc(void *p); static int snhlfe_match(zebra_snhlfe_t *snhlfe, enum nexthop_types_t gtype, - union g_addr *gate, ifindex_t ifindex); + const union g_addr *gate, ifindex_t ifindex); static zebra_snhlfe_t *snhlfe_find(zebra_slsp_t *slsp, enum nexthop_types_t gtype, - union g_addr *gate, ifindex_t ifindex); + const union g_addr *gate, ifindex_t ifindex); static zebra_snhlfe_t *snhlfe_add(zebra_slsp_t *slsp, enum nexthop_types_t gtype, - union g_addr *gate, ifindex_t ifindex, + const union g_addr *gate, ifindex_t ifindex, mpls_label_t out_label); static int snhlfe_del(zebra_snhlfe_t *snhlfe); static int snhlfe_del_all(zebra_slsp_t *slsp); @@ -960,7 +960,7 @@ static wq_item_status lsp_process(struct work_queue *wq, void *data) UNSET_FLAG(lsp->flags, LSP_FLAG_CHANGED); /* We leave the INSTALLED flag set here - * so we know an update in in-flight. + * so we know an update is in-flight. */ /* @@ -1149,7 +1149,7 @@ static char *nhlfe2str(zebra_nhlfe_t *nhlfe, char *buf, int size) * Check if NHLFE matches with search info passed. */ static int nhlfe_nhop_match(zebra_nhlfe_t *nhlfe, enum nexthop_types_t gtype, - union g_addr *gate, ifindex_t ifindex) + const union g_addr *gate, ifindex_t ifindex) { struct nexthop *nhop; int cmp = 1; @@ -1191,8 +1191,8 @@ static int nhlfe_nhop_match(zebra_nhlfe_t *nhlfe, enum nexthop_types_t gtype, * Locate NHLFE that matches with passed info. */ static zebra_nhlfe_t *nhlfe_find(zebra_lsp_t *lsp, enum lsp_types_t lsp_type, - enum nexthop_types_t gtype, union g_addr *gate, - ifindex_t ifindex) + enum nexthop_types_t gtype, + const union g_addr *gate, ifindex_t ifindex) { zebra_nhlfe_t *nhlfe; @@ -1214,9 +1214,9 @@ static zebra_nhlfe_t *nhlfe_find(zebra_lsp_t *lsp, enum lsp_types_t lsp_type, * check done. */ static zebra_nhlfe_t *nhlfe_add(zebra_lsp_t *lsp, enum lsp_types_t lsp_type, - enum nexthop_types_t gtype, union g_addr *gate, - ifindex_t ifindex, uint8_t num_labels, - mpls_label_t labels[]) + enum nexthop_types_t gtype, + const union g_addr *gate, ifindex_t ifindex, + uint8_t num_labels, mpls_label_t labels[]) { zebra_nhlfe_t *nhlfe; struct nexthop *nexthop; @@ -1520,7 +1520,7 @@ static struct list *hash_get_sorted_list(struct hash *hash, void *cmp) /* * Compare two LSPs based on their label values. */ -static int lsp_cmp(zebra_lsp_t *lsp1, zebra_lsp_t *lsp2) +static int lsp_cmp(const zebra_lsp_t *lsp1, const zebra_lsp_t *lsp2) { if (lsp1->ile.in_label < lsp2->ile.in_label) return -1; @@ -1547,7 +1547,7 @@ static void *slsp_alloc(void *p) /* * Compare two static LSPs based on their label values. */ -static int slsp_cmp(zebra_slsp_t *slsp1, zebra_slsp_t *slsp2) +static int slsp_cmp(const zebra_slsp_t *slsp1, const zebra_slsp_t *slsp2) { if (slsp1->ile.in_label < slsp2->ile.in_label) return -1; @@ -1562,7 +1562,7 @@ static int slsp_cmp(zebra_slsp_t *slsp1, zebra_slsp_t *slsp2) * Check if static NHLFE matches with search info passed. */ static int snhlfe_match(zebra_snhlfe_t *snhlfe, enum nexthop_types_t gtype, - union g_addr *gate, ifindex_t ifindex) + const union g_addr *gate, ifindex_t ifindex) { int cmp = 1; @@ -1593,7 +1593,7 @@ static int snhlfe_match(zebra_snhlfe_t *snhlfe, enum nexthop_types_t gtype, */ static zebra_snhlfe_t *snhlfe_find(zebra_slsp_t *slsp, enum nexthop_types_t gtype, - union g_addr *gate, ifindex_t ifindex) + const union g_addr *gate, ifindex_t ifindex) { zebra_snhlfe_t *snhlfe; @@ -1615,7 +1615,7 @@ static zebra_snhlfe_t *snhlfe_find(zebra_slsp_t *slsp, */ static zebra_snhlfe_t *snhlfe_add(zebra_slsp_t *slsp, enum nexthop_types_t gtype, - union g_addr *gate, ifindex_t ifindex, + const union g_addr *gate, ifindex_t ifindex, mpls_label_t out_label) { zebra_snhlfe_t *snhlfe; @@ -2746,7 +2746,7 @@ int mpls_ftn_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type, int mpls_lsp_install(struct zebra_vrf *zvrf, enum lsp_types_t type, mpls_label_t in_label, uint8_t num_out_labels, mpls_label_t out_labels[], enum nexthop_types_t gtype, - union g_addr *gate, ifindex_t ifindex) + const union g_addr *gate, ifindex_t ifindex) { struct hash *lsp_table; zebra_ile_t tmp_ile; @@ -2759,11 +2759,12 @@ int mpls_lsp_install(struct zebra_vrf *zvrf, enum lsp_types_t type, if (!lsp_table) return -1; - /* If entry is present, exit. */ + /* Find or create LSP object */ tmp_ile.in_label = in_label; lsp = hash_get(lsp_table, &tmp_ile, lsp_alloc); if (!lsp) return -1; + nhlfe = nhlfe_find(lsp, type, gtype, gate, ifindex); if (nhlfe) { struct nexthop *nh = nhlfe->nexthop; @@ -2780,8 +2781,8 @@ int mpls_lsp_install(struct zebra_vrf *zvrf, enum lsp_types_t type, return 0; if (IS_ZEBRA_DEBUG_MPLS) { - char buf2[BUFSIZ]; - char buf3[BUFSIZ]; + char buf2[MPLS_LABEL_STRLEN]; + char buf3[MPLS_LABEL_STRLEN]; nhlfe2str(nhlfe, buf, BUFSIZ); mpls_label2str(num_out_labels, out_labels, buf2, @@ -2842,7 +2843,7 @@ int mpls_lsp_install(struct zebra_vrf *zvrf, enum lsp_types_t type, */ int mpls_lsp_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type, mpls_label_t in_label, enum nexthop_types_t gtype, - union g_addr *gate, ifindex_t ifindex) + const union g_addr *gate, ifindex_t ifindex) { struct hash *lsp_table; zebra_ile_t tmp_ile; @@ -3056,11 +3057,12 @@ int zebra_mpls_static_lsp_add(struct zebra_vrf *zvrf, mpls_label_t in_label, if (!slsp_table) return -1; - /* If entry is present, exit. */ + /* Find or create LSP. */ tmp_ile.in_label = in_label; slsp = hash_get(slsp_table, &tmp_ile, slsp_alloc); if (!slsp) return -1; + snhlfe = snhlfe_find(slsp, gtype, gate, ifindex); if (snhlfe) { if (snhlfe->out_label == out_label) diff --git a/zebra/zebra_mpls.h b/zebra/zebra_mpls.h index 2489e8e510..33cb614346 100644 --- a/zebra/zebra_mpls.h +++ b/zebra/zebra_mpls.h @@ -288,7 +288,7 @@ int mpls_ftn_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type, int mpls_lsp_install(struct zebra_vrf *zvrf, enum lsp_types_t type, mpls_label_t in_label, uint8_t num_out_labels, mpls_label_t out_labels[], enum nexthop_types_t gtype, - union g_addr *gate, ifindex_t ifindex); + const union g_addr *gate, ifindex_t ifindex); /* * Uninstall a particular NHLFE in the forwarding table. If this is @@ -296,7 +296,7 @@ int mpls_lsp_install(struct zebra_vrf *zvrf, enum lsp_types_t type, */ int mpls_lsp_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type, mpls_label_t in_label, enum nexthop_types_t gtype, - union g_addr *gate, ifindex_t ifindex); + const union g_addr *gate, ifindex_t ifindex); /* * Uninstall all NHLFEs for a particular LSP forwarding entry. diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index f0d43756b5..fceddcb745 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -63,6 +63,9 @@ static struct nhg_hash_entry * depends_find_id_add(struct nhg_connected_tree_head *head, uint32_t id); static void depends_decrement_free(struct nhg_connected_tree_head *head); +static struct nhg_backup_info * +nhg_backup_copy(const struct nhg_backup_info *orig); + static void nhg_connected_free(struct nhg_connected *dep) { @@ -295,7 +298,7 @@ static void zebra_nhg_set_if(struct nhg_hash_entry *nhe, struct interface *ifp) static void zebra_nhg_connect_depends(struct nhg_hash_entry *nhe, - struct nhg_connected_tree_head nhg_depends) + struct nhg_connected_tree_head *nhg_depends) { struct nhg_connected *rb_node_dep = NULL; @@ -304,31 +307,58 @@ zebra_nhg_connect_depends(struct nhg_hash_entry *nhe, * for now. Otherwise, their might be a time trade-off for repeated * alloc/frees as startup. */ - nhe->nhg_depends = nhg_depends; + nhe->nhg_depends = *nhg_depends; /* Attach backpointer to anything that it depends on */ zebra_nhg_dependents_init(nhe); if (!zebra_nhg_depends_is_empty(nhe)) { frr_each(nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) { + if (IS_ZEBRA_DEBUG_NHG_DETAIL) + zlog_debug("%s: nhe %p (%u), dep %p (%u)", + __func__, nhe, nhe->id, + rb_node_dep->nhe, + rb_node_dep->nhe->id); + zebra_nhg_dependents_add(rb_node_dep->nhe, nhe); } } +} - /* Add the ifp now if its not a group or recursive and has ifindex */ - if (zebra_nhg_depends_is_empty(nhe) && nhe->nhg.nexthop - && nhe->nhg.nexthop->ifindex) { - struct interface *ifp = NULL; +/* Init an nhe, for use in a hash lookup for example */ +void zebra_nhe_init(struct nhg_hash_entry *nhe, afi_t afi, + const struct nexthop *nh) +{ + memset(nhe, 0, sizeof(struct nhg_hash_entry)); + nhe->vrf_id = VRF_DEFAULT; + nhe->type = ZEBRA_ROUTE_NHG; + nhe->afi = AFI_UNSPEC; - ifp = if_lookup_by_index(nhe->nhg.nexthop->ifindex, - nhe->nhg.nexthop->vrf_id); - if (ifp) - zebra_nhg_set_if(nhe, ifp); - else - flog_err( - EC_ZEBRA_IF_LOOKUP_FAILED, - "Zebra failed to lookup an interface with ifindex=%d in vrf=%u for NHE id=%u", - nhe->nhg.nexthop->ifindex, - nhe->nhg.nexthop->vrf_id, nhe->id); + /* There are some special rules that apply to groups representing + * a single nexthop. + */ + if (nh && (nh->next == NULL)) { + switch (nh->type) { + case (NEXTHOP_TYPE_IFINDEX): + case (NEXTHOP_TYPE_BLACKHOLE): + /* + * This switch case handles setting the afi different + * for ipv4/v6 routes. Ifindex/blackhole nexthop + * objects cannot be ambiguous, they must be Address + * Family specific. If we get here, we will either use + * the AF of the route, or the one we got passed from + * here from the kernel. + */ + nhe->afi = afi; + break; + case (NEXTHOP_TYPE_IPV4_IFINDEX): + case (NEXTHOP_TYPE_IPV4): + nhe->afi = AFI_IP; + break; + case (NEXTHOP_TYPE_IPV6_IFINDEX): + case (NEXTHOP_TYPE_IPV6): + nhe->afi = AFI_IP6; + break; + } } } @@ -341,7 +371,7 @@ struct nhg_hash_entry *zebra_nhg_alloc(void) return nhe; } -static struct nhg_hash_entry *zebra_nhg_copy(const struct nhg_hash_entry *copy, +static struct nhg_hash_entry *zebra_nhg_copy(const struct nhg_hash_entry *orig, uint32_t id) { struct nhg_hash_entry *nhe; @@ -350,14 +380,18 @@ static struct nhg_hash_entry *zebra_nhg_copy(const struct nhg_hash_entry *copy, nhe->id = id; - nexthop_group_copy(&(nhe->nhg), &(copy->nhg)); + nexthop_group_copy(&(nhe->nhg), &(orig->nhg)); - nhe->vrf_id = copy->vrf_id; - nhe->afi = copy->afi; - nhe->type = copy->type ? copy->type : ZEBRA_ROUTE_NHG; + nhe->vrf_id = orig->vrf_id; + nhe->afi = orig->afi; + nhe->type = orig->type ? orig->type : ZEBRA_ROUTE_NHG; nhe->refcnt = 0; nhe->dplane_ref = zebra_router_get_next_sequence(); + /* Copy backup info also, if present */ + if (orig->backup_info) + nhe->backup_info = nhg_backup_copy(orig->backup_info); + return nhe; } @@ -372,7 +406,25 @@ static void *zebra_nhg_hash_alloc(void *arg) /* Mark duplicate nexthops in a group at creation time. */ nexthop_group_mark_duplicates(&(nhe->nhg)); - zebra_nhg_connect_depends(nhe, copy->nhg_depends); + zebra_nhg_connect_depends(nhe, &(copy->nhg_depends)); + + /* Add the ifp now if it's not a group or recursive and has ifindex */ + if (zebra_nhg_depends_is_empty(nhe) && nhe->nhg.nexthop + && nhe->nhg.nexthop->ifindex) { + struct interface *ifp = NULL; + + ifp = if_lookup_by_index(nhe->nhg.nexthop->ifindex, + nhe->nhg.nexthop->vrf_id); + if (ifp) + zebra_nhg_set_if(nhe, ifp); + else + flog_err( + EC_ZEBRA_IF_LOOKUP_FAILED, + "Zebra failed to lookup an interface with ifindex=%d in vrf=%u for NHE id=%u", + nhe->nhg.nexthop->ifindex, + nhe->nhg.nexthop->vrf_id, nhe->id); + } + zebra_nhg_insert_id(nhe); return nhe; @@ -381,12 +433,17 @@ static void *zebra_nhg_hash_alloc(void *arg) uint32_t zebra_nhg_hash_key(const void *arg) { const struct nhg_hash_entry *nhe = arg; + uint32_t val, key = 0x5a351234; + + val = nexthop_group_hash(&(nhe->nhg)); + if (nhe->backup_info) { + val = jhash_2words(val, + nexthop_group_hash( + &(nhe->backup_info->nhe->nhg)), + key); + } - uint32_t key = 0x5a351234; - - key = jhash_3words(nhe->vrf_id, nhe->afi, - nexthop_group_hash(&(nhe->nhg)), - key); + key = jhash_3words(nhe->vrf_id, nhe->afi, val, key); return key; } @@ -398,6 +455,50 @@ uint32_t zebra_nhg_id_key(const void *arg) return nhe->id; } +/* Helper with common nhg/nhe nexthop comparison logic */ +static bool nhg_compare_nexthops(const struct nexthop *nh1, + const struct nexthop *nh2) +{ + if (nh1 && !nh2) + return false; + + if (!nh1 && nh2) + return false; + + /* + * We have to check the active flag of each individual one, + * not just the overall active_num. This solves the special case + * issue of a route with a nexthop group with one nexthop + * resolving to itself and thus marking it inactive. If we + * have two different routes each wanting to mark a different + * nexthop inactive, they need to hash to two different groups. + * + * If we just hashed on num_active, they would hash the same + * which is incorrect. + * + * ex) + * 1.1.1.0/24 + * -> 1.1.1.1 dummy1 (inactive) + * -> 1.1.2.1 dummy2 + * + * 1.1.2.0/24 + * -> 1.1.1.1 dummy1 + * -> 1.1.2.1 dummy2 (inactive) + * + * Without checking each individual one, they would hash to + * the same group and both have 1.1.1.1 dummy1 marked inactive. + * + */ + if (CHECK_FLAG(nh1->flags, NEXTHOP_FLAG_ACTIVE) + != CHECK_FLAG(nh2->flags, NEXTHOP_FLAG_ACTIVE)) + return false; + + if (!nexthop_same(nh1, nh2)) + return false; + + return true; +} + bool zebra_nhg_hash_equal(const void *arg1, const void *arg2) { const struct nhg_hash_entry *nhe1 = arg1; @@ -415,45 +516,44 @@ bool zebra_nhg_hash_equal(const void *arg1, const void *arg2) if (nhe1->afi != nhe2->afi) return false; - /* Nexthops should be sorted */ + /* Nexthops should be in-order, so we simply compare them in-place */ for (nexthop1 = nhe1->nhg.nexthop, nexthop2 = nhe2->nhg.nexthop; nexthop1 || nexthop2; nexthop1 = nexthop1->next, nexthop2 = nexthop2->next) { - if (nexthop1 && !nexthop2) - return false; - if (!nexthop1 && nexthop2) + if (!nhg_compare_nexthops(nexthop1, nexthop2)) return false; + } - /* - * We have to check the active flag of each individual one, - * not just the overall active_num. This solves the special case - * issue of a route with a nexthop group with one nexthop - * resolving to itself and thus marking it inactive. If we - * have two different routes each wanting to mark a different - * nexthop inactive, they need to hash to two different groups. - * - * If we just hashed on num_active, they would hash the same - * which is incorrect. - * - * ex) - * 1.1.1.0/24 - * -> 1.1.1.1 dummy1 (inactive) - * -> 1.1.2.1 dummy2 - * - * 1.1.2.0/24 - * -> 1.1.1.1 dummy1 - * -> 1.1.2.1 dummy2 (inactive) - * - * Without checking each individual one, they would hash to - * the same group and both have 1.1.1.1 dummy1 marked inactive. - * - */ - if (CHECK_FLAG(nexthop1->flags, NEXTHOP_FLAG_ACTIVE) - != CHECK_FLAG(nexthop2->flags, NEXTHOP_FLAG_ACTIVE)) - return false; + /* If there's no backup info, comparison is done. */ + if ((nhe1->backup_info == NULL) && (nhe2->backup_info == NULL)) + return true; - if (!nexthop_same(nexthop1, nexthop2)) + /* Compare backup info also - test the easy things first */ + if (nhe1->backup_info && (nhe2->backup_info == NULL)) + return false; + if (nhe2->backup_info && (nhe1->backup_info == NULL)) + return false; + + /* Compare number of backups before actually comparing any */ + for (nexthop1 = nhe1->backup_info->nhe->nhg.nexthop, + nexthop2 = nhe2->backup_info->nhe->nhg.nexthop; + nexthop1 && nexthop2; + nexthop1 = nexthop1->next, nexthop2 = nexthop2->next) { + ; + } + + /* Did we find the end of one list before the other? */ + if (nexthop1 || nexthop2) + return false; + + /* Have to compare the backup nexthops */ + for (nexthop1 = nhe1->backup_info->nhe->nhg.nexthop, + nexthop2 = nhe2->backup_info->nhe->nhg.nexthop; + nexthop1 || nexthop2; + nexthop1 = nexthop1->next, nexthop2 = nexthop2->next) { + + if (!nhg_compare_nexthops(nexthop1, nexthop2)) return false; } @@ -512,29 +612,185 @@ static void handle_recursive_depend(struct nhg_connected_tree_head *nhg_depends, resolved_ng.nexthop = nh; + if (IS_ZEBRA_DEBUG_NHG_DETAIL) + zlog_debug("%s: head %p, nh %pNHv", + __func__, nhg_depends, nh); + depend = zebra_nhg_rib_find(0, &resolved_ng, afi); + if (IS_ZEBRA_DEBUG_NHG_DETAIL) + zlog_debug("%s: nh %pNHv => %p (%u)", + __func__, nh, depend, + depend ? depend->id : 0); + if (depend) depends_add(nhg_depends, depend); } +/* + * Lookup an nhe in the global hash, using data from another nhe. If 'lookup' + * has an id value, that's used. Create a new global/shared nhe if not found. + */ +static bool zebra_nhe_find(struct nhg_hash_entry **nhe, /* return value */ + struct nhg_hash_entry *lookup, + struct nhg_connected_tree_head *nhg_depends, + afi_t afi) +{ + bool created = false; + bool recursive = false; + struct nhg_hash_entry *newnhe, *backup_nhe; + struct nexthop *nh = NULL; + + if (IS_ZEBRA_DEBUG_NHG_DETAIL) + zlog_debug("%s: id %u, lookup %p, vrf %d, type %d, depends %p", + __func__, lookup->id, lookup, + lookup->vrf_id, lookup->type, + nhg_depends); + + if (lookup->id) + (*nhe) = zebra_nhg_lookup_id(lookup->id); + else + (*nhe) = hash_lookup(zrouter.nhgs, lookup); + + if (IS_ZEBRA_DEBUG_NHG_DETAIL) + zlog_debug("%s: lookup => %p (%u)", + __func__, (*nhe), + (*nhe) ? (*nhe)->id : 0); + + /* If we found an existing object, we're done */ + if (*nhe) + goto done; + + /* We're going to create/insert a new nhe: + * assign the next global id value if necessary. + */ + if (lookup->id == 0) + lookup->id = ++id_counter; + newnhe = hash_get(zrouter.nhgs, lookup, zebra_nhg_hash_alloc); + created = true; + + /* Mail back the new object */ + *nhe = newnhe; + + if (IS_ZEBRA_DEBUG_NHG_DETAIL) + zlog_debug("%s: => created %p (%u)", __func__, newnhe, + newnhe->id); + + /* Only hash/lookup the depends if the first lookup + * fails to find something. This should hopefully save a + * lot of cycles for larger ecmp sizes. + */ + if (nhg_depends) { + /* If you don't want to hash on each nexthop in the + * nexthop group struct you can pass the depends + * directly. Kernel-side we do this since it just looks + * them up via IDs. + */ + zebra_nhg_connect_depends(newnhe, nhg_depends); + goto done; + } + + /* Prepare dependency relationships if this is not a + * singleton nexthop. There are two cases: a single + * recursive nexthop, where we need a relationship to the + * resolving nexthop; or a group of nexthops, where we need + * relationships with the corresponding singletons. + */ + zebra_nhg_depends_init(lookup); + + nh = newnhe->nhg.nexthop; + + if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_ACTIVE)) + SET_FLAG(newnhe->flags, NEXTHOP_GROUP_VALID); + + if (nh->next == NULL) { + if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_RECURSIVE)) { + /* Single recursive nexthop */ + handle_recursive_depend(&newnhe->nhg_depends, + nh->resolved, afi); + recursive = true; + } + } else { + /* List of nexthops */ + for (nh = newnhe->nhg.nexthop; nh; nh = nh->next) { + if (IS_ZEBRA_DEBUG_NHG_DETAIL) + zlog_debug("%s: depends NH %pNHv %s", + __func__, nh, + CHECK_FLAG(nh->flags, + NEXTHOP_FLAG_RECURSIVE) ? + "(R)" : ""); + + depends_find_add(&newnhe->nhg_depends, nh, afi); + } + } + + if (recursive) + SET_FLAG((*nhe)->flags, NEXTHOP_GROUP_RECURSIVE); + + if (zebra_nhg_get_backup_nhg(newnhe) == NULL || + zebra_nhg_get_backup_nhg(newnhe)->nexthop == NULL) + goto done; + + /* If there are backup nexthops, add them to the backup + * depends tree. The rules here are a little different. + */ + recursive = false; + backup_nhe = newnhe->backup_info->nhe; + + nh = backup_nhe->nhg.nexthop; + + /* Singleton recursive NH */ + if (nh->next == NULL && + CHECK_FLAG(nh->flags, NEXTHOP_FLAG_RECURSIVE)) { + if (IS_ZEBRA_DEBUG_NHG_DETAIL) + zlog_debug("%s: backup depend NH %pNHv (R)", + __func__, nh); + + /* Single recursive nexthop */ + handle_recursive_depend(&backup_nhe->nhg_depends, + nh->resolved, afi); + recursive = true; + } else { + /* One or more backup NHs */ + for (; nh; nh = nh->next) { + if (IS_ZEBRA_DEBUG_NHG_DETAIL) + zlog_debug("%s: backup depend NH %pNHv %s", + __func__, nh, + CHECK_FLAG(nh->flags, + NEXTHOP_FLAG_RECURSIVE) ? + "(R)" : ""); + + depends_find_add(&backup_nhe->nhg_depends, + nh, afi); + } + } + + if (recursive) + SET_FLAG(backup_nhe->flags, NEXTHOP_GROUP_RECURSIVE); + +done: + + return created; +} + +/* + * Lookup or create an nhe, based on an nhg or an nhe id. + */ static bool zebra_nhg_find(struct nhg_hash_entry **nhe, uint32_t id, struct nexthop_group *nhg, struct nhg_connected_tree_head *nhg_depends, vrf_id_t vrf_id, afi_t afi, int type) { struct nhg_hash_entry lookup = {}; - - uint32_t old_id_counter = id_counter; - bool created = false; - bool recursive = false; - /* - * If it has an id at this point, we must have gotten it from the kernel - */ - lookup.id = id ? id : ++id_counter; + if (IS_ZEBRA_DEBUG_NHG_DETAIL) + zlog_debug("%s: id %u, nhg %p, vrf %d, type %d, depends %p", + __func__, id, nhg, vrf_id, type, + nhg_depends); + /* Use a temporary nhe and call into the superset/common code */ + lookup.id = id; lookup.type = type ? type : ZEBRA_ROUTE_NHG; lookup.nhg = *nhg; @@ -567,53 +823,8 @@ static bool zebra_nhg_find(struct nhg_hash_entry **nhe, uint32_t id, } } - if (id) - (*nhe) = zebra_nhg_lookup_id(id); - else - (*nhe) = hash_lookup(zrouter.nhgs, &lookup); - - /* If it found an nhe in our tables, this new ID is unused */ - if (*nhe) - id_counter = old_id_counter; - - if (!(*nhe)) { - /* Only hash/lookup the depends if the first lookup - * fails to find something. This should hopefully save a - * lot of cycles for larger ecmp sizes. - */ - if (nhg_depends) - /* If you don't want to hash on each nexthop in the - * nexthop group struct you can pass the depends - * directly. Kernel-side we do this since it just looks - * them up via IDs. - */ - lookup.nhg_depends = *nhg_depends; - else { - if (nhg->nexthop->next) { - zebra_nhg_depends_init(&lookup); - - /* If its a group, create a dependency tree */ - struct nexthop *nh = NULL; - - for (nh = nhg->nexthop; nh; nh = nh->next) - depends_find_add(&lookup.nhg_depends, - nh, afi); - } else if (CHECK_FLAG(nhg->nexthop->flags, - NEXTHOP_FLAG_RECURSIVE)) { - zebra_nhg_depends_init(&lookup); - handle_recursive_depend(&lookup.nhg_depends, - nhg->nexthop->resolved, - afi); - recursive = true; - } - } - - (*nhe) = hash_get(zrouter.nhgs, &lookup, zebra_nhg_hash_alloc); - created = true; + created = zebra_nhe_find(nhe, &lookup, nhg_depends, afi); - if (recursive) - SET_FLAG((*nhe)->flags, NEXTHOP_GROUP_RECURSIVE); - } return created; } @@ -629,6 +840,10 @@ zebra_nhg_find_nexthop(uint32_t id, struct nexthop *nh, afi_t afi, int type) zebra_nhg_find(&nhe, id, &nhg, NULL, vrf_id, afi, type); + if (IS_ZEBRA_DEBUG_NHG_DETAIL) + zlog_debug("%s: nh %pNHv => %p (%u)", + __func__, nh, nhe, nhe ? nhe->id : 0); + return nhe; } @@ -807,6 +1022,9 @@ done: static void zebra_nhg_release(struct nhg_hash_entry *nhe) { + if (IS_ZEBRA_DEBUG_NHG_DETAIL) + zlog_debug("%s: nhe %p (%u)", __func__, nhe, nhe->id); + /* Remove it from any lists it may be on */ zebra_nhg_depends_release(nhe); zebra_nhg_dependents_release(nhe); @@ -872,6 +1090,10 @@ static int nhg_ctx_process_new(struct nhg_ctx *ctx) lookup = zebra_nhg_lookup_id(id); + if (IS_ZEBRA_DEBUG_NHG_DETAIL) + zlog_debug("%s: id %u, count %d, lookup => %p", + __func__, id, count, lookup); + if (lookup) { /* This is already present in our table, hence an update * that we did not initate. @@ -919,6 +1141,11 @@ static int nhg_ctx_process_new(struct nhg_ctx *ctx) */ kernel_nhe = zebra_nhg_copy(nhe, id); + + if (IS_ZEBRA_DEBUG_NHG_DETAIL) + zlog_debug("%s: copying kernel nhe (%u), dup of %u", + __func__, id, nhe->id); + zebra_nhg_insert_id(kernel_nhe); zebra_nhg_set_unhashable(kernel_nhe); } else if (zebra_nhg_contains_unhashable(nhe)) { @@ -926,10 +1153,18 @@ static int nhg_ctx_process_new(struct nhg_ctx *ctx) * depend, so lets mark this group as unhashable as well * and release it from the non-ID hash. */ + if (IS_ZEBRA_DEBUG_NHG_DETAIL) + zlog_debug("%s: nhe %p (%u) unhashable", + __func__, nhe, nhe->id); + hash_release(zrouter.nhgs, nhe); zebra_nhg_set_unhashable(nhe); } else { /* It actually created a new nhe */ + if (IS_ZEBRA_DEBUG_NHG_DETAIL) + zlog_debug("%s: nhe %p (%u) is new", + __func__, nhe, nhe->id); + SET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID); SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED); } @@ -1038,6 +1273,10 @@ int zebra_nhg_kernel_find(uint32_t id, struct nexthop *nh, struct nh_grp *grp, { struct nhg_ctx *ctx = NULL; + if (IS_ZEBRA_DEBUG_NHG_DETAIL) + zlog_debug("%s: nh %pNHv, id %u, count %d", + __func__, nh, id, (int)count); + if (id > id_counter) /* Increase our counter so we don't try to create * an ID that already exists @@ -1111,12 +1350,17 @@ static struct nhg_hash_entry *depends_find_singleton(const struct nexthop *nh, /* The copy may have allocated labels; free them if necessary. */ nexthop_del_labels(&lookup); + if (IS_ZEBRA_DEBUG_NHG_DETAIL) + zlog_debug("%s: nh %pNHv => %p (%u)", + __func__, nh, nhe, nhe ? nhe->id : 0); + return nhe; } static struct nhg_hash_entry *depends_find(const struct nexthop *nh, afi_t afi) { struct nhg_hash_entry *nhe = NULL; + char rbuf[10]; if (!nh) goto done; @@ -1124,10 +1368,18 @@ static struct nhg_hash_entry *depends_find(const struct nexthop *nh, afi_t afi) /* We are separating these functions out to increase handling speed * in the non-recursive case (by not alloc/freeing) */ - if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_RECURSIVE)) + if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_RECURSIVE)) { nhe = depends_find_recursive(nh, afi); - else + strlcpy(rbuf, "(R)", sizeof(rbuf)); + } else { nhe = depends_find_singleton(nh, afi); + rbuf[0] = '\0'; + } + + if (IS_ZEBRA_DEBUG_NHG_DETAIL) + zlog_debug("%s: nh %pNHv %s => %p (%u)", + __func__, nh, rbuf, + nhe, nhe ? nhe->id : 0); done: return nhe; @@ -1136,6 +1388,10 @@ done: static void depends_add(struct nhg_connected_tree_head *head, struct nhg_hash_entry *depend) { + if (IS_ZEBRA_DEBUG_NHG_DETAIL) + zlog_debug("%s: head %p nh %pNHv", + __func__, head, depend->nhg.nexthop); + /* If NULL is returned, it was successfully added and * needs to have its refcnt incremented. * @@ -1154,6 +1410,10 @@ depends_find_add(struct nhg_connected_tree_head *head, struct nexthop *nh, depend = depends_find(nh, afi); + if (IS_ZEBRA_DEBUG_NHG_DETAIL) + zlog_debug("%s: nh %pNHv => %p", + __func__, nh, depend); + if (depend) depends_add(head, depend); @@ -1179,7 +1439,7 @@ static void depends_decrement_free(struct nhg_connected_tree_head *head) nhg_connected_tree_free(head); } -/* Rib-side, you get a nexthop group struct */ +/* Find an nhe based on a list of nexthops */ struct nhg_hash_entry * zebra_nhg_rib_find(uint32_t id, struct nexthop_group *nhg, afi_t rt_afi) { @@ -1195,13 +1455,107 @@ zebra_nhg_rib_find(uint32_t id, struct nexthop_group *nhg, afi_t rt_afi) zebra_nhg_find(&nhe, id, nhg, NULL, vrf_id, rt_afi, 0); + if (IS_ZEBRA_DEBUG_NHG_DETAIL) + zlog_debug("%s: => nhe %p (%u)", + __func__, nhe, nhe ? nhe->id : 0); + + return nhe; +} + +/* Find an nhe based on a route's nhe */ +struct nhg_hash_entry * +zebra_nhg_rib_find_nhe(struct nhg_hash_entry *rt_nhe, afi_t rt_afi) +{ + struct nhg_hash_entry *nhe = NULL; + + if (!(rt_nhe && rt_nhe->nhg.nexthop)) { + flog_err(EC_ZEBRA_TABLE_LOOKUP_FAILED, + "No nexthop passed to %s", __func__); + return NULL; + } + + if (IS_ZEBRA_DEBUG_NHG_DETAIL) + zlog_debug("%s: rt_nhe %p (%u)", + __func__, rt_nhe, + rt_nhe ? rt_nhe->id : 0); + + zebra_nhe_find(&nhe, rt_nhe, NULL, rt_afi); + + if (IS_ZEBRA_DEBUG_NHG_DETAIL) + zlog_debug("%s: => nhe %p (%u)", + __func__, nhe, nhe ? nhe->id : 0); + return nhe; } +/* + * Allocate backup nexthop info object. Typically these are embedded in + * nhg_hash_entry objects. + */ +struct nhg_backup_info *zebra_nhg_backup_alloc(void) +{ + struct nhg_backup_info *p; + + p = XCALLOC(MTYPE_NHG, sizeof(struct nhg_backup_info)); + + p->nhe = zebra_nhg_alloc(); + + /* Identify the embedded group used to hold the list of backups */ + SET_FLAG(p->nhe->flags, NEXTHOP_GROUP_BACKUP); + + return p; +} + +/* + * Free backup nexthop info object, deal with any embedded allocations + */ +void zebra_nhg_backup_free(struct nhg_backup_info **p) +{ + if (p && *p) { + if ((*p)->nhe) + zebra_nhg_free((*p)->nhe); + + XFREE(MTYPE_NHG, (*p)); + } +} + +/* Accessor for backup nexthop group */ +struct nexthop_group *zebra_nhg_get_backup_nhg(struct nhg_hash_entry *nhe) +{ + struct nexthop_group *p = NULL; + + if (nhe) { + if (nhe->backup_info && nhe->backup_info->nhe) + p = &(nhe->backup_info->nhe->nhg); + } + + return p; +} + +/* + * Helper to return a copy of a backup_info - note that this is a shallow + * copy, meant to be used when creating a new nhe from info passed in with + * a route e.g. + */ +static struct nhg_backup_info * +nhg_backup_copy(const struct nhg_backup_info *orig) +{ + struct nhg_backup_info *b; + + b = zebra_nhg_backup_alloc(); + + /* Copy list of nexthops */ + nexthop_group_copy(&(b->nhe->nhg), &(orig->nhe->nhg)); + + return b; +} + static void zebra_nhg_free_members(struct nhg_hash_entry *nhe) { nexthops_free(nhe->nhg.nexthop); + zebra_nhg_backup_free(&nhe->backup_info); + /* Decrement to remove connection ref */ nhg_connected_tree_decrement_ref(&nhe->nhg_depends); nhg_connected_tree_free(&nhe->nhg_depends); @@ -1210,6 +1564,21 @@ static void zebra_nhg_free_members(struct nhg_hash_entry *nhe) void zebra_nhg_free(struct nhg_hash_entry *nhe) { + if (IS_ZEBRA_DEBUG_NHG_DETAIL) { + /* Group or singleton? */ + if (nhe->nhg.nexthop && nhe->nhg.nexthop->next) + zlog_debug("%s: nhe %p (%u), refcnt %d", + __func__, nhe, + (nhe ? nhe->id : 0), + (nhe ? nhe->refcnt : 0)); + else + zlog_debug("%s: nhe %p (%u), refcnt %d, NH %pNHv", + __func__, nhe, + (nhe ? nhe->id : 0), + (nhe ? nhe->refcnt : 0), + nhe->nhg.nexthop); + } + if (nhe->refcnt) zlog_debug("nhe_id=%u hash refcnt=%d", nhe->id, nhe->refcnt); @@ -1225,6 +1594,11 @@ void zebra_nhg_hash_free(void *p) void zebra_nhg_decrement_ref(struct nhg_hash_entry *nhe) { + if (IS_ZEBRA_DEBUG_NHG_DETAIL) + zlog_debug("%s: nhe %p (%u) %d => %d", + __func__, nhe, nhe->id, nhe->refcnt, + nhe->refcnt - 1); + nhe->refcnt--; if (!zebra_nhg_depends_is_empty(nhe)) @@ -1236,6 +1610,11 @@ void zebra_nhg_decrement_ref(struct nhg_hash_entry *nhe) void zebra_nhg_increment_ref(struct nhg_hash_entry *nhe) { + if (IS_ZEBRA_DEBUG_NHG_DETAIL) + zlog_debug("%s: nhe %p (%u) %d => %d", + __func__, nhe, nhe->id, nhe->refcnt, + nhe->refcnt + 1); + nhe->refcnt++; if (!zebra_nhg_depends_is_empty(nhe)) @@ -1385,6 +1764,10 @@ static int nexthop_active(afi_t afi, struct route_entry *re, nexthop->resolved = NULL; re->nexthop_mtu = 0; + if (IS_ZEBRA_DEBUG_NHG_DETAIL) + zlog_debug("%s: re %p, nexthop %pNHv", + __func__, re, nexthop); + /* * If the kernel has sent us a NEW route, then * by golly gee whiz it's a good route. @@ -1411,7 +1794,7 @@ static int nexthop_active(afi_t afi, struct route_entry *re, if (!ifp) { if (IS_ZEBRA_DEBUG_RIB_DETAILED) zlog_debug( - "\t%s: Onlink and interface: %u[%u] does not exist", + " %s: Onlink and interface: %u[%u] does not exist", __func__, nexthop->ifindex, nexthop->vrf_id); return 0; @@ -1422,14 +1805,14 @@ static int nexthop_active(afi_t afi, struct route_entry *re, if (IS_ZEBRA_DEBUG_RIB_DETAILED) zlog_debug( - "\t%s: Onlink and interface %s is not operative", + " %s: Onlink and interface %s is not operative", __func__, ifp->name); return 0; } if (!if_is_operative(ifp)) { if (IS_ZEBRA_DEBUG_RIB_DETAILED) zlog_debug( - "\t%s: Interface %s is not unnumbered", + " %s: Interface %s is not unnumbered", __func__, ifp->name); return 0; } @@ -1441,7 +1824,7 @@ static int nexthop_active(afi_t afi, struct route_entry *re, && memcmp(&nexthop->gate.ipv6, &top->p.u.prefix6, 16) == 0)) { if (IS_ZEBRA_DEBUG_RIB_DETAILED) zlog_debug( - "\t:%s: Attempting to install a max prefixlength route through itself", + " :%s: Attempting to install a max prefixlength route through itself", __func__); return 0; } @@ -1469,7 +1852,7 @@ static int nexthop_active(afi_t afi, struct route_entry *re, zvrf = zebra_vrf_lookup_by_id(nexthop->vrf_id); if (!table || !zvrf) { if (IS_ZEBRA_DEBUG_RIB_DETAILED) - zlog_debug("\t%s: Table not found", __func__); + zlog_debug(" %s: Table not found", __func__); return 0; } @@ -1487,7 +1870,7 @@ static int nexthop_active(afi_t afi, struct route_entry *re, || ((afi == AFI_IP6) && (rn->p.prefixlen != 128))) { if (IS_ZEBRA_DEBUG_RIB_DETAILED) zlog_debug( - "\t%s: Matched against ourself and prefix length is not max bit length", + " %s: Matched against ourself and prefix length is not max bit length", __func__); return 0; } @@ -1500,7 +1883,7 @@ static int nexthop_active(afi_t afi, struct route_entry *re, && !rnh_resolve_via_default(zvrf, p.family)) { if (IS_ZEBRA_DEBUG_RIB_DETAILED) zlog_debug( - "\t:%s: Resolved against default route", + " :%s: Resolved against default route", __func__); return 0; } @@ -1533,6 +1916,12 @@ static int nexthop_active(afi_t afi, struct route_entry *re, || nexthop->type == NEXTHOP_TYPE_IPV6) nexthop->ifindex = newhop->ifindex; } + + if (IS_ZEBRA_DEBUG_NHG_DETAIL) + zlog_debug("%s: CONNECT match %p (%u), newhop %pNHv", + __func__, match, + match->nhe->id, newhop); + return 1; } else if (CHECK_FLAG(re->flags, ZEBRA_FLAG_ALLOW_RECURSION)) { resolved = 0; @@ -1543,6 +1932,11 @@ static int nexthop_active(afi_t afi, struct route_entry *re, if (!nexthop_valid_resolve(nexthop, newhop)) continue; + if (IS_ZEBRA_DEBUG_NHG_DETAIL) + zlog_debug("%s: RECURSIVE match %p (%u), newhop %pNHv", + __func__, match, + match->nhe->id, newhop); + SET_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE); nexthop_set_resolved(afi, newhop, nexthop); @@ -1552,8 +1946,9 @@ static int nexthop_active(afi_t afi, struct route_entry *re, re->nexthop_mtu = match->mtu; if (!resolved && IS_ZEBRA_DEBUG_RIB_DETAILED) - zlog_debug("\t%s: Recursion failed to find", - __func__); + zlog_debug( + " %s: Recursion failed to find", + __func__); return resolved; } else if (re->type == ZEBRA_ROUTE_STATIC) { resolved = 0; @@ -1564,6 +1959,11 @@ static int nexthop_active(afi_t afi, struct route_entry *re, if (!nexthop_valid_resolve(nexthop, newhop)) continue; + if (IS_ZEBRA_DEBUG_RIB_DETAILED) + zlog_debug("%s: STATIC match %p (%u), newhop %pNHv", + __func__, match, + match->nhe->id, newhop); + SET_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE); nexthop_set_resolved(afi, newhop, nexthop); @@ -1574,24 +1974,25 @@ static int nexthop_active(afi_t afi, struct route_entry *re, if (!resolved && IS_ZEBRA_DEBUG_RIB_DETAILED) zlog_debug( - "\t%s: Static route unable to resolve", + " %s: Static route unable to resolve", __func__); return resolved; } else { if (IS_ZEBRA_DEBUG_RIB_DETAILED) { zlog_debug( - "\t%s: Route Type %s has not turned on recursion", + " %s: Route Type %s has not turned on recursion", __func__, zebra_route_string(re->type)); if (re->type == ZEBRA_ROUTE_BGP && !CHECK_FLAG(re->flags, ZEBRA_FLAG_IBGP)) zlog_debug( - "\tEBGP: see \"disable-ebgp-connected-route-check\" or \"disable-connected-check\""); + " EBGP: see \"disable-ebgp-connected-route-check\" or \"disable-connected-check\""); } return 0; } } if (IS_ZEBRA_DEBUG_RIB_DETAILED) - zlog_debug("\t%s: Nexthop did not lookup in table", __func__); + zlog_debug(" %s: Nexthop did not lookup in table", + __func__); return 0; } @@ -1681,9 +2082,10 @@ static unsigned nexthop_active_check(struct route_node *rn, default: break; } + if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) { if (IS_ZEBRA_DEBUG_RIB_DETAILED) - zlog_debug("\t%s: Unable to find a active nexthop", + zlog_debug(" %s: Unable to find active nexthop", __func__); return 0; } @@ -1713,7 +2115,7 @@ static unsigned nexthop_active_check(struct route_node *rn, zvrf = zebra_vrf_lookup_by_id(nexthop->vrf_id); if (!zvrf) { if (IS_ZEBRA_DEBUG_RIB_DETAILED) - zlog_debug("\t%s: zvrf is NULL", __func__); + zlog_debug(" %s: zvrf is NULL", __func__); return CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); } @@ -1734,46 +2136,68 @@ static unsigned nexthop_active_check(struct route_node *rn, return CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); } +/* Helper function called after resolution to walk nhg rb trees + * and toggle the NEXTHOP_GROUP_VALID flag if the nexthop + * is active on singleton NHEs. + */ +static bool zebra_nhg_set_valid_if_active(struct nhg_hash_entry *nhe) +{ + struct nhg_connected *rb_node_dep = NULL; + bool valid = false; + + if (!zebra_nhg_depends_is_empty(nhe)) { + /* Is at least one depend valid? */ + frr_each(nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) { + if (zebra_nhg_set_valid_if_active(rb_node_dep->nhe)) + valid = true; + } + + goto done; + } + + /* should be fully resolved singleton at this point */ + if (CHECK_FLAG(nhe->nhg.nexthop->flags, NEXTHOP_FLAG_ACTIVE)) + valid = true; + +done: + if (valid) + SET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID); + + return valid; +} + /* - * Iterate over all nexthops of the given RIB entry and refresh their - * ACTIVE flag. If any nexthop is found to toggle the ACTIVE flag, - * the whole re structure is flagged with ROUTE_ENTRY_CHANGED. - * - * Return value is the new number of active nexthops. + * Process a list of nexthops, given the head of the list, determining + * whether each one is ACTIVE/installable at this time. */ -int nexthop_active_update(struct route_node *rn, struct route_entry *re) +static uint32_t nexthop_list_active_update(struct route_node *rn, + struct route_entry *re, + struct nexthop *nexthop) { - struct nexthop_group new_grp = {}; - struct nexthop *nexthop; union g_addr prev_src; unsigned int prev_active, new_active; ifindex_t prev_index; - uint8_t curr_active = 0; + uint32_t counter = 0; - afi_t rt_afi = family2afi(rn->p.family); - - UNSET_FLAG(re->status, ROUTE_ENTRY_CHANGED); - - /* Copy over the nexthops in current state */ - nexthop_group_copy(&new_grp, &(re->nhe->nhg)); - - for (nexthop = new_grp.nexthop; nexthop; nexthop = nexthop->next) { + /* Process nexthops one-by-one */ + for ( ; nexthop; nexthop = nexthop->next) { /* No protocol daemon provides src and so we're skipping - * tracking it */ + * tracking it + */ prev_src = nexthop->rmap_src; prev_active = CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); prev_index = nexthop->ifindex; /* * We need to respect the multipath_num here * as that what we should be able to install from - * a multipath perpsective should not be a data plane + * a multipath perspective should not be a data plane * decision point. */ new_active = nexthop_active_check(rn, re, nexthop); - if (new_active && curr_active >= zrouter.multipath_num) { + if (new_active && counter >= zrouter.multipath_num) { struct nexthop *nh; /* Set it and its resolved nexthop as inactive. */ @@ -1784,7 +2208,7 @@ int nexthop_active_update(struct route_node *rn, struct route_entry *re) } if (new_active) - curr_active++; + counter++; /* Don't allow src setting on IPv6 addr for now */ if (prev_active != new_active || prev_index != nexthop->ifindex @@ -1800,48 +2224,122 @@ int nexthop_active_update(struct route_node *rn, struct route_entry *re) SET_FLAG(re->status, ROUTE_ENTRY_CHANGED); } + return counter; +} + +/* + * Iterate over all nexthops of the given RIB entry and refresh their + * ACTIVE flag. If any nexthop is found to toggle the ACTIVE flag, + * the whole re structure is flagged with ROUTE_ENTRY_CHANGED. + * + * Return value is the new number of active nexthops. + */ +int nexthop_active_update(struct route_node *rn, struct route_entry *re) +{ + struct nhg_hash_entry *curr_nhe; + uint32_t curr_active = 0, backup_active = 0; + + afi_t rt_afi = family2afi(rn->p.family); + + UNSET_FLAG(re->status, ROUTE_ENTRY_CHANGED); + + /* Make a local copy of the existing nhe, so we don't work on/modify + * the shared nhe. + */ + curr_nhe = zebra_nhg_copy(re->nhe, re->nhe->id); + + if (IS_ZEBRA_DEBUG_NHG_DETAIL) + zlog_debug("%s: re %p nhe %p (%u), curr_nhe %p", + __func__, re, re->nhe, re->nhe->id, + curr_nhe); + + /* Clear the existing id, if any: this will avoid any confusion + * if the id exists, and will also force the creation + * of a new nhe reflecting the changes we may make in this local copy. + */ + curr_nhe->id = 0; + + /* Process nexthops */ + curr_active = nexthop_list_active_update(rn, re, curr_nhe->nhg.nexthop); + + if (IS_ZEBRA_DEBUG_NHG_DETAIL) + zlog_debug("%s: re %p curr_active %u", __func__, re, + curr_active); + + /* If there are no backup nexthops, we are done */ + if (zebra_nhg_get_backup_nhg(curr_nhe) == NULL) + goto backups_done; + + backup_active = nexthop_list_active_update( + rn, re, zebra_nhg_get_backup_nhg(curr_nhe)->nexthop); + + if (IS_ZEBRA_DEBUG_NHG_DETAIL) + zlog_debug("%s: re %p backup_active %u", __func__, re, + backup_active); + +backups_done: + + /* + * Ref or create an nhe that matches the current state of the + * nexthop(s). + */ if (CHECK_FLAG(re->status, ROUTE_ENTRY_CHANGED)) { struct nhg_hash_entry *new_nhe = NULL; - new_nhe = zebra_nhg_rib_find(0, &new_grp, rt_afi); + new_nhe = zebra_nhg_rib_find_nhe(curr_nhe, rt_afi); + + if (IS_ZEBRA_DEBUG_NHG_DETAIL) + zlog_debug("%s: re %p CHANGED: nhe %p (%u) => new_nhe %p (%u)", + __func__, re, re->nhe, + re->nhe->id, new_nhe, new_nhe->id); route_entry_update_nhe(re, new_nhe); } - if (curr_active) { - struct nhg_hash_entry *nhe = NULL; - - nhe = zebra_nhg_lookup_id(re->nhe_id); - if (nhe) - SET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID); - else - flog_err( - EC_ZEBRA_TABLE_LOOKUP_FAILED, - "Active update on NHE id=%u that we do not have in our tables", - re->nhe_id); - } + /* Walk the NHE depends tree and toggle NEXTHOP_GROUP_VALID + * flag where appropriate. + */ + if (curr_active) + zebra_nhg_set_valid_if_active(re->nhe); /* - * Do not need these nexthops anymore since they - * were either copied over into an nhe or not + * Do not need the old / copied nhe anymore since it + * was either copied over into a new nhe or not * used at all. */ - nexthops_free(new_grp.nexthop); + zebra_nhg_free(curr_nhe); return curr_active; } -/* Convert a nhe into a group array */ -uint8_t zebra_nhg_nhe2grp(struct nh_grp *grp, struct nhg_hash_entry *nhe, - int max_num) +/* Recursively construct a grp array of fully resolved IDs. + * + * This function allows us to account for groups within groups, + * by converting them into a flat array of IDs. + * + * nh_grp is modified at every level of recursion to append + * to it the next unique, fully resolved ID from the entire tree. + * + * + * Note: + * I'm pretty sure we only allow ONE level of group within group currently. + * But making this recursive just in case that ever changes. + */ +static uint8_t zebra_nhg_nhe2grp_internal(struct nh_grp *grp, + uint8_t curr_index, + struct nhg_hash_entry *nhe, + int max_num) { struct nhg_connected *rb_node_dep = NULL; struct nhg_hash_entry *depend = NULL; - uint8_t i = 0; + uint8_t i = curr_index; frr_each(nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) { bool duplicate = false; + if (i >= max_num) + goto done; + depend = rb_node_dep->nhe; /* @@ -1858,27 +2356,78 @@ uint8_t zebra_nhg_nhe2grp(struct nh_grp *grp, struct nhg_hash_entry *nhe, } } - /* Check for duplicate IDs, kernel doesn't like that */ - for (int j = 0; j < i; j++) { - if (depend->id == grp[j].id) - duplicate = true; - } + if (!zebra_nhg_depends_is_empty(depend)) { + /* This is a group within a group */ + i = zebra_nhg_nhe2grp_internal(grp, i, depend, max_num); + } else { + if (!CHECK_FLAG(depend->flags, NEXTHOP_GROUP_VALID)) { + if (IS_ZEBRA_DEBUG_RIB_DETAILED + || IS_ZEBRA_DEBUG_NHG) + zlog_debug( + "%s: Nexthop ID (%u) not valid, not appending to dataplane install group", + __func__, depend->id); + continue; + } + + /* If the nexthop not installed/queued for install don't + * put in the ID array. + */ + if (!(CHECK_FLAG(depend->flags, NEXTHOP_GROUP_INSTALLED) + || CHECK_FLAG(depend->flags, + NEXTHOP_GROUP_QUEUED))) { + if (IS_ZEBRA_DEBUG_RIB_DETAILED + || IS_ZEBRA_DEBUG_NHG) + zlog_debug( + "%s: Nexthop ID (%u) not installed or queued for install, not appending to dataplane install group", + __func__, depend->id); + continue; + } + + /* Check for duplicate IDs, ignore if found. */ + for (int j = 0; j < i; j++) { + if (depend->id == grp[j].id) { + duplicate = true; + break; + } + } + + if (duplicate) { + if (IS_ZEBRA_DEBUG_RIB_DETAILED + || IS_ZEBRA_DEBUG_NHG) + zlog_debug( + "%s: Nexthop ID (%u) is duplicate, not appending to dataplane install group", + __func__, depend->id); + continue; + } - if (!duplicate) { grp[i].id = depend->id; - /* We aren't using weights for anything right now */ grp[i].weight = depend->nhg.nexthop->weight; i++; } - - if (i >= max_num) - goto done; } + if (nhe->backup_info == NULL || nhe->backup_info->nhe == NULL) + goto done; + + /* TODO -- For now, we are not trying to use or install any + * backup info in this nexthop-id path: we aren't prepared + * to use the backups here yet. We're just debugging what we find. + */ + if (IS_ZEBRA_DEBUG_NHG_DETAIL) + zlog_debug("%s: skipping backup nhe", __func__); + done: return i; } +/* Convert a nhe into a group array */ +uint8_t zebra_nhg_nhe2grp(struct nh_grp *grp, struct nhg_hash_entry *nhe, + int max_num) +{ + /* Call into the recursive function */ + return zebra_nhg_nhe2grp_internal(grp, 0, nhe, max_num); +} + void zebra_nhg_install_kernel(struct nhg_hash_entry *nhe) { struct nhg_connected *rb_node_dep = NULL; @@ -1891,7 +2440,8 @@ void zebra_nhg_install_kernel(struct nhg_hash_entry *nhe) zebra_nhg_install_kernel(rb_node_dep->nhe); } - if (!CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED) + if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_VALID) + && !CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED) && !CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED)) { /* Change its type to us since we are installing it */ nhe->type = ZEBRA_ROUTE_NHG; @@ -1952,7 +2502,7 @@ void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx) id = dplane_ctx_get_nhe_id(ctx); - if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) + if (IS_ZEBRA_DEBUG_DPLANE_DETAIL || IS_ZEBRA_DEBUG_NHG_DETAIL) zlog_debug( "Nexthop dplane ctx %p, op %s, nexthop ID (%u), result %s", ctx, dplane_op2str(op), id, dplane_res2str(status)); diff --git a/zebra/zebra_nhg.h b/zebra/zebra_nhg.h index dc3a47c020..0a9e97ab48 100644 --- a/zebra/zebra_nhg.h +++ b/zebra/zebra_nhg.h @@ -50,6 +50,9 @@ struct nhg_hash_entry { struct nexthop_group nhg; + /* If supported, a mapping of backup nexthops. */ + struct nhg_backup_info *backup_info; + /* If this is not a group, it * will be a single nexthop * and must have an interface @@ -72,6 +75,7 @@ struct nhg_hash_entry { * faster with ID's. */ struct nhg_connected_tree_head nhg_depends, nhg_dependents; + /* * Is this nexthop group valid, ie all nexthops are fully resolved. * What is fully resolved? It's a nexthop that is either self contained @@ -102,11 +106,25 @@ struct nhg_hash_entry { * from the kernel. Therefore, it is unhashable. */ #define NEXTHOP_GROUP_UNHASHABLE (1 << 4) + +/* + * Backup nexthop support - identify groups that are backups for + * another group. + */ +#define NEXTHOP_GROUP_BACKUP (1 << 5) + }; /* Was this one we created, either this session or previously? */ #define ZEBRA_NHG_CREATED(NHE) ((NHE->type) == ZEBRA_ROUTE_NHG) +/* + * Backup nexthops: this is a group object itself, so + * that the backup nexthops can use the same code as a normal object. + */ +struct nhg_backup_info { + struct nhg_hash_entry *nhe; +}; enum nhg_ctx_op_e { NHG_CTX_OP_NONE = 0, @@ -162,13 +180,26 @@ bool zebra_nhg_kernel_nexthops_enabled(void); /** * NHE abstracted tree functions. - * Use these where possible instead of the direct ones access ones. + * Use these where possible instead of direct access. */ struct nhg_hash_entry *zebra_nhg_alloc(void); void zebra_nhg_free(struct nhg_hash_entry *nhe); /* In order to clear a generic hash, we need a generic api, sigh. */ void zebra_nhg_hash_free(void *p); +/* Init an nhe, for use in a hash lookup for example. There's some fuzziness + * if the nhe represents only a single nexthop, so we try to capture that + * variant also. + */ +void zebra_nhe_init(struct nhg_hash_entry *nhe, afi_t afi, + const struct nexthop *nh); + +/* Allocate, free backup nexthop info objects */ +struct nhg_backup_info *zebra_nhg_backup_alloc(void); +void zebra_nhg_backup_free(struct nhg_backup_info **p); + +struct nexthop_group *zebra_nhg_get_backup_nhg(struct nhg_hash_entry *nhe); + extern struct nhg_hash_entry *zebra_nhg_resolve(struct nhg_hash_entry *nhe); extern unsigned int zebra_nhg_depends_count(const struct nhg_hash_entry *nhe); @@ -203,10 +234,14 @@ extern int zebra_nhg_kernel_find(uint32_t id, struct nexthop *nh, /* Del via kernel */ extern int zebra_nhg_kernel_del(uint32_t id, vrf_id_t vrf_id); -/* Find via route creation */ +/* Find an nhe based on a nexthop_group */ extern struct nhg_hash_entry * zebra_nhg_rib_find(uint32_t id, struct nexthop_group *nhg, afi_t rt_afi); +/* Find an nhe based on a route's nhe, used during route creation */ +struct nhg_hash_entry * +zebra_nhg_rib_find_nhe(struct nhg_hash_entry *rt_nhe, afi_t rt_afi); + /* Reference counter functions */ extern void zebra_nhg_decrement_ref(struct nhg_hash_entry *nhe); extern void zebra_nhg_increment_ref(struct nhg_hash_entry *nhe); diff --git a/zebra/zebra_northbound.c b/zebra/zebra_northbound.c new file mode 100644 index 0000000000..9f6514e12f --- /dev/null +++ b/zebra/zebra_northbound.c @@ -0,0 +1,2212 @@ +/* + * Zebra northbound implementation. + * + * Copyright (C) 2019 Network Device Education Foundation, Inc. ("NetDEF") + * Rafael Zalamena + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + */ + +#include <zebra.h> + +#include "lib/command.h" +#include "lib/log.h" +#include "lib/northbound.h" +#include "lib/routemap.h" + +#include "zebra/rib.h" + +/* + * XPath: /frr-zebra:zebra/mcast-rpf-lookup + */ +static int zebra_mcast_rpf_lookup_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_ERR_NOT_FOUND; +} + +/* + * XPath: /frr-zebra:zebra/ip-forwarding + */ +static int zebra_ip_forwarding_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_ERR_NOT_FOUND; +} + +static int zebra_ip_forwarding_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_ERR_NOT_FOUND; +} + +/* + * XPath: /frr-zebra:zebra/ipv6-forwarding + */ +static int zebra_ipv6_forwarding_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_ERR_NOT_FOUND; +} + +static int zebra_ipv6_forwarding_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_ERR_NOT_FOUND; +} + +/* + * XPath: /frr-zebra:zebra/workqueue-hold-timer + */ +static int zebra_workqueue_hold_timer_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_ERR_NOT_FOUND; +} + +/* + * XPath: /frr-zebra:zebra/zapi-packets + */ +static int zebra_zapi_packets_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_ERR_NOT_FOUND; +} + +/* + * XPath: /frr-zebra:zebra/import-kernel-table/table-id + */ +static int +zebra_import_kernel_table_table_id_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_ERR_NOT_FOUND; +} + +static int +zebra_import_kernel_table_table_id_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_ERR_NOT_FOUND; +} + +/* + * XPath: /frr-zebra:zebra/import-kernel-table/distance + */ +static int +zebra_import_kernel_table_distance_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_ERR_NOT_FOUND; +} + +/* + * XPath: /frr-zebra:zebra/import-kernel-table/route-map + */ +static int +zebra_import_kernel_table_route_map_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_ERR_NOT_FOUND; +} + +static int +zebra_import_kernel_table_route_map_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_ERR_NOT_FOUND; +} + +/* + * XPath: /frr-zebra:zebra/allow-external-route-update + */ +static int +zebra_allow_external_route_update_create(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_ERR_NOT_FOUND; +} + +static int +zebra_allow_external_route_update_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_ERR_NOT_FOUND; +} + +/* + * XPath: /frr-zebra:zebra/dplane-queue-limit + */ +static int zebra_dplane_queue_limit_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_ERR_NOT_FOUND; +} + +/* + * XPath: /frr-zebra:zebra/vrf-vni-mapping + */ +static int zebra_vrf_vni_mapping_create(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_ERR_NOT_FOUND; +} + +static int zebra_vrf_vni_mapping_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_ERR_NOT_FOUND; +} + +/* + * XPath: /frr-zebra:zebra/vrf-vni-mapping/vni-id + */ +static int zebra_vrf_vni_mapping_vni_id_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_ERR_NOT_FOUND; +} + +static int zebra_vrf_vni_mapping_vni_id_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_ERR_NOT_FOUND; +} + +/* + * XPath: /frr-zebra:zebra/vrf-vni-mapping/prefix-only + */ +static int +zebra_vrf_vni_mapping_prefix_only_create(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_ERR_NOT_FOUND; +} + +static int +zebra_vrf_vni_mapping_prefix_only_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_ERR_NOT_FOUND; +} + +/* + * XPath: /frr-zebra:zebra/debugs/debug-events + */ +static int zebra_debugs_debug_events_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_ERR_NOT_FOUND; +} + +static int zebra_debugs_debug_events_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_ERR_NOT_FOUND; +} + +/* + * XPath: /frr-zebra:zebra/debugs/debug-zapi-send + */ +static int zebra_debugs_debug_zapi_send_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_ERR_NOT_FOUND; +} + +static int zebra_debugs_debug_zapi_send_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_ERR_NOT_FOUND; +} + +/* + * XPath: /frr-zebra:zebra/debugs/debug-zapi-recv + */ +static int zebra_debugs_debug_zapi_recv_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_ERR_NOT_FOUND; +} + +static int zebra_debugs_debug_zapi_recv_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_ERR_NOT_FOUND; +} + +/* + * XPath: /frr-zebra:zebra/debugs/debug-zapi-detail + */ +static int zebra_debugs_debug_zapi_detail_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_ERR_NOT_FOUND; +} + +static int zebra_debugs_debug_zapi_detail_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_ERR_NOT_FOUND; +} + +/* + * XPath: /frr-zebra:zebra/debugs/debug-kernel + */ +static int zebra_debugs_debug_kernel_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_ERR_NOT_FOUND; +} + +static int zebra_debugs_debug_kernel_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_ERR_NOT_FOUND; +} + +/* + * XPath: /frr-zebra:zebra/debugs/debug-kernel-msg-send + */ +static int +zebra_debugs_debug_kernel_msg_send_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_ERR_NOT_FOUND; +} + +static int +zebra_debugs_debug_kernel_msg_send_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_ERR_NOT_FOUND; +} + +/* + * XPath: /frr-zebra:zebra/debugs/debug-kernel-msg-recv + */ +static int +zebra_debugs_debug_kernel_msg_recv_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_ERR_NOT_FOUND; +} + +static int +zebra_debugs_debug_kernel_msg_recv_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_ERR_NOT_FOUND; +} + +/* + * XPath: /frr-zebra:zebra/debugs/debug-rib + */ +static int zebra_debugs_debug_rib_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_ERR_NOT_FOUND; +} + +static int zebra_debugs_debug_rib_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_ERR_NOT_FOUND; +} + +/* + * XPath: /frr-zebra:zebra/debugs/debug-rib-detail + */ +static int zebra_debugs_debug_rib_detail_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_ERR_NOT_FOUND; +} + +static int zebra_debugs_debug_rib_detail_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_ERR_NOT_FOUND; +} + +/* + * XPath: /frr-zebra:zebra/debugs/debug-fpm + */ +static int zebra_debugs_debug_fpm_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_ERR_NOT_FOUND; +} + +static int zebra_debugs_debug_fpm_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_ERR_NOT_FOUND; +} + +/* + * XPath: /frr-zebra:zebra/debugs/debug-nht + */ +static int zebra_debugs_debug_nht_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_ERR_NOT_FOUND; +} + +static int zebra_debugs_debug_nht_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_ERR_NOT_FOUND; +} + +/* + * XPath: /frr-zebra:zebra/debugs/debug-nht-detail + */ +static int zebra_debugs_debug_nht_detail_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_ERR_NOT_FOUND; +} + +static int zebra_debugs_debug_nht_detail_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_ERR_NOT_FOUND; +} + +/* + * XPath: /frr-zebra:zebra/debugs/debug-mpls + */ +static int zebra_debugs_debug_mpls_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_ERR_NOT_FOUND; +} + +static int zebra_debugs_debug_mpls_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_ERR_NOT_FOUND; +} + +/* + * XPath: /frr-zebra:zebra/debugs/debug-vxlan + */ +static int zebra_debugs_debug_vxlan_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_ERR_NOT_FOUND; +} + +static int zebra_debugs_debug_vxlan_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_ERR_NOT_FOUND; +} + +/* + * XPath: /frr-zebra:zebra/debugs/debug-pw + */ +static int zebra_debugs_debug_pw_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_ERR_NOT_FOUND; +} + +static int zebra_debugs_debug_pw_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_ERR_NOT_FOUND; +} + +/* + * XPath: /frr-zebra:zebra/debugs/debug-dplane + */ +static int zebra_debugs_debug_dplane_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_ERR_NOT_FOUND; +} + +static int zebra_debugs_debug_dplane_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_ERR_NOT_FOUND; +} + +/* + * XPath: /frr-zebra:zebra/debugs/debug-dplane-detail + */ +static int zebra_debugs_debug_dplane_detail_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_ERR_NOT_FOUND; +} + +static int +zebra_debugs_debug_dplane_detail_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_ERR_NOT_FOUND; +} + +/* + * XPath: /frr-zebra:zebra/debugs/debug-mlag + */ +static int zebra_debugs_debug_mlag_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_ERR_NOT_FOUND; +} + +static int zebra_debugs_debug_mlag_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_ERR_NOT_FOUND; +} + +/* + * XPath: /frr-zebra:get-route-information + */ +static int get_route_information_rpc(const char *xpath, + const struct list *input, + struct list *output) +{ + /* TODO: implement me. */ + return NB_ERR_NOT_FOUND; +} + +/* + * XPath: /frr-zebra:get-v6-mroute-info + */ +static int get_v6_mroute_info_rpc(const char *xpath, const struct list *input, + struct list *output) +{ + /* TODO: implement me. */ + return NB_ERR_NOT_FOUND; +} + +/* + * XPath: /frr-zebra:get-vrf-info + */ +static int get_vrf_info_rpc(const char *xpath, const struct list *input, + struct list *output) +{ + /* TODO: implement me. */ + return NB_ERR_NOT_FOUND; +} + +/* + * XPath: /frr-zebra:get-vrf-vni-info + */ +static int get_vrf_vni_info_rpc(const char *xpath, const struct list *input, + struct list *output) +{ + /* TODO: implement me. */ + return NB_ERR_NOT_FOUND; +} + +/* + * XPath: /frr-zebra:get-evpn-info + */ +static int get_evpn_info_rpc(const char *xpath, const struct list *input, + struct list *output) +{ + /* TODO: implement me. */ + return NB_ERR_NOT_FOUND; +} + +/* + * XPath: /frr-zebra:get-vni-info + */ +static int get_vni_info_rpc(const char *xpath, const struct list *input, + struct list *output) +{ + /* TODO: implement me. */ + return NB_ERR_NOT_FOUND; +} + +/* + * XPath: /frr-zebra:get-evpn-vni-rmac + */ +static int get_evpn_vni_rmac_rpc(const char *xpath, const struct list *input, + struct list *output) +{ + /* TODO: implement me. */ + return NB_ERR_NOT_FOUND; +} + +/* + * XPath: /frr-zebra:get-evpn-vni-nexthops + */ +static int get_evpn_vni_nexthops_rpc(const char *xpath, + const struct list *input, + struct list *output) +{ + /* TODO: implement me. */ + return NB_ERR_NOT_FOUND; +} + +/* + * XPath: /frr-zebra:clear-evpn-dup-addr + */ +static int clear_evpn_dup_addr_rpc(const char *xpath, const struct list *input, + struct list *output) +{ + /* TODO: implement me. */ + return NB_ERR_NOT_FOUND; +} + +/* + * XPath: /frr-zebra:get-evpn-macs + */ +static int get_evpn_macs_rpc(const char *xpath, const struct list *input, + struct list *output) +{ + /* TODO: implement me. */ + return NB_ERR_NOT_FOUND; +} + +/* + * XPath: /frr-zebra:get-evpn-arp-cache + */ +static int get_evpn_arp_cache_rpc(const char *xpath, const struct list *input, + struct list *output) +{ + /* TODO: implement me. */ + return NB_ERR_NOT_FOUND; +} + +/* + * XPath: /frr-zebra:get-pbr-ipset + */ +static int get_pbr_ipset_rpc(const char *xpath, const struct list *input, + struct list *output) +{ + /* TODO: implement me. */ + return NB_ERR_NOT_FOUND; +} + +/* + * XPath: /frr-zebra:get-pbr-iptable + */ +static int get_pbr_iptable_rpc(const char *xpath, const struct list *input, + struct list *output) +{ + /* TODO: implement me. */ + return NB_ERR_NOT_FOUND; +} + +/* + * XPath: /frr-zebra:get-debugs + */ +static int get_debugs_rpc(const char *xpath, const struct list *input, + struct list *output) +{ + /* TODO: implement me. */ + return NB_ERR_NOT_FOUND; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ip4-addr-list + */ +static int +lib_interface_zebra_ip4_addr_list_create(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_ERR_NOT_FOUND; +} + +static int +lib_interface_zebra_ip4_addr_list_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_ERR_NOT_FOUND; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ip4-addr-list/ip4-peer + */ +static int +lib_interface_zebra_ip4_addr_list_ip4_peer_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_ERR_NOT_FOUND; +} + +static int +lib_interface_zebra_ip4_addr_list_ip4_peer_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_ERR_NOT_FOUND; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ip4-addr-list/label + */ +static int +lib_interface_zebra_ip4_addr_list_label_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_ERR_NOT_FOUND; +} + +static int +lib_interface_zebra_ip4_addr_list_label_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_ERR_NOT_FOUND; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ip6-addr-list + */ +static int +lib_interface_zebra_ip6_addr_list_create(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_ERR_NOT_FOUND; +} + +static int +lib_interface_zebra_ip6_addr_list_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_ERR_NOT_FOUND; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ip6-addr-list/label + */ +static int +lib_interface_zebra_ip6_addr_list_label_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_ERR_NOT_FOUND; +} + +static int +lib_interface_zebra_ip6_addr_list_label_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_ERR_NOT_FOUND; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/multicast + */ +static int lib_interface_zebra_multicast_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_ERR_NOT_FOUND; +} + +static int lib_interface_zebra_multicast_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_ERR_NOT_FOUND; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/link-detect + */ +static int lib_interface_zebra_link_detect_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_ERR_NOT_FOUND; +} + +static int lib_interface_zebra_link_detect_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_ERR_NOT_FOUND; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/shutdown + */ +static int lib_interface_zebra_shutdown_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_ERR_NOT_FOUND; +} + +static int lib_interface_zebra_shutdown_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_ERR_NOT_FOUND; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/bandwidth + */ +static int lib_interface_zebra_bandwidth_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_ERR_NOT_FOUND; +} + +static int lib_interface_zebra_bandwidth_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_ERR_NOT_FOUND; +} + +/* + * XPath: + * /frr-route-map:lib/route-map/entry/match-condition/frr-zebra:ipv4-prefix-length + */ +static int lib_route_map_entry_match_condition_ipv4_prefix_length_modify( + enum nb_event event, const struct lyd_node *dnode, + union nb_resource *resource) +{ + struct routemap_hook_context *rhc; + const char *length; + int condition, rv; + + if (event != NB_EV_APPLY) + return NB_OK; + + /* Add configuration. */ + rhc = nb_running_get_entry(dnode, NULL, true); + length = yang_dnode_get_string(dnode, NULL); + condition = yang_dnode_get_enum(dnode, "../frr-route-map:condition"); + + /* Set destroy information. */ + switch (condition) { + case 100: /* ipv4-prefix-length */ + rhc->rhc_rule = "ip address prefix-len"; + break; + + case 102: /* ipv4-next-hop-prefix-length */ + rhc->rhc_rule = "ip next-hop prefix-len"; + break; + } + rhc->rhc_mhook = generic_match_delete; + rhc->rhc_event = RMAP_EVENT_MATCH_DELETED; + + rv = generic_match_add(NULL, rhc->rhc_rmi, rhc->rhc_rule, length, + RMAP_EVENT_MATCH_ADDED); + if (rv != CMD_SUCCESS) { + rhc->rhc_mhook = NULL; + return NB_ERR_INCONSISTENCY; + } + + return NB_OK; +} + +static int lib_route_map_entry_match_condition_ipv4_prefix_length_destroy( + enum nb_event event, const struct lyd_node *dnode) +{ + return lib_route_map_entry_match_destroy(event, dnode); +} + +/* + * XPath: + * /frr-route-map:lib/route-map/entry/match-condition/frr-zebra:ipv6-prefix-length + */ +static int lib_route_map_entry_match_condition_ipv6_prefix_length_modify( + enum nb_event event, const struct lyd_node *dnode, + union nb_resource *resource) +{ + struct routemap_hook_context *rhc; + const char *length; + int rv; + + if (event != NB_EV_APPLY) + return NB_OK; + + /* Add configuration. */ + rhc = nb_running_get_entry(dnode, NULL, true); + length = yang_dnode_get_string(dnode, NULL); + + /* Set destroy information. */ + rhc->rhc_mhook = generic_match_delete; + rhc->rhc_rule = "ipv6 address prefix-len"; + rhc->rhc_event = RMAP_EVENT_MATCH_DELETED; + + rv = generic_match_add(NULL, rhc->rhc_rmi, "ipv6 address prefix-len", + length, RMAP_EVENT_MATCH_ADDED); + if (rv != CMD_SUCCESS) { + rhc->rhc_mhook = NULL; + return NB_ERR_INCONSISTENCY; + } + + return NB_OK; +} + +static int lib_route_map_entry_match_condition_ipv6_prefix_length_destroy( + enum nb_event event, const struct lyd_node *dnode) +{ + return lib_route_map_entry_match_destroy(event, dnode); +} + +/* + * XPath: + * /frr-route-map:lib/route-map/entry/match-condition/frr-zebra:source-protocol + */ +static int lib_route_map_entry_match_condition_source_protocol_modify( + enum nb_event event, const struct lyd_node *dnode, + union nb_resource *resource) +{ + struct routemap_hook_context *rhc; + const char *type; + int rv; + + switch (event) { + case NB_EV_VALIDATE: + type = yang_dnode_get_string(dnode, NULL); + if (proto_name2num(type) == -1) { + zlog_warn("%s: invalid protocol: %s", __func__, type); + return NB_ERR_VALIDATION; + } + return NB_OK; + case NB_EV_PREPARE: + case NB_EV_ABORT: + return NB_OK; + case NB_EV_APPLY: + /* NOTHING */ + break; + } + + /* Add configuration. */ + rhc = nb_running_get_entry(dnode, NULL, true); + type = yang_dnode_get_string(dnode, NULL); + + /* Set destroy information. */ + rhc->rhc_mhook = generic_match_delete; + rhc->rhc_rule = "source-protocol"; + rhc->rhc_event = RMAP_EVENT_MATCH_DELETED; + + rv = generic_match_add(NULL, rhc->rhc_rmi, "source-protocol", type, + RMAP_EVENT_MATCH_ADDED); + if (rv != CMD_SUCCESS) { + rhc->rhc_mhook = NULL; + return NB_ERR_INCONSISTENCY; + } + + return NB_OK; +} + +static int lib_route_map_entry_match_condition_source_protocol_destroy( + enum nb_event event, const struct lyd_node *dnode) +{ + return lib_route_map_entry_match_destroy(event, dnode); +} + +/* + * XPath: + * /frr-route-map:lib/route-map/entry/match-condition/frr-zebra:source-instance + */ +static int lib_route_map_entry_match_condition_source_instance_modify( + enum nb_event event, const struct lyd_node *dnode, + union nb_resource *resource) +{ + struct routemap_hook_context *rhc; + const char *type; + int rv; + + if (event != NB_EV_APPLY) + return NB_OK; + + /* Add configuration. */ + rhc = nb_running_get_entry(dnode, NULL, true); + type = yang_dnode_get_string(dnode, NULL); + + /* Set destroy information. */ + rhc->rhc_mhook = generic_match_delete; + rhc->rhc_rule = "source-instance"; + rhc->rhc_event = RMAP_EVENT_MATCH_DELETED; + + rv = generic_match_add(NULL, rhc->rhc_rmi, "source-instance", type, + RMAP_EVENT_MATCH_ADDED); + if (rv != CMD_SUCCESS) { + rhc->rhc_mhook = NULL; + return NB_ERR_INCONSISTENCY; + } + + return NB_OK; +} + +static int lib_route_map_entry_match_condition_source_instance_destroy( + enum nb_event event, const struct lyd_node *dnode) +{ + return lib_route_map_entry_match_destroy(event, dnode); +} + +/* + * XPath: /frr-route-map:lib/route-map/entry/set-action/frr-zebra:source-v4 + */ +static int +lib_route_map_entry_set_action_source_v4_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + struct routemap_hook_context *rhc; + struct interface *pif = NULL; + const char *source; + struct vrf *vrf; + struct prefix p; + int rv; + + switch (event) { + case NB_EV_VALIDATE: + memset(&p, 0, sizeof(p)); + yang_dnode_get_ipv4p(&p, dnode, NULL); + if (zebra_check_addr(&p) == 0) { + zlog_warn("%s: invalid IPv4 address: %s", __func__, + yang_dnode_get_string(dnode, NULL)); + return NB_ERR_VALIDATION; + } + + RB_FOREACH(vrf, vrf_id_head, &vrfs_by_id) { + pif = if_lookup_exact_address(&p.u.prefix4, AF_INET, + vrf->vrf_id); + if (pif != NULL) + break; + } + if (pif == NULL) { + zlog_warn("%s: is not a local adddress: %s", __func__, + yang_dnode_get_string(dnode, NULL)); + return NB_ERR_VALIDATION; + } + return NB_OK; + case NB_EV_PREPARE: + case NB_EV_ABORT: + return NB_OK; + case NB_EV_APPLY: + /* NOTHING */ + break; + } + + /* Add configuration. */ + rhc = nb_running_get_entry(dnode, NULL, true); + source = yang_dnode_get_string(dnode, NULL); + + /* Set destroy information. */ + rhc->rhc_shook = generic_set_delete; + rhc->rhc_rule = "src"; + + rv = generic_set_add(NULL, rhc->rhc_rmi, "src", source); + if (rv != CMD_SUCCESS) { + rhc->rhc_shook = NULL; + return NB_ERR_INCONSISTENCY; + } + + return NB_OK; +} + +static int +lib_route_map_entry_set_action_source_v4_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + return lib_route_map_entry_set_destroy(event, dnode); +} + +/* + * XPath: /frr-route-map:lib/route-map/entry/set-action/frr-zebra:source-v6 + */ +static int +lib_route_map_entry_set_action_source_v6_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + struct routemap_hook_context *rhc; + struct interface *pif = NULL; + const char *source; + struct vrf *vrf; + struct prefix p; + int rv; + + switch (event) { + case NB_EV_VALIDATE: + memset(&p, 0, sizeof(p)); + yang_dnode_get_ipv6p(&p, dnode, NULL); + if (zebra_check_addr(&p) == 0) { + zlog_warn("%s: invalid IPv6 address: %s", __func__, + yang_dnode_get_string(dnode, NULL)); + return NB_ERR_VALIDATION; + } + + RB_FOREACH(vrf, vrf_id_head, &vrfs_by_id) { + pif = if_lookup_exact_address(&p.u.prefix6, AF_INET6, + vrf->vrf_id); + if (pif != NULL) + break; + } + if (pif == NULL) { + zlog_warn("%s: is not a local adddress: %s", __func__, + yang_dnode_get_string(dnode, NULL)); + return NB_ERR_VALIDATION; + } + return NB_OK; + case NB_EV_PREPARE: + case NB_EV_ABORT: + return NB_OK; + case NB_EV_APPLY: + /* NOTHING */ + break; + } + + /* Add configuration. */ + rhc = nb_running_get_entry(dnode, NULL, true); + source = yang_dnode_get_string(dnode, NULL); + + /* Set destroy information. */ + rhc->rhc_shook = generic_set_delete; + rhc->rhc_rule = "src"; + + rv = generic_set_add(NULL, rhc->rhc_rmi, "src", source); + if (rv != CMD_SUCCESS) { + rhc->rhc_shook = NULL; + return NB_ERR_INCONSISTENCY; + } + + return NB_OK; +} + +static int +lib_route_map_entry_set_action_source_v6_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + return lib_route_map_entry_set_destroy(event, dnode); +} + +/* clang-format off */ +const struct frr_yang_module_info frr_zebra_info = { + .name = "frr-zebra", + .nodes = { + { + .xpath = "/frr-zebra:zebra/mcast-rpf-lookup", + .cbs = { + .modify = zebra_mcast_rpf_lookup_modify, + } + }, + { + .xpath = "/frr-zebra:zebra/ip-forwarding", + .cbs = { + .modify = zebra_ip_forwarding_modify, + .destroy = zebra_ip_forwarding_destroy, + } + }, + { + .xpath = "/frr-zebra:zebra/ipv6-forwarding", + .cbs = { + .modify = zebra_ipv6_forwarding_modify, + .destroy = zebra_ipv6_forwarding_destroy, + } + }, + { + .xpath = "/frr-zebra:zebra/workqueue-hold-timer", + .cbs = { + .modify = zebra_workqueue_hold_timer_modify, + } + }, + { + .xpath = "/frr-zebra:zebra/zapi-packets", + .cbs = { + .modify = zebra_zapi_packets_modify, + } + }, + { + .xpath = "/frr-zebra:zebra/import-kernel-table/table-id", + .cbs = { + .modify = zebra_import_kernel_table_table_id_modify, + .destroy = zebra_import_kernel_table_table_id_destroy, + } + }, + { + .xpath = "/frr-zebra:zebra/import-kernel-table/distance", + .cbs = { + .modify = zebra_import_kernel_table_distance_modify, + } + }, + { + .xpath = "/frr-zebra:zebra/import-kernel-table/route-map", + .cbs = { + .modify = zebra_import_kernel_table_route_map_modify, + .destroy = zebra_import_kernel_table_route_map_destroy, + } + }, + { + .xpath = "/frr-zebra:zebra/allow-external-route-update", + .cbs = { + .create = zebra_allow_external_route_update_create, + .destroy = zebra_allow_external_route_update_destroy, + } + }, + { + .xpath = "/frr-zebra:zebra/dplane-queue-limit", + .cbs = { + .modify = zebra_dplane_queue_limit_modify, + } + }, + { + .xpath = "/frr-zebra:zebra/vrf-vni-mapping", + .cbs = { + .create = zebra_vrf_vni_mapping_create, + .destroy = zebra_vrf_vni_mapping_destroy, + } + }, + { + .xpath = "/frr-zebra:zebra/vrf-vni-mapping/vni-id", + .cbs = { + .modify = zebra_vrf_vni_mapping_vni_id_modify, + .destroy = zebra_vrf_vni_mapping_vni_id_destroy, + } + }, + { + .xpath = "/frr-zebra:zebra/vrf-vni-mapping/prefix-only", + .cbs = { + .create = zebra_vrf_vni_mapping_prefix_only_create, + .destroy = zebra_vrf_vni_mapping_prefix_only_destroy, + } + }, + { + .xpath = "/frr-zebra:zebra/debugs/debug-events", + .cbs = { + .modify = zebra_debugs_debug_events_modify, + .destroy = zebra_debugs_debug_events_destroy, + } + }, + { + .xpath = "/frr-zebra:zebra/debugs/debug-zapi-send", + .cbs = { + .modify = zebra_debugs_debug_zapi_send_modify, + .destroy = zebra_debugs_debug_zapi_send_destroy, + } + }, + { + .xpath = "/frr-zebra:zebra/debugs/debug-zapi-recv", + .cbs = { + .modify = zebra_debugs_debug_zapi_recv_modify, + .destroy = zebra_debugs_debug_zapi_recv_destroy, + } + }, + { + .xpath = "/frr-zebra:zebra/debugs/debug-zapi-detail", + .cbs = { + .modify = zebra_debugs_debug_zapi_detail_modify, + .destroy = zebra_debugs_debug_zapi_detail_destroy, + } + }, + { + .xpath = "/frr-zebra:zebra/debugs/debug-kernel", + .cbs = { + .modify = zebra_debugs_debug_kernel_modify, + .destroy = zebra_debugs_debug_kernel_destroy, + } + }, + { + .xpath = "/frr-zebra:zebra/debugs/debug-kernel-msg-send", + .cbs = { + .modify = zebra_debugs_debug_kernel_msg_send_modify, + .destroy = zebra_debugs_debug_kernel_msg_send_destroy, + } + }, + { + .xpath = "/frr-zebra:zebra/debugs/debug-kernel-msg-recv", + .cbs = { + .modify = zebra_debugs_debug_kernel_msg_recv_modify, + .destroy = zebra_debugs_debug_kernel_msg_recv_destroy, + } + }, + { + .xpath = "/frr-zebra:zebra/debugs/debug-rib", + .cbs = { + .modify = zebra_debugs_debug_rib_modify, + .destroy = zebra_debugs_debug_rib_destroy, + } + }, + { + .xpath = "/frr-zebra:zebra/debugs/debug-rib-detail", + .cbs = { + .modify = zebra_debugs_debug_rib_detail_modify, + .destroy = zebra_debugs_debug_rib_detail_destroy, + } + }, + { + .xpath = "/frr-zebra:zebra/debugs/debug-fpm", + .cbs = { + .modify = zebra_debugs_debug_fpm_modify, + .destroy = zebra_debugs_debug_fpm_destroy, + } + }, + { + .xpath = "/frr-zebra:zebra/debugs/debug-nht", + .cbs = { + .modify = zebra_debugs_debug_nht_modify, + .destroy = zebra_debugs_debug_nht_destroy, + } + }, + { + .xpath = "/frr-zebra:zebra/debugs/debug-nht-detail", + .cbs = { + .modify = zebra_debugs_debug_nht_detail_modify, + .destroy = zebra_debugs_debug_nht_detail_destroy, + } + }, + { + .xpath = "/frr-zebra:zebra/debugs/debug-mpls", + .cbs = { + .modify = zebra_debugs_debug_mpls_modify, + .destroy = zebra_debugs_debug_mpls_destroy, + } + }, + { + .xpath = "/frr-zebra:zebra/debugs/debug-vxlan", + .cbs = { + .modify = zebra_debugs_debug_vxlan_modify, + .destroy = zebra_debugs_debug_vxlan_destroy, + } + }, + { + .xpath = "/frr-zebra:zebra/debugs/debug-pw", + .cbs = { + .modify = zebra_debugs_debug_pw_modify, + .destroy = zebra_debugs_debug_pw_destroy, + } + }, + { + .xpath = "/frr-zebra:zebra/debugs/debug-dplane", + .cbs = { + .modify = zebra_debugs_debug_dplane_modify, + .destroy = zebra_debugs_debug_dplane_destroy, + } + }, + { + .xpath = "/frr-zebra:zebra/debugs/debug-dplane-detail", + .cbs = { + .modify = zebra_debugs_debug_dplane_detail_modify, + .destroy = zebra_debugs_debug_dplane_detail_destroy, + } + }, + { + .xpath = "/frr-zebra:zebra/debugs/debug-mlag", + .cbs = { + .modify = zebra_debugs_debug_mlag_modify, + .destroy = zebra_debugs_debug_mlag_destroy, + } + }, + { + .xpath = "/frr-zebra:get-route-information", + .cbs = { + .rpc = get_route_information_rpc, + } + }, + { + .xpath = "/frr-zebra:get-v6-mroute-info", + .cbs = { + .rpc = get_v6_mroute_info_rpc, + } + }, + { + .xpath = "/frr-zebra:get-vrf-info", + .cbs = { + .rpc = get_vrf_info_rpc, + } + }, + { + .xpath = "/frr-zebra:get-vrf-vni-info", + .cbs = { + .rpc = get_vrf_vni_info_rpc, + } + }, + { + .xpath = "/frr-zebra:get-evpn-info", + .cbs = { + .rpc = get_evpn_info_rpc, + } + }, + { + .xpath = "/frr-zebra:get-vni-info", + .cbs = { + .rpc = get_vni_info_rpc, + } + }, + { + .xpath = "/frr-zebra:get-evpn-vni-rmac", + .cbs = { + .rpc = get_evpn_vni_rmac_rpc, + } + }, + { + .xpath = "/frr-zebra:get-evpn-vni-nexthops", + .cbs = { + .rpc = get_evpn_vni_nexthops_rpc, + } + }, + { + .xpath = "/frr-zebra:clear-evpn-dup-addr", + .cbs = { + .rpc = clear_evpn_dup_addr_rpc, + } + }, + { + .xpath = "/frr-zebra:get-evpn-macs", + .cbs = { + .rpc = get_evpn_macs_rpc, + } + }, + { + .xpath = "/frr-zebra:get-evpn-arp-cache", + .cbs = { + .rpc = get_evpn_arp_cache_rpc, + } + }, + { + .xpath = "/frr-zebra:get-pbr-ipset", + .cbs = { + .rpc = get_pbr_ipset_rpc, + } + }, + { + .xpath = "/frr-zebra:get-pbr-iptable", + .cbs = { + .rpc = get_pbr_iptable_rpc, + } + }, + { + .xpath = "/frr-zebra:get-debugs", + .cbs = { + .rpc = get_debugs_rpc, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ip4-addr-list", + .cbs = { + .create = lib_interface_zebra_ip4_addr_list_create, + .destroy = lib_interface_zebra_ip4_addr_list_destroy, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ip4-addr-list/ip4-peer", + .cbs = { + .modify = lib_interface_zebra_ip4_addr_list_ip4_peer_modify, + .destroy = lib_interface_zebra_ip4_addr_list_ip4_peer_destroy, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ip4-addr-list/label", + .cbs = { + .modify = lib_interface_zebra_ip4_addr_list_label_modify, + .destroy = lib_interface_zebra_ip4_addr_list_label_destroy, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ip6-addr-list", + .cbs = { + .create = lib_interface_zebra_ip6_addr_list_create, + .destroy = lib_interface_zebra_ip6_addr_list_destroy, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ip6-addr-list/label", + .cbs = { + .modify = lib_interface_zebra_ip6_addr_list_label_modify, + .destroy = lib_interface_zebra_ip6_addr_list_label_destroy, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/multicast", + .cbs = { + .modify = lib_interface_zebra_multicast_modify, + .destroy = lib_interface_zebra_multicast_destroy, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-detect", + .cbs = { + .modify = lib_interface_zebra_link_detect_modify, + .destroy = lib_interface_zebra_link_detect_destroy, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/shutdown", + .cbs = { + .modify = lib_interface_zebra_shutdown_modify, + .destroy = lib_interface_zebra_shutdown_destroy, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/bandwidth", + .cbs = { + .modify = lib_interface_zebra_bandwidth_modify, + .destroy = lib_interface_zebra_bandwidth_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/match-condition/frr-zebra:ipv4-prefix-length", + .cbs = { + .modify = lib_route_map_entry_match_condition_ipv4_prefix_length_modify, + .destroy = lib_route_map_entry_match_condition_ipv4_prefix_length_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/match-condition/frr-zebra:ipv6-prefix-length", + .cbs = { + .modify = lib_route_map_entry_match_condition_ipv6_prefix_length_modify, + .destroy = lib_route_map_entry_match_condition_ipv6_prefix_length_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/match-condition/frr-zebra:source-protocol", + .cbs = { + .modify = lib_route_map_entry_match_condition_source_protocol_modify, + .destroy = lib_route_map_entry_match_condition_source_protocol_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/match-condition/frr-zebra:source-instance", + .cbs = { + .modify = lib_route_map_entry_match_condition_source_instance_modify, + .destroy = lib_route_map_entry_match_condition_source_instance_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/set-action/frr-zebra:source-v4", + .cbs = { + .modify = lib_route_map_entry_set_action_source_v4_modify, + .destroy = lib_route_map_entry_set_action_source_v4_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/set-action/frr-zebra:source-v6", + .cbs = { + .modify = lib_route_map_entry_set_action_source_v6_modify, + .destroy = lib_route_map_entry_set_action_source_v6_destroy, + } + }, + { + .xpath = NULL, + }, + } +}; diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 29d59b515f..58967de778 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -112,7 +112,7 @@ static const struct { /* no entry/default: 150 */ }; -static void __attribute__((format(printf, 5, 6))) +static void PRINTFRR(5, 6) _rnode_zlog(const char *_func, vrf_id_t vrf_id, struct route_node *rn, int priority, const char *msgfmt, ...) { @@ -213,7 +213,7 @@ static void route_entry_attach_ref(struct route_entry *re, int route_entry_update_nhe(struct route_entry *re, struct nhg_hash_entry *new) { - struct nhg_hash_entry *old = NULL; + struct nhg_hash_entry *old; int ret = 0; if (new == NULL) { @@ -223,7 +223,7 @@ int route_entry_update_nhe(struct route_entry *re, struct nhg_hash_entry *new) goto done; } - if (re->nhe_id != new->id) { + if ((re->nhe_id != 0) && (re->nhe_id != new->id)) { old = re->nhe; route_entry_attach_ref(re, new); @@ -2338,7 +2338,6 @@ static void rib_addnode(struct route_node *rn, void rib_unlink(struct route_node *rn, struct route_entry *re) { rib_dest_t *dest; - struct nhg_hash_entry *nhe = NULL; assert(rn && re); @@ -2353,11 +2352,10 @@ void rib_unlink(struct route_node *rn, struct route_entry *re) if (dest->selected_fib == re) dest->selected_fib = NULL; - if (re->nhe_id) { - nhe = zebra_nhg_lookup_id(re->nhe_id); - if (nhe) - zebra_nhg_decrement_ref(nhe); - } else if (re->nhe->nhg.nexthop) + if (re->nhe && re->nhe_id) { + assert(re->nhe->id == re->nhe_id); + zebra_nhg_decrement_ref(re->nhe); + } else if (re->nhe && re->nhe->nhg.nexthop) nexthops_free(re->nhe->nhg.nexthop); nexthops_free(re->fib_ng.nexthop); @@ -2396,11 +2394,75 @@ void rib_delnode(struct route_node *rn, struct route_entry *re) } } +/* + * Helper that debugs a single nexthop within a route-entry + */ +static void _route_entry_dump_nh(const struct route_entry *re, + const char *straddr, + const struct nexthop *nexthop) +{ + char nhname[PREFIX_STRLEN]; + char backup_str[50]; + char wgt_str[50]; + struct interface *ifp; + struct vrf *vrf = vrf_lookup_by_id(nexthop->vrf_id); + + switch (nexthop->type) { + case NEXTHOP_TYPE_BLACKHOLE: + sprintf(nhname, "Blackhole"); + break; + case NEXTHOP_TYPE_IFINDEX: + ifp = if_lookup_by_index(nexthop->ifindex, nexthop->vrf_id); + sprintf(nhname, "%s", ifp ? ifp->name : "Unknown"); + break; + case NEXTHOP_TYPE_IPV4: + /* fallthrough */ + case NEXTHOP_TYPE_IPV4_IFINDEX: + inet_ntop(AF_INET, &nexthop->gate, nhname, INET6_ADDRSTRLEN); + break; + case NEXTHOP_TYPE_IPV6: + case NEXTHOP_TYPE_IPV6_IFINDEX: + inet_ntop(AF_INET6, &nexthop->gate, nhname, INET6_ADDRSTRLEN); + break; + } + + backup_str[0] = '\0'; + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP)) { + snprintf(backup_str, sizeof(backup_str), "backup %d,", + (int)nexthop->backup_idx); + } + + wgt_str[0] = '\0'; + if (nexthop->weight) + snprintf(wgt_str, sizeof(wgt_str), "wgt %d,", nexthop->weight); + + zlog_debug("%s: %s %s[%u] vrf %s(%u) %s%s with flags %s%s%s%s%s", + straddr, (nexthop->rparent ? " NH" : "NH"), nhname, + nexthop->ifindex, vrf ? vrf->name : "Unknown", + nexthop->vrf_id, + wgt_str, backup_str, + (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE) + ? "ACTIVE " + : ""), + (CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED) + ? "FIB " + : ""), + (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE) + ? "RECURSIVE " + : ""), + (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK) + ? "ONLINK " + : ""), + (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_DUPLICATE) + ? "DUPLICATE " + : "")); + +} + /* This function dumps the contents of a given RE entry into * standard debug log. Calling function name and IP prefix in * question are passed as 1st and 2nd arguments. */ - void _route_entry_dump(const char *func, union prefixconstptr pp, union prefixconstptr src_pp, const struct route_entry *re) @@ -2409,9 +2471,9 @@ void _route_entry_dump(const char *func, union prefixconstptr pp, bool is_srcdst = src_p && src_p->prefixlen; char straddr[PREFIX_STRLEN]; char srcaddr[PREFIX_STRLEN]; - char nhname[PREFIX_STRLEN]; struct nexthop *nexthop; struct vrf *vrf = vrf_lookup_by_id(re->vrf_id); + struct nexthop_group *nhg; zlog_debug("%s: dumping RE entry %p for %s%s%s vrf %s(%u)", func, (const void *)re, prefix2str(pp, straddr, sizeof(straddr)), @@ -2422,65 +2484,32 @@ void _route_entry_dump(const char *func, union prefixconstptr pp, zlog_debug("%s: uptime == %lu, type == %u, instance == %d, table == %d", straddr, (unsigned long)re->uptime, re->type, re->instance, re->table); - zlog_debug( - "%s: metric == %u, mtu == %u, distance == %u, flags == %u, status == %u", - straddr, re->metric, re->mtu, re->distance, re->flags, re->status); + zlog_debug("%s: metric == %u, mtu == %u, distance == %u, flags == %u, status == %u", + straddr, re->metric, re->mtu, re->distance, re->flags, + re->status); zlog_debug("%s: nexthop_num == %u, nexthop_active_num == %u", straddr, nexthop_group_nexthop_num(&(re->nhe->nhg)), nexthop_group_active_nexthop_num(&(re->nhe->nhg))); - for (ALL_NEXTHOPS(re->nhe->nhg, nexthop)) { - struct interface *ifp; - struct vrf *vrf = vrf_lookup_by_id(nexthop->vrf_id); + /* Dump nexthops */ + for (ALL_NEXTHOPS(re->nhe->nhg, nexthop)) + _route_entry_dump_nh(re, straddr, nexthop); - switch (nexthop->type) { - case NEXTHOP_TYPE_BLACKHOLE: - sprintf(nhname, "Blackhole"); - break; - case NEXTHOP_TYPE_IFINDEX: - ifp = if_lookup_by_index(nexthop->ifindex, - nexthop->vrf_id); - sprintf(nhname, "%s", ifp ? ifp->name : "Unknown"); - break; - case NEXTHOP_TYPE_IPV4: - /* fallthrough */ - case NEXTHOP_TYPE_IPV4_IFINDEX: - inet_ntop(AF_INET, &nexthop->gate, nhname, - INET6_ADDRSTRLEN); - break; - case NEXTHOP_TYPE_IPV6: - case NEXTHOP_TYPE_IPV6_IFINDEX: - inet_ntop(AF_INET6, &nexthop->gate, nhname, - INET6_ADDRSTRLEN); - break; - } - zlog_debug("%s: %s %s[%u] vrf %s(%u) with flags %s%s%s%s%s", - straddr, (nexthop->rparent ? " NH" : "NH"), nhname, - nexthop->ifindex, vrf ? vrf->name : "Unknown", - nexthop->vrf_id, - (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE) - ? "ACTIVE " - : ""), - (CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED) - ? "FIB " - : ""), - (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE) - ? "RECURSIVE " - : ""), - (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK) - ? "ONLINK " - : ""), - (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_DUPLICATE) - ? "DUPLICATE " - : "")); + if (zebra_nhg_get_backup_nhg(re->nhe)) { + zlog_debug("%s: backup nexthops:", straddr); + + nhg = zebra_nhg_get_backup_nhg(re->nhe); + for (ALL_NEXTHOPS_PTR(nhg, nexthop)) + _route_entry_dump_nh(re, straddr, nexthop); } + zlog_debug("%s: dump complete", straddr); } -/* This is an exported helper to rtm_read() to dump the strange +/* + * This is an exported helper to rtm_read() to dump the strange * RE entry found by rib_lookup_ipv4_route() */ - void rib_lookup_and_dump(struct prefix_ipv4 *p, vrf_id_t vrf_id) { struct route_table *table; @@ -2574,9 +2603,16 @@ void rib_lookup_and_pushup(struct prefix_ipv4 *p, vrf_id_t vrf_id) } } -int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, - struct prefix_ipv6 *src_p, struct route_entry *re, - struct nexthop_group *ng) +/* + * Internal route-add implementation; there are a couple of different public + * signatures. Callers in this path are responsible for the memory they + * allocate: if they allocate a nexthop_group or backup nexthop info, they + * must free those objects. If this returns < 0, an error has occurred and the + * route_entry 're' has not been captured; the caller should free that also. + */ +int rib_add_multipath_nhe(afi_t afi, safi_t safi, struct prefix *p, + struct prefix_ipv6 *src_p, struct route_entry *re, + struct nhg_hash_entry *re_nhe) { struct nhg_hash_entry *nhe = NULL; struct route_table *table; @@ -2584,41 +2620,31 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, struct route_entry *same = NULL; int ret = 0; - if (!re) - return 0; + if (!re || !re_nhe) + return -1; assert(!src_p || !src_p->prefixlen || afi == AFI_IP6); /* Lookup table. */ table = zebra_vrf_get_table_with_table_id(afi, safi, re->vrf_id, re->table); - if (!table) { - if (ng) - nexthop_group_delete(&ng); - XFREE(MTYPE_RE, re); - return 0; - } + if (!table) + return -1; - if (re->nhe_id) { - nhe = zebra_nhg_lookup_id(re->nhe_id); + if (re_nhe->id > 0) { + nhe = zebra_nhg_lookup_id(re_nhe->id); if (!nhe) { flog_err( EC_ZEBRA_TABLE_LOOKUP_FAILED, "Zebra failed to find the nexthop hash entry for id=%u in a route entry", - re->nhe_id); - XFREE(MTYPE_RE, re); + re_nhe->id); + return -1; } } else { - nhe = zebra_nhg_rib_find(0, ng, afi); - - /* - * The nexthops got copied over into an nhe, - * so free them now. - */ - nexthop_group_delete(&ng); - + /* Lookup nhe from route information */ + nhe = zebra_nhg_rib_find_nhe(re_nhe, afi); if (!nhe) { char buf[PREFIX_STRLEN] = ""; char buf2[PREFIX_STRLEN] = ""; @@ -2631,7 +2657,6 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, src_p ? prefix2str(src_p, buf2, sizeof(buf2)) : ""); - XFREE(MTYPE_RE, re); return -1; } } @@ -2709,15 +2734,51 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, ret = 1; /* Free implicit route.*/ - if (same) { + if (same) rib_delnode(rn, same); - ret = -1; - } route_unlock_node(rn); return ret; } +/* + * Add a single route. + */ +int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, + struct prefix_ipv6 *src_p, struct route_entry *re, + struct nexthop_group *ng) +{ + int ret; + struct nhg_hash_entry nhe; + + if (!re) + return -1; + + /* We either need nexthop(s) or an existing nexthop id */ + if (ng == NULL && re->nhe_id == 0) + return -1; + + /* + * Use a temporary nhe to convey info to the common/main api. + */ + zebra_nhe_init(&nhe, afi, (ng ? ng->nexthop : NULL)); + if (ng) + nhe.nhg.nexthop = ng->nexthop; + else if (re->nhe_id > 0) + nhe.id = re->nhe_id; + + ret = rib_add_multipath_nhe(afi, safi, p, src_p, re, &nhe); + + /* In this path, the callers expect memory to be freed. */ + nexthop_group_delete(&ng); + + /* In error cases, free the route also */ + if (ret < 0) + XFREE(MTYPE_RE, re); + + return ret; +} + void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, unsigned short instance, int flags, struct prefix *p, struct prefix_ipv6 *src_p, const struct nexthop *nh, @@ -3188,6 +3249,9 @@ void rib_sweep_table(struct route_table *table) if (!table) return; + if (IS_ZEBRA_DEBUG_RIB) + zlog_debug("%s: starting", __func__); + for (rn = route_top(table); rn; rn = srcdest_route_next(rn)) { RNODE_FOREACH_RE_SAFE (rn, re, next) { @@ -3234,6 +3298,9 @@ void rib_sweep_table(struct route_table *table) rib_delnode(rn, re); } } + + if (IS_ZEBRA_DEBUG_RIB) + zlog_debug("%s: ends", __func__); } /* Sweep all RIB tables. */ diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c index c758e25839..f9c74c7462 100644 --- a/zebra/zebra_rnh.c +++ b/zebra/zebra_rnh.c @@ -471,7 +471,7 @@ zebra_rnh_resolve_import_entry(struct zebra_vrf *zvrf, afi_t afi, *prn = rn; if (!re && IS_ZEBRA_DEBUG_NHT_DETAILED) - zlog_debug("\tRejected due to removed or is a bgp route"); + zlog_debug(" Rejected due to removed or is a bgp route"); return re; } @@ -656,7 +656,7 @@ zebra_rnh_resolve_nexthop_entry(struct zebra_vrf *zvrf, afi_t afi, && !rnh_resolve_via_default(zvrf, rn->p.family)) { if (IS_ZEBRA_DEBUG_NHT_DETAILED) zlog_debug( - "\tNot allowed to resolve through default prefix"); + " Not allowed to resolve through default prefix"); return NULL; } @@ -665,7 +665,7 @@ zebra_rnh_resolve_nexthop_entry(struct zebra_vrf *zvrf, afi_t afi, if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED)) { if (IS_ZEBRA_DEBUG_NHT_DETAILED) zlog_debug( - "\tRoute Entry %s removed", + " Route Entry %s removed", zebra_route_string(re->type)); continue; } @@ -673,7 +673,7 @@ zebra_rnh_resolve_nexthop_entry(struct zebra_vrf *zvrf, afi_t afi, !CHECK_FLAG(re->flags, ZEBRA_FLAG_FIB_OVERRIDE)) { if (IS_ZEBRA_DEBUG_NHT_DETAILED) zlog_debug( - "\tRoute Entry %s !selected", + " Route Entry %s !selected", zebra_route_string(re->type)); continue; } @@ -681,7 +681,7 @@ zebra_rnh_resolve_nexthop_entry(struct zebra_vrf *zvrf, afi_t afi, if (CHECK_FLAG(re->status, ROUTE_ENTRY_QUEUED)) { if (IS_ZEBRA_DEBUG_NHT_DETAILED) zlog_debug( - "\tRoute Entry %s queued", + " Route Entry %s queued", zebra_route_string(re->type)); continue; } @@ -697,7 +697,7 @@ zebra_rnh_resolve_nexthop_entry(struct zebra_vrf *zvrf, afi_t afi, if (nexthop == NULL) { if (IS_ZEBRA_DEBUG_NHT_DETAILED) zlog_debug( - "\tRoute Entry %s no nexthops", + " Route Entry %s no nexthops", zebra_route_string(re->type)); continue; } @@ -732,7 +732,7 @@ zebra_rnh_resolve_nexthop_entry(struct zebra_vrf *zvrf, afi_t afi, else { if (IS_ZEBRA_DEBUG_NHT_DETAILED) zlog_debug( - "\tNexthop must be connected, cannot recurse up"); + " Nexthop must be connected, cannot recurse up"); return NULL; } } diff --git a/zebra/zebra_routemap.c b/zebra/zebra_routemap.c index 500c2c84a1..2b3b3afbb5 100644 --- a/zebra/zebra_routemap.c +++ b/zebra/zebra_routemap.c @@ -30,6 +30,8 @@ #include "filter.h" #include "plist.h" #include "nexthop.h" +#include "northbound_cli.h" +#include "route_types.h" #include "vrf.h" #include "frrstr.h" @@ -58,82 +60,6 @@ struct nh_rmap_obj { static void zebra_route_map_set_delay_timer(uint32_t value); - -/* Add zebra route map rule */ -static int zebra_route_match_add(struct vty *vty, const char *command, - const char *arg, route_map_event_t type) -{ - VTY_DECLVAR_CONTEXT(route_map_index, index); - enum rmap_compile_rets ret; - int retval = CMD_SUCCESS; - - ret = route_map_add_match(index, command, arg, type); - switch (ret) { - case RMAP_RULE_MISSING: - vty_out(vty, "%% Zebra Can't find rule.\n"); - retval = CMD_WARNING_CONFIG_FAILED; - break; - case RMAP_COMPILE_ERROR: - vty_out(vty, "%% Zebra Argument is malformed.\n"); - retval = CMD_WARNING_CONFIG_FAILED; - break; - case RMAP_COMPILE_SUCCESS: - /* - * Nothing to do here - */ - break; - } - - return retval; -} - -/* Delete zebra route map rule. */ -static int zebra_route_match_delete(struct vty *vty, const char *command, - const char *arg, route_map_event_t type) -{ - VTY_DECLVAR_CONTEXT(route_map_index, index); - enum rmap_compile_rets ret; - int retval = CMD_SUCCESS; - char *dep_name = NULL; - const char *tmpstr; - char *rmap_name = NULL; - - if (type != RMAP_EVENT_MATCH_DELETED) { - /* ignore the mundane, the types without any dependency */ - if (arg == NULL) { - if ((tmpstr = route_map_get_match_arg(index, command)) - != NULL) - dep_name = - XSTRDUP(MTYPE_ROUTE_MAP_RULE, tmpstr); - } else { - dep_name = XSTRDUP(MTYPE_ROUTE_MAP_RULE, arg); - } - rmap_name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, index->map->name); - } - - ret = route_map_delete_match(index, command, arg, type); - switch (ret) { - case RMAP_RULE_MISSING: - vty_out(vty, "%% Zebra Can't find rule.\n"); - retval = CMD_WARNING_CONFIG_FAILED; - break; - case RMAP_COMPILE_ERROR: - vty_out(vty, "%% Zebra Argument is malformed.\n"); - retval = CMD_WARNING_CONFIG_FAILED; - break; - case RMAP_COMPILE_SUCCESS: - /* - * Nothing to do here - */ - break; - } - - XFREE(MTYPE_ROUTE_MAP_RULE, dep_name); - XFREE(MTYPE_ROUTE_MAP_NAME, rmap_name); - - return retval; -} - /* 'match tag TAG' * Match function return 1 if match is success else return 0 */ @@ -425,246 +351,227 @@ static int ip_nht_rm_del(struct zebra_vrf *zvrf, const char *rmap, int rtype, return CMD_SUCCESS; } -DEFUN (match_ip_address_prefix_len, - match_ip_address_prefix_len_cmd, - "match ip address prefix-len (0-32)", - MATCH_STR - IP_STR - "Match prefix length of ip address\n" - "Match prefix length of ip address\n" - "Prefix length\n") +DEFPY( + match_ip_address_prefix_len, match_ip_address_prefix_len_cmd, + "match ip address prefix-len (0-32)$length", + MATCH_STR + IP_STR + "Match prefix length of IP address\n" + "Match prefix length of IP address\n" + "Prefix length\n") { - return zebra_route_match_add(vty, "ip address prefix-len", argv[4]->arg, - RMAP_EVENT_MATCH_ADDED); + const char *xpath = "./match-condition[condition='ipv4-prefix-length']"; + char xpath_value[XPATH_MAXLEN]; + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + snprintf(xpath_value, sizeof(xpath_value), + "%s/frr-zebra:ipv4-prefix-length", xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, length_str); + + return nb_cli_apply_changes(vty, NULL); } -DEFUN (no_match_ip_address_prefix_len, - no_match_ip_address_prefix_len_cmd, - "no match ip address prefix-len [(0-32)]", - NO_STR - MATCH_STR - IP_STR - "Match prefix length of ip address\n" - "Match prefix length of ip address\n" - "Prefix length\n") +DEFPY( + no_match_ip_address_prefix_len, no_match_ip_address_prefix_len_cmd, + "no match ip address prefix-len [(0-32)]", + NO_STR + MATCH_STR + IP_STR + "Match prefix length of IP address\n" + "Match prefix length of IP address\n" + "Prefix length\n") { - char *plen = (argc == 6) ? argv[5]->arg : NULL; - return zebra_route_match_delete(vty, "ip address prefix-len", plen, - RMAP_EVENT_MATCH_DELETED); + const char *xpath = "./match-condition[condition='ipv4-prefix-length']"; + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); } -DEFUN (match_ipv6_address_prefix_len, - match_ipv6_address_prefix_len_cmd, - "match ipv6 address prefix-len (0-128)", - MATCH_STR - IPV6_STR - "Match prefix length of ipv6 address\n" - "Match prefix length of ipv6 address\n" - "Prefix length\n") +DEFPY( + match_ipv6_address_prefix_len, match_ipv6_address_prefix_len_cmd, + "match ipv6 address prefix-len (0-128)$length", + MATCH_STR + IPV6_STR + "Match prefix length of IPv6 address\n" + "Match prefix length of IPv6 address\n" + "Prefix length\n") { - return zebra_route_match_add(vty, "ipv6 address prefix-len", - argv[4]->arg, RMAP_EVENT_MATCH_ADDED); + const char *xpath = "./match-condition[condition='ipv6-prefix-length']"; + char xpath_value[XPATH_MAXLEN]; + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + snprintf(xpath_value, sizeof(xpath_value), + "%s/frr-zebra:ipv6-prefix-length", xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, length_str); + + return nb_cli_apply_changes(vty, NULL); } -DEFUN (no_match_ipv6_address_prefix_len, - no_match_ipv6_address_prefix_len_cmd, - "no match ipv6 address prefix-len [(0-128)]", - NO_STR - MATCH_STR - IPV6_STR - "Match prefix length of ip address\n" - "Match prefix length of ip address\n" - "Prefix length\n") +DEFPY( + no_match_ipv6_address_prefix_len, no_match_ipv6_address_prefix_len_cmd, + "no match ipv6 address prefix-len [(0-128)]", + NO_STR + MATCH_STR + IPV6_STR + "Match prefix length of IPv6 address\n" + "Match prefix length of IPv6 address\n" + "Prefix length\n") { - char *plen = (argc == 6) ? argv[5]->arg : NULL; - return zebra_route_match_delete(vty, "ipv6 address prefix-len", plen, - RMAP_EVENT_MATCH_DELETED); + const char *xpath = "./match-condition[condition='ipv6-prefix-length']"; + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); } -DEFUN (match_ip_nexthop_prefix_len, - match_ip_nexthop_prefix_len_cmd, - "match ip next-hop prefix-len (0-32)", - MATCH_STR - IP_STR - "Match prefixlen of nexthop ip address\n" - "Match prefixlen of given nexthop\n" - "Prefix length\n") +DEFPY( + match_ip_nexthop_prefix_len, match_ip_nexthop_prefix_len_cmd, + "match ip next-hop prefix-len (0-32)$length", + MATCH_STR + IP_STR + "Match prefixlen of nexthop IP address\n" + "Match prefixlen of given nexthop\n" + "Prefix length\n") { - return zebra_route_match_add(vty, "ip next-hop prefix-len", - argv[4]->arg, RMAP_EVENT_MATCH_ADDED); + const char *xpath = + "./match-condition[condition='ipv4-next-hop-prefix-length']"; + char xpath_value[XPATH_MAXLEN]; + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + snprintf(xpath_value, sizeof(xpath_value), + "%s/frr-zebra:ipv4-prefix-length", xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, length_str); + + return nb_cli_apply_changes(vty, NULL); } -DEFUN (no_match_ip_nexthop_prefix_len, - no_match_ip_nexthop_prefix_len_cmd, - "no match ip next-hop prefix-len [(0-32)]", - NO_STR - MATCH_STR - IP_STR - "Match prefixlen of nexthop ip address\n" - "Match prefix length of nexthop\n" - "Prefix length\n") -{ - char *plen = (argc == 6) ? argv[5]->arg : NULL; - return zebra_route_match_delete(vty, "ip next-hop prefix-len", plen, - RMAP_EVENT_MATCH_DELETED); -} - -DEFUN (match_source_protocol, - match_source_protocol_cmd, - "match source-protocol <bgp|ospf|rip|ripng|isis|ospf6|pim|nhrp|eigrp|babel|connected|system|kernel|static|sharp>", - MATCH_STR - "Match protocol via which the route was learnt\n" - "BGP protocol\n" - "OSPF protocol\n" - "RIP protocol\n" - "RIPNG protocol\n" - "ISIS protocol\n" - "OSPF6 protocol\n" - "PIM protocol\n" - "NHRP protocol\n" - "EIGRP protocol\n" - "BABEL protocol\n" - "Routes from directly connected peer\n" - "Routes from system configuration\n" - "Routes from kernel\n" - "Statically configured routes\n" - "SHARP process\n") -{ - char *proto = argv[2]->text; - int i; +DEFPY( + no_match_ip_nexthop_prefix_len, no_match_ip_nexthop_prefix_len_cmd, + "no match ip next-hop prefix-len [(0-32)]", + NO_STR + MATCH_STR + IP_STR + "Match prefixlen of nexthop IP address\n" + "Match prefix length of nexthop\n" + "Prefix length\n") +{ + const char *xpath = + "./match-condition[condition='ipv4-next-hop-prefix-length']"; - i = proto_name2num(proto); - if (i < 0) { - vty_out(vty, "invalid protocol name \"%s\"\n", proto); - return CMD_WARNING_CONFIG_FAILED; - } - return zebra_route_match_add(vty, "source-protocol", proto, - RMAP_EVENT_MATCH_ADDED); + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); } -DEFUN (no_match_source_protocol, - no_match_source_protocol_cmd, - "no match source-protocol [<bgp|ospf|rip|ripng|isis|ospf6|pim|nhrp|eigrp|babel|connected|system|kernel|static|sharp>]", - NO_STR - MATCH_STR - "No match protocol via which the route was learnt\n" - "BGP protocol\n" - "OSPF protocol\n" - "RIP protocol\n" - "RIPNG protocol\n" - "ISIS protocol\n" - "OSPF6 protocol\n" - "PIM protocol\n" - "NHRP protocol\n" - "EIGRP protocol\n" - "BABEL protocol\n" - "Routes from directly connected peer\n" - "Routes from system configuration\n" - "Routes from kernel\n" - "Statically configured routes\n" - "SHARP process\n") -{ - char *proto = (argc == 4) ? argv[3]->text : NULL; - return zebra_route_match_delete(vty, "source-protocol", proto, - RMAP_EVENT_MATCH_DELETED); -} - -DEFUN (match_source_instance, - match_source_instance_cmd, - "match source-instance (0-255)", - MATCH_STR - "Match the protocol's instance number\n" - "The instance number\n") -{ - char *instance = argv[2]->arg; - - return zebra_route_match_add(vty, "source-instance", instance, - RMAP_EVENT_MATCH_ADDED); -} - -DEFUN (no_match_source_instance, - no_match_source_instance_cmd, - "no match source-instance [(0-255)]", - NO_STR MATCH_STR - "Match the protocol's instance number\n" - "The instance number\n") -{ - char *instance = (argc == 4) ? argv[3]->arg : NULL; - - return zebra_route_match_delete(vty, "source-instance", instance, - RMAP_EVENT_MATCH_ADDED); +DEFPY( + match_source_protocol, match_source_protocol_cmd, + "match source-protocol " FRR_REDIST_STR_ZEBRA "$proto", + MATCH_STR + "Match protocol via which the route was learnt\n" + FRR_REDIST_HELP_STR_ZEBRA) +{ + const char *xpath = "./match-condition[condition='source-protocol']"; + char xpath_value[XPATH_MAXLEN]; + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + snprintf(xpath_value, sizeof(xpath_value), + "%s/frr-zebra:source-protocol", xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, proto); + + return nb_cli_apply_changes(vty, NULL); } -/* set functions */ +DEFPY( + no_match_source_protocol, no_match_source_protocol_cmd, + "no match source-protocol [" FRR_REDIST_STR_ZEBRA "]", + NO_STR + MATCH_STR + "Match protocol via which the route was learnt\n" + FRR_REDIST_HELP_STR_ZEBRA) +{ + const char *xpath = "./match-condition[condition='source-protocol']"; -DEFUN (set_src, - set_src_cmd, - "set src <A.B.C.D|X:X::X:X>", - SET_STR - "src address for route\n" - "IPv4 src address\n" - "IPv6 src address\n") -{ - int idx_ip = 2; - union g_addr src; - struct interface *pif = NULL; - int family; - struct prefix p; - struct vrf *vrf; - - if (inet_pton(AF_INET, argv[idx_ip]->arg, &src.ipv4) != 1) { - if (inet_pton(AF_INET6, argv[idx_ip]->arg, &src.ipv6) != 1) { - vty_out(vty, "%% not a valid IPv4/v6 address\n"); - return CMD_WARNING_CONFIG_FAILED; - } + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); - p.family = family = AF_INET6; - p.u.prefix6 = src.ipv6; - p.prefixlen = IPV6_MAX_BITLEN; - } else { - p.family = family = AF_INET; - p.u.prefix4 = src.ipv4; - p.prefixlen = IPV4_MAX_BITLEN; - } + return nb_cli_apply_changes(vty, NULL); +} - if (!zebra_check_addr(&p)) { - vty_out(vty, "%% not a valid source IPv4/v6 address\n"); - return CMD_WARNING_CONFIG_FAILED; - } +DEFPY( + match_source_instance, match_source_instance_cmd, + "match source-instance (0-255)$instance", + MATCH_STR + "Match the protocol's instance number\n" + "The instance number\n") +{ + const char *xpath = "./match-condition[condition='source-instance']"; + char xpath_value[XPATH_MAXLEN]; - RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) { - if (family == AF_INET) - pif = if_lookup_exact_address((void *)&src.ipv4, - AF_INET, vrf->vrf_id); - else if (family == AF_INET6) - pif = if_lookup_exact_address((void *)&src.ipv6, - AF_INET6, vrf->vrf_id); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + snprintf(xpath_value, sizeof(xpath_value), + "%s/frr-zebra:source-instance", xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, instance_str); - if (pif != NULL) - break; - } + return nb_cli_apply_changes(vty, NULL); +} - if (!pif) { - vty_out(vty, "%% not a local address\n"); - return CMD_WARNING_CONFIG_FAILED; +DEFPY( + no_match_source_instance, no_match_source_instance_cmd, + "no match source-instance [(0-255)]", + NO_STR MATCH_STR + "Match the protocol's instance number\n" + "The instance number\n") +{ + const char *xpath = "./match-condition[condition='source-instance']"; + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} + +/* set functions */ + +DEFPY( + set_src, set_src_cmd, + "set src <A.B.C.D$addrv4|X:X::X:X$addrv6>", + SET_STR + "src address for route\n" + "IPv4 src address\n" + "IPv6 src address\n") +{ + const char *xpath = "./set-action[action='source']"; + char xpath_value[XPATH_MAXLEN]; + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (addrv4_str) { + snprintf(xpath_value, sizeof(xpath_value), + "%s/frr-zebra:source-v4", xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, + addrv4_str); + } else { + snprintf(xpath_value, sizeof(xpath_value), + "%s/frr-zebra:source-v6", xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, + addrv6_str); } - VTY_DECLVAR_CONTEXT(route_map_index, index); - return generic_set_add(vty, index, "src", argv[idx_ip]->arg); + return nb_cli_apply_changes(vty, NULL); } -DEFUN (no_set_src, - no_set_src_cmd, - "no set src [<A.B.C.D|X:X::X:X>]", - NO_STR - SET_STR - "Source address for route\n" - "IPv4 address\n" - "IPv6 address\n") -{ - char *ip = (argc == 4) ? argv[3]->arg : NULL; - VTY_DECLVAR_CONTEXT(route_map_index, index); - return generic_set_delete(vty, index, "src", ip); +DEFPY( + no_set_src, no_set_src_cmd, + "no set src [<A.B.C.D|X:X::X:X>]", + NO_STR + SET_STR + "Source address for route\n" + "IPv4 address\n" + "IPv6 address\n") +{ + const char *xpath = "./set-action[action='source']"; + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); } DEFUN (zebra_route_map_timer, diff --git a/zebra/zebra_router.c b/zebra/zebra_router.c index a891ffb76a..ea2b6752b3 100644 --- a/zebra/zebra_router.c +++ b/zebra/zebra_router.c @@ -223,10 +223,11 @@ void zebra_router_terminate(void) zebra_vxlan_disable(); zebra_mlag_terminate(); - hash_clean(zrouter.nhgs, zebra_nhg_hash_free); - hash_free(zrouter.nhgs); - hash_clean(zrouter.nhgs_id, NULL); + /* Free NHE in ID table only since it has unhashable entries as well */ + hash_clean(zrouter.nhgs_id, zebra_nhg_hash_free); hash_free(zrouter.nhgs_id); + hash_clean(zrouter.nhgs, NULL); + hash_free(zrouter.nhgs); hash_clean(zrouter.rules_hash, zebra_pbr_rules_free); hash_free(zrouter.rules_hash); diff --git a/zebra/zebra_router.h b/zebra/zebra_router.h index 59bd0e55f0..773e5a6415 100644 --- a/zebra/zebra_router.h +++ b/zebra/zebra_router.h @@ -218,6 +218,9 @@ extern void multicast_mode_ipv4_set(enum multicast_mode mode); extern enum multicast_mode multicast_mode_ipv4_get(void); +/* zebra_northbound.c */ +extern const struct frr_yang_module_info frr_zebra_info; + #ifdef __cplusplus } #endif diff --git a/zebra/zebra_vrf.c b/zebra/zebra_vrf.c index c392303760..ee1e251a69 100644 --- a/zebra/zebra_vrf.c +++ b/zebra/zebra_vrf.c @@ -60,8 +60,13 @@ static void zebra_vrf_add_update(struct zebra_vrf *zvrf) if (IS_ZEBRA_DEBUG_EVENT) zlog_debug("MESSAGE: ZEBRA_VRF_ADD %s", zvrf_name(zvrf)); - for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) + for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) { + /* Do not send unsolicited messages to synchronous clients. */ + if (client->synchronous) + continue; + zsend_vrf_add(client, zvrf); + } } static void zebra_vrf_delete_update(struct zebra_vrf *zvrf) @@ -72,8 +77,13 @@ static void zebra_vrf_delete_update(struct zebra_vrf *zvrf) if (IS_ZEBRA_DEBUG_EVENT) zlog_debug("MESSAGE: ZEBRA_VRF_DELETE %s", zvrf_name(zvrf)); - for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) + for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) { + /* Do not send unsolicited messages to synchronous clients. */ + if (client->synchronous) + continue; + zsend_vrf_delete(client, zvrf); + } } void zebra_vrf_update_all(struct zserv *client) @@ -168,7 +178,7 @@ static int zebra_vrf_disable(struct vrf *vrf) zebra_vxlan_vrf_disable(zvrf); #if defined(HAVE_RTADV) - rtadv_terminate(zvrf); + rtadv_vrf_terminate(zvrf); #endif /* Inform clients that the VRF is now inactive. This is a diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index ccc6e9e46b..590ec57087 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -164,7 +164,8 @@ DEFUN (show_ip_rpf_addr, return CMD_SUCCESS; } -static char re_status_output_char(struct route_entry *re, struct nexthop *nhop) +static char re_status_output_char(const struct route_entry *re, + const struct nexthop *nhop) { if (CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED)) { if (!CHECK_FLAG(nhop->flags, NEXTHOP_FLAG_DUPLICATE) && @@ -187,6 +188,152 @@ static char re_status_output_char(struct route_entry *re, struct nexthop *nhop) return ' '; } +/* + * TODO -- Show backup nexthop info + */ +static void show_nh_backup_helper(struct vty *vty, + const struct nhg_hash_entry *nhe, + const struct nexthop *nexthop) +{ + /* Double-check that there _is_ a backup */ + if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP)) + return; + + /* Locate the backup nexthop */ + + /* Format the backup (indented) */ + +} + +/* + * Helper api to format output for a nexthop, used in the 'detailed' + * output path. + */ +static void show_nexthop_detail_helper(struct vty *vty, + const struct route_entry *re, + const struct nexthop *nexthop) +{ + char addrstr[32]; + char buf[MPLS_LABEL_STRLEN]; + + vty_out(vty, " %c%s", + re_status_output_char(re, nexthop), + nexthop->rparent ? " " : ""); + + switch (nexthop->type) { + case NEXTHOP_TYPE_IPV4: + case NEXTHOP_TYPE_IPV4_IFINDEX: + vty_out(vty, " %s", + inet_ntoa(nexthop->gate.ipv4)); + if (nexthop->ifindex) + vty_out(vty, ", via %s", + ifindex2ifname( + nexthop->ifindex, + nexthop->vrf_id)); + break; + case NEXTHOP_TYPE_IPV6: + case NEXTHOP_TYPE_IPV6_IFINDEX: + vty_out(vty, " %s", + inet_ntop(AF_INET6, &nexthop->gate.ipv6, + buf, sizeof(buf))); + if (nexthop->ifindex) + vty_out(vty, ", via %s", + ifindex2ifname( + nexthop->ifindex, + nexthop->vrf_id)); + break; + + case NEXTHOP_TYPE_IFINDEX: + vty_out(vty, " directly connected, %s", + ifindex2ifname(nexthop->ifindex, + nexthop->vrf_id)); + break; + case NEXTHOP_TYPE_BLACKHOLE: + vty_out(vty, " unreachable"); + switch (nexthop->bh_type) { + case BLACKHOLE_REJECT: + vty_out(vty, " (ICMP unreachable)"); + break; + case BLACKHOLE_ADMINPROHIB: + vty_out(vty, + " (ICMP admin-prohibited)"); + break; + case BLACKHOLE_NULL: + vty_out(vty, " (blackhole)"); + break; + case BLACKHOLE_UNSPEC: + break; + } + break; + default: + break; + } + + if ((re->vrf_id != nexthop->vrf_id) + && (nexthop->type != NEXTHOP_TYPE_BLACKHOLE)) { + struct vrf *vrf = + vrf_lookup_by_id(nexthop->vrf_id); + + if (vrf) + vty_out(vty, "(vrf %s)", vrf->name); + else + vty_out(vty, "(vrf UNKNOWN)"); + } + + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_DUPLICATE)) + vty_out(vty, " (duplicate nexthop removed)"); + + if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) + vty_out(vty, " inactive"); + + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK)) + vty_out(vty, " onlink"); + + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) + vty_out(vty, " (recursive)"); + + /* Source specified? */ + switch (nexthop->type) { + case NEXTHOP_TYPE_IPV4: + case NEXTHOP_TYPE_IPV4_IFINDEX: + if (nexthop->src.ipv4.s_addr) { + if (inet_ntop(AF_INET, &nexthop->src.ipv4, + addrstr, sizeof(addrstr))) + vty_out(vty, ", src %s", + addrstr); + } + break; + + case NEXTHOP_TYPE_IPV6: + case NEXTHOP_TYPE_IPV6_IFINDEX: + if (!IPV6_ADDR_SAME(&nexthop->src.ipv6, + &in6addr_any)) { + if (inet_ntop(AF_INET6, &nexthop->src.ipv6, + addrstr, sizeof(addrstr))) + vty_out(vty, ", src %s", + addrstr); + } + break; + + default: + break; + } + + if (re->nexthop_mtu) + vty_out(vty, ", mtu %u", re->nexthop_mtu); + + /* Label information */ + if (nexthop->nh_label && nexthop->nh_label->num_labels) { + vty_out(vty, ", label %s", + mpls_label2str(nexthop->nh_label->num_labels, + nexthop->nh_label->label, buf, + sizeof(buf), 1 /*pretty*/)); + } + + if (nexthop->weight) + vty_out(vty, ", weight %u", nexthop->weight); +} + /* New RIB. Detailed information for IPv4 route. */ static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn, int mcast, bool use_fib, bool show_ng) @@ -253,129 +400,122 @@ static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn, vty_out(vty, " Nexthop Group ID: %u\n", re->nhe_id); for (ALL_NEXTHOPS(re->nhe->nhg, nexthop)) { - char addrstr[32]; - - vty_out(vty, " %c%s", - re_status_output_char(re, nexthop), - nexthop->rparent ? " " : ""); - - switch (nexthop->type) { - case NEXTHOP_TYPE_IPV4: - case NEXTHOP_TYPE_IPV4_IFINDEX: - vty_out(vty, " %s", - inet_ntoa(nexthop->gate.ipv4)); - if (nexthop->ifindex) - vty_out(vty, ", via %s", - ifindex2ifname( - nexthop->ifindex, - nexthop->vrf_id)); - break; - case NEXTHOP_TYPE_IPV6: - case NEXTHOP_TYPE_IPV6_IFINDEX: - vty_out(vty, " %s", - inet_ntop(AF_INET6, &nexthop->gate.ipv6, - buf, sizeof(buf))); - if (nexthop->ifindex) - vty_out(vty, ", via %s", - ifindex2ifname( - nexthop->ifindex, - nexthop->vrf_id)); - break; - case NEXTHOP_TYPE_IFINDEX: - vty_out(vty, " directly connected, %s", - ifindex2ifname(nexthop->ifindex, - nexthop->vrf_id)); - break; - case NEXTHOP_TYPE_BLACKHOLE: - vty_out(vty, " unreachable"); - switch (nexthop->bh_type) { - case BLACKHOLE_REJECT: - vty_out(vty, " (ICMP unreachable)"); - break; - case BLACKHOLE_ADMINPROHIB: - vty_out(vty, - " (ICMP admin-prohibited)"); - break; - case BLACKHOLE_NULL: - vty_out(vty, " (blackhole)"); - break; - case BLACKHOLE_UNSPEC: - break; - } - break; - default: - break; - } - - if ((re->vrf_id != nexthop->vrf_id) - && (nexthop->type != NEXTHOP_TYPE_BLACKHOLE)) { - struct vrf *vrf = - vrf_lookup_by_id(nexthop->vrf_id); - - if (vrf) - vty_out(vty, "(vrf %s)", vrf->name); - else - vty_out(vty, "(vrf UNKNOWN)"); - } + /* Use helper to format each nexthop */ + show_nexthop_detail_helper(vty, re, nexthop); + vty_out(vty, "\n"); - if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_DUPLICATE)) - vty_out(vty, " (duplicate nexthop removed)"); + /* Include backup info, if present */ + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP)) + show_nh_backup_helper(vty, re->nhe, nexthop); + } + vty_out(vty, "\n"); + } +} - if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) - vty_out(vty, " inactive"); +/* + * Helper for nexthop output, used in the 'show ip route' path + */ +static void show_route_nexthop_helper(struct vty *vty, + const struct route_entry *re, + const struct nexthop *nexthop) +{ + char buf[MPLS_LABEL_STRLEN]; + + switch (nexthop->type) { + case NEXTHOP_TYPE_IPV4: + case NEXTHOP_TYPE_IPV4_IFINDEX: + vty_out(vty, " via %s", inet_ntoa(nexthop->gate.ipv4)); + if (nexthop->ifindex) + vty_out(vty, ", %s", + ifindex2ifname(nexthop->ifindex, + nexthop->vrf_id)); + break; + case NEXTHOP_TYPE_IPV6: + case NEXTHOP_TYPE_IPV6_IFINDEX: + vty_out(vty, " via %s", + inet_ntop(AF_INET6, &nexthop->gate.ipv6, buf, + sizeof(buf))); + if (nexthop->ifindex) + vty_out(vty, ", %s", + ifindex2ifname(nexthop->ifindex, + nexthop->vrf_id)); + break; - if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK)) - vty_out(vty, " onlink"); + case NEXTHOP_TYPE_IFINDEX: + vty_out(vty, " is directly connected, %s", + ifindex2ifname(nexthop->ifindex, + nexthop->vrf_id)); + break; + case NEXTHOP_TYPE_BLACKHOLE: + vty_out(vty, " unreachable"); + switch (nexthop->bh_type) { + case BLACKHOLE_REJECT: + vty_out(vty, " (ICMP unreachable)"); + break; + case BLACKHOLE_ADMINPROHIB: + vty_out(vty, " (ICMP admin-prohibited)"); + break; + case BLACKHOLE_NULL: + vty_out(vty, " (blackhole)"); + break; + case BLACKHOLE_UNSPEC: + break; + } + break; + default: + break; + } - if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) - vty_out(vty, " (recursive)"); + if ((re == NULL || (nexthop->vrf_id != re->vrf_id)) && + (nexthop->type != NEXTHOP_TYPE_BLACKHOLE)) { + struct vrf *vrf = vrf_lookup_by_id(nexthop->vrf_id); - switch (nexthop->type) { - case NEXTHOP_TYPE_IPV4: - case NEXTHOP_TYPE_IPV4_IFINDEX: - if (nexthop->src.ipv4.s_addr) { - if (inet_ntop(AF_INET, - &nexthop->src.ipv4, - addrstr, sizeof(addrstr))) - vty_out(vty, ", src %s", - addrstr); - } - break; - case NEXTHOP_TYPE_IPV6: - case NEXTHOP_TYPE_IPV6_IFINDEX: - if (!IPV6_ADDR_SAME(&nexthop->src.ipv6, - &in6addr_any)) { - if (inet_ntop(AF_INET6, - &nexthop->src.ipv6, - addrstr, sizeof(addrstr))) - vty_out(vty, ", src %s", - addrstr); - } - break; - default: - break; - } + if (vrf) + vty_out(vty, " (vrf %s)", vrf->name); + else + vty_out(vty, " (vrf UNKNOWN)"); + } - if (re->nexthop_mtu) - vty_out(vty, ", mtu %u", re->nexthop_mtu); + if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) + vty_out(vty, " inactive"); - /* Label information */ - if (nexthop->nh_label - && nexthop->nh_label->num_labels) { - vty_out(vty, ", label %s", - mpls_label2str( - nexthop->nh_label->num_labels, - nexthop->nh_label->label, buf, - sizeof(buf), 1)); - } + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK)) + vty_out(vty, " onlink"); - if (nexthop->weight) - vty_out(vty, ", weight %u", nexthop->weight); + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) + vty_out(vty, " (recursive)"); - vty_out(vty, "\n"); + switch (nexthop->type) { + case NEXTHOP_TYPE_IPV4: + case NEXTHOP_TYPE_IPV4_IFINDEX: + if (nexthop->src.ipv4.s_addr) { + if (inet_ntop(AF_INET, &nexthop->src.ipv4, buf, + sizeof(buf))) + vty_out(vty, ", src %s", buf); } - vty_out(vty, "\n"); + break; + case NEXTHOP_TYPE_IPV6: + case NEXTHOP_TYPE_IPV6_IFINDEX: + if (!IPV6_ADDR_SAME(&nexthop->src.ipv6, &in6addr_any)) { + if (inet_ntop(AF_INET6, &nexthop->src.ipv6, buf, + sizeof(buf))) + vty_out(vty, ", src %s", buf); + } + break; + default: + break; } + + /* Label information */ + if (nexthop->nh_label && nexthop->nh_label->num_labels) { + vty_out(vty, ", label %s", + mpls_label2str(nexthop->nh_label->num_labels, + nexthop->nh_label->label, buf, + sizeof(buf), 1)); + } + + if ((re == NULL) && nexthop->weight) + vty_out(vty, ", weight %u", nexthop->weight); } static void vty_show_ip_route(struct vty *vty, struct route_node *rn, @@ -660,105 +800,43 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, len - 3 + (2 * nexthop_level(nexthop)), ' '); } - switch (nexthop->type) { - case NEXTHOP_TYPE_IPV4: - case NEXTHOP_TYPE_IPV4_IFINDEX: - vty_out(vty, " via %s", inet_ntoa(nexthop->gate.ipv4)); - if (nexthop->ifindex) - vty_out(vty, ", %s", - ifindex2ifname(nexthop->ifindex, - nexthop->vrf_id)); - break; - case NEXTHOP_TYPE_IPV6: - case NEXTHOP_TYPE_IPV6_IFINDEX: - vty_out(vty, " via %s", - inet_ntop(AF_INET6, &nexthop->gate.ipv6, buf, - sizeof(buf))); - if (nexthop->ifindex) - vty_out(vty, ", %s", - ifindex2ifname(nexthop->ifindex, - nexthop->vrf_id)); - break; - - case NEXTHOP_TYPE_IFINDEX: - vty_out(vty, " is directly connected, %s", - ifindex2ifname(nexthop->ifindex, - nexthop->vrf_id)); - break; - case NEXTHOP_TYPE_BLACKHOLE: - vty_out(vty, " unreachable"); - switch (nexthop->bh_type) { - case BLACKHOLE_REJECT: - vty_out(vty, " (ICMP unreachable)"); - break; - case BLACKHOLE_ADMINPROHIB: - vty_out(vty, " (ICMP admin-prohibited)"); - break; - case BLACKHOLE_NULL: - vty_out(vty, " (blackhole)"); - break; - case BLACKHOLE_UNSPEC: - break; - } - break; - default: - break; - } - - if ((nexthop->vrf_id != re->vrf_id) - && (nexthop->type != NEXTHOP_TYPE_BLACKHOLE)) { - struct vrf *vrf = vrf_lookup_by_id(nexthop->vrf_id); + show_route_nexthop_helper(vty, re, nexthop); - if (vrf) - vty_out(vty, "(vrf %s)", vrf->name); - else - vty_out(vty, "(vrf UNKNOWN)"); - } - - if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) - vty_out(vty, " inactive"); + vty_out(vty, ", %s\n", up_str); - if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK)) - vty_out(vty, " onlink"); + /* Check for backup info */ + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP)) { + struct nexthop *backup; + int i; - if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) - vty_out(vty, " (recursive)"); + if (re->nhe->backup_info == NULL || + re->nhe->backup_info->nhe == NULL) + continue; - switch (nexthop->type) { - case NEXTHOP_TYPE_IPV4: - case NEXTHOP_TYPE_IPV4_IFINDEX: - if (nexthop->src.ipv4.s_addr) { - if (inet_ntop(AF_INET, &nexthop->src.ipv4, buf, - sizeof(buf))) - vty_out(vty, ", src %s", buf); - } - break; - case NEXTHOP_TYPE_IPV6: - case NEXTHOP_TYPE_IPV6_IFINDEX: - if (!IPV6_ADDR_SAME(&nexthop->src.ipv6, &in6addr_any)) { - if (inet_ntop(AF_INET6, &nexthop->src.ipv6, buf, - sizeof(buf))) - vty_out(vty, ", src %s", buf); + i = 0; + for (ALL_NEXTHOPS(re->nhe->backup_info->nhe->nhg, + backup)) { + if (i == nexthop->backup_idx) + break; + i++; } - break; - default: - break; - } - /* Label information */ - if (nexthop->nh_label && nexthop->nh_label->num_labels) { - vty_out(vty, ", label %s", - mpls_label2str(nexthop->nh_label->num_labels, - nexthop->nh_label->label, buf, - sizeof(buf), 1)); + /* Print useful backup info */ + if (backup) { + /* TODO -- install state is not accurate */ + vty_out(vty, " %*c [backup %d]", + /*re_status_output_char(re, backup),*/ + len - 3 + (2 * nexthop_level(nexthop)), + ' ', nexthop->backup_idx); + show_route_nexthop_helper(vty, re, backup); + vty_out(vty, "\n"); + } } - - vty_out(vty, ", %s\n", up_str); } } static void vty_show_ip_route_detail_json(struct vty *vty, - struct route_node *rn, bool use_fib) + struct route_node *rn, bool use_fib) { json_object *json = NULL; json_object *json_prefix = NULL; @@ -1028,9 +1106,8 @@ static void show_nexthop_group_out(struct vty *vty, struct nhg_hash_entry *nhe) { struct nexthop *nexthop = NULL; struct nhg_connected *rb_node_dep = NULL; - char buf[SRCDEST2STR_BUFFER]; - struct vrf *nhe_vrf = vrf_lookup_by_id(nhe->vrf_id); + struct nexthop_group *backup_nhg; vty_out(vty, "ID: %u\n", nhe->id); vty_out(vty, " RefCnt: %d\n", nhe->refcnt); @@ -1062,6 +1139,7 @@ static void show_nexthop_group_out(struct vty *vty, struct nhg_hash_entry *nhe) vty_out(vty, "\n"); } + /* Output nexthops */ for (ALL_NEXTHOPS(nhe->nhg, nexthop)) { if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) vty_out(vty, " "); @@ -1069,100 +1147,56 @@ static void show_nexthop_group_out(struct vty *vty, struct nhg_hash_entry *nhe) /* Make recursive nexthops a bit more clear */ vty_out(vty, " "); - switch (nexthop->type) { - case NEXTHOP_TYPE_IPV4: - case NEXTHOP_TYPE_IPV4_IFINDEX: - vty_out(vty, " %s", inet_ntoa(nexthop->gate.ipv4)); - if (nexthop->ifindex) - vty_out(vty, ", %s", - ifindex2ifname(nexthop->ifindex, - nexthop->vrf_id)); - break; - case NEXTHOP_TYPE_IPV6: - case NEXTHOP_TYPE_IPV6_IFINDEX: - vty_out(vty, " %s", - inet_ntop(AF_INET6, &nexthop->gate.ipv6, buf, - sizeof(buf))); - if (nexthop->ifindex) - vty_out(vty, ", %s", - ifindex2ifname(nexthop->ifindex, - nexthop->vrf_id)); - break; + show_route_nexthop_helper(vty, NULL, nexthop); - case NEXTHOP_TYPE_IFINDEX: - vty_out(vty, " directly connected %s", - ifindex2ifname(nexthop->ifindex, - nexthop->vrf_id)); - break; - case NEXTHOP_TYPE_BLACKHOLE: - vty_out(vty, " unreachable"); - switch (nexthop->bh_type) { - case BLACKHOLE_REJECT: - vty_out(vty, " (ICMP unreachable)"); - break; - case BLACKHOLE_ADMINPROHIB: - vty_out(vty, " (ICMP admin-prohibited)"); - break; - case BLACKHOLE_NULL: - vty_out(vty, " (blackhole)"); - break; - case BLACKHOLE_UNSPEC: - break; - } - break; - default: - break; + if (nhe->backup_info == NULL || nhe->backup_info->nhe == NULL) { + if (CHECK_FLAG(nexthop->flags, + NEXTHOP_FLAG_HAS_BACKUP)) + vty_out(vty, " [backup %d]", + nexthop->backup_idx); + + vty_out(vty, "\n"); + continue; } - struct vrf *vrf = vrf_lookup_by_id(nexthop->vrf_id); + /* TODO -- print more useful backup info */ + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP)) { + struct nexthop *backup; + int i; - if (vrf) - vty_out(vty, " (vrf %s)", vrf->name); - else - vty_out(vty, " (vrf UNKNOWN)"); + i = 0; + for (ALL_NEXTHOPS(nhe->backup_info->nhe->nhg, backup)) { + if (i == nexthop->backup_idx) + break; + i++; + } - if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) - vty_out(vty, " inactive"); + /* TODO */ + if (backup) + vty_out(vty, " [backup %d]", + nexthop->backup_idx); + else + vty_out(vty, " [backup INVALID]"); + } - if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK)) - vty_out(vty, " onlink"); + vty_out(vty, "\n"); + } - if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) - vty_out(vty, " (recursive)"); + /* Output backup nexthops (if any) */ + backup_nhg = zebra_nhg_get_backup_nhg(nhe); + if (backup_nhg) { + vty_out(vty, " Backups:\n"); - switch (nexthop->type) { - case NEXTHOP_TYPE_IPV4: - case NEXTHOP_TYPE_IPV4_IFINDEX: - if (nexthop->src.ipv4.s_addr) { - if (inet_ntop(AF_INET, &nexthop->src.ipv4, buf, - sizeof(buf))) - vty_out(vty, ", src %s", buf); - } - break; - case NEXTHOP_TYPE_IPV6: - case NEXTHOP_TYPE_IPV6_IFINDEX: - if (!IPV6_ADDR_SAME(&nexthop->src.ipv6, &in6addr_any)) { - if (inet_ntop(AF_INET6, &nexthop->src.ipv6, buf, - sizeof(buf))) - vty_out(vty, ", src %s", buf); - } - break; - default: - break; - } + for (ALL_NEXTHOPS_PTR(backup_nhg, nexthop)) { + if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) + vty_out(vty, " "); + else + /* Make recursive nexthops a bit more clear */ + vty_out(vty, " "); - /* Label information */ - if (nexthop->nh_label && nexthop->nh_label->num_labels) { - vty_out(vty, ", label %s", - mpls_label2str(nexthop->nh_label->num_labels, - nexthop->nh_label->label, buf, - sizeof(buf), 1)); + show_route_nexthop_helper(vty, NULL, nexthop); + vty_out(vty, "\n"); } - - if (nexthop->weight) - vty_out(vty, ", weight %u", nexthop->weight); - - vty_out(vty, "\n"); } if (!zebra_nhg_dependents_is_empty(nhe)) { diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 61865e5baf..aa2e5c91c9 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -121,11 +121,11 @@ static struct interface *zvni_map_to_macvlan(struct interface *br_if, /* l3-vni next-hop neigh related APIs */ static zebra_neigh_t *zl3vni_nh_lookup(zebra_l3vni_t *zl3vni, - struct ipaddr *ip); + const struct ipaddr *ip); static void *zl3vni_nh_alloc(void *p); static zebra_neigh_t *zl3vni_nh_add(zebra_l3vni_t *zl3vni, - struct ipaddr *vtep_ip, - struct ethaddr *rmac); + const struct ipaddr *vtep_ip, + const struct ethaddr *rmac); static int zl3vni_nh_del(zebra_l3vni_t *zl3vni, zebra_neigh_t *n); static int zl3vni_nh_install(zebra_l3vni_t *zl3vni, zebra_neigh_t *n); static int zl3vni_nh_uninstall(zebra_l3vni_t *zl3vni, zebra_neigh_t *n); @@ -133,10 +133,10 @@ static int zl3vni_nh_uninstall(zebra_l3vni_t *zl3vni, zebra_neigh_t *n); /* l3-vni rmac related APIs */ static void zl3vni_print_rmac_hash(struct hash_bucket *, void *); static zebra_mac_t *zl3vni_rmac_lookup(zebra_l3vni_t *zl3vni, - struct ethaddr *rmac); + const struct ethaddr *rmac); static void *zl3vni_rmac_alloc(void *p); static zebra_mac_t *zl3vni_rmac_add(zebra_l3vni_t *zl3vni, - struct ethaddr *rmac); + const struct ethaddr *rmac); static int zl3vni_rmac_del(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac); static int zl3vni_rmac_install(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac); static int zl3vni_rmac_uninstall(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac); @@ -3059,7 +3059,7 @@ static int zvni_local_neigh_update(zebra_vni_t *zvni, zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id); if (!zvrf) { if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug("\tUnable to find vrf for: %d", + zlog_debug(" Unable to find vrf for: %d", zvni->vxlan_if->vrf_id); return -1; } @@ -3094,7 +3094,7 @@ static int zvni_local_neigh_update(zebra_vni_t *zvni, if (!mac_different && is_router == cur_is_router) { if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug( - "\tIgnoring entry mac is the same and is_router == cur_is_router"); + " Ignoring entry mac is the same and is_router == cur_is_router"); n->ifindex = ifp->ifindex; return 0; } @@ -3126,7 +3126,7 @@ static int zvni_local_neigh_update(zebra_vni_t *zvni, else { if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug( - "\tNeighbor active and frozen"); + " Neighbor active and frozen"); } return 0; } @@ -3271,7 +3271,7 @@ static int zvni_local_neigh_update(zebra_vni_t *zvni, n->flags, n->loc_seq); } else { if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug("\tNeighbor on hold not sending"); + zlog_debug(" Neighbor on hold not sending"); } return 0; } @@ -4434,7 +4434,7 @@ static void zl3vni_cleanup_all(struct hash_bucket *bucket, void *args) } static void rb_find_or_add_host(struct host_rb_tree_entry *hrbe, - struct prefix *host) + const struct prefix *host) { struct host_rb_entry lookup; struct host_rb_entry *hle; @@ -4473,7 +4473,7 @@ static void rb_delete_host(struct host_rb_tree_entry *hrbe, struct prefix *host) * Look up MAC hash entry. */ static zebra_mac_t *zl3vni_rmac_lookup(zebra_l3vni_t *zl3vni, - struct ethaddr *rmac) + const struct ethaddr *rmac) { zebra_mac_t tmp; zebra_mac_t *pmac; @@ -4502,7 +4502,8 @@ static void *zl3vni_rmac_alloc(void *p) /* * Add RMAC entry to l3-vni */ -static zebra_mac_t *zl3vni_rmac_add(zebra_l3vni_t *zl3vni, struct ethaddr *rmac) +static zebra_mac_t *zl3vni_rmac_add(zebra_l3vni_t *zl3vni, + const struct ethaddr *rmac) { zebra_mac_t tmp_rmac; zebra_mac_t *zrmac = NULL; @@ -4632,9 +4633,10 @@ static int zl3vni_rmac_uninstall(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac) } /* handle rmac add */ -static int zl3vni_remote_rmac_add(zebra_l3vni_t *zl3vni, struct ethaddr *rmac, - struct ipaddr *vtep_ip, - struct prefix *host_prefix) +static int zl3vni_remote_rmac_add(zebra_l3vni_t *zl3vni, + const struct ethaddr *rmac, + const struct ipaddr *vtep_ip, + const struct prefix *host_prefix) { char buf[ETHER_ADDR_STRLEN]; char buf1[INET6_ADDRSTRLEN]; @@ -4709,7 +4711,8 @@ static void zl3vni_remote_rmac_del(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac, /* * Look up nh hash entry on a l3-vni. */ -static zebra_neigh_t *zl3vni_nh_lookup(zebra_l3vni_t *zl3vni, struct ipaddr *ip) +static zebra_neigh_t *zl3vni_nh_lookup(zebra_l3vni_t *zl3vni, + const struct ipaddr *ip) { zebra_neigh_t tmp; zebra_neigh_t *n; @@ -4739,8 +4742,9 @@ static void *zl3vni_nh_alloc(void *p) /* * Add neighbor entry. */ -static zebra_neigh_t *zl3vni_nh_add(zebra_l3vni_t *zl3vni, struct ipaddr *ip, - struct ethaddr *mac) +static zebra_neigh_t *zl3vni_nh_add(zebra_l3vni_t *zl3vni, + const struct ipaddr *ip, + const struct ethaddr *mac) { zebra_neigh_t tmp_n; zebra_neigh_t *n = NULL; @@ -4822,9 +4826,10 @@ static int zl3vni_nh_uninstall(zebra_l3vni_t *zl3vni, zebra_neigh_t *n) } /* add remote vtep as a neigh entry */ -static int zl3vni_remote_nh_add(zebra_l3vni_t *zl3vni, struct ipaddr *vtep_ip, - struct ethaddr *rmac, - struct prefix *host_prefix) +static int zl3vni_remote_nh_add(zebra_l3vni_t *zl3vni, + const struct ipaddr *vtep_ip, + const struct ethaddr *rmac, + const struct prefix *host_prefix) { char buf[ETHER_ADDR_STRLEN]; char buf1[ETHER_ADDR_STRLEN]; @@ -5960,9 +5965,9 @@ int is_l3vni_for_prefix_routes_only(vni_t vni) } /* handle evpn route in vrf table */ -void zebra_vxlan_evpn_vrf_route_add(vrf_id_t vrf_id, struct ethaddr *rmac, - struct ipaddr *vtep_ip, - struct prefix *host_prefix) +void zebra_vxlan_evpn_vrf_route_add(vrf_id_t vrf_id, const struct ethaddr *rmac, + const struct ipaddr *vtep_ip, + const struct prefix *host_prefix) { zebra_l3vni_t *zl3vni = NULL; struct ipaddr ipv4_vtep; @@ -8034,7 +8039,7 @@ int zebra_vxlan_local_mac_add_update(struct interface *ifp, if (!zvni) { if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug( - "\tAdd/Update %sMAC %s intf %s(%u) VID %u, could not find VNI", + " Add/Update %sMAC %s intf %s(%u) VID %u, could not find VNI", sticky ? "sticky " : "", prefix_mac2str(macaddr, buf, sizeof(buf)), ifp->name, ifp->ifindex, vid); @@ -8044,7 +8049,7 @@ int zebra_vxlan_local_mac_add_update(struct interface *ifp, if (!zvni->vxlan_if) { if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug( - "\tVNI %u hash %p doesn't have intf upon local MAC ADD", + " VNI %u hash %p doesn't have intf upon local MAC ADD", zvni->vni, zvni); return -1; } @@ -8052,7 +8057,7 @@ int zebra_vxlan_local_mac_add_update(struct interface *ifp, zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id); if (!zvrf) { if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug("\tNo Vrf found for vrf_id: %d", + zlog_debug(" No Vrf found for vrf_id: %d", zvni->vxlan_if->vrf_id); return -1; } @@ -8105,7 +8110,7 @@ int zebra_vxlan_local_mac_add_update(struct interface *ifp, && mac->fwd_info.local.vid == vid) { if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug( - "\tAdd/Update %sMAC %s intf %s(%u) VID %u -> VNI %u, " + " Add/Update %sMAC %s intf %s(%u) VID %u -> VNI %u, " "entry exists and has not changed ", sticky ? "sticky " : "", prefix_mac2str(macaddr, buf, diff --git a/zebra/zebra_vxlan.h b/zebra/zebra_vxlan.h index 6ca93f6cb6..a5c13a59e3 100644 --- a/zebra/zebra_vxlan.h +++ b/zebra/zebra_vxlan.h @@ -199,9 +199,9 @@ extern void zebra_vxlan_cleanup_tables(struct zebra_vrf *); extern void zebra_vxlan_init(void); extern void zebra_vxlan_disable(void); extern void zebra_vxlan_evpn_vrf_route_add(vrf_id_t vrf_id, - struct ethaddr *rmac, - struct ipaddr *ip, - struct prefix *host_prefix); + const struct ethaddr *rmac, + const struct ipaddr *ip, + const struct prefix *host_prefix); extern void zebra_vxlan_evpn_vrf_route_del(vrf_id_t vrf_id, struct ipaddr *vtep_ip, struct prefix *host_prefix); diff --git a/zebra/zserv.h b/zebra/zserv.h index 6ab7fbd918..08df664d56 100644 --- a/zebra/zserv.h +++ b/zebra/zserv.h @@ -131,6 +131,9 @@ struct zserv { bool notify_owner; + /* Indicates if client is synchronous. */ + bool synchronous; + /* client's protocol */ uint8_t proto; uint16_t instance; |
