summaryrefslogtreecommitdiffstats
path: root/bgpd
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-08-05 09:56:23 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-08-05 09:56:23 +0000
commitc15d6efd40655f717841d00839a43df1ead5cb26 (patch)
tree35d579f9a19170e2b39085669ca92533c2d161b4 /bgpd
parentAdding upstream version 10.0.1. (diff)
downloadfrr-c15d6efd40655f717841d00839a43df1ead5cb26.tar.xz
frr-c15d6efd40655f717841d00839a43df1ead5cb26.zip
Adding upstream version 10.1.upstream/10.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'bgpd')
-rw-r--r--bgpd/bgp_addpath.h6
-rw-r--r--bgpd/bgp_advertise.c11
-rw-r--r--bgpd/bgp_advertise.h9
-rw-r--r--bgpd/bgp_aspath.c49
-rw-r--r--bgpd/bgp_aspath.h7
-rw-r--r--bgpd/bgp_attr.c206
-rw-r--r--bgpd/bgp_attr.h13
-rw-r--r--bgpd/bgp_bfd.c3
-rw-r--r--bgpd/bgp_bmp.c98
-rw-r--r--bgpd/bgp_bmp.h2
-rw-r--r--bgpd/bgp_clist.c44
-rw-r--r--bgpd/bgp_clist.h26
-rw-r--r--bgpd/bgp_damp.c516
-rw-r--r--bgpd/bgp_damp.h49
-rw-r--r--bgpd/bgp_debug.c15
-rw-r--r--bgpd/bgp_debug.h9
-rw-r--r--bgpd/bgp_ecommunity.c196
-rw-r--r--bgpd/bgp_ecommunity.h62
-rw-r--r--bgpd/bgp_evpn.c421
-rw-r--r--bgpd/bgp_evpn.h15
-rw-r--r--bgpd/bgp_evpn_mh.c193
-rw-r--r--bgpd/bgp_evpn_mh.h10
-rw-r--r--bgpd/bgp_evpn_private.h3
-rw-r--r--bgpd/bgp_filter.c41
-rw-r--r--bgpd/bgp_filter.h13
-rw-r--r--bgpd/bgp_fsm.c28
-rw-r--r--bgpd/bgp_fsm.h3
-rw-r--r--bgpd/bgp_label.c129
-rw-r--r--bgpd/bgp_label.h24
-rw-r--r--bgpd/bgp_mac.c12
-rw-r--r--bgpd/bgp_main.c8
-rw-r--r--bgpd/bgp_memory.c3
-rw-r--r--bgpd/bgp_memory.h3
-rw-r--r--bgpd/bgp_mpath.c36
-rw-r--r--bgpd/bgp_mplsvpn.c185
-rw-r--r--bgpd/bgp_mplsvpn.h10
-rw-r--r--bgpd/bgp_network.c12
-rw-r--r--bgpd/bgp_nexthop.c4
-rw-r--r--bgpd/bgp_nexthop.h1
-rw-r--r--bgpd/bgp_nht.c139
-rw-r--r--bgpd/bgp_open.c180
-rw-r--r--bgpd/bgp_open.h4
-rw-r--r--bgpd/bgp_packet.c307
-rw-r--r--bgpd/bgp_route.c1007
-rw-r--r--bgpd/bgp_route.h28
-rw-r--r--bgpd/bgp_routemap.c153
-rw-r--r--bgpd/bgp_routemap_nb_config.c6
-rw-r--r--bgpd/bgp_rpki.c211
-rw-r--r--bgpd/bgp_snmp_bgp4v2.c6
-rw-r--r--bgpd/bgp_table.c4
-rw-r--r--bgpd/bgp_table.h9
-rw-r--r--bgpd/bgp_trace.c2
-rw-r--r--bgpd/bgp_updgrp.c40
-rw-r--r--bgpd/bgp_updgrp.h1
-rw-r--r--bgpd/bgp_updgrp_adv.c52
-rw-r--r--bgpd/bgp_updgrp_packet.c25
-rw-r--r--bgpd/bgp_vty.c877
-rw-r--r--bgpd/bgp_vty.h2
-rw-r--r--bgpd/bgp_zebra.c535
-rw-r--r--bgpd/bgp_zebra.h15
-rw-r--r--bgpd/bgpd.c158
-rw-r--r--bgpd/bgpd.h45
-rw-r--r--bgpd/rfapi/rfapi.c14
-rw-r--r--bgpd/rfapi/rfapi_import.c20
-rw-r--r--bgpd/rfapi/rfapi_rib.c5
-rw-r--r--bgpd/rfapi/rfapi_vty.c14
-rw-r--r--bgpd/rfapi/vnc_import_bgp.c127
67 files changed, 4518 insertions, 1943 deletions
diff --git a/bgpd/bgp_addpath.h b/bgpd/bgp_addpath.h
index d562000..c267ebe 100644
--- a/bgpd/bgp_addpath.h
+++ b/bgpd/bgp_addpath.h
@@ -21,6 +21,12 @@ struct bgp_addpath_capability {
uint8_t flags;
};
+struct bgp_paths_limit_capability {
+ uint16_t afi;
+ uint8_t safi;
+ uint16_t paths_limit;
+} __attribute__((packed));
+
#define BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE 1
void bgp_addpath_init_bgp_data(struct bgp_addpath_bgp_data *d);
diff --git a/bgpd/bgp_advertise.c b/bgpd/bgp_advertise.c
index a81f288..d5c7e18 100644
--- a/bgpd/bgp_advertise.c
+++ b/bgpd/bgp_advertise.c
@@ -163,7 +163,7 @@ bool bgp_adj_out_lookup(struct peer *peer, struct bgp_dest *dest,
void bgp_adj_in_set(struct bgp_dest *dest, struct peer *peer, struct attr *attr,
- uint32_t addpath_id)
+ uint32_t addpath_id, struct bgp_labels *labels)
{
struct bgp_adj_in *adj;
@@ -173,6 +173,10 @@ void bgp_adj_in_set(struct bgp_dest *dest, struct peer *peer, struct attr *attr,
bgp_attr_unintern(&adj->attr);
adj->attr = bgp_attr_intern(attr);
}
+ if (!bgp_labels_cmp(adj->labels, labels)) {
+ bgp_labels_unintern(&adj->labels);
+ adj->labels = bgp_labels_intern(labels);
+ }
return;
}
}
@@ -181,13 +185,18 @@ void bgp_adj_in_set(struct bgp_dest *dest, struct peer *peer, struct attr *attr,
adj->attr = bgp_attr_intern(attr);
adj->uptime = monotime(NULL);
adj->addpath_rx_id = addpath_id;
+ adj->labels = bgp_labels_intern(labels);
BGP_ADJ_IN_ADD(dest, adj);
+ peer->stat_pfx_adj_rib_in++;
bgp_dest_lock_node(dest);
}
void bgp_adj_in_remove(struct bgp_dest **dest, struct bgp_adj_in *bai)
{
bgp_attr_unintern(&bai->attr);
+ bgp_labels_unintern(&bai->labels);
+ if (bai->peer)
+ bai->peer->stat_pfx_adj_rib_in--;
BGP_ADJ_IN_DEL(*dest, bai);
*dest = bgp_dest_unlock_node(*dest);
peer_unlock(bai->peer); /* adj_in peer reference */
diff --git a/bgpd/bgp_advertise.h b/bgpd/bgp_advertise.h
index 4982106..8c83189 100644
--- a/bgpd/bgp_advertise.h
+++ b/bgpd/bgp_advertise.h
@@ -75,6 +75,9 @@ struct bgp_adj_out {
/* Advertised attribute. */
struct attr *attr;
+ /* VPN label information */
+ struct bgp_labels *labels;
+
/* Advertisement information. */
struct bgp_advertise *adv;
};
@@ -95,6 +98,9 @@ struct bgp_adj_in {
/* Received attribute. */
struct attr *attr;
+ /* VPN label information */
+ struct bgp_labels *labels;
+
/* timestamp (monotime) */
time_t uptime;
@@ -135,7 +141,8 @@ struct bgp_synchronize {
extern bool bgp_adj_out_lookup(struct peer *peer, struct bgp_dest *dest,
uint32_t addpath_tx_id);
extern void bgp_adj_in_set(struct bgp_dest *dest, struct peer *peer,
- struct attr *attr, uint32_t addpath_id);
+ struct attr *attr, uint32_t addpath_id,
+ struct bgp_labels *labels);
extern bool bgp_adj_in_unset(struct bgp_dest **dest, struct peer *peer,
uint32_t addpath_id);
extern void bgp_adj_in_remove(struct bgp_dest **dest, struct bgp_adj_in *bai);
diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c
index bc7e893..4c1615a 100644
--- a/bgpd/bgp_aspath.c
+++ b/bgpd/bgp_aspath.c
@@ -77,6 +77,9 @@ static struct hash *ashash;
/* Stream for SNMP. See aspath_snmp_pathseg */
static struct stream *snmp_stream;
+/* as-path orphan exclude list */
+static struct as_list_list_head as_exclude_list_orphan;
+
/* Callers are required to initialize the memory */
static as_t *assegment_data_new(int num)
{
@@ -1558,6 +1561,38 @@ struct aspath *aspath_prepend(struct aspath *as1, struct aspath *as2)
/* Not reached */
}
+/* insert aspath exclude in head of orphan exclude list*/
+void as_exclude_set_orphan(struct aspath_exclude *ase)
+{
+ ase->exclude_aspath_acl = NULL;
+ as_list_list_add_head(&as_exclude_list_orphan, ase);
+}
+
+void as_exclude_remove_orphan(struct aspath_exclude *ase)
+{
+ if (as_list_list_count(&as_exclude_list_orphan))
+ as_list_list_del(&as_exclude_list_orphan, ase);
+}
+
+/* currently provide only one exclude, not a list */
+struct aspath_exclude *as_exclude_lookup_orphan(const char *acl_name)
+{
+ struct aspath_exclude *ase = NULL;
+ char *name = NULL;
+
+ frr_each (as_list_list, &as_exclude_list_orphan, ase) {
+ if (ase->exclude_aspath_acl_name) {
+ name = ase->exclude_aspath_acl_name;
+ if (!strcmp(name, acl_name))
+ break;
+ }
+ }
+ if (ase)
+ as_exclude_remove_orphan(ase);
+
+ return ase;
+}
+
/* Iterate over AS_PATH segments and wipe all occurrences of the
* listed AS numbers. Hence some segments may lose some or even
* all data on the way, the operation is implemented as a smarter
@@ -2236,20 +2271,32 @@ void aspath_init(void)
{
ashash = hash_create_size(32768, aspath_key_make, aspath_cmp,
"BGP AS Path");
+
+ as_list_list_init(&as_exclude_list_orphan);
}
void aspath_finish(void)
{
+ struct aspath_exclude *ase;
+
hash_clean_and_free(&ashash, (void (*)(void *))aspath_free);
if (snmp_stream)
stream_free(snmp_stream);
+
+ while ((ase = as_list_list_pop(&as_exclude_list_orphan))) {
+ aspath_free(ase->aspath);
+ if (ase->exclude_aspath_acl_name)
+ XFREE(MTYPE_TMP, ase->exclude_aspath_acl_name);
+ XFREE(MTYPE_ROUTE_MAP_COMPILED, ase);
+ }
+ as_list_list_fini(&as_exclude_list_orphan);
}
/* return and as path value */
const char *aspath_print(struct aspath *as)
{
- return (as ? as->str : NULL);
+ return as ? as->str : "(null)";
}
/* Printing functions */
diff --git a/bgpd/bgp_aspath.h b/bgpd/bgp_aspath.h
index 2a831c3..f7e57fd 100644
--- a/bgpd/bgp_aspath.h
+++ b/bgpd/bgp_aspath.h
@@ -9,6 +9,7 @@
#include "lib/json.h"
#include "bgpd/bgp_route.h"
#include "bgpd/bgp_filter.h"
+#include <typesafe.h>
/* AS path segment type. */
#define AS_SET 1
@@ -67,11 +68,14 @@ struct aspath {
/* `set as-path exclude ASn' */
struct aspath_exclude {
+ struct as_list_list_item exclude_list;
struct aspath *aspath;
bool exclude_all;
char *exclude_aspath_acl_name;
struct as_list *exclude_aspath_acl;
};
+DECLARE_DLIST(as_list_list, struct aspath_exclude, exclude_list);
+
/* Prototypes. */
extern void aspath_init(void);
@@ -83,6 +87,9 @@ extern struct aspath *aspath_parse(struct stream *s, size_t length,
extern struct aspath *aspath_dup(struct aspath *aspath);
extern struct aspath *aspath_aggregate(struct aspath *as1, struct aspath *as2);
extern struct aspath *aspath_prepend(struct aspath *as1, struct aspath *as2);
+extern void as_exclude_set_orphan(struct aspath_exclude *ase);
+extern void as_exclude_remove_orphan(struct aspath_exclude *ase);
+extern struct aspath_exclude *as_exclude_lookup_orphan(const char *acl_name);
extern struct aspath *aspath_filter_exclude(struct aspath *source,
struct aspath *exclude_list);
extern struct aspath *aspath_filter_exclude_all(struct aspath *source);
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
index 40e074d..e4ee589 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -911,9 +911,17 @@ static void attr_show_all_iterator(struct hash_bucket *bucket, struct vty *vty)
vty_out(vty,
"\tflags: %" PRIu64
- " distance: %u med: %u local_pref: %u origin: %u weight: %u label: %u sid: %pI6\n",
+ " distance: %u med: %u local_pref: %u origin: %u weight: %u label: %u sid: %pI6 aigp_metric: %" PRIu64
+ "\n",
attr->flag, attr->distance, attr->med, attr->local_pref,
- attr->origin, attr->weight, attr->label, sid);
+ attr->origin, attr->weight, attr->label, sid, attr->aigp_metric);
+ vty_out(vty, "\taspath: %s Community: %s Large Community: %s\n",
+ aspath_print(attr->aspath),
+ community_str(attr->community, false, false),
+ lcommunity_str(attr->lcommunity, false, false));
+ vty_out(vty, "\tExtended Community: %s Extended IPv6 Community: %s\n",
+ ecommunity_str(attr->ecommunity),
+ ecommunity_str(attr->ipv6_ecommunity));
}
void attr_show_all(struct vty *vty)
@@ -2368,6 +2376,12 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args,
return BGP_ATTR_PARSE_WITHDRAW;
}
attr->nh_ifindex = peer->nexthop.ifp->ifindex;
+ if (if_is_operative(peer->nexthop.ifp))
+ SET_FLAG(attr->nh_flags,
+ BGP_ATTR_NH_IF_OPERSTATE);
+ else
+ UNSET_FLAG(attr->nh_flags,
+ BGP_ATTR_NH_IF_OPERSTATE);
}
break;
case BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL:
@@ -2385,6 +2399,12 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args,
return BGP_ATTR_PARSE_WITHDRAW;
}
attr->nh_ifindex = peer->nexthop.ifp->ifindex;
+ if (if_is_operative(peer->nexthop.ifp))
+ SET_FLAG(attr->nh_flags,
+ BGP_ATTR_NH_IF_OPERSTATE);
+ else
+ UNSET_FLAG(attr->nh_flags,
+ BGP_ATTR_NH_IF_OPERSTATE);
}
if (attr->mp_nexthop_len
== BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL) {
@@ -2640,10 +2660,7 @@ bgp_attr_ipv6_ext_communities(struct bgp_attr_parser_args *args)
if (peer->discard_attrs[args->type] || peer->withdraw_attrs[args->type])
goto ipv6_ext_community_ignore;
- ipv6_ecomm = ecommunity_parse_ipv6(
- stream_pnt(peer->curr), length,
- CHECK_FLAG(peer->flags,
- PEER_FLAG_DISABLE_LINK_BW_ENCODING_IEEE));
+ ipv6_ecomm = ecommunity_parse_ipv6(stream_pnt(peer->curr), length);
bgp_attr_set_ipv6_ecommunity(attr, ipv6_ecomm);
/* XXX: fix ecommunity_parse to use stream API */
@@ -2653,6 +2670,10 @@ bgp_attr_ipv6_ext_communities(struct bgp_attr_parser_args *args)
return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
args->total);
+ /* Extract link bandwidth, if any. */
+ (void)ecommunity_linkbw_present(bgp_attr_get_ipv6_ecommunity(attr),
+ &attr->link_bw);
+
return BGP_ATTR_PARSE_PROCEED;
ipv6_ext_community_ignore:
@@ -2700,17 +2721,20 @@ static int bgp_attr_encap(struct bgp_attr_parser_args *args)
}
}
- while (length >= 4) {
+ while (STREAM_READABLE(BGP_INPUT(peer)) >= 4) {
uint16_t subtype = 0;
uint16_t sublength = 0;
struct bgp_attr_encap_subtlv *tlv;
if (BGP_ATTR_ENCAP == type) {
subtype = stream_getc(BGP_INPUT(peer));
- sublength = (subtype < 128)
- ? stream_getc(BGP_INPUT(peer))
- : stream_getw(BGP_INPUT(peer));
- length -= 2;
+ if (subtype < 128) {
+ sublength = stream_getc(BGP_INPUT(peer));
+ length -= 2;
+ } else {
+ sublength = stream_getw(BGP_INPUT(peer));
+ length -= 3;
+ }
#ifdef ENABLE_BGP_VNC
} else {
subtype = stream_getw(BGP_INPUT(peer));
@@ -2727,6 +2751,14 @@ static int bgp_attr_encap(struct bgp_attr_parser_args *args)
args->total);
}
+ if (STREAM_READABLE(BGP_INPUT(peer)) < sublength) {
+ zlog_err("Tunnel Encap attribute sub-tlv length %d exceeds remaining stream length %zu",
+ sublength, STREAM_READABLE(BGP_INPUT(peer)));
+ return bgp_attr_malformed(args,
+ BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
+ args->total);
+ }
+
/* alloc and copy sub-tlv */
/* TBD make sure these are freed when attributes are released */
tlv = XCALLOC(MTYPE_ENCAP_TLV,
@@ -4137,7 +4169,7 @@ 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,
const struct prefix *p,
const struct prefix_rd *prd, mpls_label_t *label,
- uint32_t num_labels, bool addpath_capable,
+ uint8_t num_labels, bool addpath_capable,
uint32_t addpath_tx_id, struct attr *attr)
{
switch (safi) {
@@ -4344,13 +4376,76 @@ static bool bgp_append_local_as(struct peer *peer, afi_t afi, safi_t safi)
return false;
}
+static void bgp_packet_ecommunity_attribute(struct stream *s, struct peer *peer,
+ struct ecommunity *ecomm,
+ bool transparent, int attribute)
+{
+ if (peer->sort == BGP_PEER_IBGP || peer->sort == BGP_PEER_CONFED ||
+ peer->sub_sort == BGP_PEER_EBGP_OAD || transparent) {
+ if (ecomm->size * ecomm->unit_size > 255) {
+ stream_putc(s, BGP_ATTR_FLAG_OPTIONAL |
+ BGP_ATTR_FLAG_TRANS |
+ BGP_ATTR_FLAG_EXTLEN);
+ stream_putc(s, attribute);
+ stream_putw(s, ecomm->size * ecomm->unit_size);
+ } else {
+ stream_putc(s, BGP_ATTR_FLAG_OPTIONAL |
+ BGP_ATTR_FLAG_TRANS);
+ stream_putc(s, attribute);
+ stream_putc(s, ecomm->size * ecomm->unit_size);
+ }
+ stream_put(s, ecomm->val, ecomm->size * ecomm->unit_size);
+ } else {
+ uint8_t *pnt;
+ int tbit;
+ int ecom_tr_size = 0;
+ uint32_t i;
+
+ for (i = 0; i < ecomm->size; i++) {
+ pnt = ecomm->val + (i * ecomm->unit_size);
+ tbit = *pnt;
+
+ if (CHECK_FLAG(tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
+ continue;
+
+ ecom_tr_size++;
+ }
+
+ if (ecom_tr_size) {
+ if (ecom_tr_size * ecomm->unit_size > 255) {
+ stream_putc(s, BGP_ATTR_FLAG_OPTIONAL |
+ BGP_ATTR_FLAG_TRANS |
+ BGP_ATTR_FLAG_EXTLEN);
+ stream_putc(s, attribute);
+ stream_putw(s, ecom_tr_size * ecomm->unit_size);
+ } else {
+ stream_putc(s, BGP_ATTR_FLAG_OPTIONAL |
+ BGP_ATTR_FLAG_TRANS);
+ stream_putc(s, attribute);
+ stream_putc(s, ecom_tr_size * ecomm->unit_size);
+ }
+
+ for (i = 0; i < ecomm->size; i++) {
+ pnt = ecomm->val + (i * ecomm->unit_size);
+ tbit = *pnt;
+
+ if (CHECK_FLAG(tbit,
+ ECOMMUNITY_FLAG_NON_TRANSITIVE))
+ continue;
+
+ stream_put(s, pnt, ecomm->unit_size);
+ }
+ }
+ }
+}
+
/* Make attribute packet. */
bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
struct stream *s, struct attr *attr,
struct bpacket_attr_vec_arr *vecarr,
struct prefix *p, afi_t afi, safi_t safi,
struct peer *from, struct prefix_rd *prd,
- mpls_label_t *label, uint32_t num_labels,
+ mpls_label_t *label, uint8_t num_labels,
bool addpath_capable, uint32_t addpath_tx_id,
struct bgp_path_info *bpi)
{
@@ -4646,82 +4741,31 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
}
}
- /* Extended Communities attribute. */
- if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
- && (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES))) {
- struct ecommunity *ecomm = bgp_attr_get_ecommunity(attr);
+ /* Extended IPv6/Communities attributes. */
+ if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)) {
bool transparent = CHECK_FLAG(peer->af_flags[afi][safi],
PEER_FLAG_RSERVER_CLIENT) &&
from &&
CHECK_FLAG(from->af_flags[afi][safi],
PEER_FLAG_RSERVER_CLIENT);
- if (peer->sort == BGP_PEER_IBGP ||
- peer->sort == BGP_PEER_CONFED || transparent) {
- if (ecomm->size * 8 > 255) {
- stream_putc(s,
- BGP_ATTR_FLAG_OPTIONAL
- | BGP_ATTR_FLAG_TRANS
- | BGP_ATTR_FLAG_EXTLEN);
- stream_putc(s, BGP_ATTR_EXT_COMMUNITIES);
- stream_putw(s, ecomm->size * 8);
- } else {
- stream_putc(s,
- BGP_ATTR_FLAG_OPTIONAL
- | BGP_ATTR_FLAG_TRANS);
- stream_putc(s, BGP_ATTR_EXT_COMMUNITIES);
- stream_putc(s, ecomm->size * 8);
- }
- stream_put(s, ecomm->val, ecomm->size * 8);
- } else {
- uint8_t *pnt;
- int tbit;
- int ecom_tr_size = 0;
- uint32_t i;
-
- for (i = 0; i < ecomm->size; i++) {
- pnt = ecomm->val + (i * 8);
- tbit = *pnt;
+ if (CHECK_FLAG(attr->flag,
+ ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES))) {
+ struct ecommunity *ecomm = bgp_attr_get_ecommunity(attr);
- if (CHECK_FLAG(tbit,
- ECOMMUNITY_FLAG_NON_TRANSITIVE))
- continue;
+ bgp_packet_ecommunity_attribute(s, peer, ecomm,
+ transparent,
+ BGP_ATTR_EXT_COMMUNITIES);
+ }
- ecom_tr_size++;
- }
+ if (CHECK_FLAG(attr->flag,
+ ATTR_FLAG_BIT(BGP_ATTR_IPV6_EXT_COMMUNITIES))) {
+ struct ecommunity *ecomm =
+ bgp_attr_get_ipv6_ecommunity(attr);
- if (ecom_tr_size) {
- if (ecom_tr_size * 8 > 255) {
- stream_putc(
- s,
- BGP_ATTR_FLAG_OPTIONAL
- | BGP_ATTR_FLAG_TRANS
- | BGP_ATTR_FLAG_EXTLEN);
- stream_putc(s,
- BGP_ATTR_EXT_COMMUNITIES);
- stream_putw(s, ecom_tr_size * 8);
- } else {
- stream_putc(
- s,
- BGP_ATTR_FLAG_OPTIONAL
- | BGP_ATTR_FLAG_TRANS);
- stream_putc(s,
- BGP_ATTR_EXT_COMMUNITIES);
- stream_putc(s, ecom_tr_size * 8);
- }
-
- for (i = 0; i < ecomm->size; i++) {
- pnt = ecomm->val + (i * 8);
- tbit = *pnt;
-
- if (CHECK_FLAG(
- tbit,
- ECOMMUNITY_FLAG_NON_TRANSITIVE))
- continue;
-
- stream_put(s, pnt, 8);
- }
- }
+ bgp_packet_ecommunity_attribute(s, peer, ecomm,
+ transparent,
+ BGP_ATTR_IPV6_EXT_COMMUNITIES);
}
}
@@ -4930,7 +4974,7 @@ size_t bgp_packet_mpunreach_start(struct stream *s, afi_t afi, safi_t safi)
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,
+ mpls_label_t *label, uint8_t num_labels,
bool addpath_capable, uint32_t addpath_tx_id,
struct attr *attr)
{
diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h
index d78f04c..f353e76 100644
--- a/bgpd/bgp_attr.h
+++ b/bgpd/bgp_attr.h
@@ -158,6 +158,8 @@ struct attr {
uint8_t nh_flags;
#define BGP_ATTR_NH_VALID 0x01
+#define BGP_ATTR_NH_IF_OPERSTATE 0x02
+#define BGP_ATTR_NH_MP_PREFER_GLOBAL 0x04 /* MP Nexthop preference */
/* Path origin attribute */
uint8_t origin;
@@ -254,9 +256,6 @@ struct attr {
/* MP Nexthop length */
uint8_t mp_nexthop_len;
- /* MP Nexthop preference */
- uint8_t mp_nexthop_prefer_global;
-
/* Static MAC for EVPN */
uint8_t sticky;
@@ -302,7 +301,7 @@ struct attr {
uint32_t rmap_table_id;
/* Link bandwidth value, if any. */
- uint32_t link_bw;
+ uint64_t link_bw;
/* EVPN ES */
esi_t esi;
@@ -394,7 +393,7 @@ extern bgp_size_t bgp_packet_attribute(
struct bgp *bgp, struct peer *peer, struct stream *s, struct attr *attr,
struct bpacket_attr_vec_arr *vecarr, struct prefix *p, afi_t afi,
safi_t safi, struct peer *from, struct prefix_rd *prd,
- mpls_label_t *label, uint32_t num_labels, bool addpath_capable,
+ mpls_label_t *label, uint8_t num_labels, bool addpath_capable,
uint32_t addpath_tx_id, struct bgp_path_info *bpi);
extern void bgp_dump_routes_attr(struct stream *s, struct bgp_path_info *bpi,
const struct prefix *p);
@@ -452,7 +451,7 @@ extern size_t bgp_packet_mpattr_start(struct stream *s, struct peer *peer,
extern void bgp_packet_mpattr_prefix(struct stream *s, afi_t afi, safi_t safi,
const struct prefix *p,
const struct prefix_rd *prd,
- mpls_label_t *label, uint32_t num_labels,
+ mpls_label_t *label, uint8_t num_labels,
bool addpath_capable,
uint32_t addpath_tx_id, struct attr *);
extern size_t bgp_packet_mpattr_prefix_size(afi_t afi, safi_t safi,
@@ -463,7 +462,7 @@ 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, const struct prefix *p, afi_t afi, safi_t safi,
- const struct prefix_rd *prd, mpls_label_t *label, uint32_t num_labels,
+ const struct prefix_rd *prd, mpls_label_t *label, uint8_t num_labels,
bool addpath_capable, uint32_t addpath_tx_id, struct attr *attr);
extern void bgp_packet_mpunreach_end(struct stream *s, size_t attrlen_pnt);
diff --git a/bgpd/bgp_bfd.c b/bgpd/bgp_bfd.c
index 21864cf..14ff5f2 100644
--- a/bgpd/bgp_bfd.c
+++ b/bgpd/bgp_bfd.c
@@ -597,6 +597,9 @@ DEFUN(no_neighbor_bfd_profile, no_neighbor_bfd_profile_cmd,
if (!peer)
return CMD_WARNING_CONFIG_FAILED;
+ if (!peer->bfd_config)
+ return CMD_SUCCESS;
+
if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP))
bgp_group_configure_bfd(peer);
else
diff --git a/bgpd/bgp_bmp.c b/bgpd/bgp_bmp.c
index 1de48a0..43f8006 100644
--- a/bgpd/bgp_bmp.c
+++ b/bgpd/bgp_bmp.c
@@ -38,6 +38,7 @@
#include "bgpd/bgp_vty.h"
#include "bgpd/bgp_trace.h"
#include "bgpd/bgp_network.h"
+#include "bgpd/bgp_label.h"
static void bmp_close(struct bmp *bmp);
static struct bmp_bgp *bmp_bgp_find(struct bgp *bgp);
@@ -391,11 +392,11 @@ static int bmp_send_initiation(struct bmp *bmp)
bmp_common_hdr(s, BMP_VERSION_3, BMP_TYPE_INITIATION);
-#define BMP_INFO_TYPE_SYSDESCR 1
-#define BMP_INFO_TYPE_SYSNAME 2
- bmp_put_info_tlv(s, BMP_INFO_TYPE_SYSDESCR,
- FRR_FULL_NAME " " FRR_VER_SHORT);
- bmp_put_info_tlv(s, BMP_INFO_TYPE_SYSNAME, cmd_hostname_get());
+#define BMP_INIT_INFO_TYPE_SYSDESCR 1
+#define BMP_INIT_INFO_TYPE_SYSNAME 2
+ bmp_put_info_tlv(s, BMP_INIT_INFO_TYPE_SYSDESCR,
+ FRR_FULL_NAME " " FRR_VER_SHORT);
+ bmp_put_info_tlv(s, BMP_INIT_INFO_TYPE_SYSNAME, cmd_hostname_get());
len = stream_get_endp(s);
stream_putl_at(s, BMP_LENGTH_POS, len); /* message length is set. */
@@ -438,6 +439,7 @@ static struct stream *bmp_peerstate(struct peer *peer, bool down)
monotime_to_realtime(&uptime, &uptime_real);
#define BGP_BMP_MAX_PACKET_SIZE 1024
+#define BMP_PEERUP_INFO_TYPE_STRING 0
s = stream_new(BGP_MAX_PACKET_SIZE);
if (peer_established(peer->connection) && !down) {
@@ -493,7 +495,8 @@ static struct stream *bmp_peerstate(struct peer *peer, bool down)
}
if (peer->desc)
- bmp_put_info_tlv(s, 0, peer->desc);
+ bmp_put_info_tlv(s, BMP_PEERUP_INFO_TYPE_STRING,
+ peer->desc);
} else {
uint8_t type;
size_t type_pos;
@@ -910,7 +913,8 @@ static void bmp_eor(struct bmp *bmp, afi_t afi, safi_t safi, uint8_t flags,
static struct stream *bmp_update(const struct prefix *p, struct prefix_rd *prd,
struct peer *peer, struct attr *attr,
- afi_t afi, safi_t safi)
+ afi_t afi, safi_t safi, mpls_label_t *label,
+ uint32_t num_labels)
{
struct bpacket_attr_vec_arr vecarr;
struct stream *s;
@@ -946,8 +950,8 @@ static struct stream *bmp_update(const struct prefix *p, struct prefix_rd *prd,
mpattrlen_pos = bgp_packet_mpattr_start(s, peer, afi, safi,
&vecarr, attr);
- bgp_packet_mpattr_prefix(s, afi, safi, p, prd, NULL, 0, 0, 0,
- attr);
+ bgp_packet_mpattr_prefix(s, afi, safi, p, prd, label,
+ num_labels, 0, 0, attr);
bgp_packet_mpattr_end(s, mpattrlen_pos);
total_attr_len += stream_get_endp(s) - p1;
}
@@ -1002,7 +1006,8 @@ static struct stream *bmp_withdraw(const struct prefix *p,
static void bmp_monitor(struct bmp *bmp, struct peer *peer, uint8_t flags,
uint8_t peer_type_flag, const struct prefix *p,
struct prefix_rd *prd, struct attr *attr, afi_t afi,
- safi_t safi, time_t uptime)
+ safi_t safi, time_t uptime, mpls_label_t *label,
+ uint32_t num_labels)
{
struct stream *hdr, *msg;
struct timeval tv = { .tv_sec = uptime, .tv_usec = 0 };
@@ -1019,7 +1024,8 @@ static void bmp_monitor(struct bmp *bmp, struct peer *peer, uint8_t flags,
monotime_to_realtime(&tv, &uptime_real);
if (attr)
- msg = bmp_update(p, prd, peer, attr, afi, safi);
+ msg = bmp_update(p, prd, peer, attr, afi, safi, label,
+ num_labels);
else
msg = bmp_withdraw(p, prd, afi, safi);
@@ -1041,6 +1047,7 @@ static void bmp_monitor(struct bmp *bmp, struct peer *peer, uint8_t flags,
static bool bmp_wrsync(struct bmp *bmp, struct pullwr *pullwr)
{
+ uint8_t bpi_num_labels;
afi_t afi;
safi_t safi;
@@ -1214,23 +1221,31 @@ afibreak:
(safi == SAFI_MPLS_VPN))
prd = (struct prefix_rd *)bgp_dest_get_prefix(bmp->syncrdpos);
+ bpi_num_labels = bgp_path_info_num_labels(bpi);
+
if (bpi && CHECK_FLAG(bpi->flags, BGP_PATH_SELECTED) &&
CHECK_FLAG(bmp->targets->afimon[afi][safi], BMP_MON_LOC_RIB)) {
bmp_monitor(bmp, bpi->peer, 0, BMP_PEER_TYPE_LOC_RIB_INSTANCE,
bn_p, prd, bpi->attr, afi, safi,
bpi && bpi->extra ? bpi->extra->bgp_rib_uptime
- : (time_t)(-1L));
+ : (time_t)(-1L),
+ bpi_num_labels ? bpi->extra->labels->label : NULL,
+ bpi_num_labels);
}
if (bpi && CHECK_FLAG(bpi->flags, BGP_PATH_VALID) &&
CHECK_FLAG(bmp->targets->afimon[afi][safi], BMP_MON_POSTPOLICY))
bmp_monitor(bmp, bpi->peer, BMP_PEER_FLAG_L,
BMP_PEER_TYPE_GLOBAL_INSTANCE, bn_p, prd, bpi->attr,
- afi, safi, bpi->uptime);
+ afi, safi, bpi->uptime,
+ bpi_num_labels ? bpi->extra->labels->label : NULL,
+ bpi_num_labels);
if (adjin)
+ /* TODO: set label here when adjin supports labels */
bmp_monitor(bmp, adjin->peer, 0, BMP_PEER_TYPE_GLOBAL_INSTANCE,
- bn_p, prd, adjin->attr, afi, safi, adjin->uptime);
+ bn_p, prd, adjin->attr, afi, safi, adjin->uptime,
+ NULL, 0);
if (bn)
bgp_dest_unlock_node(bn);
@@ -1281,6 +1296,7 @@ static bool bmp_wrqueue_locrib(struct bmp *bmp, struct pullwr *pullwr)
struct peer *peer;
struct bgp_dest *bn = NULL;
bool written = false;
+ uint8_t bpi_num_labels;
bqe = bmp_pull_locrib(bmp);
if (!bqe)
@@ -1340,10 +1356,14 @@ static bool bmp_wrqueue_locrib(struct bmp *bmp, struct pullwr *pullwr)
break;
}
+ bpi_num_labels = bgp_path_info_num_labels(bpi);
+
bmp_monitor(bmp, peer, 0, BMP_PEER_TYPE_LOC_RIB_INSTANCE, &bqe->p, prd,
bpi ? bpi->attr : NULL, afi, safi,
bpi && bpi->extra ? bpi->extra->bgp_rib_uptime
- : (time_t)(-1L));
+ : (time_t)(-1L),
+ bpi_num_labels ? bpi->extra->labels->label : NULL,
+ bpi_num_labels);
written = true;
out:
@@ -1362,6 +1382,7 @@ static bool bmp_wrqueue(struct bmp *bmp, struct pullwr *pullwr)
struct peer *peer;
struct bgp_dest *bn = NULL;
bool written = false;
+ uint8_t bpi_num_labels;
bqe = bmp_pull(bmp);
if (!bqe)
@@ -1413,10 +1434,14 @@ static bool bmp_wrqueue(struct bmp *bmp, struct pullwr *pullwr)
break;
}
+ bpi_num_labels = bgp_path_info_num_labels(bpi);
+
bmp_monitor(bmp, peer, BMP_PEER_FLAG_L,
BMP_PEER_TYPE_GLOBAL_INSTANCE, &bqe->p, prd,
bpi ? bpi->attr : NULL, afi, safi,
- bpi ? bpi->uptime : monotime(NULL));
+ bpi ? bpi->uptime : monotime(NULL),
+ bpi_num_labels ? bpi->extra->labels->label : NULL,
+ bpi_num_labels);
written = true;
}
@@ -1428,9 +1453,10 @@ static bool bmp_wrqueue(struct bmp *bmp, struct pullwr *pullwr)
if (adjin->peer == peer)
break;
}
+ /* TODO: set label here when adjin supports labels */
bmp_monitor(bmp, peer, 0, BMP_PEER_TYPE_GLOBAL_INSTANCE,
&bqe->p, prd, adjin ? adjin->attr : NULL, afi, safi,
- adjin ? adjin->uptime : monotime(NULL));
+ adjin ? adjin->uptime : monotime(NULL), NULL, 0);
written = true;
}
@@ -1578,6 +1604,15 @@ static void bmp_stat_put_u32(struct stream *s, size_t *cnt, uint16_t type,
(*cnt)++;
}
+static void bmp_stat_put_u64(struct stream *s, size_t *cnt, uint16_t type,
+ uint64_t value)
+{
+ stream_putw(s, type);
+ stream_putw(s, 8);
+ stream_putq(s, value);
+ (*cnt)++;
+}
+
static void bmp_stats(struct event *thread)
{
struct bmp_targets *bt = EVENT_ARG(thread);
@@ -1619,8 +1654,13 @@ static void bmp_stats(struct event *thread)
peer->stat_pfx_dup_withdraw);
bmp_stat_put_u32(s, &count, BMP_STATS_UPD_7606_WITHDRAW,
peer->stat_upd_7606);
- bmp_stat_put_u32(s, &count, BMP_STATS_FRR_NH_INVALID,
- peer->stat_pfx_nh_invalid);
+ if (bt->stats_send_experimental)
+ bmp_stat_put_u32(s, &count, BMP_STATS_FRR_NH_INVALID,
+ peer->stat_pfx_nh_invalid);
+ bmp_stat_put_u64(s, &count, BMP_STATS_SIZE_ADJ_RIB_IN,
+ peer->stat_pfx_adj_rib_in);
+ bmp_stat_put_u64(s, &count, BMP_STATS_SIZE_LOC_RIB,
+ peer->stat_pfx_loc_rib);
stream_putl_at(s, count_pos, count);
@@ -1875,6 +1915,7 @@ static struct bmp_targets *bmp_targets_get(struct bgp *bgp, const char *name)
bt->name = XSTRDUP(MTYPE_BMP_TARGETSNAME, name);
bt->bgp = bgp;
bt->bmpbgp = bmp_bgp_get(bgp);
+ bt->stats_send_experimental = true;
bmp_session_init(&bt->sessions);
bmp_qhash_init(&bt->updhash);
bmp_qlist_init(&bt->updlist);
@@ -2455,6 +2496,21 @@ DEFPY(bmp_stats_cfg,
return CMD_SUCCESS;
}
+DEFPY(bmp_stats_send_experimental,
+ bmp_stats_send_experimental_cmd,
+ "[no] bmp stats send-experimental",
+ NO_STR
+ BMP_STR
+ "Send BMP statistics messages\n"
+ "Send experimental BMP stats [65531-65534]\n")
+{
+ VTY_DECLVAR_CONTEXT_SUB(bmp_targets, bt);
+
+ bt->stats_send_experimental = !no;
+
+ return CMD_SUCCESS;
+}
+
#define BMP_POLICY_IS_LOCRIB(str) ((str)[0] == 'l') /* __l__oc-rib */
#define BMP_POLICY_IS_PRE(str) ((str)[1] == 'r') /* p__r__e-policy */
@@ -2747,6 +2803,9 @@ static int bmp_config_write(struct bgp *bgp, struct vty *vty)
if (bt->acl_name)
vty_out(vty, " ip access-list %s\n", bt->acl_name);
+ if (!bt->stats_send_experimental)
+ vty_out(vty, " no bmp stats send-experimental\n");
+
if (bt->stat_msec)
vty_out(vty, " bmp stats interval %d\n",
bt->stat_msec);
@@ -2802,6 +2861,7 @@ static int bgp_bmp_init(struct event_loop *tm)
install_element(BMP_NODE, &no_bmp_listener_cmd);
install_element(BMP_NODE, &bmp_connect_cmd);
install_element(BMP_NODE, &bmp_acl_cmd);
+ install_element(BMP_NODE, &bmp_stats_send_experimental_cmd);
install_element(BMP_NODE, &bmp_stats_cmd);
install_element(BMP_NODE, &bmp_monitor_cmd);
install_element(BMP_NODE, &bmp_mirror_cmd);
diff --git a/bgpd/bgp_bmp.h b/bgpd/bgp_bmp.h
index dadd99e..33247c4 100644
--- a/bgpd/bgp_bmp.h
+++ b/bgpd/bgp_bmp.h
@@ -240,6 +240,8 @@ struct bmp_targets {
uint64_t cnt_accept, cnt_aclrefused;
+ bool stats_send_experimental;
+
QOBJ_FIELDS;
};
DECLARE_QOBJ_TYPE(bmp_targets);
diff --git a/bgpd/bgp_clist.c b/bgpd/bgp_clist.c
index 8336d6f..153cbd6 100644
--- a/bgpd/bgp_clist.c
+++ b/bgpd/bgp_clist.c
@@ -904,9 +904,9 @@ int community_list_set(struct community_list_handler *ch, const char *name,
}
/* Unset community-list */
-int community_list_unset(struct community_list_handler *ch, const char *name,
- const char *str, const char *seq, int direct,
- int style)
+void community_list_unset(struct community_list_handler *ch, const char *name,
+ const char *str, const char *seq, int direct,
+ int style)
{
struct community_list_master *cm = NULL;
struct community_entry *entry = NULL;
@@ -916,14 +916,14 @@ int community_list_unset(struct community_list_handler *ch, const char *name,
/* Lookup community list. */
list = community_list_lookup(ch, name, 0, COMMUNITY_LIST_MASTER);
if (list == NULL)
- return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
+ return;
cm = community_list_master_lookup(ch, COMMUNITY_LIST_MASTER);
/* Delete all of entry belongs to this community-list. */
if (!str) {
community_list_delete(cm, list);
route_map_notify_dependencies(name, RMAP_EVENT_CLIST_DELETED);
- return 0;
+ return;
}
if (style == COMMUNITY_LIST_STANDARD)
@@ -936,12 +936,10 @@ int community_list_unset(struct community_list_handler *ch, const char *name,
entry = community_list_entry_lookup(list, str, direct);
if (!entry)
- return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
+ return;
community_list_entry_delete(cm, list, entry);
route_map_notify_dependencies(name, RMAP_EVENT_CLIST_DELETED);
-
- return 0;
}
bool lcommunity_list_any_match(struct lcommunity *lcom,
@@ -1172,9 +1170,9 @@ int lcommunity_list_set(struct community_list_handler *ch, const char *name,
/* Unset community-list. When str is NULL, delete all of
community-list entry belongs to the specified name. */
-int lcommunity_list_unset(struct community_list_handler *ch, const char *name,
- const char *str, const char *seq, int direct,
- int style)
+void lcommunity_list_unset(struct community_list_handler *ch, const char *name,
+ const char *str, const char *seq, int direct,
+ int style)
{
struct community_list_master *cm = NULL;
struct community_entry *entry = NULL;
@@ -1185,14 +1183,14 @@ int lcommunity_list_unset(struct community_list_handler *ch, const char *name,
/* Lookup community list. */
list = community_list_lookup(ch, name, 0, LARGE_COMMUNITY_LIST_MASTER);
if (list == NULL)
- return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
+ return;
cm = community_list_master_lookup(ch, LARGE_COMMUNITY_LIST_MASTER);
/* Delete all of entry belongs to this community-list. */
if (!str) {
community_list_delete(cm, list);
route_map_notify_dependencies(name, RMAP_EVENT_LLIST_DELETED);
- return 0;
+ return;
}
if (style == LARGE_COMMUNITY_LIST_STANDARD)
@@ -1201,7 +1199,7 @@ int lcommunity_list_unset(struct community_list_handler *ch, const char *name,
regex = bgp_regcomp(str);
if (!lcom && !regex)
- return COMMUNITY_LIST_ERR_MALFORMED_VAL;
+ return;
if (lcom)
entry = community_list_entry_lookup(list, lcom, direct);
@@ -1214,12 +1212,10 @@ int lcommunity_list_unset(struct community_list_handler *ch, const char *name,
bgp_regex_free(regex);
if (!entry)
- return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
+ return;
community_list_entry_delete(cm, list, entry);
route_map_notify_dependencies(name, RMAP_EVENT_LLIST_DELETED);
-
- return 0;
}
/* Set extcommunity-list. */
@@ -1299,9 +1295,9 @@ int extcommunity_list_set(struct community_list_handler *ch, const char *name,
* When str is NULL, delete all extcommunity-list entries belonging to the
* specified name.
*/
-int extcommunity_list_unset(struct community_list_handler *ch, const char *name,
- const char *str, const char *seq, int direct,
- int style)
+void extcommunity_list_unset(struct community_list_handler *ch,
+ const char *name, const char *str, const char *seq,
+ int direct, int style)
{
struct community_list_master *cm = NULL;
struct community_entry *entry = NULL;
@@ -1311,14 +1307,14 @@ int extcommunity_list_unset(struct community_list_handler *ch, const char *name,
/* Lookup extcommunity list. */
list = community_list_lookup(ch, name, 0, EXTCOMMUNITY_LIST_MASTER);
if (list == NULL)
- return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
+ return;
cm = community_list_master_lookup(ch, EXTCOMMUNITY_LIST_MASTER);
/* Delete all of entry belongs to this extcommunity-list. */
if (!str) {
community_list_delete(cm, list);
route_map_notify_dependencies(name, RMAP_EVENT_ECLIST_DELETED);
- return 0;
+ return;
}
if (style == EXTCOMMUNITY_LIST_STANDARD)
@@ -1331,12 +1327,10 @@ int extcommunity_list_unset(struct community_list_handler *ch, const char *name,
entry = community_list_entry_lookup(list, str, direct);
if (!entry)
- return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
+ return;
community_list_entry_delete(cm, list, entry);
route_map_notify_dependencies(name, RMAP_EVENT_ECLIST_DELETED);
-
- return 0;
}
/* Initializa community-list. Return community-list handler. */
diff --git a/bgpd/bgp_clist.h b/bgpd/bgp_clist.h
index a435b92..29bd880 100644
--- a/bgpd/bgp_clist.h
+++ b/bgpd/bgp_clist.h
@@ -109,11 +109,9 @@ struct community_list_handler {
};
/* Error code of community-list. */
-#define COMMUNITY_LIST_ERR_CANT_FIND_LIST -1
-#define COMMUNITY_LIST_ERR_MALFORMED_VAL -2
-#define COMMUNITY_LIST_ERR_STANDARD_CONFLICT -3
-#define COMMUNITY_LIST_ERR_EXPANDED_CONFLICT -4
-
+#define COMMUNITY_LIST_ERR_MALFORMED_VAL -1
+#define COMMUNITY_LIST_ERR_STANDARD_CONFLICT -2
+#define COMMUNITY_LIST_ERR_EXPANDED_CONFLICT -3
/* Handler. */
extern struct community_list_handler *bgp_clist;
@@ -124,22 +122,22 @@ extern void community_list_terminate(struct community_list_handler *ch);
extern int community_list_set(struct community_list_handler *ch,
const char *name, const char *str,
const char *seq, int direct, int style);
-extern int community_list_unset(struct community_list_handler *ch,
- const char *name, const char *str,
- const char *seq, int direct, int style);
+extern void community_list_unset(struct community_list_handler *ch,
+ const char *name, const char *str,
+ const char *seq, int direct, int style);
extern int extcommunity_list_set(struct community_list_handler *ch,
const char *name, const char *str,
const char *seq, int direct, int style);
-extern int extcommunity_list_unset(struct community_list_handler *ch,
- const char *name, const char *str,
- const char *seq, int direct, int style);
+extern void extcommunity_list_unset(struct community_list_handler *ch,
+ const char *name, const char *str,
+ const char *seq, int direct, int style);
extern int lcommunity_list_set(struct community_list_handler *ch,
const char *name, const char *str,
const char *seq, int direct, int style);
extern bool lcommunity_list_valid(const char *community, int style);
-extern int lcommunity_list_unset(struct community_list_handler *ch,
- const char *name, const char *str,
- const char *seq, int direct, int style);
+extern void lcommunity_list_unset(struct community_list_handler *ch,
+ const char *name, const char *str,
+ const char *seq, int direct, int style);
extern struct community_list_master *
community_list_master_lookup(struct community_list_handler *ch, int master);
diff --git a/bgpd/bgp_damp.c b/bgpd/bgp_damp.c
index 80425eb..339bfae 100644
--- a/bgpd/bgp_damp.c
+++ b/bgpd/bgp_damp.c
@@ -22,19 +22,76 @@
#include "bgpd/bgp_advertise.h"
#include "bgpd/bgp_vty.h"
-/* Global variable to access damping configuration */
-static struct bgp_damp_config damp[AFI_MAX][SAFI_MAX];
+static void bgp_reuselist_add(struct reuselist *list, struct bgp_damp_info *info)
+{
+ assert(info);
+ SLIST_INSERT_HEAD(list, info, entry);
+}
+
+static void bgp_reuselist_del(struct reuselist *list, struct bgp_damp_info *info)
+{
+ assert(info);
+ SLIST_REMOVE(list, info, bgp_damp_info, entry);
+}
-/* Utility macro to add and delete BGP dampening information to no
- used list. */
-#define BGP_DAMP_LIST_ADD(N, A) BGP_PATH_INFO_ADD(N, A, no_reuse_list)
-#define BGP_DAMP_LIST_DEL(N, A) BGP_PATH_INFO_DEL(N, A, no_reuse_list)
+static void bgp_reuselist_switch(struct reuselist *source,
+ struct bgp_damp_info *info,
+ struct reuselist *target)
+{
+ assert(source && target && info);
+ SLIST_REMOVE(source, info, bgp_damp_info, entry);
+ SLIST_INSERT_HEAD(target, info, entry);
+}
+
+static void bgp_damp_info_unclaim(struct bgp_damp_info *bdi,
+ struct reuselist *list)
+{
+ assert(bdi && bdi->config);
+ if (bdi->index == BGP_DAMP_NO_REUSE_LIST_INDEX)
+ bgp_reuselist_del(&bdi->config->no_reuse_list, bdi);
+ else
+ bgp_reuselist_del(list ? list
+ : &bdi->config->reuse_list[bdi->index],
+ bdi);
+ bdi->config = NULL;
+}
+
+static void bgp_damp_info_claim(struct bgp_damp_info *bdi,
+ struct bgp_damp_config *bdc)
+{
+ assert(bdc && bdi);
+ if (bdi->config == NULL) {
+ bdi->config = bdc;
+ return;
+ }
+ bgp_damp_info_unclaim(bdi, NULL);
+ bdi->config = bdc;
+ bdi->afi = bdc->afi;
+ bdi->safi = bdc->safi;
+}
+
+struct bgp_damp_config *get_active_bdc_from_pi(struct bgp_path_info *pi,
+ afi_t afi, safi_t safi)
+{
+ if (!pi)
+ return NULL;
+ if (CHECK_FLAG(pi->peer->af_flags[afi][safi],
+ PEER_FLAG_CONFIG_DAMPENING))
+ return &pi->peer->damp[afi][safi];
+ if (peer_group_active(pi->peer))
+ if (CHECK_FLAG(pi->peer->group->conf->af_flags[afi][safi],
+ PEER_FLAG_CONFIG_DAMPENING))
+ return &pi->peer->group->conf->damp[afi][safi];
+ if (CHECK_FLAG(pi->peer->bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING))
+ return &pi->peer->bgp->damp[afi][safi];
+ return NULL;
+}
/* Calculate reuse list index by penalty value. */
static int bgp_reuse_index(int penalty, struct bgp_damp_config *bdc)
{
unsigned int i;
- int index;
+ unsigned int index;
/*
* reuse_limit can't be zero, this is for Coverity
@@ -57,27 +114,28 @@ static int bgp_reuse_index(int penalty, struct bgp_damp_config *bdc)
static void bgp_reuse_list_add(struct bgp_damp_info *bdi,
struct bgp_damp_config *bdc)
{
- int index;
-
- index = bdi->index = bgp_reuse_index(bdi->penalty, bdc);
-
- bdi->prev = NULL;
- bdi->next = bdc->reuse_list[index];
- if (bdc->reuse_list[index])
- bdc->reuse_list[index]->prev = bdi;
- bdc->reuse_list[index] = bdi;
+ bgp_damp_info_claim(bdi, bdc);
+ bdi->index = bgp_reuse_index(bdi->penalty, bdc);
+ bgp_reuselist_add(&bdc->reuse_list[bdi->index], bdi);
}
/* Delete BGP dampening information from reuse list. */
-static void bgp_reuse_list_delete(struct bgp_damp_info *bdi,
+static void bgp_reuse_list_delete(struct bgp_damp_info *bdi)
+{
+ bgp_damp_info_unclaim(bdi, NULL);
+}
+
+static void bgp_no_reuse_list_add(struct bgp_damp_info *bdi,
struct bgp_damp_config *bdc)
{
- if (bdi->next)
- bdi->next->prev = bdi->prev;
- if (bdi->prev)
- bdi->prev->next = bdi->next;
- else
- bdc->reuse_list[bdi->index] = bdi->next;
+ bgp_damp_info_claim(bdi, bdc);
+ bdi->index = BGP_DAMP_NO_REUSE_LIST_INDEX;
+ bgp_reuselist_add(&bdc->no_reuse_list, bdi);
+}
+
+static void bgp_no_reuse_list_delete(struct bgp_damp_info *bdi)
+{
+ bgp_damp_info_unclaim(bdi, NULL);
}
/* Return decayed penalty value. */
@@ -100,10 +158,10 @@ int bgp_damp_decay(time_t tdiff, int penalty, struct bgp_damp_config *bdc)
is evaluated. RFC2439 Section 4.8.7. */
static void bgp_reuse_timer(struct event *t)
{
- struct bgp_damp_info *bdi;
- struct bgp_damp_info *next;
+ struct bgp_damp_info *bdi, *bdi_next;
+ struct reuselist plist;
+ struct bgp *bgp;
time_t t_now, t_diff;
-
struct bgp_damp_config *bdc = EVENT_ARG(t);
bdc->t_reuse = NULL;
@@ -112,20 +170,20 @@ static void bgp_reuse_timer(struct event *t)
t_now = monotime(NULL);
- /* 1. save a pointer to the current zeroth queue head and zero the
- list head entry. */
- bdi = bdc->reuse_list[bdc->reuse_offset];
- bdc->reuse_list[bdc->reuse_offset] = NULL;
+ /* 1. save a pointer to the current queue head and zero the list head
+ * list head entry. */
+ assert(bdc->reuse_offset < bdc->reuse_list_size);
+ plist = bdc->reuse_list[bdc->reuse_offset];
+ SLIST_INIT(&bdc->reuse_list[bdc->reuse_offset]);
/* 2. set offset = modulo reuse-list-size ( offset + 1 ), thereby
rotating the circular queue of list-heads. */
bdc->reuse_offset = (bdc->reuse_offset + 1) % bdc->reuse_list_size;
+ assert(bdc->reuse_offset < bdc->reuse_list_size);
/* 3. if ( the saved list head pointer is non-empty ) */
- for (; bdi; bdi = next) {
- struct bgp *bgp = bdi->path->peer->bgp;
-
- next = bdi->next;
+ SLIST_FOREACH_SAFE (bdi, &plist, entry, bdi_next) {
+ bgp = bdi->path->peer->bgp;
/* Set t-diff = t-now - t-updated. */
t_diff = t_now - bdi->t_updated;
@@ -150,19 +208,27 @@ static void bgp_reuse_timer(struct event *t)
bgp_aggregate_increment(
bgp, bgp_dest_get_prefix(bdi->dest),
bdi->path, bdi->afi, bdi->safi);
- bgp_process(bgp, bdi->dest, bdi->afi,
+ bgp_process(bgp, bdi->dest, bdi->path, bdi->afi,
bdi->safi);
}
- if (bdi->penalty <= bdc->reuse_limit / 2.0)
- bgp_damp_info_free(bdi, 1, bdc->afi, bdc->safi);
- else
- BGP_DAMP_LIST_ADD(bdc, bdi);
- } else
+ if (bdi->penalty <= bdc->reuse_limit / 2.0) {
+ bgp_damp_info_free(bdi, &plist, 1);
+ } else {
+ bdi->index = BGP_DAMP_NO_REUSE_LIST_INDEX;
+ bgp_reuselist_switch(&plist, bdi,
+ &bdc->no_reuse_list);
+ }
+ } else {
/* Re-insert into another list (See RFC2439 Section
* 4.8.6). */
- bgp_reuse_list_add(bdi, bdc);
+ bdi->index = bgp_reuse_index(bdi->penalty, bdc);
+ bgp_reuselist_switch(&plist, bdi,
+ &bdc->reuse_list[bdi->index]);
+ }
}
+
+ assert(SLIST_EMPTY(&plist));
}
/* A route becomes unreachable (RFC2439 Section 4.8.2). */
@@ -172,10 +238,13 @@ int bgp_damp_withdraw(struct bgp_path_info *path, struct bgp_dest *dest,
time_t t_now;
struct bgp_damp_info *bdi = NULL;
unsigned int last_penalty = 0;
- struct bgp_damp_config *bdc = &damp[afi][safi];
+ struct bgp_damp_config *bdc;
- t_now = monotime(NULL);
+ bdc = get_active_bdc_from_pi(path, afi, safi);
+ if (!bdc)
+ return BGP_DAMP_USED;
+ t_now = monotime(NULL);
/* Processing Unreachable Messages. */
if (path->extra)
bdi = path->extra->damp_info;
@@ -197,12 +266,20 @@ int bgp_damp_withdraw(struct bgp_path_info *path, struct bgp_dest *dest,
bdi->flap = 1;
bdi->start_time = t_now;
bdi->suppress_time = 0;
- bdi->index = -1;
+ bdi->index = BGP_DAMP_NO_REUSE_LIST_INDEX;
bdi->afi = afi;
bdi->safi = safi;
(bgp_path_info_extra_get(path))->damp_info = bdi;
- BGP_DAMP_LIST_ADD(bdc, bdi);
+ bgp_no_reuse_list_add(bdi, bdc);
} else {
+ if (bdi->config != bdc) {
+ bgp_damp_info_claim(bdi, bdc);
+ if (bdi->index == BGP_DAMP_NO_REUSE_LIST_INDEX)
+ bgp_reuselist_add(&bdc->no_reuse_list, bdi);
+ else
+ bgp_reuselist_add(&bdc->reuse_list[bdi->index],
+ bdi);
+ }
last_penalty = bdi->penalty;
/* 1. Set t-diff = t-now - t-updated. */
@@ -228,8 +305,8 @@ int bgp_damp_withdraw(struct bgp_path_info *path, struct bgp_dest *dest,
/* Remove the route from a reuse list if it is on one. */
if (CHECK_FLAG(bdi->path->flags, BGP_PATH_DAMPED)) {
/* If decay rate isn't equal to 0, reinsert brn. */
- if (bdi->penalty != last_penalty && bdi->index >= 0) {
- bgp_reuse_list_delete(bdi, bdc);
+ if (bdi->penalty != last_penalty) {
+ bgp_reuse_list_delete(bdi);
bgp_reuse_list_add(bdi, bdc);
}
return BGP_DAMP_SUPPRESSED;
@@ -240,10 +317,9 @@ int bgp_damp_withdraw(struct bgp_path_info *path, struct bgp_dest *dest,
if (bdi->penalty >= bdc->suppress_value) {
bgp_path_info_set_flag(dest, path, BGP_PATH_DAMPED);
bdi->suppress_time = t_now;
- BGP_DAMP_LIST_DEL(bdc, bdi);
+ bgp_no_reuse_list_delete(bdi);
bgp_reuse_list_add(bdi, bdc);
}
-
return BGP_DAMP_USED;
}
@@ -253,7 +329,10 @@ int bgp_damp_update(struct bgp_path_info *path, struct bgp_dest *dest,
time_t t_now;
struct bgp_damp_info *bdi;
int status;
- struct bgp_damp_config *bdc = &damp[afi][safi];
+ struct bgp_damp_config *bdc;
+
+ bdc = get_active_bdc_from_pi(path, afi, safi);
+ assert(bdc);
if (!path->extra || !((bdi = path->extra->damp_info)))
return BGP_DAMP_USED;
@@ -271,8 +350,8 @@ int bgp_damp_update(struct bgp_path_info *path, struct bgp_dest *dest,
else if (CHECK_FLAG(bdi->path->flags, BGP_PATH_DAMPED)
&& (bdi->penalty < bdc->reuse_limit)) {
bgp_path_info_unset_flag(dest, path, BGP_PATH_DAMPED);
- bgp_reuse_list_delete(bdi, bdc);
- BGP_DAMP_LIST_ADD(bdc, bdi);
+ bgp_reuse_list_delete(bdi);
+ bgp_no_reuse_list_add(bdi, bdc);
bdi->suppress_time = 0;
status = BGP_DAMP_USED;
} else
@@ -281,33 +360,32 @@ int bgp_damp_update(struct bgp_path_info *path, struct bgp_dest *dest,
if (bdi->penalty > bdc->reuse_limit / 2.0)
bdi->t_updated = t_now;
else
- bgp_damp_info_free(bdi, 0, afi, safi);
+ bgp_damp_info_free(bdi, NULL, 0);
return status;
}
-void bgp_damp_info_free(struct bgp_damp_info *bdi, int withdraw, afi_t afi,
- safi_t safi)
+void bgp_damp_info_free(struct bgp_damp_info *bdi, struct reuselist *list,
+ int withdraw)
{
- struct bgp_path_info *path;
- struct bgp_damp_config *bdc = &damp[afi][safi];
-
- if (!bdi)
- return;
-
- path = bdi->path;
- path->extra->damp_info = NULL;
-
- if (CHECK_FLAG(path->flags, BGP_PATH_DAMPED))
- bgp_reuse_list_delete(bdi, bdc);
- else
- BGP_DAMP_LIST_DEL(bdc, bdi);
-
- bgp_path_info_unset_flag(bdi->dest, path,
- BGP_PATH_HISTORY | BGP_PATH_DAMPED);
-
- if (bdi->lastrecord == BGP_RECORD_WITHDRAW && withdraw)
- bgp_path_info_delete(bdi->dest, path);
+ assert(bdi);
+
+ afi_t afi = bdi->afi;
+ safi_t safi = bdi->safi;
+ struct bgp_path_info *bpi = bdi->path;
+ struct bgp_dest *dest = bdi->dest;
+ struct bgp *bgp = bpi->peer->bgp;
+ const struct prefix *p = bgp_dest_get_prefix(bdi->dest);
+
+ bgp_damp_info_unclaim(bdi, list);
+
+ bpi->extra->damp_info = NULL;
+ bgp_path_info_unset_flag(dest, bpi, BGP_PATH_HISTORY | BGP_PATH_DAMPED);
+ if (bdi->lastrecord == BGP_RECORD_WITHDRAW && withdraw) {
+ bgp_aggregate_decrement(bgp, p, bpi, afi, SAFI_UNICAST);
+ bgp_path_info_delete(dest, bpi);
+ bgp_process(bgp, dest, bpi, afi, safi);
+ }
XFREE(MTYPE_BGP_DAMP_INFO, bdi);
}
@@ -353,8 +431,7 @@ static void bgp_damp_parameter_set(time_t hlife, unsigned int reuse,
bdc->reuse_list =
XCALLOC(MTYPE_BGP_DAMP_ARRAY,
- bdc->reuse_list_size * sizeof(struct bgp_reuse_node *));
-
+ bdc->reuse_list_size * sizeof(struct reuselist));
/* Reuse-array computations */
bdc->reuse_index = XCALLOC(MTYPE_BGP_DAMP_ARRAY,
sizeof(int) * bdc->reuse_index_size);
@@ -381,7 +458,7 @@ static void bgp_damp_parameter_set(time_t hlife, unsigned int reuse,
int bgp_damp_enable(struct bgp *bgp, afi_t afi, safi_t safi, time_t half,
unsigned int reuse, unsigned int suppress, time_t max)
{
- struct bgp_damp_config *bdc = &damp[afi][safi];
+ struct bgp_damp_config *bdc = &bgp->damp[afi][safi];
if (CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)) {
if (bdc->half_life == half && bdc->reuse_limit == reuse
@@ -393,6 +470,8 @@ int bgp_damp_enable(struct bgp *bgp, afi_t afi, safi_t safi, time_t half,
SET_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING);
bgp_damp_parameter_set(half, reuse, suppress, max, bdc);
+ bdc->afi = afi;
+ bdc->safi = safi;
/* Register reuse timer. */
event_add_timer(bm->master, bgp_reuse_timer, bdc, DELTA_REUSE,
@@ -401,8 +480,34 @@ int bgp_damp_enable(struct bgp *bgp, afi_t afi, safi_t safi, time_t half,
return 0;
}
-static void bgp_damp_config_clean(struct bgp_damp_config *bdc)
+/* Clean all the bgp_damp_info stored in reuse_list and no_reuse_list. */
+void bgp_damp_info_clean(struct bgp *bgp, struct bgp_damp_config *bdc,
+ afi_t afi, safi_t safi)
{
+ struct bgp_damp_info *bdi;
+ struct reuselist *list;
+ unsigned int i;
+
+ bdc->reuse_offset = 0;
+ for (i = 0; i < bdc->reuse_list_size; ++i) {
+ list = &bdc->reuse_list[i];
+ while ((bdi = SLIST_FIRST(list)) != NULL) {
+ if (bdi->lastrecord == BGP_RECORD_UPDATE) {
+ bgp_aggregate_increment(bgp,
+ bgp_dest_get_prefix(
+ bdi->dest),
+ bdi->path, bdi->afi,
+ bdi->safi);
+ bgp_process(bgp, bdi->dest, bdi->path, bdi->afi,
+ bdi->safi);
+ }
+ bgp_damp_info_free(bdi, list, 1);
+ }
+ }
+
+ while ((bdi = SLIST_FIRST(&bdc->no_reuse_list)) != NULL)
+ bgp_damp_info_free(bdi, &bdc->no_reuse_list, 1);
+
/* Free decay array */
XFREE(MTYPE_BGP_DAMP_ARRAY, bdc->decay_array);
bdc->decay_array_size = 0;
@@ -411,41 +516,25 @@ static void bgp_damp_config_clean(struct bgp_damp_config *bdc)
XFREE(MTYPE_BGP_DAMP_ARRAY, bdc->reuse_index);
bdc->reuse_index_size = 0;
- /* Free reuse list array. */
XFREE(MTYPE_BGP_DAMP_ARRAY, bdc->reuse_list);
bdc->reuse_list_size = 0;
-}
-
-/* Clean all the bgp_damp_info stored in reuse_list. */
-void bgp_damp_info_clean(afi_t afi, safi_t safi)
-{
- unsigned int i;
- struct bgp_damp_info *bdi, *next;
- struct bgp_damp_config *bdc = &damp[afi][safi];
-
- bdc->reuse_offset = 0;
- for (i = 0; i < bdc->reuse_list_size; i++) {
- if (!bdc->reuse_list[i])
- continue;
-
- for (bdi = bdc->reuse_list[i]; bdi; bdi = next) {
- next = bdi->next;
- bgp_damp_info_free(bdi, 1, afi, safi);
- }
- bdc->reuse_list[i] = NULL;
- }
-
- for (bdi = bdc->no_reuse_list; bdi; bdi = next) {
- next = bdi->next;
- bgp_damp_info_free(bdi, 1, afi, safi);
- }
- bdc->no_reuse_list = NULL;
+ EVENT_OFF(bdc->t_reuse);
}
+/* Disable route flap dampening for a bgp instance.
+ *
+ * Please note that this function also gets used to free memory when deleting a
+ * bgp instance.
+ */
int bgp_damp_disable(struct bgp *bgp, afi_t afi, safi_t safi)
{
- struct bgp_damp_config *bdc = &damp[afi][safi];
+ struct bgp_damp_config *bdc;
+
+ bdc = &bgp->damp[afi][safi];
+ if (!bdc)
+ return 0;
+
/* If it wasn't enabled, there's nothing to do. */
if (!CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING))
return 0;
@@ -454,54 +543,51 @@ int bgp_damp_disable(struct bgp *bgp, afi_t afi, safi_t safi)
EVENT_OFF(bdc->t_reuse);
/* Clean BGP dampening information. */
- bgp_damp_info_clean(afi, safi);
-
- /* Clear configuration */
- bgp_damp_config_clean(bdc);
+ bgp_damp_info_clean(bgp, bdc, afi, safi);
UNSET_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING);
+
return 0;
}
-void bgp_config_write_damp(struct vty *vty, afi_t afi, safi_t safi)
+void bgp_config_write_damp(struct vty *vty, struct bgp *bgp, afi_t afi,
+ safi_t safi)
{
- if (damp[afi][safi].half_life == DEFAULT_HALF_LIFE * 60
- && damp[afi][safi].reuse_limit == DEFAULT_REUSE
- && damp[afi][safi].suppress_value == DEFAULT_SUPPRESS
- && damp[afi][safi].max_suppress_time
- == damp[afi][safi].half_life * 4)
+ struct bgp_damp_config *bdc;
+
+ bdc = &bgp->damp[afi][safi];
+ if (bdc->half_life == DEFAULT_HALF_LIFE * 60 &&
+ bdc->reuse_limit == DEFAULT_REUSE &&
+ bdc->suppress_value == DEFAULT_SUPPRESS &&
+ bdc->max_suppress_time == bdc->half_life * 4)
vty_out(vty, " bgp dampening\n");
- else if (damp[afi][safi].half_life != DEFAULT_HALF_LIFE * 60
- && damp[afi][safi].reuse_limit == DEFAULT_REUSE
- && damp[afi][safi].suppress_value == DEFAULT_SUPPRESS
- && damp[afi][safi].max_suppress_time
- == damp[afi][safi].half_life * 4)
- vty_out(vty, " bgp dampening %lld\n",
- damp[afi][safi].half_life / 60LL);
+ else if (bdc->half_life != DEFAULT_HALF_LIFE * 60 &&
+ bdc->reuse_limit == DEFAULT_REUSE &&
+ bdc->suppress_value == DEFAULT_SUPPRESS &&
+ bdc->max_suppress_time == bdc->half_life * 4)
+ vty_out(vty, " bgp dampening %lld\n", bdc->half_life / 60LL);
else
vty_out(vty, " bgp dampening %lld %d %d %lld\n",
- damp[afi][safi].half_life / 60LL,
- damp[afi][safi].reuse_limit,
- damp[afi][safi].suppress_value,
- damp[afi][safi].max_suppress_time / 60LL);
+ bdc->half_life / 60LL, bdc->reuse_limit,
+ bdc->suppress_value, bdc->max_suppress_time / 60LL);
}
-static const char *bgp_get_reuse_time(unsigned int penalty, char *buf,
- size_t len, afi_t afi, safi_t safi,
- bool use_json, json_object *json)
+static const char *bgp_get_reuse_time(struct bgp_damp_config *bdc,
+ unsigned int penalty, char *buf,
+ size_t len, bool use_json,
+ json_object *json)
{
time_t reuse_time = 0;
struct tm tm;
int time_store = 0;
- if (penalty > damp[afi][safi].reuse_limit) {
- reuse_time = (int)(DELTA_T
- * ((log((double)damp[afi][safi].reuse_limit
- / penalty))
- / (log(damp[afi][safi].decay_array[1]))));
+ if (penalty > bdc->reuse_limit) {
+ reuse_time = (int)(DELTA_T *
+ ((log((double)bdc->reuse_limit / penalty)) /
+ (log(bdc->decay_array[1]))));
- if (reuse_time > damp[afi][safi].max_suppress_time)
- reuse_time = damp[afi][safi].max_suppress_time;
+ if (reuse_time > bdc->max_suppress_time)
+ reuse_time = bdc->max_suppress_time;
gmtime_r(&reuse_time, &tm);
} else
@@ -553,14 +639,15 @@ static const char *bgp_get_reuse_time(unsigned int penalty, char *buf,
return buf;
}
-void bgp_damp_info_vty(struct vty *vty, struct bgp_path_info *path, afi_t afi,
- safi_t safi, json_object *json_path)
+void bgp_damp_info_vty(struct vty *vty, struct bgp *bgp,
+ struct bgp_path_info *path, afi_t afi, safi_t safi,
+ json_object *json_path)
{
struct bgp_damp_info *bdi;
time_t t_now, t_diff;
char timebuf[BGP_UPTIME_LEN] = {};
int penalty;
- struct bgp_damp_config *bdc = &damp[afi][safi];
+ struct bgp_damp_config *bdc = &bgp->damp[afi][safi];
if (!path->extra)
return;
@@ -588,8 +675,8 @@ void bgp_damp_info_vty(struct vty *vty, struct bgp_path_info *path, afi_t afi,
if (CHECK_FLAG(path->flags, BGP_PATH_DAMPED)
&& !CHECK_FLAG(path->flags, BGP_PATH_HISTORY))
- bgp_get_reuse_time(penalty, timebuf, BGP_UPTIME_LEN,
- afi, safi, 1, json_path);
+ bgp_get_reuse_time(bdc, penalty, timebuf,
+ BGP_UPTIME_LEN, 1, json_path);
} else {
vty_out(vty,
" Dampinfo: penalty %d, flapped %d times in %s",
@@ -600,14 +687,15 @@ void bgp_damp_info_vty(struct vty *vty, struct bgp_path_info *path, afi_t afi,
if (CHECK_FLAG(path->flags, BGP_PATH_DAMPED)
&& !CHECK_FLAG(path->flags, BGP_PATH_HISTORY))
vty_out(vty, ", reuse in %s",
- bgp_get_reuse_time(penalty, timebuf,
- BGP_UPTIME_LEN, afi, safi, 0,
+ bgp_get_reuse_time(bdc, penalty, timebuf,
+ BGP_UPTIME_LEN, 0,
json_path));
vty_out(vty, "\n");
}
}
+
const char *bgp_damp_reuse_time_vty(struct vty *vty, struct bgp_path_info *path,
char *timebuf, size_t len, afi_t afi,
safi_t safi, bool use_json,
@@ -616,7 +704,11 @@ const char *bgp_damp_reuse_time_vty(struct vty *vty, struct bgp_path_info *path,
struct bgp_damp_info *bdi;
time_t t_now, t_diff;
int penalty;
- struct bgp_damp_config *bdc = &damp[afi][safi];
+ struct bgp_damp_config *bdc;
+
+ bdc = get_active_bdc_from_pi(path, afi, safi);
+ if (!bdc)
+ return NULL;
if (!path->extra)
return NULL;
@@ -636,15 +728,15 @@ const char *bgp_damp_reuse_time_vty(struct vty *vty, struct bgp_path_info *path,
t_diff = t_now - bdi->t_updated;
penalty = bgp_damp_decay(t_diff, bdi->penalty, bdc);
- return bgp_get_reuse_time(penalty, timebuf, len, afi, safi, use_json,
- json);
+ return bgp_get_reuse_time(bdc, penalty, timebuf, len, use_json, json);
}
+
static int bgp_print_dampening_parameters(struct bgp *bgp, struct vty *vty,
afi_t afi, safi_t safi, bool use_json)
{
if (CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)) {
- struct bgp_damp_config *bdc = &damp[afi][safi];
+ struct bgp_damp_config *bdc = &bgp->damp[afi][safi];
if (use_json) {
json_object *json = json_object_new_object();
@@ -687,7 +779,6 @@ int bgp_show_dampening_parameters(struct vty *vty, afi_t afi, safi_t safi,
bool use_json = CHECK_FLAG(show_flags, BGP_SHOW_OPT_JSON);
bgp = bgp_get_default();
-
if (bgp == NULL) {
vty_out(vty, "No BGP process is configured\n");
return CMD_WARNING;
@@ -729,3 +820,130 @@ int bgp_show_dampening_parameters(struct vty *vty, afi_t afi, safi_t safi,
}
return CMD_SUCCESS;
}
+
+void bgp_peer_damp_enable(struct peer *peer, afi_t afi, safi_t safi, time_t half,
+ unsigned int reuse, unsigned int suppress, time_t max)
+{
+ struct bgp_damp_config *bdc;
+
+ if (!peer)
+ return;
+ bdc = &peer->damp[afi][safi];
+ if (peer_af_flag_check(peer, afi, safi, PEER_FLAG_CONFIG_DAMPENING)) {
+ if (bdc->half_life == half && bdc->reuse_limit == reuse &&
+ bdc->suppress_value == suppress &&
+ bdc->max_suppress_time == max)
+ return;
+ bgp_peer_damp_disable(peer, afi, safi);
+ }
+ SET_FLAG(peer->af_flags[afi][safi], PEER_FLAG_CONFIG_DAMPENING);
+ bgp_damp_parameter_set(half, reuse, suppress, max, bdc);
+ bdc->afi = afi;
+ bdc->safi = safi;
+ event_add_timer(bm->master, bgp_reuse_timer, bdc, DELTA_REUSE,
+ &bdc->t_reuse);
+}
+
+/* Disable route flap dampening for a peer.
+ *
+ * Please note that this function also gets used to free memory when deleting a
+ * peer or peer group.
+ */
+void bgp_peer_damp_disable(struct peer *peer, afi_t afi, safi_t safi)
+{
+ struct bgp_damp_config *bdc;
+
+ if (!peer_af_flag_check(peer, afi, safi, PEER_FLAG_CONFIG_DAMPENING))
+ return;
+ bdc = &peer->damp[afi][safi];
+ if (!bdc)
+ return;
+ bgp_damp_info_clean(peer->bgp, bdc, afi, safi);
+ UNSET_FLAG(peer->af_flags[afi][safi], PEER_FLAG_CONFIG_DAMPENING);
+}
+
+void bgp_config_write_peer_damp(struct vty *vty, struct peer *peer, afi_t afi,
+ safi_t safi)
+{
+ struct bgp_damp_config *bdc;
+
+ bdc = &peer->damp[afi][safi];
+ if (bdc->half_life == DEFAULT_HALF_LIFE * 60 &&
+ bdc->reuse_limit == DEFAULT_REUSE &&
+ bdc->suppress_value == DEFAULT_SUPPRESS &&
+ bdc->max_suppress_time == bdc->half_life * 4)
+ vty_out(vty, " neighbor %s dampening\n", peer->host);
+ else if (bdc->half_life != DEFAULT_HALF_LIFE * 60 &&
+ bdc->reuse_limit == DEFAULT_REUSE &&
+ bdc->suppress_value == DEFAULT_SUPPRESS &&
+ bdc->max_suppress_time == bdc->half_life * 4)
+ vty_out(vty, " neighbor %s dampening %lld\n", peer->host,
+ bdc->half_life / 60LL);
+ else
+ vty_out(vty, " neighbor %s dampening %lld %d %d %lld\n",
+ peer->host, bdc->half_life / 60LL, bdc->reuse_limit,
+ bdc->suppress_value, bdc->max_suppress_time / 60LL);
+}
+
+static void bgp_print_peer_dampening_parameters(struct vty *vty,
+ struct peer *peer, afi_t afi,
+ safi_t safi, bool use_json,
+ json_object *json)
+{
+ struct bgp_damp_config *bdc;
+
+ if (!peer)
+ return;
+ if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_CONFIG_DAMPENING)) {
+ bdc = &peer->damp[afi][safi];
+ if (!bdc)
+ return;
+ if (use_json) {
+ json_object_int_add(json, "halfLifeSecs",
+ bdc->half_life);
+ json_object_int_add(json, "reusePenalty",
+ bdc->reuse_limit);
+ json_object_int_add(json, "suppressPenalty",
+ bdc->suppress_value);
+ json_object_int_add(json, "maxSuppressTimeSecs",
+ bdc->max_suppress_time);
+ json_object_int_add(json, "maxSuppressPenalty",
+ bdc->ceiling);
+ } else {
+ vty_out(vty, "Half-life time: %lld min\n",
+ (long long)bdc->half_life / 60);
+ vty_out(vty, "Reuse penalty: %d\n", bdc->reuse_limit);
+ vty_out(vty, "Suppress penalty: %d\n",
+ bdc->suppress_value);
+ vty_out(vty, "Max suppress time: %lld min\n",
+ (long long)bdc->max_suppress_time / 60);
+ vty_out(vty, "Max suppress penalty: %u\n", bdc->ceiling);
+ vty_out(vty, "\n");
+ }
+ } else if (!use_json)
+ vty_out(vty, "neighbor dampening not enabled for %s\n",
+ get_afi_safi_str(afi, safi, false));
+}
+
+void bgp_show_peer_dampening_parameters(struct vty *vty, struct peer *peer,
+ afi_t afi, safi_t safi, bool use_json)
+{
+ json_object *json;
+
+ if (use_json) {
+ json = json_object_new_object();
+ json_object_string_add(json, "addressFamily",
+ get_afi_safi_str(afi, safi, false));
+ bgp_print_peer_dampening_parameters(vty, peer, afi, safi, true,
+ json);
+ vty_out(vty, "%s\n",
+ json_object_to_json_string_ext(json,
+ JSON_C_TO_STRING_PRETTY));
+ json_object_free(json);
+ } else {
+ vty_out(vty, "\nFor address family: %s\n",
+ get_afi_safi_str(afi, safi, false));
+ bgp_print_peer_dampening_parameters(vty, peer, afi, safi, false,
+ NULL);
+ }
+}
diff --git a/bgpd/bgp_damp.h b/bgpd/bgp_damp.h
index 6033c34..851c6f9 100644
--- a/bgpd/bgp_damp.h
+++ b/bgpd/bgp_damp.h
@@ -10,11 +10,6 @@
/* Structure maintained on a per-route basis. */
struct bgp_damp_info {
- /* Doubly linked list. This information must be linked to
- reuse_list or no_reuse_list. */
- struct bgp_damp_info *next;
- struct bgp_damp_info *prev;
-
/* Figure-of-merit. */
unsigned int penalty;
@@ -30,6 +25,9 @@ struct bgp_damp_info {
/* Time of route start to be suppressed. */
time_t suppress_time;
+ /* Back reference to associated dampening configuration. */
+ struct bgp_damp_config *config;
+
/* Back reference to bgp_path_info. */
struct bgp_path_info *path;
@@ -38,6 +36,8 @@ struct bgp_damp_info {
/* Current index in the reuse_list. */
int index;
+#define BGP_DAMP_NO_REUSE_LIST_INDEX \
+ (-1) /* index for elements on no_reuse_list */
/* Last time message type. */
uint8_t lastrecord;
@@ -46,8 +46,12 @@ struct bgp_damp_info {
afi_t afi;
safi_t safi;
+
+ SLIST_ENTRY(bgp_damp_info) entry;
};
+SLIST_HEAD(reuselist, bgp_damp_info);
+
/* Specified parameter set configuration. */
struct bgp_damp_config {
/* Value over which routes suppressed. */
@@ -84,12 +88,12 @@ struct bgp_damp_config {
int *reuse_index;
/* Reuse list array per-set based. */
- struct bgp_damp_info **reuse_list;
- int reuse_offset;
+ struct reuselist *reuse_list;
+ unsigned int reuse_offset;
safi_t safi;
/* All dampening information which is not on reuse list. */
- struct bgp_damp_info *no_reuse_list;
+ struct reuselist no_reuse_list;
/* Reuse timer thread per-set base. */
struct event *t_reuse;
@@ -116,6 +120,8 @@ struct bgp_damp_config {
#define REUSE_LIST_SIZE 256
#define REUSE_ARRAY_SIZE 1024
+extern struct bgp_damp_config *get_active_bdc_from_pi(struct bgp_path_info *pi,
+ afi_t afi, safi_t safi);
extern int bgp_damp_enable(struct bgp *bgp, afi_t afi, safi_t safi, time_t half,
unsigned int reuse, unsigned int suppress,
time_t max);
@@ -124,14 +130,18 @@ extern int bgp_damp_withdraw(struct bgp_path_info *path, struct bgp_dest *dest,
afi_t afi, safi_t safi, int attr_change);
extern int bgp_damp_update(struct bgp_path_info *path, struct bgp_dest *dest,
afi_t afi, safi_t saff);
-extern void bgp_damp_info_free(struct bgp_damp_info *path, int withdraw,
- afi_t afi, safi_t safi);
-extern void bgp_damp_info_clean(afi_t afi, safi_t safi);
+extern void bgp_damp_info_free(struct bgp_damp_info *bdi,
+ struct reuselist *list, int withdraw);
+extern void bgp_damp_info_clean(struct bgp *bgp, struct bgp_damp_config *bdc,
+ afi_t afi, safi_t safi);
+extern void bgp_damp_config_clean(struct bgp_damp_config *bdc);
extern int bgp_damp_decay(time_t tdiff, int penalty,
- struct bgp_damp_config *damp);
-extern void bgp_config_write_damp(struct vty *vty, afi_t afi, safi_t safi);
-extern void bgp_damp_info_vty(struct vty *vty, struct bgp_path_info *path,
- afi_t afi, safi_t safi, json_object *json_path);
+ struct bgp_damp_config *bdc);
+extern void bgp_config_write_damp(struct vty *vty, struct bgp *bgp, afi_t afi,
+ safi_t safi);
+extern void bgp_damp_info_vty(struct vty *vty, struct bgp *bgp,
+ struct bgp_path_info *path, afi_t afi,
+ safi_t safi, json_object *json_path);
extern const char *bgp_damp_reuse_time_vty(struct vty *vty,
struct bgp_path_info *path,
char *timebuf, size_t len, afi_t afi,
@@ -139,5 +149,14 @@ extern const char *bgp_damp_reuse_time_vty(struct vty *vty,
json_object *json);
extern int bgp_show_dampening_parameters(struct vty *vty, afi_t afi,
safi_t safi, uint16_t show_flags);
+extern void bgp_peer_damp_enable(struct peer *peer, afi_t afi, safi_t safi,
+ time_t half, unsigned int reuse,
+ unsigned int suppress, time_t max);
+extern void bgp_peer_damp_disable(struct peer *peer, afi_t afi, safi_t safi);
+extern void bgp_config_write_peer_damp(struct vty *vty, struct peer *peer,
+ afi_t afi, safi_t safi);
+extern void bgp_show_peer_dampening_parameters(struct vty *vty,
+ struct peer *peer, afi_t afi,
+ safi_t safi, bool use_json);
#endif /* _QUAGGA_BGP_DAMP_H */
diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c
index 3ecdc0d..6228432 100644
--- a/bgpd/bgp_debug.c
+++ b/bgpd/bgp_debug.c
@@ -50,7 +50,6 @@ unsigned long conf_bgp_debug_keepalive;
unsigned long conf_bgp_debug_update;
unsigned long conf_bgp_debug_bestpath;
unsigned long conf_bgp_debug_zebra;
-unsigned long conf_bgp_debug_allow_martians;
unsigned long conf_bgp_debug_nht;
unsigned long conf_bgp_debug_update_groups;
unsigned long conf_bgp_debug_vpn;
@@ -71,7 +70,6 @@ unsigned long term_bgp_debug_keepalive;
unsigned long term_bgp_debug_update;
unsigned long term_bgp_debug_bestpath;
unsigned long term_bgp_debug_zebra;
-unsigned long term_bgp_debug_allow_martians;
unsigned long term_bgp_debug_nht;
unsigned long term_bgp_debug_update_groups;
unsigned long term_bgp_debug_vpn;
@@ -116,6 +114,7 @@ static const struct message bgp_notify_msg[] = {
{BGP_NOTIFY_FSM_ERR, "Neighbor Events Error"},
{BGP_NOTIFY_CEASE, "Cease"},
{BGP_NOTIFY_ROUTE_REFRESH_ERR, "ROUTE-REFRESH Message Error"},
+ {BGP_NOTIFY_SEND_HOLD_ERR, "Send Hold Timer Expired"},
{0}};
static const struct message bgp_notify_head_msg[] = {
@@ -515,6 +514,7 @@ const char *bgp_notify_subcode_str(char code, char subcode)
return lookup_msg(bgp_notify_update_msg, subcode,
"Unrecognized Error Subcode");
case BGP_NOTIFY_HOLD_ERR:
+ case BGP_NOTIFY_SEND_HOLD_ERR:
break;
case BGP_NOTIFY_FSM_ERR:
return lookup_msg(bgp_notify_fsm_msg, subcode,
@@ -2163,7 +2163,6 @@ DEFUN (no_debug_bgp,
TERM_DEBUG_OFF(as4, AS4_SEGMENT);
TERM_DEBUG_OFF(neighbor_events, NEIGHBOR_EVENTS);
TERM_DEBUG_OFF(zebra, ZEBRA);
- TERM_DEBUG_OFF(allow_martians, ALLOW_MARTIANS);
TERM_DEBUG_OFF(nht, NHT);
TERM_DEBUG_OFF(vpn, VPN_LEAK_FROM_VRF);
TERM_DEBUG_OFF(vpn, VPN_LEAK_TO_VRF);
@@ -2239,9 +2238,6 @@ DEFUN_NOSH (show_debugging_bgp,
if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
vty_out(vty, " BGP graceful-restart debugging is on\n");
- if (BGP_DEBUG(allow_martians, ALLOW_MARTIANS))
- vty_out(vty, " BGP allow martian next hop debugging is on\n");
-
if (BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF))
vty_out(vty,
" BGP route leak from vrf to vpn debugging is on\n");
@@ -2354,11 +2350,6 @@ static int bgp_config_write_debug(struct vty *vty)
}
}
- if (CONF_BGP_DEBUG(allow_martians, ALLOW_MARTIANS)) {
- vty_out(vty, "debug bgp allow-martians\n");
- write++;
- }
-
if (CONF_BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF)) {
vty_out(vty, "debug bgp vpn leak-from-vrf\n");
write++;
@@ -2722,7 +2713,7 @@ bool bgp_debug_zebra(const struct prefix *p)
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,
+ mpls_label_t *label, uint8_t num_labels,
int addpath_valid, uint32_t addpath_id,
struct bgp_route_evpn *overlay_index,
char *str, int size)
diff --git a/bgpd/bgp_debug.h b/bgpd/bgp_debug.h
index 5b09501..061d966 100644
--- a/bgpd/bgp_debug.h
+++ b/bgpd/bgp_debug.h
@@ -61,7 +61,6 @@ extern unsigned long conf_bgp_debug_keepalive;
extern unsigned long conf_bgp_debug_update;
extern unsigned long conf_bgp_debug_bestpath;
extern unsigned long conf_bgp_debug_zebra;
-extern unsigned long conf_bgp_debug_allow_martians;
extern unsigned long conf_bgp_debug_nht;
extern unsigned long conf_bgp_debug_update_groups;
extern unsigned long conf_bgp_debug_vpn;
@@ -80,7 +79,6 @@ extern unsigned long term_bgp_debug_keepalive;
extern unsigned long term_bgp_debug_update;
extern unsigned long term_bgp_debug_bestpath;
extern unsigned long term_bgp_debug_zebra;
-extern unsigned long term_bgp_debug_allow_martians;
extern unsigned long term_bgp_debug_nht;
extern unsigned long term_bgp_debug_update_groups;
extern unsigned long term_bgp_debug_vpn;
@@ -120,7 +118,6 @@ struct bgp_debug_filter {
#define BGP_DEBUG_UPDATE_PREFIX 0x04
#define BGP_DEBUG_UPDATE_DETAIL 0x08
#define BGP_DEBUG_ZEBRA 0x01
-#define BGP_DEBUG_ALLOW_MARTIANS 0x01
#define BGP_DEBUG_NHT 0x01
#define BGP_DEBUG_UPDATE_GROUPS 0x01
#define BGP_DEBUG_VPN_LEAK_FROM_VRF 0x01
@@ -156,8 +153,8 @@ struct bgp_debug_filter {
TERM_DEBUG_OFF(a, b); \
} while (0)
-#define BGP_DEBUG(a, b) (term_bgp_debug_ ## a & BGP_DEBUG_ ## b)
-#define CONF_BGP_DEBUG(a, b) (conf_bgp_debug_ ## a & BGP_DEBUG_ ## b)
+#define BGP_DEBUG(a, b) (unlikely(term_bgp_debug_##a & BGP_DEBUG_##b))
+#define CONF_BGP_DEBUG(a, b) (unlikely(conf_bgp_debug_##a & BGP_DEBUG_##b))
extern const char *const bgp_type_str[];
@@ -178,7 +175,7 @@ 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,
+ union prefixconstptr pu, mpls_label_t *label, uint8_t num_labels,
int addpath_valid, uint32_t addpath_id,
struct bgp_route_evpn *overlay_index, char *str, int size);
const char *bgp_notify_admin_message(char *buf, size_t bufsz, uint8_t *data,
diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c
index a8ae177..1beb030 100644
--- a/bgpd/bgp_ecommunity.c
+++ b/bgpd/bgp_ecommunity.c
@@ -237,11 +237,10 @@ struct ecommunity *ecommunity_parse(uint8_t *pnt, unsigned short length,
disable_ieee_floating);
}
-struct ecommunity *ecommunity_parse_ipv6(uint8_t *pnt, unsigned short length,
- bool disable_ieee_floating)
+struct ecommunity *ecommunity_parse_ipv6(uint8_t *pnt, unsigned short length)
{
return ecommunity_parse_internal(pnt, length, IPV6_ECOMMUNITY_SIZE,
- disable_ieee_floating);
+ false);
}
/* Duplicate the Extended Communities Attribute structure. */
@@ -263,8 +262,11 @@ struct ecommunity *ecommunity_dup(struct ecommunity *ecom)
}
/* Return string representation of ecommunities attribute. */
-char *ecommunity_str(struct ecommunity *ecom)
+const char *ecommunity_str(struct ecommunity *ecom)
{
+ if (!ecom)
+ return "(null)";
+
if (!ecom->str)
ecom->str =
ecommunity_ecom2str(ecom, ECOMMUNITY_FORMAT_DISPLAY, 0);
@@ -724,15 +726,21 @@ static const char *ecommunity_gettoken(const char *str, void *eval_ptr,
memset(buf, 0, INET_ADDRSTRLEN + 1);
memcpy(buf, str, p - str);
- if (dot) {
+ if (dot == 3) {
/* Parsing A.B.C.D in:
* A.B.C.D:MN
*/
ret = inet_aton(buf, &ip);
if (ret == 0)
goto error;
+ } else if (dot == 1) {
+ /* Parsing A.B AS number in:
+ * A.B:MN
+ */
+ if (!asn_str2asn(buf, &as))
+ goto error;
} else {
- /* ASN */
+ /* Parsing A AS number in A:MN */
errno = 0;
tmp_as = strtoul(buf, &endptr, 10);
/* 'unsigned long' is a uint64 on 64-bit
@@ -750,8 +758,11 @@ static const char *ecommunity_gettoken(const char *str, void *eval_ptr,
} else if (*p == '.') {
if (separator)
goto error;
+ /* either IP or AS format */
dot++;
- if (dot > 4)
+ if (dot > 1)
+ ecomm_type = ECOMMUNITY_ENCODE_IP;
+ if (dot >= 4)
goto error;
} else {
digit = 1;
@@ -776,19 +787,18 @@ static const char *ecommunity_gettoken(const char *str, void *eval_ptr,
if (!digit && (!separator || !val_color_set))
goto error;
- /* Encode result into extended community. */
- if (dot)
- ecomm_type = ECOMMUNITY_ENCODE_IP;
- else if (as > BGP_AS_MAX)
- ecomm_type = ECOMMUNITY_ENCODE_AS4;
- else if (as > 0)
- ecomm_type = ECOMMUNITY_ENCODE_AS;
- else if (val_color) {
- ecomm_type = ECOMMUNITY_ENCODE_OPAQUE;
- sub_type = ECOMMUNITY_COLOR;
- val = val_color;
+ if (ecomm_type != ECOMMUNITY_ENCODE_IP) {
+ /* Encode result into extended community for AS format or color. */
+ if (as > BGP_AS_MAX)
+ ecomm_type = ECOMMUNITY_ENCODE_AS4;
+ else if (as > 0)
+ ecomm_type = ECOMMUNITY_ENCODE_AS;
+ else if (val_color) {
+ ecomm_type = ECOMMUNITY_ENCODE_OPAQUE;
+ sub_type = ECOMMUNITY_COLOR;
+ val = val_color;
+ }
}
-
if (ecommunity_encode(ecomm_type, sub_type, 1, as, ip, val, eval))
goto error;
*token = ecommunity_token_val;
@@ -1015,10 +1025,6 @@ static int ecommunity_lb_str(char *buf, size_t bufsz, const uint8_t *pnt,
uint32_t bw_tmp, bw;
char bps_buf[20] = {0};
-#define ONE_GBPS_BYTES (1000 * 1000 * 1000 / 8)
-#define ONE_MBPS_BYTES (1000 * 1000 / 8)
-#define ONE_KBPS_BYTES (1000 / 8)
-
as = (*pnt++ << 8);
as |= (*pnt++);
(void)ptr_get_be32(pnt, &bw_tmp);
@@ -1042,6 +1048,38 @@ static int ecommunity_lb_str(char *buf, size_t bufsz, const uint8_t *pnt,
return len;
}
+static int ipv6_ecommunity_lb_str(char *buf, size_t bufsz, const uint8_t *pnt,
+ size_t length)
+{
+ int len = 0;
+ as_t as = 0;
+ uint64_t bw = 0;
+ char bps_buf[20] = { 0 };
+
+ if (length < IPV6_ECOMMUNITY_SIZE)
+ goto done;
+
+ pnt += 2; /* Reserved */
+ pnt = ptr_get_be64(pnt, &bw);
+ (void)ptr_get_be32(pnt, &as);
+
+ if (bw >= ONE_GBPS_BYTES)
+ snprintf(bps_buf, sizeof(bps_buf), "%.3f Gbps",
+ (float)(bw / ONE_GBPS_BYTES));
+ else if (bw >= ONE_MBPS_BYTES)
+ snprintf(bps_buf, sizeof(bps_buf), "%.3f Mbps",
+ (float)(bw / ONE_MBPS_BYTES));
+ else if (bw >= ONE_KBPS_BYTES)
+ snprintf(bps_buf, sizeof(bps_buf), "%.3f Kbps",
+ (float)(bw / ONE_KBPS_BYTES));
+ else
+ snprintfrr(bps_buf, sizeof(bps_buf), "%" PRIu64 " bps", bw * 8);
+
+done:
+ len = snprintfrr(buf, bufsz, "LB:%u:%" PRIu64 " (%s)", as, bw, bps_buf);
+ return len;
+}
+
bool ecommunity_has_route_target(struct ecommunity *ecom)
{
uint32_t i;
@@ -1110,7 +1148,7 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter)
char encbuf[128];
for (i = 0; i < ecom->size; i++) {
- int unk_ecom = 0;
+ bool unk_ecom = false;
memset(encbuf, 0x00, sizeof(encbuf));
/* Space between each value. */
@@ -1120,6 +1158,18 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter)
/* Retrieve value field */
pnt = ecom->val + (i * ecom->unit_size);
+ uint8_t *data = pnt;
+ uint8_t *end = data + ecom->unit_size;
+ size_t len = end - data;
+
+ /* Sanity check for extended communities lenght, to avoid
+ * overrun when dealing with bits, e.g. ptr_get_be64().
+ */
+ if (len < ecom->unit_size) {
+ unk_ecom = true;
+ goto unknown;
+ }
+
/* High-order octet is the type */
type = *pnt++;
@@ -1142,13 +1192,19 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter)
ecommunity_lb_str(
encbuf, sizeof(encbuf), pnt,
ecom->disable_ieee_floating);
+ } else if (sub_type ==
+ ECOMMUNITY_EXTENDED_LINK_BANDWIDTH &&
+ type == ECOMMUNITY_ENCODE_AS4) {
+ ipv6_ecommunity_lb_str(encbuf,
+ sizeof(encbuf),
+ pnt, len);
} else if (sub_type == ECOMMUNITY_NODE_TARGET &&
type == ECOMMUNITY_ENCODE_IP) {
ecommunity_node_target_str(
encbuf, sizeof(encbuf), pnt,
format);
} else
- unk_ecom = 1;
+ unk_ecom = true;
} else {
ecommunity_rt_soo_str(encbuf, sizeof(encbuf),
pnt, type, sub_type,
@@ -1171,7 +1227,7 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter)
ecommunity_color_str(encbuf, sizeof(encbuf),
pnt);
} else {
- unk_ecom = 1;
+ unk_ecom = true;
}
} else if (type == ECOMMUNITY_ENCODE_EVPN) {
if (filter == ECOMMUNITY_ROUTE_TARGET)
@@ -1264,14 +1320,14 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter)
"DF: (alg: %u, pref: %u)", alg,
pref);
} else
- unk_ecom = 1;
+ unk_ecom = true;
} else if (type == ECOMMUNITY_ENCODE_REDIRECT_IP_NH) {
sub_type = *pnt++;
if (sub_type == ECOMMUNITY_REDIRECT_IP_NH) {
snprintf(encbuf, sizeof(encbuf),
"FS:redirect IP 0x%x", *(pnt + 5));
} else
- unk_ecom = 1;
+ unk_ecom = true;
} else if (type == ECOMMUNITY_ENCODE_TRANS_EXP ||
type == ECOMMUNITY_EXTENDED_COMMUNITY_PART_2 ||
type == ECOMMUNITY_EXTENDED_COMMUNITY_PART_3) {
@@ -1318,7 +1374,7 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter)
snprintf(encbuf, sizeof(encbuf),
"FS:redirect VRF %s", buf);
} else if (type != ECOMMUNITY_ENCODE_TRANS_EXP)
- unk_ecom = 1;
+ unk_ecom = true;
else if (sub_type == ECOMMUNITY_TRAFFIC_ACTION) {
char action[64];
@@ -1351,33 +1407,37 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter)
snprintf(encbuf, sizeof(encbuf),
"FS:marking %u", *(pnt + 5));
} else
- unk_ecom = 1;
+ unk_ecom = true;
} else if (type == ECOMMUNITY_ENCODE_AS_NON_TRANS) {
sub_type = *pnt++;
if (sub_type == ECOMMUNITY_LINK_BANDWIDTH)
ecommunity_lb_str(encbuf, sizeof(encbuf), pnt,
ecom->disable_ieee_floating);
+ else if (sub_type == ECOMMUNITY_EXTENDED_LINK_BANDWIDTH)
+ ipv6_ecommunity_lb_str(encbuf, sizeof(encbuf),
+ pnt, len);
else
- unk_ecom = 1;
+ unk_ecom = true;
} else if (type == ECOMMUNITY_ENCODE_IP_NON_TRANS) {
sub_type = *pnt++;
if (sub_type == ECOMMUNITY_NODE_TARGET)
ecommunity_node_target_str(
encbuf, sizeof(encbuf), pnt, format);
else
- unk_ecom = 1;
+ unk_ecom = true;
} else if (type == ECOMMUNITY_ENCODE_OPAQUE_NON_TRANS) {
sub_type = *pnt++;
if (sub_type == ECOMMUNITY_ORIGIN_VALIDATION_STATE)
ecommunity_origin_validation_state_str(
encbuf, sizeof(encbuf), pnt);
else
- unk_ecom = 1;
+ unk_ecom = true;
} else {
sub_type = *pnt++;
- unk_ecom = 1;
+ unk_ecom = true;
}
+unknown:
if (unk_ecom)
snprintf(encbuf, sizeof(encbuf), "UNK:%d, %d", type,
sub_type);
@@ -1794,9 +1854,9 @@ ecommunity_add_origin_validation_state(enum rpki_states rpki_state,
* return the BGP link bandwidth extended community, if present;
* the actual bandwidth is returned via param
*/
-const uint8_t *ecommunity_linkbw_present(struct ecommunity *ecom, uint32_t *bw)
+const uint8_t *ecommunity_linkbw_present(struct ecommunity *ecom, uint64_t *bw)
{
- const uint8_t *eval;
+ const uint8_t *data;
uint32_t i;
if (bw)
@@ -1808,24 +1868,49 @@ const uint8_t *ecommunity_linkbw_present(struct ecommunity *ecom, uint32_t *bw)
for (i = 0; i < ecom->size; i++) {
const uint8_t *pnt;
uint8_t type, sub_type;
- uint32_t bwval;
- eval = pnt = (ecom->val + (i * ECOMMUNITY_SIZE));
+ data = pnt = (ecom->val + (i * ecom->unit_size));
type = *pnt++;
sub_type = *pnt++;
+ const uint8_t *end = data + ecom->unit_size;
+ size_t len = end - data;
+
+ /* Sanity check for extended communities lenght, to avoid
+ * overrun when dealing with bits, e.g. ptr_get_be64().
+ */
+ if (len < ecom->unit_size)
+ return NULL;
+
if ((type == ECOMMUNITY_ENCODE_AS ||
type == ECOMMUNITY_ENCODE_AS_NON_TRANS) &&
sub_type == ECOMMUNITY_LINK_BANDWIDTH) {
+ uint32_t bwval;
+
pnt += 2; /* bandwidth is encoded as AS:val */
pnt = ptr_get_be32(pnt, &bwval);
(void)pnt; /* consume value */
if (bw)
- *bw = ecom->disable_ieee_floating
- ? bwval
- : ieee_float_uint32_to_uint32(
- bwval);
- return eval;
+ *bw = (uint64_t)(ecom->disable_ieee_floating
+ ? bwval
+ : ieee_float_uint32_to_uint32(
+ bwval));
+ return data;
+ } else if (type == ECOMMUNITY_ENCODE_AS4 &&
+ sub_type == ECOMMUNITY_EXTENDED_LINK_BANDWIDTH) {
+ uint64_t bwval;
+
+ if (len < IPV6_ECOMMUNITY_SIZE)
+ return NULL;
+
+ pnt += 2; /* Reserved */
+ pnt = ptr_get_be64(pnt, &bwval);
+ (void)pnt;
+
+ if (bw)
+ *bw = bwval;
+
+ return data;
}
}
@@ -1835,13 +1920,13 @@ const uint8_t *ecommunity_linkbw_present(struct ecommunity *ecom, uint32_t *bw)
struct ecommunity *ecommunity_replace_linkbw(as_t as, struct ecommunity *ecom,
uint64_t cum_bw,
- bool disable_ieee_floating)
+ bool disable_ieee_floating,
+ bool extended)
{
struct ecommunity *new;
- struct ecommunity_val lb_eval;
const uint8_t *eval;
uint8_t type;
- uint32_t cur_bw;
+ uint64_t cur_bw;
/* Nothing to replace if link-bandwidth doesn't exist or
* is non-transitive - just return existing extcommunity.
@@ -1865,10 +1950,21 @@ struct ecommunity *ecommunity_replace_linkbw(as_t as, struct ecommunity *ecom,
*/
if (cum_bw > 0xFFFFFFFF)
cum_bw = 0xFFFFFFFF;
- encode_lb_extcomm(as > BGP_AS_MAX ? BGP_AS_TRANS : as, cum_bw, false,
- &lb_eval, disable_ieee_floating);
- new = ecommunity_dup(ecom);
- ecommunity_add_val(new, &lb_eval, true, true);
+
+ if (extended) {
+ struct ecommunity_val_ipv6 lb_eval;
+
+ encode_lb_extended_extcomm(as, cum_bw, false, &lb_eval);
+ new = ecommunity_dup(ecom);
+ ecommunity_add_val_ipv6(new, &lb_eval, true, true);
+ } else {
+ struct ecommunity_val lb_eval;
+
+ encode_lb_extcomm(as > BGP_AS_MAX ? BGP_AS_TRANS : as, cum_bw,
+ false, &lb_eval, disable_ieee_floating);
+ new = ecommunity_dup(ecom);
+ ecommunity_add_val(new, &lb_eval, true, true);
+ }
return new;
}
diff --git a/bgpd/bgp_ecommunity.h b/bgpd/bgp_ecommunity.h
index 62e0430..929e4e6 100644
--- a/bgpd/bgp_ecommunity.h
+++ b/bgpd/bgp_ecommunity.h
@@ -10,6 +10,10 @@
#include "bgpd/bgp_rpki.h"
#include "bgpd/bgpd.h"
+#define ONE_GBPS_BYTES (1000 * 1000 * 1000 / 8)
+#define ONE_MBPS_BYTES (1000 * 1000 / 8)
+#define ONE_KBPS_BYTES (1000 / 8)
+
/* Refer to rfc7153 for the IANA registry definitions. These are
* updated by other standards like rfc7674.
*/
@@ -52,10 +56,14 @@
* 0x0c Flow-spec Redirect to IPv4 - draft-ietf-idr-flowspec-redirect
*/
#define ECOMMUNITY_FLOWSPEC_REDIRECT_IPV4 0x0c
-/* from draft-ietf-idr-flow-spec-v6-09
- * 0x0b Flow-spec Redirect to IPv6
+/* RFC 8956 */
+#define ECOMMUNITY_FLOWSPEC_REDIRECT_IPV6 0x0d
+
+/* https://datatracker.ietf.org/doc/html/draft-li-idr-link-bandwidth-ext-01
+ * Sub-type is allocated by IANA, just the draft is not yet updated with the
+ * new value.
*/
-#define ECOMMUNITY_FLOWSPEC_REDIRECT_IPV6 0x0b
+#define ECOMMUNITY_EXTENDED_LINK_BANDWIDTH 0x0006
/* Low-order octet of the Extended Communities type field for EVPN types */
#define ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY 0x00
@@ -226,12 +234,13 @@ static uint32_t uint32_to_ieee_float_uint32(uint32_t u)
* Encode BGP Link Bandwidth extended community
* bandwidth (bw) is in bytes-per-sec
*/
-static inline void encode_lb_extcomm(as_t as, uint32_t bw, bool non_trans,
+static inline void encode_lb_extcomm(as_t as, uint64_t bw, bool non_trans,
struct ecommunity_val *eval,
bool disable_ieee_floating)
{
- uint32_t bandwidth =
- disable_ieee_floating ? bw : uint32_to_ieee_float_uint32(bw);
+ uint64_t bandwidth = disable_ieee_floating
+ ? bw
+ : uint32_to_ieee_float_uint32(bw);
memset(eval, 0, sizeof(*eval));
eval->val[0] = ECOMMUNITY_ENCODE_AS;
@@ -246,6 +255,33 @@ static inline void encode_lb_extcomm(as_t as, uint32_t bw, bool non_trans,
eval->val[7] = bandwidth & 0xff;
}
+/*
+ * Encode BGP Link Bandwidth inside IPv6 Extended Community,
+ * bandwidth is in bytes per second.
+ */
+static inline void encode_lb_extended_extcomm(as_t as, uint64_t bandwidth,
+ bool non_trans,
+ struct ecommunity_val_ipv6 *eval)
+{
+ memset(eval, 0, sizeof(*eval));
+ eval->val[0] = ECOMMUNITY_ENCODE_AS4;
+ if (non_trans)
+ eval->val[0] |= ECOMMUNITY_FLAG_NON_TRANSITIVE;
+ eval->val[1] = ECOMMUNITY_EXTENDED_LINK_BANDWIDTH;
+ eval->val[4] = (bandwidth >> 56) & 0xff;
+ eval->val[5] = (bandwidth >> 48) & 0xff;
+ eval->val[6] = (bandwidth >> 40) & 0xff;
+ eval->val[7] = (bandwidth >> 32) & 0xff;
+ eval->val[8] = (bandwidth >> 24) & 0xff;
+ eval->val[9] = (bandwidth >> 16) & 0xff;
+ eval->val[10] = (bandwidth >> 8) & 0xff;
+ eval->val[11] = bandwidth & 0xff;
+ eval->val[12] = (as >> 24) & 0xff;
+ eval->val[13] = (as >> 16) & 0xff;
+ eval->val[14] = (as >> 8) & 0xff;
+ eval->val[15] = as & 0xff;
+}
+
static inline void encode_origin_validation_state(enum rpki_states state,
struct ecommunity_val *eval)
{
@@ -327,8 +363,7 @@ extern void ecommunity_free(struct ecommunity **);
extern struct ecommunity *ecommunity_parse(uint8_t *, unsigned short,
bool disable_ieee_floating);
extern struct ecommunity *ecommunity_parse_ipv6(uint8_t *pnt,
- unsigned short length,
- bool disable_ieee_floating);
+ unsigned short length);
extern struct ecommunity *ecommunity_dup(struct ecommunity *);
extern struct ecommunity *ecommunity_merge(struct ecommunity *,
struct ecommunity *);
@@ -346,7 +381,7 @@ extern void ecommunity_strfree(char **s);
extern bool ecommunity_include(struct ecommunity *e1, struct ecommunity *e2);
extern bool ecommunity_match(const struct ecommunity *,
const struct ecommunity *);
-extern char *ecommunity_str(struct ecommunity *ecom);
+extern const char *ecommunity_str(struct ecommunity *ecom);
extern struct ecommunity_val *ecommunity_lookup(const struct ecommunity *,
uint8_t, uint8_t);
@@ -387,11 +422,10 @@ extern void bgp_remove_ecomm_from_aggregate_hash(
struct ecommunity *ecommunity);
extern void bgp_aggr_ecommunity_remove(void *arg);
extern const uint8_t *ecommunity_linkbw_present(struct ecommunity *ecom,
- uint32_t *bw);
-extern struct ecommunity *ecommunity_replace_linkbw(as_t as,
- struct ecommunity *ecom,
- uint64_t cum_bw,
- bool disable_ieee_floating);
+ uint64_t *bw);
+extern struct ecommunity *
+ecommunity_replace_linkbw(as_t as, struct ecommunity *ecom, uint64_t cum_bw,
+ bool disable_ieee_floating, bool extended);
extern bool soo_in_ecom(struct ecommunity *ecom, struct ecommunity *soo);
diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c
index a846484..e660ca5 100644
--- a/bgpd/bgp_evpn.c
+++ b/bgpd/bgp_evpn.c
@@ -892,11 +892,10 @@ struct bgp_dest *bgp_evpn_vni_node_lookup(const struct bgpevpn *vpn,
/*
* Add (update) or delete MACIP from zebra.
*/
-static int bgp_zebra_send_remote_macip(struct bgp *bgp, struct bgpevpn *vpn,
- const struct prefix_evpn *p,
- const struct ethaddr *mac,
- struct in_addr remote_vtep_ip, int add,
- uint8_t flags, uint32_t seq, esi_t *esi)
+static enum zclient_send_status bgp_zebra_send_remote_macip(
+ struct bgp *bgp, struct bgpevpn *vpn, const struct prefix_evpn *p,
+ const struct ethaddr *mac, struct in_addr remote_vtep_ip, int add,
+ uint8_t flags, uint32_t seq, esi_t *esi)
{
struct stream *s;
uint16_t ipa_len;
@@ -904,8 +903,12 @@ static int bgp_zebra_send_remote_macip(struct bgp *bgp, struct bgpevpn *vpn,
bool esi_valid;
/* Check socket. */
- if (!zclient || zclient->sock < 0)
- return 0;
+ if (!zclient || zclient->sock < 0) {
+ if (BGP_DEBUG(zebra, ZEBRA))
+ zlog_debug("%s: No zclient or zclient->sock exists",
+ __func__);
+ return ZCLIENT_SEND_SUCCESS;
+ }
/* Don't try to register if Zebra doesn't know of this instance. */
if (!IS_BGP_INST_KNOWN_TO_ZEBRA(bgp)) {
@@ -913,7 +916,7 @@ static int bgp_zebra_send_remote_macip(struct bgp *bgp, struct bgpevpn *vpn,
zlog_debug(
"%s: No zebra instance to talk to, not installing remote macip",
__func__);
- return 0;
+ return ZCLIENT_SEND_SUCCESS;
}
if (!esi)
@@ -979,24 +982,26 @@ static int bgp_zebra_send_remote_macip(struct bgp *bgp, struct bgpevpn *vpn,
frrtrace(5, frr_bgp, evpn_mac_ip_zsend, add, vpn, p, remote_vtep_ip,
esi);
- if (zclient_send_message(zclient) == ZCLIENT_SEND_FAILURE)
- return -1;
-
- return 0;
+ return zclient_send_message(zclient);
}
/*
* Add (update) or delete remote VTEP from zebra.
*/
-static int bgp_zebra_send_remote_vtep(struct bgp *bgp, struct bgpevpn *vpn,
- const struct prefix_evpn *p,
- int flood_control, int add)
+static enum zclient_send_status
+bgp_zebra_send_remote_vtep(struct bgp *bgp, struct bgpevpn *vpn,
+ const struct prefix_evpn *p, int flood_control,
+ int add)
{
struct stream *s;
/* Check socket. */
- if (!zclient || zclient->sock < 0)
- return 0;
+ if (!zclient || zclient->sock < 0) {
+ if (BGP_DEBUG(zebra, ZEBRA))
+ zlog_debug("%s: No zclient or zclient->sock exists",
+ __func__);
+ return ZCLIENT_SEND_SUCCESS;
+ }
/* Don't try to register if Zebra doesn't know of this instance. */
if (!IS_BGP_INST_KNOWN_TO_ZEBRA(bgp)) {
@@ -1004,7 +1009,7 @@ static int bgp_zebra_send_remote_vtep(struct bgp *bgp, struct bgpevpn *vpn,
zlog_debug(
"%s: No zebra instance to talk to, not installing remote vtep",
__func__);
- return 0;
+ return ZCLIENT_SEND_SUCCESS;
}
s = zclient->obuf;
@@ -1021,7 +1026,7 @@ static int bgp_zebra_send_remote_vtep(struct bgp *bgp, struct bgpevpn *vpn,
EC_BGP_VTEP_INVALID,
"Bad remote IP when trying to %s remote VTEP for VNI %u",
add ? "ADD" : "DEL", (vpn ? vpn->vni : 0));
- return -1;
+ return ZCLIENT_SEND_FAILURE;
}
stream_putl(s, flood_control);
@@ -1034,10 +1039,7 @@ static int bgp_zebra_send_remote_vtep(struct bgp *bgp, struct bgpevpn *vpn,
frrtrace(3, frr_bgp, evpn_bum_vtep_zsend, add, vpn, p);
- if (zclient_send_message(zclient) == ZCLIENT_SEND_FAILURE)
- return -1;
-
- return 0;
+ return zclient_send_message(zclient);
}
/*
@@ -1263,14 +1265,14 @@ 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,
- const struct prefix_evpn *p,
- struct bgp_path_info *pi)
+enum zclient_send_status evpn_zebra_install(struct bgp *bgp, struct bgpevpn *vpn,
+ const struct prefix_evpn *p,
+ struct bgp_path_info *pi)
{
- int ret;
uint8_t flags;
int flood_control = VXLAN_FLOOD_DISABLED;
uint32_t seq;
+ enum zclient_send_status ret = ZCLIENT_SEND_SUCCESS;
if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) {
flags = 0;
@@ -1348,6 +1350,7 @@ static int evpn_zebra_install(struct bgp *bgp, struct bgpevpn *vpn,
flood_control = VXLAN_FLOOD_DISABLED;
break;
}
+
ret = bgp_zebra_send_remote_vtep(bgp, vpn, p, flood_control, 1);
}
@@ -1355,11 +1358,13 @@ 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,
- const struct prefix_evpn *p,
- struct bgp_path_info *pi, bool is_sync)
+enum zclient_send_status evpn_zebra_uninstall(struct bgp *bgp,
+ struct bgpevpn *vpn,
+ const struct prefix_evpn *p,
+ struct bgp_path_info *pi,
+ bool is_sync)
{
- int ret;
+ enum zclient_send_status ret = ZCLIENT_SEND_SUCCESS;
if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE)
ret = bgp_zebra_send_remote_macip(
@@ -1374,7 +1379,7 @@ static int evpn_zebra_uninstall(struct bgp *bgp, struct bgpevpn *vpn,
ret = bgp_evpn_remote_es_evi_del(bgp, vpn, p);
else
ret = bgp_zebra_send_remote_vtep(bgp, vpn, p,
- VXLAN_FLOOD_DISABLED, 0);
+ VXLAN_FLOOD_DISABLED, 0);
return ret;
}
@@ -1424,7 +1429,7 @@ static void evpn_delete_old_local_route(struct bgp *bgp, struct bgpevpn *vpn,
* this table.
*/
if (pi)
- bgp_process(bgp, global_dest, afi, safi);
+ bgp_process(bgp, global_dest, pi, afi, safi);
bgp_dest_unlock_node(global_dest);
}
@@ -1438,14 +1443,29 @@ static void evpn_delete_old_local_route(struct bgp *bgp, struct bgpevpn *vpn,
* Note: vpn is NULL for local EAD-ES routes.
*/
int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn,
- struct bgp_dest *dest)
+ struct bgp_dest *dest, struct bgp_path_info *pi)
{
- struct bgp_path_info *old_select, *new_select;
+ struct bgp_path_info *old_select, *new_select, *first;
struct bgp_path_info_pair old_and_new;
afi_t afi = AFI_L2VPN;
safi_t safi = SAFI_EVPN;
int ret = 0;
+ first = bgp_dest_get_bgp_path_info(dest);
+ SET_FLAG(pi->flags, BGP_PATH_UNSORTED);
+ if (pi != first) {
+ if (pi->next)
+ pi->next->prev = pi->prev;
+ if (pi->prev)
+ pi->prev->next = pi->next;
+
+ if (first)
+ first->prev = pi;
+ pi->next = first;
+ pi->prev = NULL;
+ bgp_dest_set_bgp_path_info(dest, pi);
+ }
+
/* Compute the best path. */
bgp_best_selection(bgp, dest, &bgp->maxpaths[afi][safi], &old_and_new,
afi, safi);
@@ -1465,12 +1485,19 @@ int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn,
&& !CHECK_FLAG(dest->flags, BGP_NODE_USER_CLEAR)
&& !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(old_select))
- ret = evpn_zebra_install(
- bgp, vpn,
- (const struct prefix_evpn *)bgp_dest_get_prefix(
- dest),
- old_select);
+ if (bgp_zebra_has_route_changed(old_select)) {
+ if (CHECK_FLAG(bgp->flags, BGP_FLAG_DELETE_IN_PROGRESS))
+ ret = evpn_zebra_install(bgp, vpn,
+ (const struct prefix_evpn
+ *)
+ bgp_dest_get_prefix(
+ dest),
+ old_select);
+ else
+ bgp_zebra_route_install(dest, old_select, bgp,
+ true, vpn, false);
+ }
+
UNSET_FLAG(old_select->flags, BGP_PATH_MULTIPATH_CHG);
UNSET_FLAG(old_select->flags, BGP_PATH_LINK_BW_CHG);
bgp_zebra_clear_route_change_flags(dest);
@@ -1502,10 +1529,15 @@ 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 ||
bgp_evpn_attr_is_sync(new_select->attr))) {
- ret = evpn_zebra_install(
- bgp, vpn,
- (struct prefix_evpn *)bgp_dest_get_prefix(dest),
- new_select);
+ if (CHECK_FLAG(bgp->flags, BGP_FLAG_DELETE_IN_PROGRESS))
+ ret = evpn_zebra_install(bgp, vpn,
+ (const struct prefix_evpn *)
+ bgp_dest_get_prefix(
+ dest),
+ new_select);
+ else
+ bgp_zebra_route_install(dest, new_select, bgp, true,
+ vpn, false);
/* If an old best existed and it was a "local" route, the only
* reason
@@ -1522,13 +1554,20 @@ int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn,
evpn_delete_old_local_route(bgp, vpn, dest,
old_select, new_select);
} else {
- if (old_select && old_select->type == ZEBRA_ROUTE_BGP
- && old_select->sub_type == BGP_ROUTE_IMPORTED)
- ret = evpn_zebra_uninstall(
- bgp, vpn,
- (const struct prefix_evpn *)bgp_dest_get_prefix(
- dest),
- old_select, false);
+ if (old_select && old_select->type == ZEBRA_ROUTE_BGP &&
+ old_select->sub_type == BGP_ROUTE_IMPORTED) {
+ if (CHECK_FLAG(bgp->flags, BGP_FLAG_DELETE_IN_PROGRESS) ||
+ CHECK_FLAG(bgp->flags, BGP_FLAG_VNI_DOWN))
+ ret = evpn_zebra_uninstall(bgp, vpn,
+ (const struct prefix_evpn
+ *)
+ bgp_dest_get_prefix(
+ dest),
+ old_select, false);
+ else
+ bgp_zebra_route_install(dest, old_select, bgp,
+ false, vpn, false);
+ }
}
/* Clear any route change flags. */
@@ -1561,11 +1600,12 @@ static struct bgp_path_info *bgp_evpn_route_get_local_path(
static int update_evpn_type5_route_entry(struct bgp *bgp_evpn,
struct bgp *bgp_vrf, afi_t afi,
safi_t safi, struct bgp_dest *dest,
- struct attr *attr, int *route_changed)
+ struct attr *attr, int *route_changed,
+ struct bgp_path_info **entry)
{
struct attr *attr_new = NULL;
struct bgp_path_info *pi = NULL;
- mpls_label_t label = MPLS_INVALID_LABEL;
+ struct bgp_labels bgp_labels = {};
struct bgp_path_info *local_pi = NULL;
struct bgp_path_info *tmp_pi = NULL;
@@ -1593,14 +1633,19 @@ static int update_evpn_type5_route_entry(struct bgp *bgp_evpn,
/* Type-5 routes advertise the L3-VNI */
bgp_path_info_extra_get(pi);
- vni2label(bgp_vrf->l3vni, &label);
- memcpy(&pi->extra->label, &label, sizeof(label));
- pi->extra->num_labels = 1;
+ vni2label(bgp_vrf->l3vni, &bgp_labels.label[0]);
+ bgp_labels.num_labels = 1;
+ if (!bgp_path_info_labels_same(pi, &bgp_labels.label[0],
+ bgp_labels.num_labels)) {
+ bgp_labels_unintern(&pi->extra->labels);
+ pi->extra->labels = bgp_labels_intern(&bgp_labels);
+ }
+
/* add the route entry to route node*/
bgp_path_info_add(dest, pi);
+ *entry = pi;
} else {
-
tmp_pi = local_pi;
if (!attrhash_cmp(tmp_pi->attr, attr)) {
@@ -1622,6 +1667,7 @@ static int update_evpn_type5_route_entry(struct bgp *bgp_evpn,
tmp_pi->attr = attr_new;
tmp_pi->uptime = monotime(NULL);
}
+ *entry = local_pi;
}
return 0;
}
@@ -1637,6 +1683,7 @@ static int update_evpn_type5_route(struct bgp *bgp_vrf, struct prefix_evpn *evp,
struct bgp_dest *dest = NULL;
struct bgp *bgp_evpn = NULL;
int route_changed = 0;
+ struct bgp_path_info *pi = NULL;
bgp_evpn = bgp_get_evpn();
if (!bgp_evpn)
@@ -1718,11 +1765,11 @@ static int update_evpn_type5_route(struct bgp *bgp_vrf, struct prefix_evpn *evp,
/* create or update the route entry within the route node */
update_evpn_type5_route_entry(bgp_evpn, bgp_vrf, afi, safi, dest, &attr,
- &route_changed);
+ &route_changed, &pi);
/* schedule for processing and unlock node */
if (route_changed) {
- bgp_process(bgp_evpn, dest, afi, safi);
+ bgp_process(bgp_evpn, dest, pi, afi, safi);
bgp_dest_unlock_node(dest);
}
@@ -1891,15 +1938,13 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
struct bgp_path_info *local_pi;
struct attr *attr_new;
struct attr local_attr;
- mpls_label_t label[BGP_MAX_LABELS];
- uint32_t num_labels = 1;
+ struct bgp_labels bgp_labels = {};
int route_change = 1;
uint8_t sticky = 0;
const struct prefix_evpn *evp;
*pi = NULL;
evp = (const struct prefix_evpn *)bgp_dest_get_prefix(dest);
- memset(&label, 0, sizeof(label));
/* See if this is an update of an existing route, or a new add. */
local_pi = bgp_evpn_route_get_local_path(bgp, dest);
@@ -1941,7 +1986,8 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
bgp_path_info_extra_get(tmp_pi);
/* The VNI goes into the 'label' field of the route */
- vni2label(vpn->vni, &label[0]);
+ vni2label(vpn->vni, &bgp_labels.label[0]);
+ bgp_labels.num_labels = 1;
/* Type-2 routes may carry a second VNI - the L3-VNI.
* Only attach second label if we are advertising two labels for
@@ -1953,13 +1999,16 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
l3vni = bgpevpn_get_l3vni(vpn);
if (l3vni) {
- vni2label(l3vni, &label[1]);
- num_labels++;
+ vni2label(l3vni, &bgp_labels.label[1]);
+ bgp_labels.num_labels++;
}
}
- memcpy(&tmp_pi->extra->label, label, sizeof(label));
- tmp_pi->extra->num_labels = num_labels;
+ if (!bgp_path_info_labels_same(tmp_pi, &bgp_labels.label[0],
+ bgp_labels.num_labels)) {
+ bgp_labels_unintern(&tmp_pi->extra->labels);
+ tmp_pi->extra->labels = bgp_labels_intern(&bgp_labels);
+ }
if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) {
if (mac)
@@ -1983,7 +2032,8 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
* The attributes have changed, type-2 routes needs to
* be advertised with right labels.
*/
- vni2label(vpn->vni, &label[0]);
+ vni2label(vpn->vni, &bgp_labels.label[0]);
+ bgp_labels.num_labels = 1;
if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE
&& CHECK_FLAG(vpn->flags,
VNI_FLAG_USE_TWO_LABELS)) {
@@ -1991,12 +2041,17 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
l3vni = bgpevpn_get_l3vni(vpn);
if (l3vni) {
- vni2label(l3vni, &label[1]);
- num_labels++;
+ vni2label(l3vni, &bgp_labels.label[1]);
+ bgp_labels.num_labels++;
}
}
- memcpy(&tmp_pi->extra->label, label, sizeof(label));
- tmp_pi->extra->num_labels = num_labels;
+ if (!bgp_path_info_labels_same(tmp_pi,
+ &bgp_labels.label[0],
+ bgp_labels.num_labels)) {
+ bgp_labels_unintern(&tmp_pi->extra->labels);
+ tmp_pi->extra->labels =
+ bgp_labels_intern(&bgp_labels);
+ }
if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) {
if (mac)
@@ -2062,9 +2117,19 @@ 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 ||
bgp_evpn_attr_is_sync(curr_select->attr)))
- evpn_zebra_install(bgp, vpn,
- (const struct prefix_evpn *)bgp_dest_get_prefix(dest),
- curr_select);
+ if (curr_select && curr_select->type == ZEBRA_ROUTE_BGP &&
+ (curr_select->sub_type == BGP_ROUTE_IMPORTED ||
+ bgp_evpn_attr_is_sync(curr_select->attr))) {
+ if (CHECK_FLAG(bgp->flags, BGP_FLAG_DELETE_IN_PROGRESS))
+ evpn_zebra_install(bgp, vpn,
+ (const struct prefix_evpn *)
+ bgp_dest_get_prefix(
+ dest),
+ curr_select);
+ else
+ bgp_zebra_route_install(dest, curr_select, bgp,
+ true, vpn, false);
+ }
}
/*
@@ -2222,7 +2287,7 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn,
* route would win, and we should evict the defunct local route
* and (re)install the remote route into zebra.
*/
- evpn_route_select_install(bgp, vpn, dest);
+ evpn_route_select_install(bgp, vpn, dest, pi);
/*
* If the new local route was not selected evict it and tell zebra
* to re-add the best remote dest. BGP doesn't retain non-best local
@@ -2245,8 +2310,16 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn,
* has been removed.
*/
new_is_sync = bgp_evpn_attr_is_sync(pi->attr);
- if (!new_is_sync && old_is_sync)
- evpn_zebra_uninstall(bgp, vpn, p, pi, true);
+ if (!new_is_sync && old_is_sync) {
+ if (CHECK_FLAG(bgp->flags,
+ BGP_FLAG_DELETE_IN_PROGRESS))
+ evpn_zebra_uninstall(bgp, vpn, p, pi,
+ true);
+ else
+ bgp_zebra_route_install(dest, pi, bgp,
+ false, vpn,
+ true);
+ }
}
}
bgp_path_info_unlock(pi);
@@ -2270,7 +2343,7 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn,
false /* setup_sync */, NULL /* old_is_sync */);
/* Schedule for processing and unlock node. */
- bgp_process(bgp, dest, afi, safi);
+ bgp_process(bgp, dest, global_pi, afi, safi);
bgp_dest_unlock_node(dest);
}
@@ -2330,7 +2403,7 @@ static int delete_evpn_type5_route(struct bgp *bgp_vrf, struct prefix_evpn *evp)
delete_evpn_route_entry(bgp_evpn, afi, safi, dest, &pi);
if (pi)
- bgp_process(bgp_evpn, dest, afi, safi);
+ bgp_process(bgp_evpn, dest, pi, afi, safi);
bgp_dest_unlock_node(dest);
return 0;
}
@@ -2370,7 +2443,7 @@ static int delete_evpn_route(struct bgp *bgp, struct bgpevpn *vpn,
* this table.
*/
if (pi)
- bgp_process(bgp, global_dest, afi, safi);
+ bgp_process(bgp, global_dest, pi, afi, safi);
bgp_dest_unlock_node(global_dest);
}
@@ -2378,9 +2451,8 @@ static int delete_evpn_route(struct bgp *bgp, struct bgpevpn *vpn,
*/
delete_evpn_route_entry(bgp, afi, safi, dest, &pi);
if (pi) {
- dest = bgp_path_info_reap(dest, pi);
- assert(dest);
- evpn_route_select_install(bgp, vpn, dest);
+ bgp_path_info_delete(dest, pi);
+ evpn_route_select_install(bgp, vpn, dest, pi);
}
/* dest should still exist due to locking make coverity happy */
@@ -2494,7 +2566,7 @@ void bgp_evpn_update_type2_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
* advertised to peers; otherwise, ensure it is evicted and
* (re)install the remote route into zebra.
*/
- evpn_route_select_install(bgp, vpn, dest);
+ evpn_route_select_install(bgp, vpn, dest, pi);
if (CHECK_FLAG(pi->flags, BGP_PATH_REMOVED)) {
route_change = 0;
@@ -2512,8 +2584,17 @@ void bgp_evpn_update_type2_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
* has been removed.
*/
new_is_sync = bgp_evpn_attr_is_sync(pi->attr);
- if (!new_is_sync && old_is_sync)
- evpn_zebra_uninstall(bgp, vpn, &evp, pi, true);
+ if (!new_is_sync && old_is_sync) {
+ if (CHECK_FLAG(bgp->flags,
+ BGP_FLAG_DELETE_IN_PROGRESS))
+ (void)evpn_zebra_uninstall(bgp, vpn,
+ &evp, pi,
+ true);
+ else
+ bgp_zebra_route_install(dest, pi, bgp,
+ false, vpn,
+ true);
+ }
}
}
@@ -2533,7 +2614,7 @@ void bgp_evpn_update_type2_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
NULL /* old_is_sync */);
/* Schedule for processing and unlock node. */
- bgp_process(bgp, global_dest, afi, safi);
+ bgp_process(bgp, global_dest, global_pi, afi, safi);
bgp_dest_unlock_node(global_dest);
}
@@ -2618,7 +2699,7 @@ static void delete_global_type2_routes(struct bgp *bgp, struct bgpevpn *vpn)
delete_evpn_route_entry(bgp, afi, safi, dest, &pi);
if (pi)
- bgp_process(bgp, dest, afi, safi);
+ bgp_process(bgp, dest, pi, afi, safi);
}
/* Unlock RD node. */
@@ -2795,7 +2876,22 @@ static int delete_routes_for_vni(struct bgp *bgp, struct bgpevpn *vpn)
delete_all_type2_routes(bgp, vpn);
build_evpn_type3_prefix(&p, vpn->originator_ip);
+
+ /*
+ * To handle the following scenario:
+ * - Say, the new zebra announce fifo list has few vni Evpn prefixes yet
+ * to be sent to zebra.
+ * - At this point if we have triggers like "no advertise-all-vni" or
+ * "networking restart", where a vni is going down.
+ *
+ * Perform the below
+ * 1) send withdraw routes to zebra immediately in case it is installed.
+ * 2) before we blow up the vni table, we need to walk the list and
+ * pop all the dest whose za_vpn points to this vni.
+ */
+ SET_FLAG(bgp->flags, BGP_FLAG_VNI_DOWN);
ret = delete_evpn_route(bgp, vpn, &p);
+ UNSET_FLAG(bgp->flags, BGP_FLAG_VNI_DOWN);
if (ret)
return ret;
@@ -2903,12 +2999,11 @@ bgp_create_evpn_bgp_path_info(struct bgp_path_info *parent_pi,
sizeof(struct bgp_path_info_extra_vrfleak));
pi->extra->vrfleak->parent = bgp_path_info_lock(parent_pi);
bgp_dest_lock_node((struct bgp_dest *)parent_pi->net);
- if (parent_pi->extra) {
- memcpy(&pi->extra->label, &parent_pi->extra->label,
- sizeof(pi->extra->label));
- pi->extra->num_labels = parent_pi->extra->num_labels;
+ if (parent_pi->extra)
pi->extra->igpmetric = parent_pi->extra->igpmetric;
- }
+
+ if (bgp_path_info_num_labels(parent_pi))
+ pi->extra->labels = bgp_labels_intern(parent_pi->extra->labels);
bgp_path_info_add(dest, pi);
@@ -2945,6 +3040,9 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf,
vrf_id_to_name(bgp_vrf->vrf_id), evp, parent_pi,
parent_pi->flags);
+ if (bgp_vrf->vrf_id == VRF_UNKNOWN)
+ return -1;
+
/* Create (or fetch) route within the VRF. */
/* NOTE: There is no RD here. */
if (is_evpn_prefix_ipaddr_v4(evp)) {
@@ -3072,7 +3170,7 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf,
safi);
/* Perform route selection and update zebra, if required. */
- bgp_process(bgp_vrf, dest, afi, safi);
+ bgp_process(bgp_vrf, dest, pi, afi, safi);
/* Process for route leaking. */
vpn_leak_from_vrf_update(bgp_get_default(), bgp_vrf, pi);
@@ -3184,7 +3282,7 @@ static int install_evpn_route_entry_in_vni_common(
bgp_evpn_remote_ip_hash_add(vpn, pi);
/* Perform route selection and update zebra, if required. */
- ret = evpn_route_select_install(bgp, vpn, dest);
+ ret = evpn_route_select_install(bgp, vpn, dest, pi);
/* if the best path is a local path with a non-zero ES
* sync info against the local path may need to be updated
@@ -3226,7 +3324,7 @@ static int uninstall_evpn_route_entry_in_vni_common(
bgp_path_info_delete(dest, pi);
/* Perform route selection and update zebra, if required. */
- ret = evpn_route_select_install(bgp, vpn, dest);
+ ret = evpn_route_select_install(bgp, vpn, dest, pi);
/* if the best path is a local path with a non-zero ES
* sync info against the local path may need to be updated
@@ -3434,7 +3532,7 @@ static int uninstall_evpn_route_entry_in_vrf(struct bgp *bgp_vrf,
bgp_evpn_path_nh_del(bgp_vrf, pi);
/* Perform route selection and update zebra, if required. */
- bgp_process(bgp_vrf, dest, afi, safi);
+ bgp_process(bgp_vrf, dest, pi, afi, safi);
/* Unlock route node. */
bgp_dest_unlock_node(dest);
@@ -3799,7 +3897,7 @@ int bgp_evpn_route_entry_install_if_vrf_match(struct bgp *bgp_vrf,
* Install or uninstall mac-ip routes are appropriate for this
* particular VRF.
*/
-static int install_uninstall_routes_for_vrf(struct bgp *bgp_vrf, int install)
+static int install_uninstall_routes_for_vrf(struct bgp *bgp_vrf, bool install)
{
afi_t afi;
safi_t safi;
@@ -3863,9 +3961,7 @@ static int install_uninstall_routes_for_vrf(struct bgp *bgp_vrf, int install)
* particular VNI.
*/
static int install_uninstall_routes_for_vni(struct bgp *bgp,
- struct bgpevpn *vpn,
- bgp_evpn_route_type rtype,
- int install)
+ struct bgpevpn *vpn, bool install)
{
afi_t afi;
safi_t safi;
@@ -3896,7 +3992,9 @@ static int install_uninstall_routes_for_vni(struct bgp *bgp,
(const struct prefix_evpn *)bgp_dest_get_prefix(
dest);
- if (evp->prefix.route_type != rtype)
+ if (evp->prefix.route_type != BGP_EVPN_IMET_ROUTE &&
+ evp->prefix.route_type != BGP_EVPN_AD_ROUTE &&
+ evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE)
continue;
for (pi = bgp_dest_get_bgp_path_info(dest); pi;
@@ -3923,16 +4021,16 @@ static int install_uninstall_routes_for_vni(struct bgp *bgp,
bgp, vpn, evp, pi);
if (ret) {
- flog_err(
- EC_BGP_EVPN_FAIL,
- "%u: Failed to %s EVPN %s route in VNI %u",
- bgp->vrf_id,
- install ? "install"
- : "uninstall",
- rtype == BGP_EVPN_MAC_IP_ROUTE
- ? "MACIP"
- : "IMET",
- vpn->vni);
+ flog_err(EC_BGP_EVPN_FAIL,
+ "%u: Failed to %s EVPN %s route in VNI %u",
+ bgp->vrf_id,
+ install ? "install"
+ : "uninstall",
+ evp->prefix.route_type ==
+ BGP_EVPN_MAC_IP_ROUTE
+ ? "MACIP"
+ : "IMET",
+ vpn->vni);
bgp_dest_unlock_node(rd_dest);
bgp_dest_unlock_node(dest);
@@ -3950,7 +4048,7 @@ static int install_uninstall_routes_for_vni(struct bgp *bgp,
*/
static int install_routes_for_vrf(struct bgp *bgp_vrf)
{
- install_uninstall_routes_for_vrf(bgp_vrf, 1);
+ install_uninstall_routes_for_vrf(bgp_vrf, true);
return 0;
}
@@ -3961,29 +4059,17 @@ static int install_routes_for_vrf(struct bgp *bgp_vrf)
*/
static int install_routes_for_vni(struct bgp *bgp, struct bgpevpn *vpn)
{
- int ret;
-
- /* Install type-3 routes followed by type-2 routes - the ones applicable
+ /*
+ * Install type-3 routes followed by type-2 routes - the ones applicable
* for this VNI.
*/
- ret = install_uninstall_routes_for_vni(bgp, vpn, BGP_EVPN_IMET_ROUTE,
- 1);
- if (ret)
- return ret;
-
- ret = install_uninstall_routes_for_vni(bgp, vpn, BGP_EVPN_AD_ROUTE,
- 1);
- if (ret)
- return ret;
-
- return install_uninstall_routes_for_vni(bgp, vpn, BGP_EVPN_MAC_IP_ROUTE,
- 1);
+ return install_uninstall_routes_for_vni(bgp, vpn, true);
}
/* uninstall routes from l3vni vrf. */
static int uninstall_routes_for_vrf(struct bgp *bgp_vrf)
{
- install_uninstall_routes_for_vrf(bgp_vrf, 0);
+ install_uninstall_routes_for_vrf(bgp_vrf, false);
return 0;
}
@@ -3993,25 +4079,11 @@ static int uninstall_routes_for_vrf(struct bgp *bgp_vrf)
*/
static int uninstall_routes_for_vni(struct bgp *bgp, struct bgpevpn *vpn)
{
- int ret;
-
- /* Uninstall type-2 routes followed by type-3 routes - the ones
- * applicable
- * for this VNI.
+ /*
+ * Uninstall type-2 routes followed by type-3 routes - the ones
+ * applicable for this VNI.
*/
- ret = install_uninstall_routes_for_vni(bgp, vpn, BGP_EVPN_MAC_IP_ROUTE,
- 0);
- if (ret)
- return ret;
-
- ret = install_uninstall_routes_for_vni(bgp, vpn, BGP_EVPN_AD_ROUTE,
- 0);
- if (ret)
- return ret;
-
-
- return install_uninstall_routes_for_vni(bgp, vpn, BGP_EVPN_IMET_ROUTE,
- 0);
+ return install_uninstall_routes_for_vni(bgp, vpn, false);
}
/*
@@ -4431,7 +4503,7 @@ static void update_advertise_vni_route(struct bgp *bgp, struct bgpevpn *vpn,
}
/* Schedule for processing and unlock node. */
- bgp_process(bgp, global_dest, afi, safi);
+ bgp_process(bgp, global_dest, global_pi, afi, safi);
bgp_dest_unlock_node(global_dest);
}
@@ -4481,7 +4553,7 @@ static void update_advertise_vni_routes(struct bgp *bgp, struct bgpevpn *vpn)
false /* setup_sync */, NULL /* old_is_sync */);
/* Schedule for processing and unlock node. */
- bgp_process(bgp, global_dest, afi, safi);
+ bgp_process(bgp, global_dest, pi, afi, safi);
bgp_dest_unlock_node(global_dest);
}
@@ -4526,7 +4598,7 @@ static int delete_withdraw_vni_routes(struct bgp *bgp, struct bgpevpn *vpn)
* this table.
*/
if (pi)
- bgp_process(bgp, global_dest, afi, safi);
+ bgp_process(bgp, global_dest, pi, afi, safi);
bgp_dest_unlock_node(global_dest);
}
@@ -4622,7 +4694,7 @@ static int process_type2_route(struct peer *peer, afi_t afi, safi_t safi,
uint8_t macaddr_len;
/* holds the VNI(s) as in packet */
mpls_label_t label[BGP_MAX_LABELS] = {};
- uint32_t num_labels = 0;
+ uint8_t num_labels = 0;
uint32_t eth_tag;
int ret = 0;
@@ -4965,7 +5037,7 @@ static int process_type5_route(struct peer *peer, afi_t afi, safi_t safi,
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,
+ mpls_label_t *label, uint8_t num_labels,
struct attr *attr)
{
int len;
@@ -5755,7 +5827,7 @@ int bgp_evpn_uninstall_routes(struct bgp *bgp, struct bgpevpn *vpn)
/*
* TODO: Hardcoded for a maximum of 2 VNIs right now
*/
-char *bgp_evpn_label2str(mpls_label_t *label, uint32_t num_labels, char *buf,
+char *bgp_evpn_label2str(mpls_label_t *label, uint8_t num_labels, char *buf,
int len)
{
vni_t vni1, vni2;
@@ -5839,7 +5911,7 @@ void bgp_evpn_route2json(const struct prefix_evpn *p, json_object *json)
*/
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,
+ uint8_t num_labels, struct attr *attr,
bool addpath_capable, uint32_t addpath_tx_id)
{
struct prefix_evpn *evp = (struct prefix_evpn *)p;
@@ -6262,6 +6334,19 @@ struct bgpevpn *bgp_evpn_new(struct bgp *bgp, vni_t vni,
*/
void bgp_evpn_free(struct bgp *bgp, struct bgpevpn *vpn)
{
+ struct bgp_dest *dest = NULL;
+ struct bgp_dest *dest_next = NULL;
+
+ for (dest = zebra_announce_first(&bm->zebra_announce_head); dest;
+ dest = dest_next) {
+ dest_next = zebra_announce_next(&bm->zebra_announce_head, dest);
+ if (dest->za_vpn == vpn) {
+ zebra_announce_del(&bm->zebra_announce_head, dest);
+ bgp_path_info_unlock(dest->za_bgp_pi);
+ bgp_dest_unlock_node(dest);
+ }
+ }
+
bgp_evpn_remote_ip_hash_destroy(vpn);
bgp_evpn_vni_es_cleanup(vpn);
bgpevpn_unlink_from_l3vni(vpn);
@@ -6425,9 +6510,10 @@ void bgp_filter_evpn_routes_upon_martian_change(
for (dest = bgp_table_top(table); dest;
dest = bgp_route_next(dest)) {
+ struct bgp_path_info *next;
- for (pi = bgp_dest_get_bgp_path_info(dest); pi;
- pi = pi->next) {
+ for (pi = bgp_dest_get_bgp_path_info(dest);
+ (pi != NULL) && (next = pi->next, 1); pi = next) {
bool affected = false;
const struct prefix *p;
@@ -6904,6 +6990,17 @@ int bgp_evpn_local_l3vni_del(vni_t l3vni, vrf_id_t vrf_id)
}
/*
+ * When bgp instance goes down also clean up what might have been left over
+ * from evpn.
+ */
+void bgp_evpn_instance_down(struct bgp *bgp)
+{
+ /* If we have a stale local vni, delete it */
+ if (bgp->l3vni)
+ bgp_evpn_local_l3vni_del(bgp->l3vni, bgp->vrf_id);
+}
+
+/*
* Handle del of a local VNI.
*/
int bgp_evpn_local_vni_del(struct bgp *bgp, vni_t vni)
@@ -7669,7 +7766,7 @@ void bgp_evpn_handle_resolve_overlay_index_unset(struct hash_bucket *bucket,
*
*/
mpls_label_t *bgp_evpn_path_info_labels_get_l3vni(mpls_label_t *labels,
- uint32_t num_labels)
+ uint8_t num_labels)
{
if (!labels)
return NULL;
@@ -7688,8 +7785,10 @@ vni_t bgp_evpn_path_info_get_l3vni(const struct bgp_path_info *pi)
if (!pi->extra)
return 0;
- return label2vni(bgp_evpn_path_info_labels_get_l3vni(
- pi->extra->label, pi->extra->num_labels));
+ return label2vni(
+ bgp_evpn_path_info_labels_get_l3vni(pi->extra->labels->label,
+ pi->extra->labels
+ ->num_labels));
}
/*
diff --git a/bgpd/bgp_evpn.h b/bgpd/bgp_evpn.h
index c641a64..dc82bcf 100644
--- a/bgpd/bgp_evpn.h
+++ b/bgpd/bgp_evpn.h
@@ -115,12 +115,12 @@ extern void bgp_evpn_advertise_type5_routes(struct bgp *bgp_vrf, afi_t afi,
safi_t safi);
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,
+extern char *bgp_evpn_label2str(mpls_label_t *label, uint8_t num_labels,
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,
+ mpls_label_t *label, uint8_t num_labels,
struct attr *attr, bool addpath_capable,
uint32_t addpath_tx_id);
extern int bgp_nlri_parse_evpn(struct peer *peer, struct attr *attr,
@@ -153,6 +153,7 @@ extern int bgp_evpn_local_l3vni_add(vni_t vni, vrf_id_t vrf_id,
struct in_addr originator_ip, int filter,
ifindex_t svi_ifindex, bool is_anycast_mac);
extern int bgp_evpn_local_l3vni_del(vni_t vni, vrf_id_t vrf_id);
+extern void bgp_evpn_instance_down(struct bgp *bgp);
extern int bgp_evpn_local_vni_del(struct bgp *bgp, vni_t vni);
extern int bgp_evpn_local_vni_add(struct bgp *bgp, vni_t vni,
struct in_addr originator_ip,
@@ -177,7 +178,7 @@ extern void
bgp_evpn_handle_resolve_overlay_index_unset(struct hash_bucket *bucket,
void *arg);
extern mpls_label_t *bgp_evpn_path_info_labels_get_l3vni(mpls_label_t *labels,
- uint32_t num_labels);
+ uint8_t num_labels);
extern vni_t bgp_evpn_path_info_get_l3vni(const struct bgp_path_info *pi);
extern bool bgp_evpn_mpath_has_dvni(const struct bgp *bgp_vrf,
struct bgp_path_info *mpinfo);
@@ -186,4 +187,12 @@ extern bool is_route_injectable_into_evpn_non_supp(struct bgp_path_info *pi);
extern void bgp_aggr_supp_withdraw_from_evpn(struct bgp *bgp, afi_t afi,
safi_t safi);
+extern enum zclient_send_status evpn_zebra_install(struct bgp *bgp,
+ struct bgpevpn *vpn,
+ const struct prefix_evpn *p,
+ struct bgp_path_info *pi);
+extern enum zclient_send_status
+evpn_zebra_uninstall(struct bgp *bgp, struct bgpevpn *vpn,
+ const struct prefix_evpn *p, struct bgp_path_info *pi,
+ bool is_sync);
#endif /* _QUAGGA_BGP_EVPN_H */
diff --git a/bgpd/bgp_evpn_mh.c b/bgpd/bgp_evpn_mh.c
index d88c52d..d723a2b 100644
--- a/bgpd/bgp_evpn_mh.c
+++ b/bgpd/bgp_evpn_mh.c
@@ -45,13 +45,14 @@ static void bgp_evpn_local_es_down(struct bgp *bgp,
struct bgp_evpn_es *es);
static void bgp_evpn_local_type1_evi_route_del(struct bgp *bgp,
struct bgp_evpn_es *es);
-static struct bgp_evpn_es_vtep *bgp_evpn_es_vtep_add(struct bgp *bgp,
+static struct bgp_evpn_es_vtep *
+bgp_evpn_es_vtep_add(struct bgp *bgp, struct bgp_evpn_es *es,
+ struct in_addr vtep_ip, bool esr, uint8_t df_alg,
+ uint16_t df_pref, int *zret);
+static enum zclient_send_status bgp_evpn_es_vtep_del(struct bgp *bgp,
struct bgp_evpn_es *es,
struct in_addr vtep_ip,
- bool esr, uint8_t df_alg,
- uint16_t df_pref);
-static void bgp_evpn_es_vtep_del(struct bgp *bgp,
- struct bgp_evpn_es *es, struct in_addr vtep_ip, bool esr);
+ bool esr);
static void bgp_evpn_es_cons_checks_pend_add(struct bgp_evpn_es *es);
static void bgp_evpn_es_cons_checks_pend_del(struct bgp_evpn_es *es);
static struct bgp_evpn_es_evi *
@@ -91,15 +92,19 @@ static void bgp_evpn_path_nh_unlink(struct bgp_path_evpn_nh_info *nh_info);
*/
static int bgp_evpn_es_route_select_install(struct bgp *bgp,
struct bgp_evpn_es *es,
- struct bgp_dest *dest)
+ struct bgp_dest *dest,
+ struct bgp_path_info *pi)
{
int ret = 0;
+ int zret = 0;
afi_t afi = AFI_L2VPN;
safi_t safi = SAFI_EVPN;
struct bgp_path_info *old_select; /* old best */
struct bgp_path_info *new_select; /* new best */
struct bgp_path_info_pair old_and_new;
+ SET_FLAG(pi->flags, BGP_PATH_UNSORTED);
+
/* Compute the best path. */
bgp_best_selection(bgp, dest, &bgp->maxpaths[afi][safi], &old_and_new,
afi, safi);
@@ -120,7 +125,7 @@ static int bgp_evpn_es_route_select_install(struct bgp *bgp,
bgp_evpn_es_vtep_add(bgp, es, old_select->attr->nexthop,
true /*esr*/,
old_select->attr->df_alg,
- old_select->attr->df_pref);
+ old_select->attr->df_pref, &zret);
}
UNSET_FLAG(old_select->flags, BGP_PATH_MULTIPATH_CHG);
bgp_zebra_clear_route_change_flags(dest);
@@ -149,7 +154,7 @@ static int bgp_evpn_es_route_select_install(struct bgp *bgp,
&& new_select->sub_type == BGP_ROUTE_IMPORTED) {
bgp_evpn_es_vtep_add(bgp, es, new_select->attr->nexthop,
true /*esr */, new_select->attr->df_alg,
- new_select->attr->df_pref);
+ new_select->attr->df_pref, &zret);
} else {
if (old_select && old_select->type == ZEBRA_ROUTE_BGP
&& old_select->sub_type == BGP_ROUTE_IMPORTED)
@@ -231,7 +236,7 @@ static int bgp_evpn_es_route_install(struct bgp *bgp,
}
/* Perform route selection and update zebra, if required. */
- ret = bgp_evpn_es_route_select_install(bgp, es, dest);
+ ret = bgp_evpn_es_route_select_install(bgp, es, dest, pi);
bgp_dest_unlock_node(dest);
@@ -272,7 +277,7 @@ static int bgp_evpn_es_route_uninstall(struct bgp *bgp, struct bgp_evpn_es *es,
bgp_path_info_delete(dest, pi);
/* Perform route selection and update zebra, if required. */
- ret = bgp_evpn_es_route_select_install(bgp, es, dest);
+ ret = bgp_evpn_es_route_select_install(bgp, es, dest, pi);
/* Unlock route node. */
bgp_dest_unlock_node(dest);
@@ -353,6 +358,7 @@ int bgp_evpn_mh_route_update(struct bgp *bgp, struct bgp_evpn_es *es,
struct bgp_path_info *tmp_pi = NULL;
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 bgp_labels bgp_labels = {};
struct attr *attr_new = NULL;
struct prefix_evpn *evp;
@@ -399,11 +405,16 @@ int bgp_evpn_mh_route_update(struct bgp *bgp, struct bgp_evpn_es *es,
if (evp->prefix.route_type == BGP_EVPN_AD_ROUTE) {
bgp_path_info_extra_get(tmp_pi);
- tmp_pi->extra->num_labels = 1;
+ bgp_labels.num_labels = 1;
if (vpn)
- vni2label(vpn->vni, &tmp_pi->extra->label[0]);
- else
- tmp_pi->extra->label[0] = 0;
+ vni2label(vpn->vni, &bgp_labels.label[0]);
+ if (!bgp_path_info_labels_same(tmp_pi,
+ &bgp_labels.label[0],
+ bgp_labels.num_labels)) {
+ bgp_labels_unintern(&tmp_pi->extra->labels);
+ tmp_pi->extra->labels =
+ bgp_labels_intern(&bgp_labels);
+ }
}
/* add the newly created path to the route-node */
@@ -447,7 +458,7 @@ int bgp_evpn_mh_route_update(struct bgp *bgp, struct bgp_evpn_es *es,
attr->mp_nexthop_global_in);
}
- /* Return back the route entry. */
+ /* Return back th*e route entry. */
*ri = tmp_pi;
return 0;
}
@@ -511,7 +522,7 @@ static int bgp_evpn_mh_route_delete(struct bgp *bgp, struct bgp_evpn_es *es,
* this table.
*/
if (pi)
- bgp_process(bgp, global_dest, afi, safi);
+ bgp_process(bgp, global_dest, pi, afi, safi);
bgp_dest_unlock_node(global_dest);
}
@@ -562,7 +573,7 @@ int delete_global_ead_evi_routes(struct bgp *bgp, struct bgpevpn *vpn)
delete_evpn_route_entry(bgp, afi, safi, bd, &pi);
if (pi)
- bgp_process(bgp, bd, afi, safi);
+ bgp_process(bgp, bd, pi, afi, safi);
}
}
@@ -668,7 +679,7 @@ static int bgp_evpn_type4_route_update(struct bgp *bgp,
* this is just to set the flags correctly
* as local route in the ES always wins.
*/
- bgp_evpn_es_route_select_install(bgp, es, dest);
+ bgp_evpn_es_route_select_install(bgp, es, dest, pi);
bgp_dest_unlock_node(dest);
/* If this is a new route or some attribute has changed, export the
@@ -686,7 +697,7 @@ static int bgp_evpn_type4_route_update(struct bgp *bgp,
attr_new, &global_pi, &route_changed);
/* Schedule for processing and unlock node. */
- bgp_process(bgp, dest, afi, safi);
+ bgp_process(bgp, dest, global_pi, afi, safi);
bgp_dest_unlock_node(dest);
}
@@ -1008,7 +1019,7 @@ static int bgp_evpn_type1_route_update(struct bgp *bgp, struct bgp_evpn_es *es,
* this is just to set the flags correctly as local route in
* the ES always wins.
*/
- evpn_route_select_install(bgp, vpn, dest);
+ evpn_route_select_install(bgp, vpn, dest, pi);
bgp_dest_unlock_node(dest);
/* If this is a new route or some attribute has changed, export the
@@ -1025,7 +1036,7 @@ static int bgp_evpn_type1_route_update(struct bgp *bgp, struct bgp_evpn_es *es,
attr_new, &global_pi, &route_changed);
/* Schedule for processing and unlock node. */
- bgp_process(bgp, dest, afi, safi);
+ bgp_process(bgp, dest, global_pi, afi, safi);
bgp_dest_unlock_node(dest);
}
@@ -1371,23 +1382,28 @@ static struct bgp_evpn_es_vtep *bgp_evpn_es_vtep_find(struct bgp_evpn_es *es,
}
/* Send the remote ES to zebra for NHG programming */
-static int bgp_zebra_send_remote_es_vtep(struct bgp *bgp,
- struct bgp_evpn_es_vtep *es_vtep, bool add)
+static enum zclient_send_status
+bgp_zebra_send_remote_es_vtep(struct bgp *bgp, struct bgp_evpn_es_vtep *es_vtep,
+ bool add)
{
struct bgp_evpn_es *es = es_vtep->es;
struct stream *s;
uint32_t flags = 0;
/* Check socket. */
- if (!zclient || zclient->sock < 0)
- return 0;
+ if (!zclient || zclient->sock < 0) {
+ if (BGP_DEBUG(zebra, ZEBRA))
+ zlog_debug("%s: No zclient or zclient->sock exists",
+ __func__);
+ return ZCLIENT_SEND_SUCCESS;
+ }
/* Don't try to register if Zebra doesn't know of this instance. */
if (!IS_BGP_INST_KNOWN_TO_ZEBRA(bgp)) {
if (BGP_DEBUG(zebra, ZEBRA))
zlog_debug("No zebra instance, not installing remote es %s",
es->esi_str);
- return 0;
+ return ZCLIENT_SEND_SUCCESS;
}
if (es_vtep->flags & BGP_EVPNES_VTEP_ESR)
@@ -1418,12 +1434,12 @@ static int bgp_zebra_send_remote_es_vtep(struct bgp *bgp,
return zclient_send_message(zclient);
}
-static void bgp_evpn_es_vtep_re_eval_active(struct bgp *bgp,
- struct bgp_evpn_es_vtep *es_vtep,
- bool param_change)
+static enum zclient_send_status bgp_evpn_es_vtep_re_eval_active(
+ struct bgp *bgp, struct bgp_evpn_es_vtep *es_vtep, bool param_change)
{
bool old_active;
bool new_active;
+ enum zclient_send_status ret = ZCLIENT_SEND_SUCCESS;
old_active = CHECK_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ACTIVE);
/* currently we need an active EVI reference to use the VTEP as
@@ -1445,7 +1461,7 @@ static void bgp_evpn_es_vtep_re_eval_active(struct bgp *bgp,
es_vtep->df_alg, es_vtep->df_pref);
/* send remote ES to zebra */
- bgp_zebra_send_remote_es_vtep(bgp, es_vtep, new_active);
+ ret = bgp_zebra_send_remote_es_vtep(bgp, es_vtep, new_active);
/* The NHG is updated first for efficient failover handling.
* Note the NHG can be de-activated while there are bgp
@@ -1457,13 +1473,14 @@ static void bgp_evpn_es_vtep_re_eval_active(struct bgp *bgp,
/* queue up the es for background consistency checks */
bgp_evpn_es_cons_checks_pend_add(es_vtep->es);
}
+
+ return ret;
}
-static struct bgp_evpn_es_vtep *bgp_evpn_es_vtep_add(struct bgp *bgp,
- struct bgp_evpn_es *es,
- struct in_addr vtep_ip,
- bool esr, uint8_t df_alg,
- uint16_t df_pref)
+static struct bgp_evpn_es_vtep *
+bgp_evpn_es_vtep_add(struct bgp *bgp, struct bgp_evpn_es *es,
+ struct in_addr vtep_ip, bool esr, uint8_t df_alg,
+ uint16_t df_pref, int *zret)
{
struct bgp_evpn_es_vtep *es_vtep;
bool param_change = false;
@@ -1490,15 +1507,17 @@ static struct bgp_evpn_es_vtep *bgp_evpn_es_vtep_add(struct bgp *bgp,
++es_vtep->evi_cnt;
}
- bgp_evpn_es_vtep_re_eval_active(bgp, es_vtep, param_change);
+ *zret = bgp_evpn_es_vtep_re_eval_active(bgp, es_vtep, param_change);
return es_vtep;
}
-static void bgp_evpn_es_vtep_do_del(struct bgp *bgp,
- struct bgp_evpn_es_vtep *es_vtep, bool esr)
+static enum zclient_send_status
+bgp_evpn_es_vtep_do_del(struct bgp *bgp, struct bgp_evpn_es_vtep *es_vtep,
+ bool esr)
{
bool param_change = false;
+ enum zclient_send_status ret = ZCLIENT_SEND_SUCCESS;
if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
zlog_debug("es %s vtep %pI4 del %s", es_vtep->es->esi_str,
@@ -1515,18 +1534,25 @@ static void bgp_evpn_es_vtep_do_del(struct bgp *bgp,
--es_vtep->evi_cnt;
}
- bgp_evpn_es_vtep_re_eval_active(bgp, es_vtep, param_change);
+ ret = bgp_evpn_es_vtep_re_eval_active(bgp, es_vtep, param_change);
bgp_evpn_es_vtep_free(es_vtep);
+
+ return ret;
}
-static void bgp_evpn_es_vtep_del(struct bgp *bgp,
- struct bgp_evpn_es *es, struct in_addr vtep_ip, bool esr)
+static enum zclient_send_status bgp_evpn_es_vtep_del(struct bgp *bgp,
+ struct bgp_evpn_es *es,
+ struct in_addr vtep_ip,
+ bool esr)
{
struct bgp_evpn_es_vtep *es_vtep;
+ enum zclient_send_status ret = ZCLIENT_SEND_SUCCESS;
es_vtep = bgp_evpn_es_vtep_find(es, vtep_ip);
if (es_vtep)
- bgp_evpn_es_vtep_do_del(bgp, es_vtep, esr);
+ ret = bgp_evpn_es_vtep_do_del(bgp, es_vtep, esr);
+
+ return ret;
}
/********************** ES MAC-IP paths *************************************
@@ -2435,7 +2461,7 @@ static void bgp_evpn_es_frag_show_detail(struct vty *vty,
}
static char *bgp_evpn_es_vteps_str(char *vtep_str, struct bgp_evpn_es *es,
- uint8_t vtep_str_size)
+ size_t vtep_str_size)
{
char vtep_flag_str[BGP_EVPN_FLAG_STR_SZ];
struct listnode *node;
@@ -3399,12 +3425,14 @@ static struct bgp_evpn_es_evi_vtep *bgp_evpn_es_evi_vtep_find(
/* A VTEP can be added as "active" attach to an ES if EAD-per-ES and
* EAD-per-EVI routes are rxed from it.
*/
-static void bgp_evpn_es_evi_vtep_re_eval_active(struct bgp *bgp,
- struct bgp_evpn_es_evi_vtep *evi_vtep)
+static enum zclient_send_status
+bgp_evpn_es_evi_vtep_re_eval_active(struct bgp *bgp,
+ struct bgp_evpn_es_evi_vtep *evi_vtep)
{
bool old_active;
bool new_active;
uint32_t ead_activity_flags;
+ enum zclient_send_status ret = ZCLIENT_SEND_SUCCESS;
old_active = CHECK_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_ACTIVE);
@@ -3425,7 +3453,7 @@ static void bgp_evpn_es_evi_vtep_re_eval_active(struct bgp *bgp,
new_active = CHECK_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_ACTIVE);
if (old_active == new_active)
- return;
+ return ret;
if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
zlog_debug("es %s evi %u vtep %pI4 %s",
@@ -3434,24 +3462,27 @@ static void bgp_evpn_es_evi_vtep_re_eval_active(struct bgp *bgp,
new_active ? "active" : "inactive");
/* add VTEP to parent es */
- if (new_active)
- evi_vtep->es_vtep = bgp_evpn_es_vtep_add(
- bgp, evi_vtep->es_evi->es, evi_vtep->vtep_ip,
- false /*esr*/, 0, 0);
- else {
+ if (new_active) {
+ evi_vtep->es_vtep =
+ bgp_evpn_es_vtep_add(bgp, evi_vtep->es_evi->es,
+ evi_vtep->vtep_ip, false /*esr*/,
+ 0, 0, &ret);
+ } else {
if (evi_vtep->es_vtep) {
- bgp_evpn_es_vtep_do_del(bgp, evi_vtep->es_vtep,
- false /*esr*/);
+ ret = bgp_evpn_es_vtep_do_del(bgp, evi_vtep->es_vtep,
+ false /*esr*/);
evi_vtep->es_vtep = NULL;
}
}
/* queue up the parent es for background consistency checks */
bgp_evpn_es_cons_checks_pend_add(evi_vtep->es_evi->es);
+
+ return ret;
}
-static void bgp_evpn_es_evi_vtep_add(struct bgp *bgp,
- struct bgp_evpn_es_evi *es_evi, struct in_addr vtep_ip,
- bool ead_es)
+static enum zclient_send_status
+bgp_evpn_es_evi_vtep_add(struct bgp *bgp, struct bgp_evpn_es_evi *es_evi,
+ struct in_addr vtep_ip, bool ead_es)
{
struct bgp_evpn_es_evi_vtep *evi_vtep;
@@ -3475,18 +3506,19 @@ static void bgp_evpn_es_evi_vtep_add(struct bgp *bgp,
else
SET_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_EAD_PER_EVI);
- bgp_evpn_es_evi_vtep_re_eval_active(bgp, evi_vtep);
+ return bgp_evpn_es_evi_vtep_re_eval_active(bgp, evi_vtep);
}
-static void bgp_evpn_es_evi_vtep_del(struct bgp *bgp,
- struct bgp_evpn_es_evi *es_evi, struct in_addr vtep_ip,
- bool ead_es)
+static enum zclient_send_status
+bgp_evpn_es_evi_vtep_del(struct bgp *bgp, struct bgp_evpn_es_evi *es_evi,
+ struct in_addr vtep_ip, bool ead_es)
{
struct bgp_evpn_es_evi_vtep *evi_vtep;
+ enum zclient_send_status ret = ZCLIENT_SEND_SUCCESS;
evi_vtep = bgp_evpn_es_evi_vtep_find(es_evi, vtep_ip);
if (!evi_vtep)
- return;
+ return ret;
if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
zlog_debug("del es %s evi %u vtep %pI4 %s",
@@ -3503,8 +3535,10 @@ static void bgp_evpn_es_evi_vtep_del(struct bgp *bgp,
else
UNSET_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_EAD_PER_EVI);
- bgp_evpn_es_evi_vtep_re_eval_active(bgp, evi_vtep);
+ ret = bgp_evpn_es_evi_vtep_re_eval_active(bgp, evi_vtep);
bgp_evpn_es_evi_vtep_free(evi_vtep);
+
+ return ret;
}
/* compare ES-IDs for the ES-EVI RB tree maintained per-VNI */
@@ -3780,18 +3814,20 @@ int bgp_evpn_local_es_evi_add(struct bgp *bgp, esi_t *esi, vni_t vni)
/* Add remote ES-EVI entry. This is actually the remote VTEP add and the
* ES-EVI is implicity created on first VTEP's reference.
*/
-int bgp_evpn_remote_es_evi_add(struct bgp *bgp, struct bgpevpn *vpn,
- const struct prefix_evpn *p)
+enum zclient_send_status bgp_evpn_remote_es_evi_add(struct bgp *bgp,
+ struct bgpevpn *vpn,
+ const struct prefix_evpn *p)
{
char buf[ESI_STR_LEN];
struct bgp_evpn_es *es;
struct bgp_evpn_es_evi *es_evi;
bool ead_es;
const esi_t *esi = &p->prefix.ead_addr.esi;
+ enum zclient_send_status ret = ZCLIENT_SEND_SUCCESS;
if (!vpn)
/* local EAD-ES need not be sent back to zebra */
- return 0;
+ return ret;
if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
zlog_debug("add remote %s es %s evi %u vtep %pI4",
@@ -3808,27 +3844,29 @@ int bgp_evpn_remote_es_evi_add(struct bgp *bgp, struct bgpevpn *vpn,
es_evi = bgp_evpn_es_evi_new(es, vpn);
ead_es = !!p->prefix.ead_addr.eth_tag;
- bgp_evpn_es_evi_vtep_add(bgp, es_evi, p->prefix.ead_addr.ip.ipaddr_v4,
- ead_es);
+ ret = bgp_evpn_es_evi_vtep_add(bgp, es_evi,
+ p->prefix.ead_addr.ip.ipaddr_v4, ead_es);
bgp_evpn_es_evi_remote_info_re_eval(es_evi);
- return 0;
+ return ret;
}
/* A remote VTEP has withdrawn. The es-evi-vtep will be deleted and the
* parent es-evi freed up implicitly in last VTEP's deref.
*/
-int bgp_evpn_remote_es_evi_del(struct bgp *bgp, struct bgpevpn *vpn,
- const struct prefix_evpn *p)
+enum zclient_send_status bgp_evpn_remote_es_evi_del(struct bgp *bgp,
+ struct bgpevpn *vpn,
+ const struct prefix_evpn *p)
{
char buf[ESI_STR_LEN];
struct bgp_evpn_es *es;
struct bgp_evpn_es_evi *es_evi;
bool ead_es;
+ enum zclient_send_status ret = ZCLIENT_SEND_SUCCESS;
if (!vpn)
/* local EAD-ES need not be sent back to zebra */
- return 0;
+ return ret;
if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
zlog_debug(
@@ -3847,7 +3885,7 @@ int bgp_evpn_remote_es_evi_del(struct bgp *bgp, struct bgpevpn *vpn,
esi_to_str(&p->prefix.ead_addr.esi, buf,
sizeof(buf)),
vpn->vni, &p->prefix.ead_addr.ip.ipaddr_v4);
- return 0;
+ return ret;
}
es_evi = bgp_evpn_es_evi_find(es, vpn);
if (!es_evi) {
@@ -3860,14 +3898,15 @@ int bgp_evpn_remote_es_evi_del(struct bgp *bgp, struct bgpevpn *vpn,
sizeof(buf)),
vpn->vni,
&p->prefix.ead_addr.ip.ipaddr_v4);
- return 0;
+ return ret;
}
ead_es = !!p->prefix.ead_addr.eth_tag;
- bgp_evpn_es_evi_vtep_del(bgp, es_evi, p->prefix.ead_addr.ip.ipaddr_v4,
- ead_es);
+ ret = bgp_evpn_es_evi_vtep_del(bgp, es_evi,
+ p->prefix.ead_addr.ip.ipaddr_v4, ead_es);
bgp_evpn_es_evi_remote_info_re_eval(es_evi);
- return 0;
+
+ return ret;
}
/* If a VNI is being deleted we need to force del all remote VTEPs */
@@ -3923,7 +3962,7 @@ void bgp_evpn_vni_es_cleanup(struct bgpevpn *vpn)
static char *bgp_evpn_es_evi_vteps_str(char *vtep_str,
struct bgp_evpn_es_evi *es_evi,
- uint8_t vtep_str_size)
+ size_t vtep_str_size)
{
char vtep_flag_str[BGP_EVPN_FLAG_STR_SZ];
struct listnode *node;
diff --git a/bgpd/bgp_evpn_mh.h b/bgpd/bgp_evpn_mh.h
index cebabb9..5d393c3 100644
--- a/bgpd/bgp_evpn_mh.h
+++ b/bgpd/bgp_evpn_mh.h
@@ -418,10 +418,12 @@ extern int bgp_evpn_local_es_add(struct bgp *bgp, esi_t *esi,
extern int bgp_evpn_local_es_del(struct bgp *bgp, esi_t *esi);
extern int bgp_evpn_local_es_evi_add(struct bgp *bgp, esi_t *esi, vni_t vni);
extern int bgp_evpn_local_es_evi_del(struct bgp *bgp, esi_t *esi, vni_t vni);
-extern int bgp_evpn_remote_es_evi_add(struct bgp *bgp, struct bgpevpn *vpn,
- const struct prefix_evpn *p);
-extern int bgp_evpn_remote_es_evi_del(struct bgp *bgp, struct bgpevpn *vpn,
- const struct prefix_evpn *p);
+extern enum zclient_send_status
+bgp_evpn_remote_es_evi_add(struct bgp *bgp, struct bgpevpn *vpn,
+ const struct prefix_evpn *p);
+extern enum zclient_send_status
+bgp_evpn_remote_es_evi_del(struct bgp *bgp, struct bgpevpn *vpn,
+ const struct prefix_evpn *p);
extern void bgp_evpn_mh_init(void);
extern void bgp_evpn_mh_finish(void);
void bgp_evpn_vni_es_init(struct bgpevpn *vpn);
diff --git a/bgpd/bgp_evpn_private.h b/bgpd/bgp_evpn_private.h
index 5af99af..07bba9b 100644
--- a/bgpd/bgp_evpn_private.h
+++ b/bgpd/bgp_evpn_private.h
@@ -716,7 +716,8 @@ extern void delete_evpn_route_entry(struct bgp *bgp, afi_t afi, safi_t safi,
struct bgp_path_info **pi);
int vni_list_cmp(void *p1, void *p2);
extern int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn,
- struct bgp_dest *dest);
+ struct bgp_dest *dest,
+ struct bgp_path_info *pi);
extern struct bgp_dest *
bgp_evpn_global_node_get(struct bgp_table *table, afi_t afi, safi_t safi,
const struct prefix_evpn *evp, struct prefix_rd *prd,
diff --git a/bgpd/bgp_filter.c b/bgpd/bgp_filter.c
index a851179..002f054 100644
--- a/bgpd/bgp_filter.c
+++ b/bgpd/bgp_filter.c
@@ -16,7 +16,7 @@
#include "bgpd/bgp_aspath.h"
#include "bgpd/bgp_regex.h"
-/* List of AS filter list. */
+/* List of AS list. */
struct as_list_list {
struct as_list *head;
struct as_list *tail;
@@ -205,14 +205,6 @@ static struct as_list *as_list_new(void)
static void as_list_free(struct as_list *aslist)
{
- struct aspath_exclude_list *cur_bp = aslist->exclude_list;
- struct aspath_exclude_list *next_bp = NULL;
-
- while (cur_bp) {
- next_bp = cur_bp->next;
- XFREE(MTYPE_ROUTE_MAP_COMPILED, cur_bp);
- cur_bp = next_bp;
- }
XFREE (MTYPE_AS_STR, aslist->name);
XFREE (MTYPE_AS_LIST, aslist);
@@ -299,7 +291,6 @@ static void as_list_delete(struct as_list *aslist)
{
struct as_list_list *list;
struct as_filter *filter, *next;
- struct aspath_exclude_list *cur_bp;
for (filter = aslist->head; filter; filter = next) {
next = filter->next;
@@ -318,12 +309,6 @@ static void as_list_delete(struct as_list *aslist)
else
list->head = aslist->next;
- cur_bp = aslist->exclude_list;
- while (cur_bp) {
- cur_bp->bp_as_excl->exclude_aspath_acl = NULL;
- cur_bp = cur_bp->next;
- }
-
as_list_free(aslist);
}
@@ -431,6 +416,7 @@ DEFUN(as_path, bgp_as_path_cmd,
enum as_filter_type type;
struct as_filter *asfilter;
struct as_list *aslist;
+ struct aspath_exclude *ase;
regex_t *regex;
char *regstr;
int64_t seqnum = ASPATH_SEQ_NUMBER_AUTO;
@@ -482,6 +468,22 @@ DEFUN(as_path, bgp_as_path_cmd,
else
as_list_filter_add(aslist, asfilter);
+ /* init the exclude rule list*/
+ as_list_list_init(&aslist->exclude_rule);
+
+ /* get aspath orphan exclude that are using this acl */
+ ase = as_exclude_lookup_orphan(alname);
+ if (ase) {
+ as_list_list_add_head(&aslist->exclude_rule, ase);
+ /* set reverse pointer */
+ ase->exclude_aspath_acl = aslist;
+ /* set list of aspath excludes using that acl */
+ while ((ase = as_exclude_lookup_orphan(alname))) {
+ as_list_list_add_head(&aslist->exclude_rule, ase);
+ ase->exclude_aspath_acl = aslist;
+ }
+ }
+
return CMD_SUCCESS;
}
@@ -502,6 +504,7 @@ DEFUN(no_as_path, no_bgp_as_path_cmd,
enum as_filter_type type;
struct as_filter *asfilter;
struct as_list *aslist;
+ struct aspath_exclude *ase;
char *regstr;
regex_t *regex;
@@ -556,6 +559,12 @@ DEFUN(no_as_path, no_bgp_as_path_cmd,
XFREE(MTYPE_TMP, regstr);
+ /* put aspath exclude list into orphan */
+ if (as_list_list_count(&aslist->exclude_rule))
+ while ((ase = as_list_list_pop(&aslist->exclude_rule)))
+ as_exclude_set_orphan(ase);
+
+ as_list_list_fini(&aslist->exclude_rule);
as_list_filter_delete(aslist, asfilter);
return CMD_SUCCESS;
diff --git a/bgpd/bgp_filter.h b/bgpd/bgp_filter.h
index 2d9f07c..77a3f3c 100644
--- a/bgpd/bgp_filter.h
+++ b/bgpd/bgp_filter.h
@@ -6,11 +6,12 @@
#ifndef _QUAGGA_BGP_FILTER_H
#define _QUAGGA_BGP_FILTER_H
+#include <typesafe.h>
+
#define ASPATH_SEQ_NUMBER_AUTO -1
enum as_filter_type { AS_FILTER_DENY, AS_FILTER_PERMIT };
-
/* Element of AS path filter. */
struct as_filter {
struct as_filter *next;
@@ -25,11 +26,7 @@ struct as_filter {
int64_t seq;
};
-struct aspath_exclude_list {
- struct aspath_exclude_list *next;
- struct aspath_exclude *bp_as_excl;
-};
-
+PREDECL_DLIST(as_list_list);
/* AS path filter list. */
struct as_list {
char *name;
@@ -39,7 +36,9 @@ struct as_list {
struct as_filter *head;
struct as_filter *tail;
- struct aspath_exclude_list *exclude_list;
+
+ /* Changes in AS path */
+ struct as_list_list_head exclude_rule;
};
diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c
index 5043439..d41ef8a 100644
--- a/bgpd/bgp_fsm.c
+++ b/bgpd/bgp_fsm.c
@@ -260,6 +260,8 @@ static struct peer *peer_xfer_conn(struct peer *from_peer)
peer->afc_recv[afi][safi] = from_peer->afc_recv[afi][safi];
peer->orf_plist[afi][safi] = from_peer->orf_plist[afi][safi];
peer->llgr[afi][safi] = from_peer->llgr[afi][safi];
+ peer->addpath_paths_limit[afi][safi] =
+ from_peer->addpath_paths_limit[afi][safi];
}
if (bgp_getsockname(peer) < 0) {
@@ -1239,7 +1241,7 @@ void bgp_fsm_change_status(struct peer_connection *connection,
/* Transition into Clearing or Deleted must /always/ clear all routes..
* (and must do so before actually changing into Deleted..
*/
- if (status >= Clearing) {
+ if (status >= Clearing && (peer->established || peer == bgp->peer_self)) {
bgp_clear_route_all(peer);
/* If no route was queued for the clear-node processing,
@@ -1587,7 +1589,7 @@ bgp_stop_with_error(struct peer_connection *connection)
/* something went wrong, send notify and tear down */
-static enum bgp_fsm_state_progress
+enum bgp_fsm_state_progress
bgp_stop_with_notify(struct peer_connection *connection, uint8_t code,
uint8_t sub_code)
{
@@ -1794,6 +1796,26 @@ bgp_connect_fail(struct peer_connection *connection)
return bgp_stop(connection);
}
+/* after connect is called(), getpeername is able to return
+ * port and address on non established streams
+ */
+static void bgp_connect_in_progress_update_connection(struct peer *peer)
+{
+ if (bgp_getsockname(peer) < 0) {
+ if (!peer->su_remote &&
+ !BGP_CONNECTION_SU_UNSPEC(peer->connection)) {
+ /* if connect initiated, then dest port and dest addresses are well known */
+ peer->su_remote = sockunion_dup(&peer->connection->su);
+ if (sockunion_family(peer->su_remote) == AF_INET)
+ peer->su_remote->sin.sin_port =
+ htons(peer->port);
+ else if (sockunion_family(peer->su_remote) == AF_INET6)
+ peer->su_remote->sin6.sin6_port =
+ htons(peer->port);
+ }
+ }
+}
+
/* This function is the first starting point of all BGP connection. It
* try to connect to remote peer with non-blocking IO.
*/
@@ -1890,6 +1912,8 @@ static enum bgp_fsm_state_progress bgp_start(struct peer_connection *connection)
__func__, peer->connection->fd);
return BGP_FSM_FAILURE;
}
+ bgp_connect_in_progress_update_connection(peer);
+
/*
* - when the socket becomes ready, poll() will signify POLLOUT
* - if it fails to connect, poll() will signify POLLHUP
diff --git a/bgpd/bgp_fsm.h b/bgpd/bgp_fsm.h
index 2e96ac4..bcdd491 100644
--- a/bgpd/bgp_fsm.h
+++ b/bgpd/bgp_fsm.h
@@ -122,6 +122,9 @@ extern void bgp_maxmed_update(struct bgp *);
extern bool bgp_maxmed_onstartup_configured(struct bgp *);
extern bool bgp_maxmed_onstartup_active(struct bgp *);
extern int bgp_fsm_error_subcode(int status);
+extern enum bgp_fsm_state_progress
+bgp_stop_with_notify(struct peer_connection *connection, uint8_t code,
+ uint8_t sub_code);
/**
* Start the route advertisement timer (that honors MRAI) for all the
diff --git a/bgpd/bgp_label.c b/bgpd/bgp_label.c
index 7327ab5..839437e 100644
--- a/bgpd/bgp_label.c
+++ b/bgpd/bgp_label.c
@@ -15,6 +15,7 @@
#include "memory.h"
#include "nexthop.h"
#include "mpls.h"
+#include "jhash.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_table.h"
@@ -27,6 +28,124 @@
extern struct zclient *zclient;
+
+/* MPLS Labels hash routines. */
+static struct hash *labels_hash;
+
+static void *bgp_labels_hash_alloc(void *p)
+{
+ const struct bgp_labels *labels = p;
+ struct bgp_labels *new;
+ uint8_t i;
+
+ new = XMALLOC(MTYPE_BGP_LABELS, sizeof(struct bgp_labels));
+
+ new->num_labels = labels->num_labels;
+ for (i = 0; i < labels->num_labels; i++)
+ new->label[i] = labels->label[i];
+
+ return new;
+}
+
+static uint32_t bgp_labels_hash_key_make(const void *p)
+{
+ const struct bgp_labels *labels = p;
+ uint32_t key = 0;
+
+ if (labels->num_labels)
+ key = jhash(&labels->label,
+ labels->num_labels * sizeof(mpls_label_t), key);
+
+ return key;
+}
+
+static bool bgp_labels_hash_cmp(const void *p1, const void *p2)
+{
+ return bgp_labels_cmp(p1, p2);
+}
+
+void bgp_labels_init(void)
+{
+ labels_hash = hash_create(bgp_labels_hash_key_make, bgp_labels_hash_cmp,
+ "BGP Labels hash");
+}
+
+/*
+ * special for hash_clean below
+ */
+static void bgp_labels_free(void *labels)
+{
+ XFREE(MTYPE_BGP_LABELS, labels);
+}
+
+void bgp_labels_finish(void)
+{
+ hash_clean_and_free(&labels_hash, bgp_labels_free);
+}
+
+struct bgp_labels *bgp_labels_intern(struct bgp_labels *labels)
+{
+ struct bgp_labels *find;
+
+ if (!labels)
+ return NULL;
+
+ if (!labels->num_labels)
+ /* do not intern void labels structure */
+ return NULL;
+
+ find = (struct bgp_labels *)hash_get(labels_hash, labels,
+ bgp_labels_hash_alloc);
+ find->refcnt++;
+
+ return find;
+}
+
+void bgp_labels_unintern(struct bgp_labels **plabels)
+{
+ struct bgp_labels *labels = *plabels;
+ struct bgp_labels *ret;
+
+ if (!*plabels)
+ return;
+
+ /* Decrement labels reference. */
+ labels->refcnt--;
+
+ /* If reference becomes zero then free labels object. */
+ if (labels->refcnt == 0) {
+ ret = hash_release(labels_hash, labels);
+ assert(ret != NULL);
+ bgp_labels_free(labels);
+ *plabels = NULL;
+ }
+}
+
+bool bgp_labels_cmp(const struct bgp_labels *labels1,
+ const struct bgp_labels *labels2)
+{
+ uint8_t i;
+
+ if (!labels1 && !labels2)
+ return true;
+
+ if (!labels1 && labels2)
+ return false;
+
+ if (labels1 && !labels2)
+ return false;
+
+ if (labels1->num_labels != labels2->num_labels)
+ return false;
+
+ for (i = 0; i < labels1->num_labels; i++) {
+ if (labels1->label[i] != labels2->label[i])
+ return false;
+ }
+
+ return true;
+}
+
int bgp_parse_fec_update(void)
{
struct stream *s;
@@ -74,7 +193,7 @@ int bgp_parse_fec_update(void)
bgp_set_valid_label(&dest->local_label);
}
SET_FLAG(dest->flags, BGP_NODE_LABEL_CHANGED);
- bgp_process(bgp, dest, afi, safi);
+ bgp_process(bgp, dest, NULL, afi, safi);
bgp_dest_unlock_node(dest);
return 1;
}
@@ -89,7 +208,9 @@ mpls_label_t bgp_adv_label(struct bgp_dest *dest, struct bgp_path_info *pi,
if (!dest || !pi || !to)
return MPLS_INVALID_LABEL;
- remote_label = pi->extra ? pi->extra->label[0] : MPLS_INVALID_LABEL;
+ remote_label = bgp_path_info_num_labels(pi)
+ ? pi->extra->labels->label[0]
+ : MPLS_INVALID_LABEL;
from = pi->peer;
reflect =
((from->sort == BGP_PEER_IBGP) && (to->sort == BGP_PEER_IBGP));
@@ -471,8 +592,8 @@ int bgp_nlri_parse_label(struct peer *peer, struct attr *attr,
return BGP_NLRI_PARSE_OK;
}
-bool bgp_labels_same(const mpls_label_t *tbl_a, const uint32_t num_labels_a,
- const mpls_label_t *tbl_b, const uint32_t num_labels_b)
+bool bgp_labels_same(const mpls_label_t *tbl_a, const uint8_t num_labels_a,
+ const mpls_label_t *tbl_b, const uint8_t num_labels_b)
{
uint32_t i;
diff --git a/bgpd/bgp_label.h b/bgpd/bgp_label.h
index b54403e..2ffd5b6 100644
--- a/bgpd/bgp_label.h
+++ b/bgpd/bgp_label.h
@@ -15,6 +15,26 @@ struct bgp_dest;
struct bgp_path_info;
struct peer;
+/* Maximum number of labels we can process or send with a prefix. We
+ * really do only 1 for MPLS (BGP-LU) but we can do 2 for EVPN-VxLAN.
+ */
+#define BGP_MAX_LABELS 2
+
+/* MPLS label(s) - VNI(s) for EVPN-VxLAN */
+struct bgp_labels {
+ mpls_label_t label[BGP_MAX_LABELS];
+ uint8_t num_labels;
+
+ unsigned long refcnt;
+};
+
+extern void bgp_labels_init(void);
+extern void bgp_labels_finish(void);
+extern struct bgp_labels *bgp_labels_intern(struct bgp_labels *labels);
+extern void bgp_labels_unintern(struct bgp_labels **plabels);
+extern bool bgp_labels_cmp(const struct bgp_labels *labels1,
+ const struct bgp_labels *labels2);
+
extern int bgp_reg_for_label_callback(mpls_label_t new_label, void *labelid,
bool allocated);
extern void bgp_reg_dereg_for_label(struct bgp_dest *dest,
@@ -27,9 +47,9 @@ extern mpls_label_t bgp_adv_label(struct bgp_dest *dest,
extern int bgp_nlri_parse_label(struct peer *peer, struct attr *attr,
struct bgp_nlri *packet);
extern bool bgp_labels_same(const mpls_label_t *tbl_a,
- const uint32_t num_labels_a,
+ const uint8_t num_labels_a,
const mpls_label_t *tbl_b,
- const uint32_t num_labels_b);
+ const uint8_t num_labels_b);
static inline int bgp_labeled_safi(safi_t safi)
{
diff --git a/bgpd/bgp_mac.c b/bgpd/bgp_mac.c
index e629732..31e84d1 100644
--- a/bgpd/bgp_mac.c
+++ b/bgpd/bgp_mac.c
@@ -14,6 +14,7 @@
#include "bgpd/bgpd.h"
#include "bgpd/bgp_mac.h"
#include "bgpd/bgp_memory.h"
+#include "bgpd/bgp_label.h"
#include "bgpd/bgp_route.h"
#include "bgpd/bgp_packet.h"
#include "bgpd/bgp_rd.h"
@@ -125,6 +126,8 @@ static void bgp_process_mac_rescan_table(struct bgp *bgp, struct peer *peer,
{
struct bgp_dest *pdest, *dest;
struct bgp_path_info *pi;
+ uint8_t num_labels;
+ mpls_label_t *label_pnt;
for (pdest = bgp_table_top(table); pdest;
pdest = bgp_route_next(pdest)) {
@@ -140,8 +143,6 @@ static void bgp_process_mac_rescan_table(struct bgp *bgp, struct peer *peer,
const struct prefix *p = bgp_dest_get_prefix(dest);
struct prefix_evpn *pevpn = (struct prefix_evpn *)dest;
struct prefix_rd prd;
- uint32_t num_labels = 0;
- mpls_label_t *label_pnt = NULL;
struct bgp_route_evpn *evpn;
if (pevpn->family == AF_EVPN
@@ -169,10 +170,9 @@ static void bgp_process_mac_rescan_table(struct bgp *bgp, struct peer *peer,
&& !dest_affected)
continue;
- if (pi->extra)
- num_labels = pi->extra->num_labels;
- if (num_labels)
- label_pnt = &pi->extra->label[0];
+ num_labels = bgp_path_info_num_labels(pi);
+ label_pnt = num_labels ? &pi->extra->labels->label[0]
+ : NULL;
prd.family = AF_UNSPEC;
prd.prefixlen = 64;
diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c
index 851c488..97658d3 100644
--- a/bgpd/bgp_main.c
+++ b/bgpd/bgp_main.c
@@ -26,6 +26,7 @@
#include "bfd.h"
#include "libfrr.h"
#include "ns.h"
+#include "libagentx.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_attr.h"
@@ -207,6 +208,8 @@ static __attribute__((__noreturn__)) void bgp_exit(int status)
bgp_evpn_mh_finish();
bgp_nhg_finish();
+ zebra_announce_fini(&bm->zebra_announce_head);
+
/* reverse bgp_dump_init */
bgp_dump_finish();
@@ -222,6 +225,9 @@ static __attribute__((__noreturn__)) void bgp_exit(int status)
/* reverse bgp_attr_init */
bgp_attr_finish();
+ /* reverse bgp_labels_init */
+ bgp_labels_finish();
+
/* stop pthreads */
bgp_pthreads_finish();
@@ -514,8 +520,10 @@ int main(int argc, char **argv)
bgp_option_set(BGP_OPT_NO_ZEBRA);
bgp_error_init();
/* Initializations. */
+ libagentx_init();
bgp_vrf_init();
+
#ifdef HAVE_SCRIPTING
bgp_script_init();
#endif
diff --git a/bgpd/bgp_memory.c b/bgpd/bgp_memory.c
index 0764f1e..c1804fb 100644
--- a/bgpd/bgp_memory.c
+++ b/bgpd/bgp_memory.c
@@ -91,6 +91,7 @@ DEFINE_MTYPE(BGPD, PEER_UPDATE_SOURCE, "BGP peer update interface");
DEFINE_MTYPE(BGPD, PEER_CONF_IF, "BGP peer config interface");
DEFINE_MTYPE(BGPD, BGP_DAMP_INFO, "Dampening info");
DEFINE_MTYPE(BGPD, BGP_DAMP_ARRAY, "BGP Dampening array");
+DEFINE_MTYPE(BGPD, BGP_DAMP_REUSELIST, "BGP Dampening reuse list");
DEFINE_MTYPE(BGPD, BGP_REGEXP, "BGP regexp");
DEFINE_MTYPE(BGPD, BGP_AGGREGATE, "BGP aggregate");
DEFINE_MTYPE(BGPD, BGP_ADDR, "BGP own address");
@@ -101,6 +102,8 @@ DEFINE_MTYPE(BGPD, BGP_FILTER_NAME, "BGP Filter Information");
DEFINE_MTYPE(BGPD, BGP_DUMP_STR, "BGP Dump String Information");
DEFINE_MTYPE(BGPD, ENCAP_TLV, "ENCAP TLV");
+DEFINE_MTYPE(BGPD, BGP_LABELS, "BGP LABELS");
+
DEFINE_MTYPE(BGPD, BGP_TEA_OPTIONS, "BGP TEA Options");
DEFINE_MTYPE(BGPD, BGP_TEA_OPTIONS_VALUE, "BGP TEA Options Value");
diff --git a/bgpd/bgp_memory.h b/bgpd/bgp_memory.h
index 29584cd..4ae49a2 100644
--- a/bgpd/bgp_memory.h
+++ b/bgpd/bgp_memory.h
@@ -87,6 +87,7 @@ DECLARE_MTYPE(PEER_UPDATE_SOURCE);
DECLARE_MTYPE(PEER_CONF_IF);
DECLARE_MTYPE(BGP_DAMP_INFO);
DECLARE_MTYPE(BGP_DAMP_ARRAY);
+DECLARE_MTYPE(BGP_DAMP_REUSELIST);
DECLARE_MTYPE(BGP_REGEXP);
DECLARE_MTYPE(BGP_AGGREGATE);
DECLARE_MTYPE(BGP_ADDR);
@@ -97,6 +98,8 @@ DECLARE_MTYPE(BGP_FILTER_NAME);
DECLARE_MTYPE(BGP_DUMP_STR);
DECLARE_MTYPE(ENCAP_TLV);
+DECLARE_MTYPE(BGP_LABELS);
+
DECLARE_MTYPE(BGP_TEA_OPTIONS);
DECLARE_MTYPE(BGP_TEA_OPTIONS_VALUE);
diff --git a/bgpd/bgp_mpath.c b/bgpd/bgp_mpath.c
index c773c21..e12d84b 100644
--- a/bgpd/bgp_mpath.c
+++ b/bgpd/bgp_mpath.c
@@ -129,15 +129,19 @@ int bgp_path_info_nexthop_cmp(struct bgp_path_info *bpi1,
&bpi2->attr->mp_nexthop_global);
break;
case BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL:
- addr1 = (bpi1->attr->mp_nexthop_prefer_global)
+ addr1 = (CHECK_FLAG(bpi1->attr->nh_flags,
+ BGP_ATTR_NH_MP_PREFER_GLOBAL))
? bpi1->attr->mp_nexthop_global
: bpi1->attr->mp_nexthop_local;
- addr2 = (bpi2->attr->mp_nexthop_prefer_global)
+ addr2 = (CHECK_FLAG(bpi2->attr->nh_flags,
+ BGP_ATTR_NH_MP_PREFER_GLOBAL))
? bpi2->attr->mp_nexthop_global
: bpi2->attr->mp_nexthop_local;
- if (!bpi1->attr->mp_nexthop_prefer_global
- && !bpi2->attr->mp_nexthop_prefer_global)
+ if (!CHECK_FLAG(bpi1->attr->nh_flags,
+ BGP_ATTR_NH_MP_PREFER_GLOBAL) &&
+ !CHECK_FLAG(bpi2->attr->nh_flags,
+ BGP_ATTR_NH_MP_PREFER_GLOBAL))
compare = !bgp_interface_same(
bpi1->peer->ifp,
bpi2->peer->ifp);
@@ -517,7 +521,7 @@ void bgp_path_info_mpath_update(struct bgp *bgp, struct bgp_dest *dest,
struct bgp_maxpaths_cfg *mpath_cfg)
{
uint16_t maxpaths, mpath_count, old_mpath_count;
- uint32_t bwval;
+ uint64_t bwval;
uint64_t cum_bw, old_cum_bw;
struct listnode *mp_node, *mp_next_node;
struct bgp_path_info *cur_mpath, *new_mpath, *next_mpath, *prev_mpath;
@@ -609,8 +613,11 @@ void bgp_path_info_mpath_update(struct bgp *bgp, struct bgp_dest *dest,
cur_mpath);
prev_mpath = cur_mpath;
mpath_count++;
- if (ecommunity_linkbw_present(
- bgp_attr_get_ecommunity(
+ if (ecommunity_linkbw_present(bgp_attr_get_ecommunity(
+ cur_mpath->attr),
+ &bwval) ||
+ ecommunity_linkbw_present(
+ bgp_attr_get_ipv6_ecommunity(
cur_mpath->attr),
&bwval))
cum_bw += bwval;
@@ -696,8 +703,11 @@ void bgp_path_info_mpath_update(struct bgp *bgp, struct bgp_dest *dest,
prev_mpath = new_mpath;
mpath_changed = 1;
mpath_count++;
- if (ecommunity_linkbw_present(
- bgp_attr_get_ecommunity(
+ if (ecommunity_linkbw_present(bgp_attr_get_ecommunity(
+ new_mpath->attr),
+ &bwval) ||
+ ecommunity_linkbw_present(
+ bgp_attr_get_ipv6_ecommunity(
new_mpath->attr),
&bwval))
cum_bw += bwval;
@@ -720,8 +730,12 @@ void bgp_path_info_mpath_update(struct bgp *bgp, struct bgp_dest *dest,
if (new_best) {
bgp_path_info_mpath_count_set(new_best, mpath_count - 1);
if (mpath_count <= 1 ||
- !ecommunity_linkbw_present(
- bgp_attr_get_ecommunity(new_best->attr), &bwval))
+ (!ecommunity_linkbw_present(bgp_attr_get_ecommunity(
+ new_best->attr),
+ &bwval) &&
+ !ecommunity_linkbw_present(bgp_attr_get_ipv6_ecommunity(
+ new_best->attr),
+ &bwval)))
all_paths_lb = false;
else
cum_bw += bwval;
diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c
index 58e3097..1bc1a47 100644
--- a/bgpd/bgp_mplsvpn.c
+++ b/bgpd/bgp_mplsvpn.c
@@ -964,50 +964,6 @@ void transpose_sid(struct in6_addr *sid, uint32_t label, uint8_t offset,
}
}
-static bool labels_same(struct bgp_path_info *bpi, mpls_label_t *label,
- uint32_t n)
-{
- if (!bpi->extra) {
- if (!n)
- return true;
- else
- return false;
- }
-
- return bgp_labels_same((const mpls_label_t *)bpi->extra->label,
- bpi->extra->num_labels,
- (const mpls_label_t *)label, n);
-}
-
-/*
- * make encoded route labels match specified encoded label set
- */
-static void setlabels(struct bgp_path_info *bpi,
- mpls_label_t *label, /* array of labels */
- uint32_t num_labels)
-{
- if (num_labels)
- assert(label);
- assert(num_labels <= BGP_MAX_LABELS);
-
- if (!num_labels) {
- if (bpi->extra)
- bpi->extra->num_labels = 0;
- return;
- }
-
- struct bgp_path_info_extra *extra = bgp_path_info_extra_get(bpi);
- uint32_t i;
-
- for (i = 0; i < num_labels; ++i) {
- extra->label[i] = label[i];
- if (!bgp_is_valid_label(&label[i])) {
- bgp_set_valid_label(&extra->label[i]);
- }
- }
- extra->num_labels = num_labels;
-}
-
static bool leak_update_nexthop_valid(struct bgp *to_bgp, struct bgp_dest *bn,
struct attr *new_attr, afi_t afi,
safi_t safi,
@@ -1086,7 +1042,7 @@ static struct bgp_path_info *
leak_update(struct bgp *to_bgp, struct bgp_dest *bn,
struct attr *new_attr, /* already interned */
afi_t afi, safi_t safi, struct bgp_path_info *source_bpi,
- mpls_label_t *label, uint32_t num_labels, struct bgp *bgp_orig,
+ mpls_label_t *label, uint8_t num_labels, struct bgp *bgp_orig,
struct prefix *nexthop_orig, int nexthop_self_flag, int debug)
{
const struct prefix *p = bgp_dest_get_prefix(bn);
@@ -1094,6 +1050,9 @@ leak_update(struct bgp *to_bgp, struct bgp_dest *bn,
struct bgp_path_info *new;
struct bgp_path_info_extra *extra;
struct bgp_path_info *parent = source_bpi;
+ struct bgp_labels bgp_labels = {};
+ bool labelssame;
+ uint8_t i;
if (debug)
zlog_debug(
@@ -1128,8 +1087,15 @@ leak_update(struct bgp *to_bgp, struct bgp_dest *bn,
break;
}
+ bgp_labels.num_labels = num_labels;
+ for (i = 0; i < num_labels; i++) {
+ bgp_labels.label[i] = label[i];
+ bgp_set_valid_label(&bgp_labels.label[i]);
+ }
+
if (bpi) {
- bool labelssame = labels_same(bpi, label, num_labels);
+ labelssame = bgp_path_info_labels_same(bpi, bgp_labels.label,
+ bgp_labels.num_labels);
if (CHECK_FLAG(source_bpi->flags, BGP_PATH_REMOVED)
&& CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED)) {
@@ -1187,11 +1153,13 @@ leak_update(struct bgp *to_bgp, struct bgp_dest *bn,
bpi->uptime = monotime(NULL);
/*
- * rewrite labels
+ * update labels
*/
- if (!labelssame)
- setlabels(bpi, label, num_labels);
-
+ if (!labelssame) {
+ bgp_path_info_extra_get(bpi);
+ bgp_labels_unintern(&bpi->extra->labels);
+ bpi->extra->labels = bgp_labels_intern(&bgp_labels);
+ }
if (nexthop_self_flag)
bgp_path_info_set_flag(bn, bpi, BGP_PATH_ANNC_NH_SELF);
@@ -1208,7 +1176,7 @@ leak_update(struct bgp *to_bgp, struct bgp_dest *bn,
/* Process change. */
bgp_aggregate_increment(to_bgp, p, bpi, afi, safi);
- bgp_process(to_bgp, bn, afi, safi);
+ bgp_process(to_bgp, bn, bpi, afi, safi);
if (debug)
zlog_debug("%s: ->%s: %pBD Found route, changed attr",
@@ -1249,8 +1217,8 @@ leak_update(struct bgp *to_bgp, struct bgp_dest *bn,
if (CHECK_FLAG(source_bpi->flags, BGP_PATH_ACCEPT_OWN))
bgp_path_info_set_flag(bn, new, BGP_PATH_ACCEPT_OWN);
- if (num_labels)
- setlabels(new, label, num_labels);
+ if (bgp_labels.num_labels)
+ new->extra->labels = bgp_labels_intern(&bgp_labels);
new->extra->vrfleak->parent = bgp_path_info_lock(parent);
bgp_dest_lock_node(
@@ -1270,7 +1238,7 @@ leak_update(struct bgp *to_bgp, struct bgp_dest *bn,
bgp_aggregate_increment(to_bgp, p, new, afi, safi);
bgp_path_info_add(bn, new);
- bgp_process(to_bgp, bn, afi, safi);
+ bgp_process(to_bgp, bn, new, afi, safi);
if (debug)
zlog_debug("%s: ->%s: %pBD: Added new route", __func__,
@@ -1441,6 +1409,16 @@ _vpn_leak_from_vrf_get_per_nexthop_label(struct bgp_path_info *pi,
return blnc->label;
}
+static mpls_label_t bgp_mplsvpn_get_vpn_label(struct vpn_policy *bgp_policy)
+{
+ if (bgp_policy->tovpn_label == MPLS_LABEL_NONE &&
+ CHECK_FLAG(bgp_policy->flags, BGP_VPN_POLICY_TOVPN_LABEL_AUTO)) {
+ bgp_lp_get(LP_TYPE_VRF, bgp_policy, vpn_leak_label_callback);
+ return MPLS_INVALID_LABEL;
+ }
+ return bgp_policy->tovpn_label;
+}
+
/* Filter out all the cases where a per nexthop label is not possible:
* - return an invalid label when the nexthop is invalid
* - return the per VRF label when the per nexthop label is not supported
@@ -1469,7 +1447,7 @@ vpn_leak_from_vrf_get_per_nexthop_label(afi_t afi, struct bgp_path_info *pi,
* Fallback to the per VRF label.
*/
bgp_mplsvpn_path_nh_label_unlink(pi);
- return from_bgp->vpn_policy[afi].tovpn_label;
+ return bgp_mplsvpn_get_vpn_label(&from_bgp->vpn_policy[afi]);
}
if (is_bgp_static_route == false && afi == AFI_IP &&
@@ -1481,7 +1459,7 @@ vpn_leak_from_vrf_get_per_nexthop_label(afi_t afi, struct bgp_path_info *pi,
* Fallback to the per VRF label.
*/
bgp_mplsvpn_path_nh_label_unlink(pi);
- return from_bgp->vpn_policy[afi].tovpn_label;
+ return bgp_mplsvpn_get_vpn_label(&from_bgp->vpn_policy[afi]);
}
if (is_bgp_static_route == false && afi == AFI_IP6 &&
@@ -1495,7 +1473,7 @@ vpn_leak_from_vrf_get_per_nexthop_label(afi_t afi, struct bgp_path_info *pi,
* Fallback to the per VRF label.
*/
bgp_mplsvpn_path_nh_label_unlink(pi);
- return from_bgp->vpn_policy[afi].tovpn_label;
+ return bgp_mplsvpn_get_vpn_label(&from_bgp->vpn_policy[afi]);
}
/* Check the next-hop reachability.
@@ -1517,7 +1495,7 @@ vpn_leak_from_vrf_get_per_nexthop_label(afi_t afi, struct bgp_path_info *pi,
* table. Fallback to the per-vrf label
*/
bgp_mplsvpn_path_nh_label_unlink(pi);
- return from_bgp->vpn_policy[afi].tovpn_label;
+ return bgp_mplsvpn_get_vpn_label(&from_bgp->vpn_policy[afi]);
}
if (!nh_valid || !pi->nexthop || pi->nexthop->nexthop_num == 0 ||
@@ -1540,7 +1518,7 @@ vpn_leak_from_vrf_get_per_nexthop_label(afi_t afi, struct bgp_path_info *pi,
* Fallback to per-vrf label.
*/
bgp_mplsvpn_path_nh_label_unlink(pi);
- return from_bgp->vpn_policy[afi].tovpn_label;
+ return bgp_mplsvpn_get_vpn_label(&from_bgp->vpn_policy[afi]);
}
return _vpn_leak_from_vrf_get_per_nexthop_label(pi, to_bgp, from_bgp,
@@ -1755,12 +1733,10 @@ void vpn_leak_from_vrf_update(struct bgp *to_bgp, /* to */
label_val = vpn_leak_from_vrf_get_per_nexthop_label(
afi, path_vrf, from_bgp, to_bgp);
else
- /* per VRF label mode */
- label_val = from_bgp->vpn_policy[afi].tovpn_label;
+ label_val =
+ bgp_mplsvpn_get_vpn_label(&from_bgp->vpn_policy[afi]);
- if (label_val == MPLS_INVALID_LABEL &&
- CHECK_FLAG(from_bgp->vpn_policy[afi].flags,
- BGP_VPN_POLICY_TOVPN_LABEL_PER_NEXTHOP)) {
+ if (label_val == MPLS_INVALID_LABEL) {
/* no valid label for the moment
* when the 'bgp_mplsvpn_get_label_per_nexthop_cb' callback gets
* a valid label value, it will call the current function again.
@@ -1956,7 +1932,7 @@ void vpn_leak_from_vrf_withdraw(struct bgp *to_bgp, /* to */
bgp_aggregate_decrement(to_bgp, p, bpi, afi, safi);
bgp_path_info_delete(bn, bpi);
- bgp_process(to_bgp, bn, afi, safi);
+ bgp_process(to_bgp, bn, bpi, afi, safi);
}
bgp_dest_unlock_node(bn);
}
@@ -1976,7 +1952,7 @@ void vpn_leak_from_vrf_withdraw_all(struct bgp *to_bgp, struct bgp *from_bgp,
struct bgp_table *table;
struct bgp_dest *bn;
- struct bgp_path_info *bpi;
+ struct bgp_path_info *bpi, *next;
/* This is the per-RD table of prefixes */
table = bgp_dest_get_bgp_table_info(pdest);
@@ -1991,7 +1967,8 @@ void vpn_leak_from_vrf_withdraw_all(struct bgp *to_bgp, struct bgp *from_bgp,
__func__, bn);
}
- for (; bpi; bpi = bpi->next) {
+ for (; (bpi != NULL) && (next = bpi->next, 1);
+ bpi = next) {
if (debug)
zlog_debug("%s: type %d, sub_type %d",
__func__, bpi->type,
@@ -2012,7 +1989,7 @@ void vpn_leak_from_vrf_withdraw_all(struct bgp *to_bgp, struct bgp *from_bgp,
to_bgp, bgp_dest_get_prefix(bn),
bpi, afi, safi);
bgp_path_info_delete(bn, bpi);
- bgp_process(to_bgp, bn, afi, safi);
+ bgp_process(to_bgp, bn, bpi, afi, safi);
bgp_mplsvpn_path_nh_label_unlink(
bpi->extra->vrfleak->parent);
}
@@ -2093,15 +2070,16 @@ static void vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */
safi_t safi = SAFI_UNICAST;
const char *debugmsg;
struct prefix nexthop_orig;
- mpls_label_t *pLabels = NULL;
- uint32_t num_labels = 0;
+ mpls_label_t *label_pnt = NULL;
+ uint8_t num_labels = 0;
int nexthop_self_flag = 1;
struct bgp_path_info *bpi_ultimate = NULL;
struct bgp_path_info *bpi;
int origin_local = 0;
struct bgp *src_vrf;
- struct interface *ifp;
+ struct interface *ifp = NULL;
char rd_buf[RD_ADDRSTRLEN];
+
int debug = BGP_DEBUG(vpn, VPN_LEAK_TO_VRF);
if (!vpn_leak_from_vpn_active(to_bgp, afi, &debugmsg)) {
@@ -2268,6 +2246,15 @@ static void vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */
break;
}
+ if (!ifp && static_attr.nh_ifindex)
+ ifp = if_lookup_by_index(static_attr.nh_ifindex,
+ src_vrf->vrf_id);
+
+ if (ifp && if_is_operative(ifp))
+ SET_FLAG(static_attr.nh_flags, BGP_ATTR_NH_IF_OPERSTATE);
+ else
+ UNSET_FLAG(static_attr.nh_flags, BGP_ATTR_NH_IF_OPERSTATE);
+
/*
* route map handling
*/
@@ -2330,21 +2317,16 @@ static void vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */
origin_local = 1;
}
- /* copy labels */
- if (!origin_local && path_vpn->extra
- && path_vpn->extra->num_labels) {
- num_labels = path_vpn->extra->num_labels;
- if (num_labels > BGP_MAX_LABELS)
- num_labels = BGP_MAX_LABELS;
- pLabels = path_vpn->extra->label;
- }
+ num_labels = origin_local ? 0
+ : bgp_path_info_num_labels(path_vpn);
+ label_pnt = num_labels ? path_vpn->extra->labels->label : NULL;
}
if (debug)
zlog_debug("%s: pfx %pBD: num_labels %d", __func__,
path_vpn->net, num_labels);
- if (!leak_update(to_bgp, bn, new_attr, afi, safi, path_vpn, pLabels,
+ if (!leak_update(to_bgp, bn, new_attr, afi, safi, path_vpn, label_pnt,
num_labels, src_vrf, &nexthop_orig, nexthop_self_flag,
debug))
bgp_dest_unlock_node(bn);
@@ -2497,7 +2479,7 @@ void vpn_leak_to_vrf_withdraw(struct bgp_path_info *path_vpn)
bpi);
bgp_aggregate_decrement(bgp, p, bpi, afi, safi);
bgp_path_info_delete(bn, bpi);
- bgp_process(bgp, bn, afi, safi);
+ bgp_process(bgp, bn, bpi, afi, safi);
}
bgp_dest_unlock_node(bn);
}
@@ -2506,7 +2488,7 @@ void vpn_leak_to_vrf_withdraw(struct bgp_path_info *path_vpn)
void vpn_leak_to_vrf_withdraw_all(struct bgp *to_bgp, afi_t afi)
{
struct bgp_dest *bn;
- struct bgp_path_info *bpi;
+ struct bgp_path_info *bpi, *next;
safi_t safi = SAFI_UNICAST;
int debug = BGP_DEBUG(vpn, VPN_LEAK_TO_VRF);
@@ -2517,9 +2499,8 @@ void vpn_leak_to_vrf_withdraw_all(struct bgp *to_bgp, afi_t afi)
*/
for (bn = bgp_table_top(to_bgp->rib[afi][safi]); bn;
bn = bgp_route_next(bn)) {
-
- for (bpi = bgp_dest_get_bgp_path_info(bn); bpi;
- bpi = bpi->next) {
+ for (bpi = bgp_dest_get_bgp_path_info(bn);
+ (bpi != NULL) && (next = bpi->next, 1); bpi = next) {
if (bpi->extra && bpi->extra->vrfleak &&
bpi->extra->vrfleak->bgp_orig != to_bgp &&
bpi->extra->vrfleak->parent &&
@@ -2529,7 +2510,7 @@ void vpn_leak_to_vrf_withdraw_all(struct bgp *to_bgp, afi_t afi)
bgp_dest_get_prefix(bn),
bpi, afi, safi);
bgp_path_info_delete(bn, bpi);
- bgp_process(to_bgp, bn, afi, safi);
+ bgp_process(to_bgp, bn, bpi, afi, safi);
}
}
}
@@ -2558,8 +2539,11 @@ void vpn_leak_no_retain(struct bgp *to_bgp, struct bgp *vpn_from, afi_t afi)
continue;
for (bn = bgp_table_top(table); bn; bn = bgp_route_next(bn)) {
- for (bpi = bgp_dest_get_bgp_path_info(bn); bpi;
- bpi = bpi->next) {
+ struct bgp_path_info *next;
+
+ for (bpi = bgp_dest_get_bgp_path_info(bn);
+ (bpi != NULL) && (next = bpi->next, 1);
+ bpi = next) {
if (bpi->extra && bpi->extra->vrfleak &&
bpi->extra->vrfleak->bgp_orig == to_bgp)
continue;
@@ -3746,6 +3730,9 @@ void vpn_leak_postchange_all(void)
if (bgp->inst_type != BGP_INSTANCE_TYPE_VRF)
continue;
+ if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_AUTO))
+ continue;
+
vpn_leak_postchange(
BGP_VPN_POLICY_DIR_TOVPN,
AFI_IP,
@@ -3765,6 +3752,9 @@ void vpn_leak_postchange_all(void)
if (bgp->inst_type != BGP_INSTANCE_TYPE_VRF)
continue;
+ if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_AUTO))
+ continue;
+
vpn_leak_postchange(
BGP_VPN_POLICY_DIR_FROMVPN,
AFI_IP,
@@ -3974,7 +3964,7 @@ static void bgp_mplsvpn_nh_label_bind_send_nexthop_label(
struct bgp_mplsvpn_nh_label_bind_cache *bmnc, int cmd)
{
struct prefix pfx_nh, *p = NULL;
- uint32_t num_labels = 0, lsp_num_labels;
+ uint8_t num_labels = 0, lsp_num_labels;
mpls_label_t label[MPLS_MAX_LABELS];
struct nexthop *nh;
ifindex_t ifindex = IFINDEX_INTERNAL;
@@ -4109,7 +4099,7 @@ bool bgp_mplsvpn_path_uses_valid_mpls_label(struct bgp_path_info *pi)
/* prefix_sid attribute */
return false;
- if (!pi->extra || !bgp_is_valid_label(&pi->extra->label[0]))
+ if (!bgp_path_info_has_valid_label(pi))
/* invalid MPLS label */
return false;
return true;
@@ -4180,7 +4170,7 @@ static int bgp_mplsvpn_nh_label_bind_get_local_label_cb(mpls_label_t label,
if (!table)
continue;
SET_FLAG(pi->net->flags, BGP_NODE_LABEL_CHANGED);
- bgp_process(table->bgp, pi->net, table->afi, table->safi);
+ bgp_process(table->bgp, pi->net, pi, table->afi, table->safi);
}
return 0;
@@ -4216,14 +4206,17 @@ void bgp_mplsvpn_nh_label_bind_register_local_label(struct bgp *bgp,
{
struct bgp_mplsvpn_nh_label_bind_cache *bmnc;
struct bgp_mplsvpn_nh_label_bind_cache_head *tree;
+ mpls_label_t label;
+
+ label = bgp_path_info_num_labels(pi)
+ ? decode_label(&pi->extra->labels->label[0])
+ : MPLS_INVALID_LABEL;
tree = &bgp->mplsvpn_nh_label_bind;
- bmnc = bgp_mplsvpn_nh_label_bind_find(
- tree, &pi->nexthop->prefix, decode_label(&pi->extra->label[0]));
+ bmnc = bgp_mplsvpn_nh_label_bind_find(tree, &pi->nexthop->prefix, label);
if (!bmnc) {
- bmnc = bgp_mplsvpn_nh_label_bind_new(
- tree, &pi->nexthop->prefix,
- decode_label(&pi->extra->label[0]));
+ bmnc = bgp_mplsvpn_nh_label_bind_new(tree, &pi->nexthop->prefix,
+ label);
bmnc->bgp_vpn = bgp;
bmnc->allocation_in_progress = true;
bgp_lp_get(LP_TYPE_BGP_L3VPN_BIND, bmnc,
diff --git a/bgpd/bgp_mplsvpn.h b/bgpd/bgp_mplsvpn.h
index cd25899..92a9fba 100644
--- a/bgpd/bgp_mplsvpn.h
+++ b/bgpd/bgp_mplsvpn.h
@@ -170,16 +170,6 @@ static inline int vpn_leak_to_vpn_active(struct bgp *bgp_vrf, afi_t afi,
return 0;
}
- /* Is there an "auto" export label that isn't allocated yet? */
- if (CHECK_FLAG(bgp_vrf->vpn_policy[afi].flags,
- BGP_VPN_POLICY_TOVPN_LABEL_AUTO) &&
- (bgp_vrf->vpn_policy[afi].tovpn_label == MPLS_LABEL_NONE)) {
-
- if (pmsg)
- *pmsg = "auto label not allocated";
- return 0;
- }
-
/* Is there a "manual" export label that isn't allocated yet? */
if (!CHECK_FLAG(bgp_vrf->vpn_policy[afi].flags,
BGP_VPN_POLICY_TOVPN_LABEL_AUTO) &&
diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c
index dbb34b0..e09dbc2 100644
--- a/bgpd/bgp_network.c
+++ b/bgpd/bgp_network.c
@@ -817,9 +817,9 @@ int bgp_connect(struct peer_connection *connection)
#ifdef IPTOS_PREC_INTERNETCONTROL
frr_with_privs(&bgpd_privs) {
if (sockunion_family(&connection->su) == AF_INET)
- setsockopt_ipv4_tos(connection->fd, bm->tcp_dscp);
+ setsockopt_ipv4_tos(connection->fd, bm->ip_tos);
else if (sockunion_family(&connection->su) == AF_INET6)
- setsockopt_ipv6_tclass(connection->fd, bm->tcp_dscp);
+ setsockopt_ipv6_tclass(connection->fd, bm->ip_tos);
}
#endif
@@ -875,11 +875,7 @@ int bgp_getsockname(struct peer *peer)
}
peer->su_local = sockunion_getsockname(peer->connection->fd);
- if (!peer->su_local)
- return -1;
peer->su_remote = sockunion_getpeername(peer->connection->fd);
- if (!peer->su_remote)
- return -1;
if (!bgp_zebra_nexthop_set(peer->su_local, peer->su_remote,
&peer->nexthop, peer)) {
@@ -909,9 +905,9 @@ static int bgp_listener(int sock, struct sockaddr *sa, socklen_t salen,
#ifdef IPTOS_PREC_INTERNETCONTROL
if (sa->sa_family == AF_INET)
- setsockopt_ipv4_tos(sock, bm->tcp_dscp);
+ setsockopt_ipv4_tos(sock, bm->ip_tos);
else if (sa->sa_family == AF_INET6)
- setsockopt_ipv6_tclass(sock, bm->tcp_dscp);
+ setsockopt_ipv6_tclass(sock, bm->ip_tos);
#endif
sockopt_v6only(sa->sa_family, sock);
diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c
index d12dc22..98eb956 100644
--- a/bgpd/bgp_nexthop.c
+++ b/bgpd/bgp_nexthop.c
@@ -1003,6 +1003,8 @@ static void bgp_show_nexthop(struct vty *vty, struct bgp *bgp,
if (bnc->is_evpn_gwip_nexthop)
json_object_boolean_true_add(json_nexthop,
"isEvpnGatewayIp");
+ json_object_string_addf(json, "resolvedPrefix", "%pFX",
+ &bnc->resolved_prefix);
} else {
vty_out(vty, " %s valid [IGP metric %d], #paths %d",
buf, bnc->metric, bnc->path_count);
@@ -1010,6 +1012,8 @@ static void bgp_show_nexthop(struct vty *vty, struct bgp *bgp,
vty_out(vty, ", peer %s", peer->host);
if (bnc->is_evpn_gwip_nexthop)
vty_out(vty, " EVPN Gateway IP");
+ vty_out(vty, "\n Resolved prefix %pFX",
+ &bnc->resolved_prefix);
vty_out(vty, "\n");
}
bgp_show_nexthops_detail(vty, bgp, bnc, json_nexthop);
diff --git a/bgpd/bgp_nexthop.h b/bgpd/bgp_nexthop.h
index 8308838..430c8f1 100644
--- a/bgpd/bgp_nexthop.h
+++ b/bgpd/bgp_nexthop.h
@@ -90,6 +90,7 @@ struct bgp_nexthop_cache {
struct bgp_nexthop_cache_head *tree;
struct prefix prefix;
+ struct prefix resolved_prefix;
void *nht_info; /* In BGP, peer session */
LIST_HEAD(path_list, bgp_path_info) paths;
unsigned int path_count;
diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c
index e2c103b..8ce4555 100644
--- a/bgpd/bgp_nht.c
+++ b/bgpd/bgp_nht.c
@@ -116,24 +116,36 @@ static int bgp_isvalid_nexthop_for_mplsovergre(struct bgp_nexthop_cache *bnc,
static int bgp_isvalid_nexthop_for_mpls(struct bgp_nexthop_cache *bnc,
struct bgp_path_info *path)
{
+ return (bnc && (bnc->nexthop_num > 0 &&
+ (CHECK_FLAG(path->flags, BGP_PATH_ACCEPT_OWN) ||
+ CHECK_FLAG(bnc->flags, BGP_NEXTHOP_LABELED_VALID) ||
+ bgp_isvalid_nexthop_for_ebgp(bnc, path) ||
+ bgp_isvalid_nexthop_for_mplsovergre(bnc, path))));
+}
+
+static bool bgp_isvalid_nexthop_for_l3vpn(struct bgp_nexthop_cache *bnc,
+ struct bgp_path_info *path)
+{
+ if (bgp_zebra_num_connects() == 0)
+ return 1;
+
+ if (path->attr->srv6_l3vpn || path->attr->srv6_vpn) {
+ /* In the case of SRv6-VPN, we need to track the reachability to the
+ * SID (in other words, IPv6 address). We check that the SID is
+ * available in the BGP update; then if it is available, we check
+ * for the nexthop reachability.
+ */
+ if (bnc && (bnc->nexthop_num > 0 && bgp_isvalid_nexthop(bnc)))
+ return 1;
+ return 0;
+ }
/*
- * - In the case of MPLS-VPN, the label is learned from LDP or other
+ * In the case of MPLS-VPN, the label is learned from LDP or other
* protocols, and nexthop tracking is enabled for the label.
* The value is recorded as BGP_NEXTHOP_LABELED_VALID.
- * - In the case of SRv6-VPN, we need to track the reachability to the
- * SID (in other words, IPv6 address). As in MPLS, we need to record
- * the value as BGP_NEXTHOP_SID_VALID. However, this function is
- * currently not implemented, and this function assumes that all
- * Transit routes for SRv6-VPN are valid.
* - Otherwise check for mpls-gre acceptance
*/
- return (bgp_zebra_num_connects() == 0 ||
- (bnc && (bnc->nexthop_num > 0 &&
- (CHECK_FLAG(path->flags, BGP_PATH_ACCEPT_OWN) ||
- CHECK_FLAG(bnc->flags, BGP_NEXTHOP_LABELED_VALID) ||
- bnc->bgp->srv6_enabled ||
- bgp_isvalid_nexthop_for_ebgp(bnc, path) ||
- bgp_isvalid_nexthop_for_mplsovergre(bnc, path)))));
+ return bgp_isvalid_nexthop_for_mpls(bnc, path);
}
static void bgp_unlink_nexthop_check(struct bgp_nexthop_cache *bnc)
@@ -308,11 +320,6 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop,
afi = BGP_ATTR_MP_NEXTHOP_LEN_IP6(pi->attr) ? AFI_IP6
: AFI_IP;
- /* Validation for the ipv4 mapped ipv6 nexthop. */
- if (IS_MAPPED_IPV6(&pi->attr->mp_nexthop_global)) {
- afi = AFI_IP;
- }
-
/* This will return true if the global IPv6 NH is a link local
* addr */
if (make_prefix(afi, pi, &p) < 0)
@@ -345,9 +352,7 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop,
return 0;
}
- if (CHECK_FLAG(pi->attr->flag,
- ATTR_FLAG_BIT(BGP_ATTR_SRTE_COLOR)))
- srte_color = bgp_attr_get_color(pi->attr);
+ srte_color = bgp_attr_get_color(pi->attr);
} else if (peer) {
/*
@@ -494,9 +499,9 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop,
if (bgp_route->inst_type == BGP_INSTANCE_TYPE_VIEW)
return 1;
else if (safi == SAFI_UNICAST && pi &&
- pi->sub_type == BGP_ROUTE_IMPORTED && pi->extra &&
- pi->extra->num_labels && !bnc->is_evpn_gwip_nexthop)
- return bgp_isvalid_nexthop_for_mpls(bnc, pi);
+ pi->sub_type == BGP_ROUTE_IMPORTED &&
+ bgp_path_info_num_labels(pi) && !bnc->is_evpn_gwip_nexthop)
+ return bgp_isvalid_nexthop_for_l3vpn(bnc, pi);
else if (safi == SAFI_MPLS_VPN && pi &&
pi->sub_type != BGP_ROUTE_IMPORTED)
/* avoid not redistributing mpls vpn routes */
@@ -614,6 +619,8 @@ static void bgp_process_nexthop_update(struct bgp_nexthop_cache *bnc,
} else if (nhr->nexthop_num) {
struct peer *peer = bnc->nht_info;
+ prefix_copy(&bnc->resolved_prefix, &nhr->prefix);
+
/* notify bgp fsm if nbr ip goes from invalid->valid */
if (!bnc->nexthop_num)
UNSET_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED);
@@ -719,6 +726,7 @@ static void bgp_process_nexthop_update(struct bgp_nexthop_cache *bnc,
}
}
} else {
+ memset(&bnc->resolved_prefix, 0, sizeof(bnc->resolved_prefix));
bnc->flags &= ~BGP_NEXTHOP_EVPN_INCOMPLETE;
bnc->flags &= ~BGP_NEXTHOP_VALID;
bnc->flags &= ~BGP_NEXTHOP_LABELED_VALID;
@@ -964,14 +972,13 @@ void bgp_nexthop_update(struct vrf *vrf, struct prefix *match,
* which should provide a better infrastructure to solve this issue in
* a more efficient and elegant way.
*/
- if (nhr->srte_color == 0 && bnc_nhc) {
+ if (nhr->srte_color == 0) {
struct bgp_nexthop_cache *bnc_iter;
frr_each (bgp_nexthop_cache, &bgp->nexthop_cache_table[afi],
bnc_iter) {
- if (!prefix_same(&bnc_nhc->prefix, &bnc_iter->prefix) ||
- bnc_iter->srte_color == 0 ||
- CHECK_FLAG(bnc_iter->flags, BGP_NEXTHOP_VALID))
+ if (!prefix_same(match, &bnc_iter->prefix) ||
+ bnc_iter->srte_color == 0)
continue;
bgp_process_nexthop_update(bnc_iter, nhr, false);
@@ -1028,52 +1035,57 @@ static int make_prefix(int afi, struct bgp_path_info *pi, struct prefix *p)
p->u.prefix4 = p_orig->u.prefix4;
p->prefixlen = p_orig->prefixlen;
} else {
- if (IS_MAPPED_IPV6(&pi->attr->mp_nexthop_global)) {
- ipv4_mapped_ipv6_to_ipv4(
- &pi->attr->mp_nexthop_global, &ipv4);
- p->u.prefix4 = ipv4;
- p->prefixlen = IPV4_MAX_BITLEN;
- } else {
- if (p_orig->family == AF_EVPN)
- p->u.prefix4 =
- pi->attr->mp_nexthop_global_in;
- else
- p->u.prefix4 = pi->attr->nexthop;
- p->prefixlen = IPV4_MAX_BITLEN;
- }
+ if (p_orig->family == AF_EVPN)
+ p->u.prefix4 = pi->attr->mp_nexthop_global_in;
+ else
+ p->u.prefix4 = pi->attr->nexthop;
+ p->prefixlen = IPV4_MAX_BITLEN;
}
break;
case AFI_IP6:
p->family = AF_INET6;
-
- if (is_bgp_static) {
+ if (pi->attr->srv6_l3vpn) {
+ IPV6_ADDR_COPY(&(p->u.prefix6),
+ &(pi->attr->srv6_l3vpn->sid));
+ p->prefixlen = IPV6_MAX_BITLEN;
+ } else if (is_bgp_static) {
p->u.prefix6 = p_orig->u.prefix6;
p->prefixlen = p_orig->prefixlen;
} else {
/* If we receive MP_REACH nexthop with ::(LL)
* or LL(LL), use LL address as nexthop cache.
*/
- if (pi->attr->mp_nexthop_len
- == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL
- && (IN6_IS_ADDR_UNSPECIFIED(
- &pi->attr->mp_nexthop_global)
- || IN6_IS_ADDR_LINKLOCAL(
- &pi->attr->mp_nexthop_global)))
+ p->prefixlen = IPV6_MAX_BITLEN;
+ if (pi->attr &&
+ pi->attr->mp_nexthop_len ==
+ BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL &&
+ (IN6_IS_ADDR_UNSPECIFIED(
+ &pi->attr->mp_nexthop_global) ||
+ IN6_IS_ADDR_LINKLOCAL(&pi->attr->mp_nexthop_global)))
p->u.prefix6 = pi->attr->mp_nexthop_local;
/* If we receive MR_REACH with (GA)::(LL)
* then check for route-map to choose GA or LL
*/
- else if (pi->attr->mp_nexthop_len
- == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) {
- if (pi->attr->mp_nexthop_prefer_global)
- p->u.prefix6 =
- pi->attr->mp_nexthop_global;
- else
+ else if (pi->attr &&
+ pi->attr->mp_nexthop_len ==
+ BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) {
+ if (CHECK_FLAG(pi->attr->nh_flags,
+ BGP_ATTR_NH_MP_PREFER_GLOBAL)) {
+ if (IS_MAPPED_IPV6(
+ &pi->attr->mp_nexthop_global)) {
+ ipv4_mapped_ipv6_to_ipv4(
+ &pi->attr->mp_nexthop_global,
+ &ipv4);
+ p->u.prefix4 = ipv4;
+ p->prefixlen = IPV4_MAX_BITLEN;
+ } else
+ p->u.prefix6 =
+ pi->attr->mp_nexthop_global;
+ } else
p->u.prefix6 =
pi->attr->mp_nexthop_local;
} else
p->u.prefix6 = pi->attr->mp_nexthop_global;
- p->prefixlen = IPV6_MAX_BITLEN;
}
break;
default:
@@ -1289,13 +1301,14 @@ void evaluate_paths(struct bgp_nexthop_cache *bnc)
bool bnc_is_valid_nexthop = false;
bool path_valid = false;
- if (safi == SAFI_UNICAST && path->sub_type == BGP_ROUTE_IMPORTED
- && path->extra && path->extra->num_labels
- && (path->attr->evpn_overlay.type
- != OVERLAY_INDEX_GATEWAY_IP)) {
+ if (safi == SAFI_UNICAST &&
+ path->sub_type == BGP_ROUTE_IMPORTED &&
+ bgp_path_info_num_labels(path) &&
+ (path->attr->evpn_overlay.type != OVERLAY_INDEX_GATEWAY_IP)) {
bnc_is_valid_nexthop =
- bgp_isvalid_nexthop_for_mpls(bnc, path) ? true
- : false;
+ bgp_isvalid_nexthop_for_l3vpn(bnc, path)
+ ? true
+ : false;
} else if (safi == SAFI_MPLS_VPN &&
path->sub_type != BGP_ROUTE_IMPORTED) {
/* avoid not redistributing mpls vpn routes */
@@ -1414,7 +1427,7 @@ void evaluate_paths(struct bgp_nexthop_cache *bnc)
}
}
- bgp_process(bgp_path, dest, afi, safi);
+ bgp_process(bgp_path, dest, path, afi, safi);
}
if (peer) {
diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c
index 6c96ffc..248d478 100644
--- a/bgpd/bgp_open.c
+++ b/bgpd/bgp_open.c
@@ -42,25 +42,27 @@ const struct message capcode_str[] = {
{ CAPABILITY_CODE_LLGR, "Long-lived BGP Graceful Restart" },
{ CAPABILITY_CODE_ROLE, "Role" },
{ CAPABILITY_CODE_SOFT_VERSION, "Software Version" },
+ { CAPABILITY_CODE_PATHS_LIMIT, "Paths-Limit" },
{ 0 }
};
/* Minimum sizes for length field of each cap (so not inc. the header) */
-static const size_t cap_minsizes[] = {
- [CAPABILITY_CODE_MP] = CAPABILITY_CODE_MP_LEN,
- [CAPABILITY_CODE_REFRESH] = CAPABILITY_CODE_REFRESH_LEN,
- [CAPABILITY_CODE_ORF] = CAPABILITY_CODE_ORF_LEN,
- [CAPABILITY_CODE_RESTART] = CAPABILITY_CODE_RESTART_LEN,
- [CAPABILITY_CODE_AS4] = CAPABILITY_CODE_AS4_LEN,
- [CAPABILITY_CODE_ADDPATH] = CAPABILITY_CODE_ADDPATH_LEN,
- [CAPABILITY_CODE_DYNAMIC] = CAPABILITY_CODE_DYNAMIC_LEN,
- [CAPABILITY_CODE_ENHE] = CAPABILITY_CODE_ENHE_LEN,
- [CAPABILITY_CODE_FQDN] = CAPABILITY_CODE_MIN_FQDN_LEN,
- [CAPABILITY_CODE_ENHANCED_RR] = CAPABILITY_CODE_ENHANCED_LEN,
- [CAPABILITY_CODE_EXT_MESSAGE] = CAPABILITY_CODE_EXT_MESSAGE_LEN,
- [CAPABILITY_CODE_LLGR] = CAPABILITY_CODE_LLGR_LEN,
- [CAPABILITY_CODE_ROLE] = CAPABILITY_CODE_ROLE_LEN,
- [CAPABILITY_CODE_SOFT_VERSION] = CAPABILITY_CODE_SOFT_VERSION_LEN,
+const size_t cap_minsizes[] = {
+ [CAPABILITY_CODE_MP] = CAPABILITY_CODE_MP_LEN,
+ [CAPABILITY_CODE_REFRESH] = CAPABILITY_CODE_REFRESH_LEN,
+ [CAPABILITY_CODE_ORF] = CAPABILITY_CODE_ORF_LEN,
+ [CAPABILITY_CODE_RESTART] = CAPABILITY_CODE_RESTART_LEN,
+ [CAPABILITY_CODE_AS4] = CAPABILITY_CODE_AS4_LEN,
+ [CAPABILITY_CODE_ADDPATH] = CAPABILITY_CODE_ADDPATH_LEN,
+ [CAPABILITY_CODE_DYNAMIC] = CAPABILITY_CODE_DYNAMIC_LEN,
+ [CAPABILITY_CODE_ENHE] = CAPABILITY_CODE_ENHE_LEN,
+ [CAPABILITY_CODE_FQDN] = CAPABILITY_CODE_MIN_FQDN_LEN,
+ [CAPABILITY_CODE_ENHANCED_RR] = CAPABILITY_CODE_ENHANCED_LEN,
+ [CAPABILITY_CODE_EXT_MESSAGE] = CAPABILITY_CODE_EXT_MESSAGE_LEN,
+ [CAPABILITY_CODE_LLGR] = CAPABILITY_CODE_LLGR_LEN,
+ [CAPABILITY_CODE_ROLE] = CAPABILITY_CODE_ROLE_LEN,
+ [CAPABILITY_CODE_SOFT_VERSION] = CAPABILITY_CODE_SOFT_VERSION_LEN,
+ [CAPABILITY_CODE_PATHS_LIMIT] = CAPABILITY_CODE_PATHS_LIMIT_LEN,
};
/* value the capability must be a multiple of.
@@ -68,21 +70,22 @@ static const size_t cap_minsizes[] = {
* Other capabilities whose data doesn't fall on convenient boundaries for this
* table should be set to 1.
*/
-static const size_t cap_modsizes[] = {
- [CAPABILITY_CODE_MP] = 4,
- [CAPABILITY_CODE_REFRESH] = 1,
- [CAPABILITY_CODE_ORF] = 1,
- [CAPABILITY_CODE_RESTART] = 1,
- [CAPABILITY_CODE_AS4] = 4,
- [CAPABILITY_CODE_ADDPATH] = 4,
- [CAPABILITY_CODE_DYNAMIC] = 1,
- [CAPABILITY_CODE_ENHE] = 6,
- [CAPABILITY_CODE_FQDN] = 1,
- [CAPABILITY_CODE_ENHANCED_RR] = 1,
- [CAPABILITY_CODE_EXT_MESSAGE] = 1,
- [CAPABILITY_CODE_LLGR] = 1,
- [CAPABILITY_CODE_ROLE] = 1,
- [CAPABILITY_CODE_SOFT_VERSION] = 1,
+const size_t cap_modsizes[] = {
+ [CAPABILITY_CODE_MP] = 4,
+ [CAPABILITY_CODE_REFRESH] = 1,
+ [CAPABILITY_CODE_ORF] = 1,
+ [CAPABILITY_CODE_RESTART] = 1,
+ [CAPABILITY_CODE_AS4] = 4,
+ [CAPABILITY_CODE_ADDPATH] = 4,
+ [CAPABILITY_CODE_DYNAMIC] = 1,
+ [CAPABILITY_CODE_ENHE] = 6,
+ [CAPABILITY_CODE_FQDN] = 1,
+ [CAPABILITY_CODE_ENHANCED_RR] = 1,
+ [CAPABILITY_CODE_EXT_MESSAGE] = 1,
+ [CAPABILITY_CODE_LLGR] = 1,
+ [CAPABILITY_CODE_ROLE] = 1,
+ [CAPABILITY_CODE_SOFT_VERSION] = 1,
+ [CAPABILITY_CODE_PATHS_LIMIT] = 5,
};
/* BGP-4 Multiprotocol Extentions lead us to the complex world. We can
@@ -739,6 +742,62 @@ static int bgp_capability_addpath(struct peer *peer,
return 0;
}
+static int bgp_capability_paths_limit(struct peer *peer,
+ struct capability_header *hdr)
+{
+ struct stream *s = BGP_INPUT(peer);
+ size_t end = stream_get_getp(s) + hdr->length;
+
+ if (hdr->length % CAPABILITY_CODE_PATHS_LIMIT_LEN) {
+ flog_warn(EC_BGP_CAPABILITY_INVALID_LENGTH,
+ "Paths-Limit: Received invalid length %d, non-multiple of %d",
+ hdr->length, CAPABILITY_CODE_PATHS_LIMIT_LEN);
+ return -1;
+ }
+
+ if (!CHECK_FLAG(peer->cap, PEER_CAP_ADDPATH_RCV)) {
+ flog_warn(EC_BGP_CAPABILITY_INVALID_DATA,
+ "Paths-Limit: Received Paths-Limit capability without Add-Path capability");
+ return -1;
+ }
+
+ SET_FLAG(peer->cap, PEER_CAP_PATHS_LIMIT_RCV);
+
+ while (stream_get_getp(s) + CAPABILITY_CODE_PATHS_LIMIT_LEN <= end) {
+ afi_t afi;
+ safi_t safi;
+ iana_afi_t pkt_afi = stream_getw(s);
+ iana_safi_t pkt_safi = stream_getc(s);
+ uint16_t paths_limit = stream_getw(s);
+
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug("%s OPEN has %s capability for afi/safi: %s/%s limit: %u",
+ peer->host,
+ lookup_msg(capcode_str, hdr->code, NULL),
+ iana_afi2str(pkt_afi),
+ iana_safi2str(pkt_safi), paths_limit);
+
+ if (bgp_map_afi_safi_iana2int(pkt_afi, pkt_safi, &afi, &safi)) {
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug("%s Addr-family %s/%s(afi/safi) not supported. Ignore the Paths-Limit capability for this AFI/SAFI",
+ peer->host, iana_afi2str(pkt_afi),
+ iana_safi2str(pkt_safi));
+ continue;
+ } else if (!peer->afc[afi][safi]) {
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug("%s Addr-family %s/%s(afi/safi) not enabled. Ignore the Paths-Limit capability for this AFI/SAFI",
+ peer->host, iana_afi2str(pkt_afi),
+ iana_safi2str(pkt_safi));
+ continue;
+ }
+
+ SET_FLAG(peer->af_cap[afi][safi], PEER_CAP_PATHS_LIMIT_AF_RCV);
+ peer->addpath_paths_limit[afi][safi].receive = paths_limit;
+ }
+
+ return 0;
+}
+
static int bgp_capability_enhe(struct peer *peer, struct capability_header *hdr)
{
struct stream *s = BGP_INPUT(peer);
@@ -1012,6 +1071,7 @@ static int bgp_capability_parse(struct peer *peer, size_t length,
case CAPABILITY_CODE_EXT_MESSAGE:
case CAPABILITY_CODE_ROLE:
case CAPABILITY_CODE_SOFT_VERSION:
+ case CAPABILITY_CODE_PATHS_LIMIT:
/* Check length. */
if (caphdr.length < cap_minsizes[caphdr.code]) {
zlog_info(
@@ -1113,6 +1173,9 @@ static int bgp_capability_parse(struct peer *peer, size_t length,
case CAPABILITY_CODE_SOFT_VERSION:
ret = bgp_capability_software_version(peer, &caphdr);
break;
+ case CAPABILITY_CODE_PATHS_LIMIT:
+ ret = bgp_capability_paths_limit(peer, &caphdr);
+ break;
default:
if (caphdr.code > 128) {
/* We don't send Notification for unknown vendor
@@ -1389,8 +1452,10 @@ int bgp_open_option_parse(struct peer *peer, uint16_t length,
/* All OPEN option is parsed. Check capability when strict compare
flag is enabled.*/
if (CHECK_FLAG(peer->flags, PEER_FLAG_STRICT_CAP_MATCH)) {
- /* If Unsupported Capability exists. */
- if (error != error_data) {
+ /* If Unsupported Capability exists or local capability does
+ * not negotiated with remote peer
+ */
+ if (error != error_data || !strict_capability_same(peer)) {
bgp_notify_send_with_data(peer->connection,
BGP_NOTIFY_OPEN_ERR,
BGP_NOTIFY_OPEN_UNSUP_CAPBL,
@@ -1398,14 +1463,6 @@ int bgp_open_option_parse(struct peer *peer, uint16_t length,
error - error_data);
return -1;
}
-
- /* Check local capability does not negotiated with remote
- peer. */
- if (!strict_capability_same(peer)) {
- bgp_notify_send(peer->connection, BGP_NOTIFY_OPEN_ERR,
- BGP_NOTIFY_OPEN_UNSUP_CAPBL);
- return -1;
- }
}
/* Extended Message Support */
@@ -1440,17 +1497,11 @@ int bgp_open_option_parse(struct peer *peer, uint16_t length,
"%s [Error] Configured AFI/SAFIs do not overlap with received MP capabilities",
peer->host);
- if (error != error_data)
- bgp_notify_send_with_data(peer->connection,
- BGP_NOTIFY_OPEN_ERR,
- BGP_NOTIFY_OPEN_UNSUP_CAPBL,
- error_data,
- error - error_data);
- else
- bgp_notify_send(peer->connection,
- BGP_NOTIFY_OPEN_ERR,
- BGP_NOTIFY_OPEN_UNSUP_CAPBL);
- return -1;
+ bgp_notify_send_with_data(peer->connection,
+ BGP_NOTIFY_OPEN_ERR,
+ BGP_NOTIFY_OPEN_UNSUP_CAPBL,
+ error_data,
+ error - error_data);
}
}
return 0;
@@ -1874,6 +1925,31 @@ uint16_t bgp_open_capability(struct stream *s, struct peer *peer,
}
}
+ /* Paths-Limit capability */
+ SET_FLAG(peer->cap, PEER_CAP_PATHS_LIMIT_ADV);
+ stream_putc(s, BGP_OPEN_OPT_CAP);
+ ext_opt_params ? stream_putw(s, (CAPABILITY_CODE_PATHS_LIMIT_LEN *
+ afi_safi_count) +
+ 2)
+ : stream_putc(s, (CAPABILITY_CODE_PATHS_LIMIT_LEN *
+ afi_safi_count) +
+ 2);
+ stream_putc(s, CAPABILITY_CODE_PATHS_LIMIT);
+ stream_putc(s, CAPABILITY_CODE_PATHS_LIMIT_LEN * afi_safi_count);
+
+ FOREACH_AFI_SAFI (afi, safi) {
+ if (!peer->afc[afi][safi])
+ continue;
+
+ bgp_map_afi_safi_int2iana(afi, safi, &pkt_afi, &pkt_safi);
+
+ stream_putw(s, pkt_afi);
+ stream_putc(s, pkt_safi);
+ stream_putw(s, peer->addpath_paths_limit[afi][safi].send);
+
+ SET_FLAG(peer->af_cap[afi][safi], PEER_CAP_PATHS_LIMIT_AF_ADV);
+ }
+
/* ORF capability. */
FOREACH_AFI_SAFI (afi, safi) {
if (CHECK_FLAG(peer->af_flags[afi][safi],
@@ -1887,7 +1963,7 @@ uint16_t bgp_open_capability(struct stream *s, struct peer *peer,
}
/* Dynamic capability. */
- if (CHECK_FLAG(peer->flags, PEER_FLAG_DYNAMIC_CAPABILITY)) {
+ if (peergroup_flag_check(peer, PEER_FLAG_DYNAMIC_CAPABILITY)) {
SET_FLAG(peer->cap, PEER_CAP_DYNAMIC_ADV);
stream_putc(s, BGP_OPEN_OPT_CAP);
ext_opt_params
diff --git a/bgpd/bgp_open.h b/bgpd/bgp_open.h
index 34f4b76..3a8cba9 100644
--- a/bgpd/bgp_open.h
+++ b/bgpd/bgp_open.h
@@ -53,6 +53,7 @@ struct graceful_restart_af {
#define CAPABILITY_CODE_ENHE 5 /* Extended Next Hop Encoding */
#define CAPABILITY_CODE_EXT_MESSAGE 6 /* Extended Message Support */
#define CAPABILITY_CODE_ROLE 9 /* Role Capability */
+#define CAPABILITY_CODE_PATHS_LIMIT 76 /* Paths Limit Capability */
/* Capability Length */
#define CAPABILITY_CODE_MP_LEN 4
@@ -61,6 +62,7 @@ struct graceful_restart_af {
#define CAPABILITY_CODE_RESTART_LEN 2 /* Receiving only case */
#define CAPABILITY_CODE_AS4_LEN 4
#define CAPABILITY_CODE_ADDPATH_LEN 4
+#define CAPABILITY_CODE_PATHS_LIMIT_LEN 5
#define CAPABILITY_CODE_ENHE_LEN 6 /* NRLI AFI = 2, SAFI = 2, Nexthop AFI = 2 */
#define CAPABILITY_CODE_MIN_FQDN_LEN 2
#define CAPABILITY_CODE_ENHANCED_LEN 0
@@ -110,5 +112,7 @@ extern as_t peek_for_as4_capability(struct peer *peer, uint16_t length);
extern const struct message capcode_str[];
extern const struct message orf_type_str[];
extern const struct message orf_mode_str[];
+extern const size_t cap_minsizes[];
+extern const size_t cap_modsizes[];
#endif /* _QUAGGA_BGP_OPEN_H */
diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c
index 1f808ee..010a31a 100644
--- a/bgpd/bgp_packet.c
+++ b/bgpd/bgp_packet.c
@@ -148,7 +148,8 @@ static void bgp_packet_add(struct peer_connection *connection,
EC_BGP_SENDQ_STUCK_PROPER,
"%pBP has not made any SendQ progress for 2 holdtimes (%jds), terminating session",
peer, sendholdtime);
- BGP_EVENT_ADD(connection, TCP_fatal_error);
+ bgp_stop_with_notify(connection,
+ BGP_NOTIFY_SEND_HOLD_ERR, 0);
} else if (delta > (intmax_t)holdtime &&
monotime(NULL) - peer->last_sendq_warn > 5) {
flog_warn(
@@ -559,40 +560,37 @@ void bgp_generate_updgrp_packets(struct event *thread)
}
}
- if (CHECK_FLAG(peer->cap,
- PEER_CAP_RESTART_RCV)) {
- if (!(PAF_SUBGRP(paf))->t_coalesce
- && peer->afc_nego[afi][safi]
- && peer->synctime
- && !CHECK_FLAG(
- peer->af_sflags[afi][safi],
- PEER_STATUS_EOR_SEND)) {
- /* If EOR is disabled,
- * the message is not sent
- */
- if (BGP_SEND_EOR(peer->bgp, afi,
- safi)) {
- SET_FLAG(
- peer->af_sflags
- [afi]
- [safi],
- PEER_STATUS_EOR_SEND);
-
- /* Update EOR
- * send time
- */
- peer->eor_stime[afi]
- [safi] =
- monotime(NULL);
-
- BGP_UPDATE_EOR_PKT(
- peer, afi, safi,
- s);
- bgp_process_pending_refresh(
- peer, afi,
- safi);
- }
- }
+ /* rfc4724 says:
+ * Although the End-of-RIB marker is
+ * specified for the purpose of BGP
+ * graceful restart, it is noted that
+ * the generation of such a marker upon
+ * completion of the initial update would
+ * be useful for routing convergence in
+ * general, and thus the practice is
+ * recommended.
+ */
+ if (!(PAF_SUBGRP(paf))->t_coalesce &&
+ peer->afc_nego[afi][safi] &&
+ peer->synctime &&
+ !CHECK_FLAG(peer->af_sflags[afi][safi],
+ PEER_STATUS_EOR_SEND)) {
+ /* If EOR is disabled, the message is
+ * not sent.
+ */
+ if (!BGP_SEND_EOR(peer->bgp, afi, safi))
+ continue;
+
+ SET_FLAG(peer->af_sflags[afi][safi],
+ PEER_STATUS_EOR_SEND);
+
+ /* Update EOR send time */
+ peer->eor_stime[afi][safi] =
+ monotime(NULL);
+
+ BGP_UPDATE_EOR_PKT(peer, afi, safi, s);
+ bgp_process_pending_refresh(peer, afi,
+ safi);
}
continue;
}
@@ -1224,7 +1222,7 @@ void bgp_capability_send(struct peer *peer, afi_t afi, safi_t safi,
if (!peer_established(peer->connection))
return;
- if (!CHECK_FLAG(peer->cap, PEER_CAP_DYNAMIC_RCV) &&
+ if (!CHECK_FLAG(peer->cap, PEER_CAP_DYNAMIC_RCV) ||
!CHECK_FLAG(peer->cap, PEER_CAP_DYNAMIC_ADV))
return;
@@ -1459,6 +1457,49 @@ void bgp_capability_send(struct peer *peer, afi_t afi, safi_t safi,
COND_FLAG(peer->cap, PEER_CAP_ADDPATH_ADV,
action == CAPABILITY_ACTION_SET);
break;
+ case CAPABILITY_CODE_PATHS_LIMIT:
+ FOREACH_AFI_SAFI (afi, safi) {
+ if (!peer->afc[afi][safi])
+ continue;
+
+ addpath_afi_safi_count++;
+ }
+
+ stream_putc(s, action);
+ stream_putc(s, CAPABILITY_CODE_PATHS_LIMIT);
+ stream_putc(s, CAPABILITY_CODE_PATHS_LIMIT_LEN *
+ addpath_afi_safi_count);
+
+ FOREACH_AFI_SAFI (afi, safi) {
+ if (!peer->afc[afi][safi])
+ continue;
+
+ bgp_map_afi_safi_int2iana(afi, safi, &pkt_afi,
+ &pkt_safi);
+
+ stream_putw(s, pkt_afi);
+ stream_putc(s, pkt_safi);
+ stream_putw(s,
+ peer->addpath_paths_limit[afi][safi].send);
+
+ SET_FLAG(peer->af_cap[afi][safi],
+ PEER_CAP_PATHS_LIMIT_AF_ADV);
+
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug("%pBP sending CAPABILITY has %s %s for afi/safi: %s/%s, limit: %u",
+ peer,
+ action == CAPABILITY_ACTION_SET
+ ? "Advertising"
+ : "Removing",
+ capability, iana_afi2str(pkt_afi),
+ iana_safi2str(pkt_safi),
+ peer->addpath_paths_limit[afi][safi]
+ .send);
+ }
+
+ COND_FLAG(peer->cap, PEER_CAP_PATHS_LIMIT_ADV,
+ action == CAPABILITY_ACTION_SET);
+ break;
case CAPABILITY_CODE_ORF:
/* Convert AFI, SAFI to values for packet. */
bgp_map_afi_safi_int2iana(afi, safi, &pkt_afi, &pkt_safi);
@@ -3165,6 +3206,86 @@ ignore:
}
}
+static void bgp_dynamic_capability_paths_limit(uint8_t *pnt, int action,
+ struct capability_header *hdr,
+ struct peer *peer)
+{
+ uint8_t *data = pnt + 3;
+ uint8_t *end = data + hdr->length;
+ size_t len = end - data;
+ afi_t afi;
+ safi_t safi;
+
+ if (action == CAPABILITY_ACTION_SET) {
+ if (len % CAPABILITY_CODE_PATHS_LIMIT_LEN) {
+ flog_warn(EC_BGP_CAPABILITY_INVALID_LENGTH,
+ "Paths-Limit: Received invalid length %zu, non-multiple of %d",
+ len, CAPABILITY_CODE_PATHS_LIMIT_LEN);
+ return;
+ }
+
+ if (!CHECK_FLAG(peer->cap, PEER_CAP_ADDPATH_RCV)) {
+ flog_warn(EC_BGP_CAPABILITY_INVALID_DATA,
+ "Paths-Limit: Received Paths-Limit capability without Add-Path capability");
+ goto ignore;
+ }
+
+ SET_FLAG(peer->cap, PEER_CAP_PATHS_LIMIT_RCV);
+
+ while (data + CAPABILITY_CODE_PATHS_LIMIT_LEN <= end) {
+ afi_t afi;
+ safi_t safi;
+ iana_afi_t pkt_afi;
+ iana_safi_t pkt_safi;
+ uint16_t paths_limit = 0;
+ struct bgp_paths_limit_capability bpl = {};
+
+ memcpy(&bpl, data, sizeof(bpl));
+ pkt_afi = ntohs(bpl.afi);
+ pkt_safi = safi_int2iana(bpl.safi);
+ paths_limit = ntohs(bpl.paths_limit);
+
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug("%s OPEN has %s capability for afi/safi: %s/%s limit: %u",
+ peer->host,
+ lookup_msg(capcode_str, hdr->code,
+ NULL),
+ iana_afi2str(pkt_afi),
+ iana_safi2str(pkt_safi), paths_limit);
+
+ if (bgp_map_afi_safi_iana2int(pkt_afi, pkt_safi, &afi,
+ &safi)) {
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug("%s Addr-family %s/%s(afi/safi) not supported. Ignore the Paths-Limit capability for this AFI/SAFI",
+ peer->host,
+ iana_afi2str(pkt_afi),
+ iana_safi2str(pkt_safi));
+ goto ignore;
+ } else if (!peer->afc[afi][safi]) {
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug("%s Addr-family %s/%s(afi/safi) not enabled. Ignore the Paths-Limit capability for this AFI/SAFI",
+ peer->host,
+ iana_afi2str(pkt_afi),
+ iana_safi2str(pkt_safi));
+ goto ignore;
+ }
+
+ SET_FLAG(peer->af_cap[afi][safi],
+ PEER_CAP_PATHS_LIMIT_AF_RCV);
+ peer->addpath_paths_limit[afi][safi].receive =
+ paths_limit;
+ignore:
+ data += CAPABILITY_CODE_PATHS_LIMIT_LEN;
+ }
+ } else {
+ FOREACH_AFI_SAFI (afi, safi)
+ UNSET_FLAG(peer->af_cap[afi][safi],
+ PEER_CAP_PATHS_LIMIT_AF_RCV);
+
+ UNSET_FLAG(peer->cap, PEER_CAP_PATHS_LIMIT_RCV);
+ }
+}
+
static void bgp_dynamic_capability_orf(uint8_t *pnt, int action,
struct capability_header *hdr,
struct peer *peer)
@@ -3282,6 +3403,22 @@ static void bgp_dynamic_capability_orf(uint8_t *pnt, int action,
}
}
+static void bgp_dynamic_capability_role(uint8_t *pnt, int action,
+ struct peer *peer)
+{
+ uint8_t role;
+
+ if (action == CAPABILITY_ACTION_SET) {
+ SET_FLAG(peer->cap, PEER_CAP_ROLE_RCV);
+ memcpy(&role, pnt + 3, sizeof(role));
+
+ peer->remote_role = role;
+ } else {
+ UNSET_FLAG(peer->cap, PEER_CAP_ROLE_RCV);
+ peer->remote_role = ROLE_UNDEFINED;
+ }
+}
+
static void bgp_dynamic_capability_fqdn(uint8_t *pnt, int action,
struct capability_header *hdr,
struct peer *peer)
@@ -3293,14 +3430,14 @@ static void bgp_dynamic_capability_fqdn(uint8_t *pnt, int action,
if (action == CAPABILITY_ACTION_SET) {
/* hostname */
- if (data + 1 > end) {
+ if (data + 1 >= end) {
zlog_err("%pBP: Received invalid FQDN capability (host name length)",
peer);
return;
}
len = *data;
- if (data + len > end) {
+ if (data + len + 1 > end) {
zlog_err("%pBP: Received invalid FQDN capability length (host name) %d",
peer, hdr->length);
return;
@@ -3323,7 +3460,7 @@ static void bgp_dynamic_capability_fqdn(uint8_t *pnt, int action,
peer->hostname = XSTRDUP(MTYPE_BGP_PEER_HOST, str);
}
- if (data + 1 > end) {
+ if (data + 1 >= end) {
zlog_err("%pBP: Received invalid FQDN capability (domain name length)",
peer);
return;
@@ -3331,7 +3468,7 @@ static void bgp_dynamic_capability_fqdn(uint8_t *pnt, int action,
/* domainname */
len = *data;
- if (data + len > end) {
+ if (data + len + 1 > end) {
zlog_err("%pBP: Received invalid FQDN capability length (domain name) %d",
peer, len);
return;
@@ -3557,7 +3694,7 @@ static void bgp_dynamic_capability_software_version(uint8_t *pnt, int action,
char soft_version[BGP_MAX_SOFT_VERSION + 1] = {};
if (action == CAPABILITY_ACTION_SET) {
- if (data + len > end) {
+ if (data + len + 1 > end) {
zlog_err("%pBP: Received invalid Software Version capability length %d",
peer, len);
return;
@@ -3610,7 +3747,10 @@ static int bgp_capability_msg_parse(struct peer *peer, uint8_t *pnt,
zlog_err("%pBP: Capability length error", peer);
bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE,
BGP_NOTIFY_SUBCODE_UNSPECIFIC);
- pnt += length;
+ /*
+ * If we did not return then
+ * pnt += length;
+ */
return BGP_Stop;
}
action = *pnt;
@@ -3635,7 +3775,10 @@ static int bgp_capability_msg_parse(struct peer *peer, uint8_t *pnt,
zlog_err("%pBP: Capability length error", peer);
bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE,
BGP_NOTIFY_SUBCODE_UNSPECIFIC);
- pnt += length;
+ /*
+ * If we did not return then
+ * pnt += length;
+ */
return BGP_Stop;
}
@@ -3645,6 +3788,46 @@ static int bgp_capability_msg_parse(struct peer *peer, uint8_t *pnt,
capability = lookup_msg(capcode_str, hdr->code, "Unknown");
+ /* Length sanity check, type-specific, for known capabilities */
+ switch (hdr->code) {
+ case CAPABILITY_CODE_MP:
+ case CAPABILITY_CODE_REFRESH:
+ case CAPABILITY_CODE_ORF:
+ case CAPABILITY_CODE_RESTART:
+ case CAPABILITY_CODE_AS4:
+ case CAPABILITY_CODE_ADDPATH:
+ case CAPABILITY_CODE_DYNAMIC:
+ case CAPABILITY_CODE_ENHE:
+ case CAPABILITY_CODE_FQDN:
+ case CAPABILITY_CODE_ENHANCED_RR:
+ case CAPABILITY_CODE_EXT_MESSAGE:
+ case CAPABILITY_CODE_ROLE:
+ case CAPABILITY_CODE_SOFT_VERSION:
+ case CAPABILITY_CODE_PATHS_LIMIT:
+ if (hdr->length < cap_minsizes[hdr->code]) {
+ zlog_info("%pBP: %s Capability length error: got %u, expected at least %u",
+ peer, capability, hdr->length,
+ (unsigned int)cap_minsizes[hdr->code]);
+ bgp_notify_send(peer->connection,
+ BGP_NOTIFY_OPEN_ERR,
+ BGP_NOTIFY_OPEN_MALFORMED_ATTR);
+ goto done;
+ }
+ if (hdr->length &&
+ hdr->length % cap_modsizes[hdr->code] != 0) {
+ zlog_info("%pBP %s Capability length error: got %u, expected a multiple of %u",
+ peer, capability, hdr->length,
+ (unsigned int)cap_modsizes[hdr->code]);
+ bgp_notify_send(peer->connection,
+ BGP_NOTIFY_OPEN_ERR,
+ BGP_NOTIFY_OPEN_MALFORMED_ATTR);
+ goto done;
+ }
+ break;
+ default:
+ break;
+ }
+
switch (hdr->code) {
case CAPABILITY_CODE_SOFT_VERSION:
bgp_dynamic_capability_software_version(pnt, action,
@@ -3702,15 +3885,6 @@ static int bgp_capability_msg_parse(struct peer *peer, uint8_t *pnt,
}
break;
case CAPABILITY_CODE_RESTART:
- if ((hdr->length - 2) % 4) {
- zlog_err("%pBP: Received invalid Graceful-Restart capability length %d",
- peer, hdr->length);
- bgp_notify_send(peer->connection,
- BGP_NOTIFY_CEASE,
- BGP_NOTIFY_SUBCODE_UNSPECIFIC);
- goto done;
- }
-
bgp_dynamic_capability_graceful_restart(pnt, action,
hdr, peer);
break;
@@ -3720,6 +3894,10 @@ static int bgp_capability_msg_parse(struct peer *peer, uint8_t *pnt,
case CAPABILITY_CODE_ADDPATH:
bgp_dynamic_capability_addpath(pnt, action, hdr, peer);
break;
+ case CAPABILITY_CODE_PATHS_LIMIT:
+ bgp_dynamic_capability_paths_limit(pnt, action, hdr,
+ peer);
+ break;
case CAPABILITY_CODE_ORF:
bgp_dynamic_capability_orf(pnt, action, hdr, peer);
break;
@@ -3734,26 +3912,7 @@ static int bgp_capability_msg_parse(struct peer *peer, uint8_t *pnt,
case CAPABILITY_CODE_EXT_MESSAGE:
break;
case CAPABILITY_CODE_ROLE:
- if (hdr->length != CAPABILITY_CODE_ROLE_LEN) {
- zlog_err("%pBP: Capability (%s) length error",
- peer, capability);
- bgp_notify_send(peer->connection,
- BGP_NOTIFY_CEASE,
- BGP_NOTIFY_SUBCODE_UNSPECIFIC);
- goto done;
- }
-
- uint8_t role;
-
- if (action == CAPABILITY_ACTION_SET) {
- SET_FLAG(peer->cap, PEER_CAP_ROLE_RCV);
- memcpy(&role, pnt + 3, sizeof(role));
-
- peer->remote_role = role;
- } else {
- UNSET_FLAG(peer->cap, PEER_CAP_ROLE_RCV);
- peer->remote_role = ROLE_UNDEFINED;
- }
+ bgp_dynamic_capability_role(pnt, action, peer);
break;
default:
flog_warn(EC_BGP_UNRECOGNIZED_CAPABILITY,
@@ -3790,8 +3949,8 @@ int bgp_capability_receive(struct peer_connection *connection,
if (bgp_debug_neighbor_events(peer))
zlog_debug("%s rcv CAPABILITY", peer->host);
- /* If peer does not have the capability, send notification. */
- if (!CHECK_FLAG(peer->cap, PEER_CAP_DYNAMIC_ADV)) {
+ if (!CHECK_FLAG(peer->cap, PEER_CAP_DYNAMIC_ADV) ||
+ !CHECK_FLAG(peer->cap, PEER_CAP_DYNAMIC_RCV)) {
flog_err(EC_BGP_NO_CAP,
"%s [Error] BGP dynamic capability is not enabled",
peer->host);
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index a69d6ee..f6fe87e 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -114,6 +114,46 @@ static const struct message bgp_pmsi_tnltype_str[] = {
#define VRFID_NONE_STR "-"
#define SOFT_RECONFIG_TASK_MAX_PREFIX 25000
+static inline char *bgp_route_dump_path_info_flags(struct bgp_path_info *pi,
+ char *buf, size_t len)
+{
+ uint32_t flags = pi->flags;
+
+ if (flags == 0) {
+ snprintfrr(buf, len, "None ");
+ return buf;
+ }
+
+ snprintfrr(buf, len, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
+ CHECK_FLAG(flags, BGP_PATH_IGP_CHANGED) ? "IGP Changed " : "",
+ CHECK_FLAG(flags, BGP_PATH_DAMPED) ? "Damped" : "",
+ CHECK_FLAG(flags, BGP_PATH_HISTORY) ? "History " : "",
+ CHECK_FLAG(flags, BGP_PATH_SELECTED) ? "Selected " : "",
+ CHECK_FLAG(flags, BGP_PATH_VALID) ? "Valid " : "",
+ CHECK_FLAG(flags, BGP_PATH_ATTR_CHANGED) ? "Attr Changed "
+ : "",
+ CHECK_FLAG(flags, BGP_PATH_DMED_CHECK) ? "Dmed Check " : "",
+ CHECK_FLAG(flags, BGP_PATH_DMED_SELECTED) ? "Dmed Selected "
+ : "",
+ CHECK_FLAG(flags, BGP_PATH_STALE) ? "Stale " : "",
+ CHECK_FLAG(flags, BGP_PATH_REMOVED) ? "Removed " : "",
+ CHECK_FLAG(flags, BGP_PATH_COUNTED) ? "Counted " : "",
+ CHECK_FLAG(flags, BGP_PATH_MULTIPATH) ? "Mpath " : "",
+ CHECK_FLAG(flags, BGP_PATH_MULTIPATH_CHG) ? "Mpath Chg " : "",
+ CHECK_FLAG(flags, BGP_PATH_RIB_ATTR_CHG) ? "Rib Chg " : "",
+ CHECK_FLAG(flags, BGP_PATH_ANNC_NH_SELF) ? "NH Self " : "",
+ CHECK_FLAG(flags, BGP_PATH_LINK_BW_CHG) ? "LinkBW Chg " : "",
+ CHECK_FLAG(flags, BGP_PATH_ACCEPT_OWN) ? "Accept Own " : "",
+ CHECK_FLAG(flags, BGP_PATH_MPLSVPN_LABEL_NH) ? "MPLS Label "
+ : "",
+ CHECK_FLAG(flags, BGP_PATH_MPLSVPN_NH_LABEL_BIND)
+ ? "MPLS Label Bind "
+ : "",
+ CHECK_FLAG(flags, BGP_PATH_UNSORTED) ? "Unsorted " : "");
+
+ return buf;
+}
+
DEFINE_HOOK(bgp_process,
(struct bgp * bgp, afi_t afi, safi_t safi, struct bgp_dest *bn,
struct peer *peer, bool withdraw),
@@ -195,8 +235,6 @@ static struct bgp_path_info_extra *bgp_path_info_extra_new(void)
struct bgp_path_info_extra *new;
new = XCALLOC(MTYPE_BGP_ROUTE_EXTRA,
sizeof(struct bgp_path_info_extra));
- new->label[0] = MPLS_INVALID_LABEL;
- new->num_labels = 0;
new->flowspec = NULL;
return new;
}
@@ -209,10 +247,9 @@ void bgp_path_info_extra_free(struct bgp_path_info_extra **extra)
return;
e = *extra;
- if (e->damp_info)
- bgp_damp_info_free(e->damp_info, 0, e->damp_info->afi,
- e->damp_info->safi);
+ if (e->damp_info)
+ bgp_damp_info_free(e->damp_info, NULL, 0);
e->damp_info = NULL;
if (e->vrfleak && e->vrfleak->parent) {
struct bgp_path_info *bpi =
@@ -268,6 +305,9 @@ void bgp_path_info_extra_free(struct bgp_path_info_extra **extra)
XFREE(MTYPE_BGP_ROUTE_EXTRA_VNC, e->vnc);
#endif
+ if (e->labels)
+ bgp_labels_unintern(&e->labels);
+
XFREE(MTYPE_BGP_ROUTE_EXTRA, *extra);
}
@@ -285,6 +325,41 @@ struct bgp_path_info_extra *bgp_path_info_extra_get(struct bgp_path_info *pi)
return pi->extra;
}
+bool bgp_path_info_has_valid_label(const struct bgp_path_info *path)
+{
+ if (!bgp_path_info_num_labels(path))
+ return false;
+
+ return bgp_is_valid_label(&path->extra->labels->label[0]);
+}
+
+bool bgp_path_info_labels_same(const struct bgp_path_info *bpi,
+ const mpls_label_t *label, uint32_t n)
+{
+ uint8_t bpi_num_labels;
+ const mpls_label_t *bpi_label;
+
+ bpi_num_labels = bgp_path_info_num_labels(bpi);
+ bpi_label = bpi_num_labels ? bpi->extra->labels->label : NULL;
+
+ return bgp_labels_same(bpi_label, bpi_num_labels,
+ (const mpls_label_t *)label, n);
+}
+
+uint8_t bgp_path_info_num_labels(const struct bgp_path_info *pi)
+{
+ if (!pi)
+ return 0;
+
+ if (!pi->extra)
+ return 0;
+
+ if (!pi->extra->labels)
+ return 0;
+
+ return pi->extra->labels->num_labels;
+}
+
/* Free bgp route information. */
void bgp_path_info_free_with_caller(const char *name,
struct bgp_path_info *path)
@@ -442,10 +517,13 @@ void bgp_path_info_add_with_caller(const char *name, struct bgp_dest *dest,
top->prev = pi;
bgp_dest_set_bgp_path_info(dest, pi);
+ SET_FLAG(pi->flags, BGP_PATH_UNSORTED);
bgp_path_info_lock(pi);
bgp_dest_lock_node(dest);
peer_lock(pi->peer); /* bgp_path_info peer reference */
bgp_dest_set_defer_flag(dest, false);
+ if (pi->peer)
+ pi->peer->stat_pfx_loc_rib++;
hook_call(bgp_snmp_update_stats, dest, pi, true);
}
@@ -462,8 +540,30 @@ struct bgp_dest *bgp_path_info_reap(struct bgp_dest *dest,
bgp_dest_set_bgp_path_info(dest, pi->next);
bgp_path_info_mpath_dequeue(pi);
+
+ pi->next = NULL;
+ pi->prev = NULL;
+
+ if (pi->peer)
+ pi->peer->stat_pfx_loc_rib--;
+ hook_call(bgp_snmp_update_stats, dest, pi, false);
+
bgp_path_info_unlock(pi);
+ return bgp_dest_unlock_node(dest);
+}
+
+static struct bgp_dest *bgp_path_info_reap_unsorted(struct bgp_dest *dest,
+ struct bgp_path_info *pi)
+{
+ bgp_path_info_mpath_dequeue(pi);
+
+ pi->next = NULL;
+ pi->prev = NULL;
+
+ if (pi->peer)
+ pi->peer->stat_pfx_loc_rib--;
hook_call(bgp_snmp_update_stats, dest, pi, false);
+ bgp_path_info_unlock(pi);
return bgp_dest_unlock_node(dest);
}
@@ -581,6 +681,11 @@ void bgp_path_info_path_with_addpath_rx_str(struct bgp_path_info *pi, char *buf,
{
struct peer *peer;
+ if (!pi) {
+ snprintf(buf, buf_len, "NONE");
+ return;
+ }
+
if (pi->sub_type == BGP_ROUTE_IMPORTED &&
bgp_get_imported_bpi_ultimate(pi))
peer = bgp_get_imported_bpi_ultimate(pi)->peer;
@@ -683,12 +788,18 @@ int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new,
}
if (debug) {
+ char buf1[256], buf2[256];
+
bpi_ultimate = bgp_get_imported_bpi_ultimate(exist);
bgp_path_info_path_with_addpath_rx_str(bpi_ultimate, exist_buf,
sizeof(exist_buf));
- zlog_debug("%s(%s): Comparing %s flags 0x%x with %s flags 0x%x",
- pfx_buf, bgp->name_pretty, new_buf, new->flags,
- exist_buf, exist->flags);
+ zlog_debug("%s(%s): Comparing %s flags %s with %s flags %s",
+ pfx_buf, bgp->name_pretty, new_buf,
+ bgp_route_dump_path_info_flags(new, buf1,
+ sizeof(buf1)),
+ exist_buf,
+ bgp_route_dump_path_info_flags(exist, buf2,
+ sizeof(buf2)));
}
newattr = new->attr;
@@ -1284,25 +1395,18 @@ int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new,
/* If one path has a label but the other does not, do not treat
* them as equals for multipath
*/
- int newl, existl;
-
- newl = existl = 0;
-
- if (new->extra)
- newl = new->extra->num_labels;
- if (exist->extra)
- existl = exist->extra->num_labels;
- if (((new->extra &&bgp_is_valid_label(&new->extra->label[0])) !=
- (exist->extra &&
- bgp_is_valid_label(&exist->extra->label[0]))) ||
- (newl != existl)) {
+ bool new_label_valid, exist_label_valid;
+
+ new_label_valid = bgp_path_info_has_valid_label(new);
+ exist_label_valid = bgp_path_info_has_valid_label(exist);
+
+ if (new_label_valid != exist_label_valid) {
if (debug)
zlog_debug(
"%s: %s and %s cannot be multipath, one has a label while the other does not",
pfx_buf, new_buf, exist_buf);
} else if (CHECK_FLAG(bgp->flags,
BGP_FLAG_ASPATH_MULTIPATH_RELAX)) {
-
/*
* For the two paths, all comparison steps till IGP
* metric
@@ -1768,11 +1872,12 @@ static bool bgp_check_role_applicability(afi_t afi, safi_t safi)
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_dest *dest)
+ uint8_t num_labels, struct bgp_dest *dest)
{
struct bgp_filter *filter;
struct bgp_path_info rmap_path = { 0 };
struct bgp_path_info_extra extra = { 0 };
+ struct bgp_labels bgp_labels = {};
route_map_result_t ret;
struct route_map *rmap = NULL;
@@ -1804,11 +1909,12 @@ static int bgp_input_modifier(struct peer *peer, const struct prefix *p,
rmap_path.attr = attr;
rmap_path.extra = &extra;
rmap_path.net = dest;
+ extra.labels = &bgp_labels;
- extra.num_labels = num_labels;
+ bgp_labels.num_labels = num_labels;
if (label && num_labels && num_labels <= BGP_MAX_LABELS)
- memcpy(extra.label, label,
- num_labels * sizeof(mpls_label_t));
+ memcpy(bgp_labels.label, label,
+ num_labels * sizeof(mpls_label_t));
SET_FLAG(peer->rmap_type, PEER_RMAP_TYPE_IN);
@@ -2143,8 +2249,8 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi,
* off box as that the RT and RD created are localy
* significant and globaly useless.
*/
- if (safi == SAFI_MPLS_VPN && pi->extra && pi->extra->num_labels
- && pi->extra->label[0] == BGP_PREVENT_VRF_2_VRF_LEAK)
+ if (safi == SAFI_MPLS_VPN && bgp_path_info_num_labels(pi) &&
+ pi->extra->labels->label[0] == BGP_PREVENT_VRF_2_VRF_LEAK)
return false;
/* If it's labeled safi, make sure the route has a valid label. */
@@ -2246,7 +2352,7 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi,
}
/* AS path loop check. */
- if (peer->as_path_loop_detection &&
+ if (CHECK_FLAG(peer->flags, PEER_FLAG_AS_LOOP_DETECTION) &&
aspath_loop_check(piattr->aspath, peer->as)) {
if (bgp_debug_update(NULL, p, subgrp->update_group, 0))
zlog_debug(
@@ -2701,17 +2807,26 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi,
* the most sense. However, don't modify if the link-bandwidth has
* been explicitly set by user policy.
*/
- if (nh_reset &&
- bgp_path_info_mpath_chkwtd(bgp, pi) &&
+ if (nh_reset && bgp_path_info_mpath_chkwtd(bgp, pi) &&
(cum_bw = bgp_path_info_mpath_cumbw(pi)) != 0 &&
- !CHECK_FLAG(attr->rmap_change_flags, BATTR_RMAP_LINK_BW_SET))
- bgp_attr_set_ecommunity(
- attr,
- ecommunity_replace_linkbw(
- bgp->as, bgp_attr_get_ecommunity(attr), cum_bw,
- CHECK_FLAG(
- peer->flags,
- PEER_FLAG_DISABLE_LINK_BW_ENCODING_IEEE)));
+ !CHECK_FLAG(attr->rmap_change_flags, BATTR_RMAP_LINK_BW_SET)) {
+ if (CHECK_FLAG(peer->flags, PEER_FLAG_EXTENDED_LINK_BANDWIDTH))
+ bgp_attr_set_ipv6_ecommunity(
+ attr,
+ ecommunity_replace_linkbw(bgp->as,
+ bgp_attr_get_ipv6_ecommunity(
+ attr),
+ cum_bw, false, true));
+ else
+ bgp_attr_set_ecommunity(
+ attr,
+ ecommunity_replace_linkbw(
+ bgp->as, bgp_attr_get_ecommunity(attr),
+ cum_bw,
+ CHECK_FLAG(peer->flags,
+ PEER_FLAG_DISABLE_LINK_BW_ENCODING_IEEE),
+ false));
+ }
return true;
}
@@ -2740,17 +2855,18 @@ void bgp_best_selection(struct bgp *bgp, struct bgp_dest *dest,
struct bgp_path_info_pair *result, afi_t afi,
safi_t safi)
{
- struct bgp_path_info *new_select;
- struct bgp_path_info *old_select;
+ struct bgp_path_info *new_select, *look_thru;
+ struct bgp_path_info *old_select, *worse, *first;
struct bgp_path_info *pi;
struct bgp_path_info *pi1;
struct bgp_path_info *pi2;
- struct bgp_path_info *nextpi = NULL;
int paths_eq, do_mpath;
- bool debug;
+ bool debug, any_comparisons;
struct list mp_list;
char pfx_buf[PREFIX2STR_BUFFER] = {};
char path_buf[PATH_ADDPATH_STR_BUFFER];
+ enum bgp_path_selection_reason reason = bgp_path_selection_none;
+ bool unsorted_items = true;
bgp_mp_list_init(&mp_list);
do_mpath =
@@ -2761,16 +2877,16 @@ void bgp_best_selection(struct bgp *bgp, struct bgp_dest *dest,
if (debug)
prefix2str(bgp_dest_get_prefix(dest), pfx_buf, sizeof(pfx_buf));
- dest->reason = bgp_path_selection_none;
/* bgp deterministic-med */
new_select = NULL;
if (CHECK_FLAG(bgp->flags, BGP_FLAG_DETERMINISTIC_MED)) {
-
/* Clear BGP_PATH_DMED_SELECTED for all paths */
for (pi1 = bgp_dest_get_bgp_path_info(dest); pi1;
- pi1 = pi1->next)
+ pi1 = pi1->next) {
bgp_path_info_unset_flag(dest, pi1,
BGP_PATH_DMED_SELECTED);
+ UNSET_FLAG(pi1->flags, BGP_PATH_DMED_CHECK);
+ }
for (pi1 = bgp_dest_get_bgp_path_info(dest); pi1;
pi1 = pi1->next) {
@@ -2786,41 +2902,35 @@ void bgp_best_selection(struct bgp *bgp, struct bgp_dest *dest,
}
new_select = pi1;
- if (pi1->next) {
- for (pi2 = pi1->next; pi2; pi2 = pi2->next) {
- if (CHECK_FLAG(pi2->flags,
- BGP_PATH_DMED_CHECK))
- continue;
- if (BGP_PATH_HOLDDOWN(pi2))
- continue;
- if (pi2->peer != bgp->peer_self &&
- !CHECK_FLAG(pi2->peer->sflags,
- PEER_STATUS_NSF_WAIT) &&
- !peer_established(
- pi2->peer->connection))
- continue;
-
- if (!aspath_cmp_left(pi1->attr->aspath,
- pi2->attr->aspath)
- && !aspath_cmp_left_confed(
- pi1->attr->aspath,
- pi2->attr->aspath))
- continue;
+ for (pi2 = pi1->next; pi2; pi2 = pi2->next) {
+ if (CHECK_FLAG(pi2->flags, BGP_PATH_DMED_CHECK))
+ continue;
+ if (BGP_PATH_HOLDDOWN(pi2))
+ continue;
+ if (pi2->peer != bgp->peer_self &&
+ !CHECK_FLAG(pi2->peer->sflags,
+ PEER_STATUS_NSF_WAIT) &&
+ !peer_established(pi2->peer->connection))
+ continue;
- if (bgp_path_info_cmp(
- bgp, pi2, new_select,
- &paths_eq, mpath_cfg, debug,
- pfx_buf, afi, safi,
- &dest->reason)) {
- bgp_path_info_unset_flag(
- dest, new_select,
- BGP_PATH_DMED_SELECTED);
- new_select = pi2;
- }
+ if (!aspath_cmp_left(pi1->attr->aspath,
+ pi2->attr->aspath) &&
+ !aspath_cmp_left_confed(pi1->attr->aspath,
+ pi2->attr->aspath))
+ continue;
- bgp_path_info_set_flag(
- dest, pi2, BGP_PATH_DMED_CHECK);
+ if (bgp_path_info_cmp(bgp, pi2, new_select,
+ &paths_eq, mpath_cfg,
+ debug, pfx_buf, afi, safi,
+ &dest->reason)) {
+ bgp_path_info_unset_flag(dest,
+ new_select,
+ BGP_PATH_DMED_SELECTED);
+ new_select = pi2;
}
+
+ bgp_path_info_set_flag(dest, pi2,
+ BGP_PATH_DMED_CHECK);
}
bgp_path_info_set_flag(dest, new_select,
BGP_PATH_DMED_CHECK);
@@ -2839,69 +2949,273 @@ void bgp_best_selection(struct bgp *bgp, struct bgp_dest *dest,
}
}
- /* Check old selected route and new selected route. */
+ /*
+ * Let's grab the unsorted items from the list
+ */
+ struct bgp_path_info *unsorted_list = NULL;
+ struct bgp_path_info *unsorted_list_spot = NULL;
+ struct bgp_path_info *unsorted_holddown = NULL;
+
old_select = NULL;
- new_select = NULL;
- for (pi = bgp_dest_get_bgp_path_info(dest);
- (pi != NULL) && (nextpi = pi->next, 1); pi = nextpi) {
- enum bgp_path_selection_reason reason;
+ pi = bgp_dest_get_bgp_path_info(dest);
+ while (pi && CHECK_FLAG(pi->flags, BGP_PATH_UNSORTED)) {
+ struct bgp_path_info *next = pi->next;
if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED))
old_select = pi;
- if (BGP_PATH_HOLDDOWN(pi)) {
- /* reap REMOVED routes, if needs be
+ /*
+ * Pull off pi off the list
+ */
+ if (pi->next)
+ pi->next->prev = NULL;
+
+ bgp_dest_set_bgp_path_info(dest, pi->next);
+ pi->next = NULL;
+ pi->prev = NULL;
+
+ /*
+ * Place it on the unsorted list
+ */
+ if (unsorted_list_spot) {
+ unsorted_list_spot->next = pi;
+ pi->prev = unsorted_list_spot;
+ pi->next = NULL;
+ } else {
+ unsorted_list = pi;
+
+ pi->next = NULL;
+ pi->prev = NULL;
+ }
+
+ unsorted_list_spot = pi;
+ pi = next;
+ }
+
+ if (!old_select) {
+ old_select = bgp_dest_get_bgp_path_info(dest);
+ if (old_select &&
+ !CHECK_FLAG(old_select->flags, BGP_PATH_SELECTED))
+ old_select = NULL;
+ }
+
+ if (!unsorted_list)
+ unsorted_items = true;
+ else
+ unsorted_items = false;
+
+ any_comparisons = false;
+ worse = NULL;
+ while (unsorted_list) {
+ first = unsorted_list;
+ unsorted_list = unsorted_list->next;
+
+ if (unsorted_list)
+ unsorted_list->prev = NULL;
+ first->next = NULL;
+ first->prev = NULL;
+
+ /*
+ * It's not likely that the just received unsorted entry
+ * is in holddown and scheduled for removal but we should
+ * check
+ */
+ if (BGP_PATH_HOLDDOWN(first)) {
+ /*
+ * reap REMOVED routes, if needs be
* selected route must stay for a while longer though
*/
if (debug)
- zlog_debug(
- "%s: %pBD(%s) pi from %s in holddown",
- __func__, dest, bgp->name_pretty,
- pi->peer->host);
+ zlog_debug("%s: %pBD(%s) pi %p from %s in holddown",
+ __func__, dest, bgp->name_pretty,
+ first, first->peer->host);
- if (CHECK_FLAG(pi->flags, BGP_PATH_REMOVED) &&
- (pi != old_select)) {
- dest = bgp_path_info_reap(dest, pi);
+ if (old_select != first &&
+ CHECK_FLAG(first->flags, BGP_PATH_REMOVED)) {
+ dest = bgp_path_info_reap_unsorted(dest, first);
assert(dest);
- }
+ } else {
+ /*
+ * We are in hold down, so we cannot sort this
+ * item yet. Let's wait, so hold the unsorted
+ * to the side
+ */
+ if (unsorted_holddown) {
+ first->next = unsorted_holddown;
+ unsorted_holddown->prev = first;
+ unsorted_holddown = first;
+ } else
+ unsorted_holddown = first;
+ UNSET_FLAG(first->flags, BGP_PATH_UNSORTED);
+ }
continue;
}
- if (pi->peer && pi->peer != bgp->peer_self
- && !CHECK_FLAG(pi->peer->sflags, PEER_STATUS_NSF_WAIT))
- if (!peer_established(pi->peer->connection)) {
+ bgp_path_info_unset_flag(dest, first, BGP_PATH_DMED_CHECK);
+
+ worse = NULL;
+
+ struct bgp_path_info *look_thru_next;
+
+ for (look_thru = bgp_dest_get_bgp_path_info(dest); look_thru;
+ look_thru = look_thru_next) {
+ /* look thru can be reaped save the next pointer */
+ look_thru_next = look_thru->next;
+
+ /*
+ * Now we have the first unsorted and the best selected
+ * Let's do best path comparison
+ */
+ if (BGP_PATH_HOLDDOWN(look_thru)) {
+ /* reap REMOVED routes, if needs be
+ * selected route must stay for a while longer though
+ */
if (debug)
- zlog_debug(
- "%s: %pBD(%s) non self peer %s not estab state",
- __func__, dest,
- bgp->name_pretty,
- pi->peer->host);
+ zlog_debug("%s: %pBD(%s) pi from %s %p in holddown",
+ __func__, dest,
+ bgp->name_pretty,
+ look_thru->peer->host,
+ look_thru);
+
+ if (CHECK_FLAG(look_thru->flags,
+ BGP_PATH_REMOVED) &&
+ (look_thru != old_select)) {
+ dest = bgp_path_info_reap(dest,
+ look_thru);
+ assert(dest);
+ }
continue;
}
- if (CHECK_FLAG(bgp->flags, BGP_FLAG_DETERMINISTIC_MED)
- && (!CHECK_FLAG(pi->flags, BGP_PATH_DMED_SELECTED))) {
- bgp_path_info_unset_flag(dest, pi, BGP_PATH_DMED_CHECK);
- if (debug)
- zlog_debug("%s: %pBD(%s) pi %s dmed", __func__,
- dest, bgp->name_pretty,
- pi->peer->host);
- continue;
+ if (look_thru->peer &&
+ look_thru->peer != bgp->peer_self &&
+ !CHECK_FLAG(look_thru->peer->sflags,
+ PEER_STATUS_NSF_WAIT))
+ if (!peer_established(
+ look_thru->peer->connection)) {
+ if (debug)
+ zlog_debug("%s: %pBD(%s) non self peer %s not estab state",
+ __func__, dest,
+ bgp->name_pretty,
+ look_thru->peer->host);
+
+ continue;
+ }
+
+ bgp_path_info_unset_flag(dest, look_thru,
+ BGP_PATH_DMED_CHECK);
+ if (CHECK_FLAG(bgp->flags, BGP_FLAG_DETERMINISTIC_MED) &&
+ (!CHECK_FLAG(look_thru->flags,
+ BGP_PATH_DMED_SELECTED))) {
+ bgp_path_info_unset_flag(dest, look_thru,
+ BGP_PATH_DMED_CHECK);
+ if (debug)
+ zlog_debug("%s: %pBD(%s) pi %s dmed",
+ __func__, dest,
+ bgp->name_pretty,
+ look_thru->peer->host);
+
+ worse = look_thru;
+ continue;
+ }
+
+ reason = dest->reason;
+ any_comparisons = true;
+ if (bgp_path_info_cmp(bgp, first, look_thru, &paths_eq,
+ mpath_cfg, debug, pfx_buf, afi,
+ safi, &reason)) {
+ first->reason = reason;
+ worse = look_thru;
+ /*
+ * We can stop looking
+ */
+ break;
+ }
+
+ look_thru->reason = reason;
}
- bgp_path_info_unset_flag(dest, pi, BGP_PATH_DMED_CHECK);
+ if (!any_comparisons)
+ first->reason = bgp_path_selection_first;
+
+ /*
+ * At this point worse if NON-NULL is where the first
+ * pointer should be before. if worse is NULL then
+ * first is bestpath too. Let's remove first from the
+ * list and place it in the right spot
+ */
+
+ if (!worse) {
+ struct bgp_path_info *end =
+ bgp_dest_get_bgp_path_info(dest);
+
+ for (; end && end->next != NULL; end = end->next)
+ ;
+
+ if (end)
+ end->next = first;
+ else
+ bgp_dest_set_bgp_path_info(dest, first);
+ first->prev = end;
+ first->next = NULL;
+
+ dest->reason = first->reason;
+ } else {
+ if (worse->prev)
+ worse->prev->next = first;
+ first->next = worse;
+ if (worse) {
+ first->prev = worse->prev;
+ worse->prev = first;
+ } else
+ first->prev = NULL;
- reason = dest->reason;
- if (bgp_path_info_cmp(bgp, pi, new_select, &paths_eq, mpath_cfg,
- debug, pfx_buf, afi, safi,
- &dest->reason)) {
- if (new_select == NULL &&
- reason != bgp_path_selection_none)
- dest->reason = reason;
- new_select = pi;
+ if (dest->info == worse) {
+ bgp_dest_set_bgp_path_info(dest, first);
+ dest->reason = first->reason;
+ }
}
+ UNSET_FLAG(first->flags, BGP_PATH_UNSORTED);
+ }
+
+ if (!unsorted_items) {
+ new_select = bgp_dest_get_bgp_path_info(dest);
+ while (new_select && BGP_PATH_HOLDDOWN(new_select))
+ new_select = new_select->next;
+
+ if (new_select) {
+ if (new_select->reason == bgp_path_selection_none)
+ new_select->reason = bgp_path_selection_first;
+ else if (new_select == bgp_dest_get_bgp_path_info(dest) &&
+ new_select->next == NULL)
+ new_select->reason = bgp_path_selection_first;
+ dest->reason = new_select->reason;
+ } else
+ dest->reason = bgp_path_selection_none;
+ } else
+ new_select = old_select;
+
+
+ /*
+ * Reinsert all the unsorted_holddown items for future processing
+ * at the end of the list.
+ */
+ if (unsorted_holddown) {
+ struct bgp_path_info *top = bgp_dest_get_bgp_path_info(dest);
+ struct bgp_path_info *prev = NULL;
+
+ while (top != NULL) {
+ prev = top;
+ top = top->next;
+ }
+
+ if (prev) {
+ prev->next = unsorted_holddown;
+ unsorted_holddown->prev = prev;
+ } else
+ bgp_dest_set_bgp_path_info(dest, unsorted_holddown);
}
/* Now that we know which path is the bestpath see if any of the other
@@ -2909,11 +3223,8 @@ void bgp_best_selection(struct bgp *bgp, struct bgp_dest *dest,
* qualify as multipaths
*/
if (debug) {
- if (new_select)
- bgp_path_info_path_with_addpath_rx_str(
- new_select, path_buf, sizeof(path_buf));
- else
- snprintf(path_buf, sizeof(path_buf), "NONE");
+ bgp_path_info_path_with_addpath_rx_str(new_select, path_buf,
+ sizeof(path_buf));
zlog_debug(
"%pBD(%s): After path selection, newbest is %s oldbest was %s",
dest, bgp->name_pretty, path_buf,
@@ -2921,9 +3232,7 @@ void bgp_best_selection(struct bgp *bgp, struct bgp_dest *dest,
}
if (do_mpath && new_select) {
- for (pi = bgp_dest_get_bgp_path_info(dest);
- (pi != NULL) && (nextpi = pi->next, 1); pi = nextpi) {
-
+ for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) {
if (debug)
bgp_path_info_path_with_addpath_rx_str(
pi, path_buf, sizeof(path_buf));
@@ -3177,8 +3486,7 @@ static bool bgp_lu_need_null_label(struct bgp *bgp,
|| new_select->sub_type == BGP_ROUTE_AGGREGATE
|| new_select->sub_type == BGP_ROUTE_REDISTRIBUTE)
goto need_null_label;
- else if (new_select->extra &&
- bgp_is_valid_label(&new_select->extra->label[0]))
+ else if (bgp_path_info_has_valid_label(new_select))
return false;
need_null_label:
if (label == NULL)
@@ -3355,7 +3663,9 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_dest *dest,
return;
}
+#ifdef ENABLE_BGP_VNC
const struct prefix *p = bgp_dest_get_prefix(dest);
+#endif
debug = bgp_debug_bestpath(dest);
if (debug)
@@ -3418,9 +3728,9 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_dest *dest,
&& (new_select->sub_type == BGP_ROUTE_NORMAL
|| new_select->sub_type
== BGP_ROUTE_IMPORTED))
-
- bgp_zebra_announce(dest, p, old_select,
- bgp, afi, safi);
+ bgp_zebra_route_install(dest, old_select,
+ bgp, true, NULL,
+ false);
}
}
@@ -3480,7 +3790,8 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_dest *dest,
bgp_path_info_unset_flag(dest, old_select, BGP_PATH_SELECTED);
if (new_select) {
if (debug)
- zlog_debug("%s: setting SELECTED flag", __func__);
+ zlog_debug("%s: %pBD setting SELECTED flag", __func__,
+ dest);
bgp_path_info_set_flag(dest, new_select, BGP_PATH_SELECTED);
bgp_path_info_unset_flag(dest, new_select,
BGP_PATH_ATTR_CHANGED);
@@ -3529,10 +3840,10 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_dest *dest,
*/
if (old_select &&
is_route_parent_evpn(old_select))
- bgp_zebra_withdraw(p, old_select, bgp, afi,
- safi);
+ bgp_zebra_withdraw_actual(dest, old_select, bgp);
- bgp_zebra_announce(dest, p, new_select, bgp, afi, safi);
+ bgp_zebra_route_install(dest, new_select, bgp, true,
+ NULL, false);
} else {
/* Withdraw the route from the kernel. */
if (old_select && old_select->type == ZEBRA_ROUTE_BGP
@@ -3540,8 +3851,8 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_dest *dest,
|| old_select->sub_type == BGP_ROUTE_AGGREGATE
|| old_select->sub_type == BGP_ROUTE_IMPORTED))
- bgp_zebra_withdraw(p, old_select, bgp, afi,
- safi);
+ bgp_zebra_route_install(dest, old_select, bgp,
+ false, NULL, false);
}
}
@@ -3704,13 +4015,38 @@ static struct bgp_process_queue *bgp_processq_alloc(struct bgp *bgp)
return pqnode;
}
-void bgp_process(struct bgp *bgp, struct bgp_dest *dest, afi_t afi, safi_t safi)
+void bgp_process(struct bgp *bgp, struct bgp_dest *dest,
+ struct bgp_path_info *pi, afi_t afi, safi_t safi)
{
#define ARBITRARY_PROCESS_QLEN 10000
struct work_queue *wq = bgp->process_queue;
struct bgp_process_queue *pqnode;
int pqnode_reuse = 0;
+ /*
+ * Indicate that *this* pi is in an unsorted
+ * situation, even if the node is already
+ * scheduled.
+ */
+ if (pi) {
+ struct bgp_path_info *first = bgp_dest_get_bgp_path_info(dest);
+
+ SET_FLAG(pi->flags, BGP_PATH_UNSORTED);
+
+ if (pi != first) {
+ if (pi->next)
+ pi->next->prev = pi->prev;
+ if (pi->prev)
+ pi->prev->next = pi->next;
+
+ if (first)
+ first->prev = pi;
+ pi->next = first;
+ pi->prev = NULL;
+ bgp_dest_set_bgp_path_info(dest, pi);
+ }
+ }
+
/* already scheduled for processing? */
if (CHECK_FLAG(dest->flags, BGP_NODE_PROCESS_SCHEDULED))
return;
@@ -3959,7 +4295,7 @@ void bgp_rib_remove(struct bgp_dest *dest, struct bgp_path_info *pi,
}
hook_call(bgp_process, peer->bgp, afi, safi, dest, peer, true);
- bgp_process(peer->bgp, dest, afi, safi);
+ bgp_process(peer->bgp, dest, pi, afi, safi);
}
static void bgp_rib_withdraw(struct bgp_dest *dest, struct bgp_path_info *pi,
@@ -3971,14 +4307,16 @@ static void bgp_rib_withdraw(struct bgp_dest *dest, struct bgp_path_info *pi,
/* apply dampening, if result is suppressed, we'll be retaining
* the bgp_path_info in the RIB for historical reference.
*/
- if (CHECK_FLAG(peer->bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)
- && peer->sort == BGP_PEER_EBGP)
- if ((bgp_damp_withdraw(pi, dest, afi, safi, 0))
- == BGP_DAMP_SUPPRESSED) {
- bgp_aggregate_decrement(peer->bgp, p, pi, afi,
- safi);
- return;
+ if (peer->sort == BGP_PEER_EBGP) {
+ if (get_active_bdc_from_pi(pi, afi, safi)) {
+ if (bgp_damp_withdraw(pi, dest, afi, safi, 0) ==
+ BGP_DAMP_SUPPRESSED) {
+ bgp_aggregate_decrement(peer->bgp, p, pi, afi,
+ safi);
+ return;
+ }
}
+ }
#ifdef ENABLE_BGP_VNC
if (safi == SAFI_MPLS_VPN) {
@@ -4198,7 +4536,7 @@ static bool bgp_accept_own(struct peer *peer, afi_t afi, safi_t safi,
void 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,
+ uint8_t num_labels, int soft_reconfig,
struct bgp_route_evpn *evpn)
{
int ret;
@@ -4209,16 +4547,16 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
struct attr *attr_new;
struct bgp_path_info *pi;
struct bgp_path_info *new = NULL;
- struct bgp_path_info_extra *extra;
const char *reason;
char pfx_buf[BGP_PRD_PATH_STRLEN];
int connected = 0;
int do_loop_check = 1;
- int has_valid_label = 0;
afi_t nh_afi;
bool force_evpn_import = false;
safi_t orig_safi = safi;
int allowas_in = 0;
+ struct bgp_labels bgp_labels = {};
+ uint8_t i;
if (frrtrace_enabled(frr_bgp, process_update)) {
char pfxprint[PREFIX2STR_BUFFER];
@@ -4240,15 +4578,12 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
bgp = peer->bgp;
dest = bgp_afi_node_get(bgp->rib[afi][safi], afi, safi, p, prd);
- /* TODO: Check to see if we can get rid of "is_valid_label" */
- if (afi == AFI_L2VPN && safi == SAFI_EVPN)
- has_valid_label = (num_labels > 0) ? 1 : 0;
- else
- has_valid_label = bgp_is_valid_label(label);
-
- if (has_valid_label)
- assert(label != NULL);
+ if ((afi == AFI_L2VPN && safi == SAFI_EVPN) ||
+ bgp_is_valid_label(&label[0]))
+ bgp_labels.num_labels = num_labels;
+ for (i = 0; i < bgp_labels.num_labels; i++)
+ bgp_labels.label[i] = label[i];
/* When peer's soft reconfiguration enabled. Record input packet in
Adj-RIBs-In. */
@@ -4265,7 +4600,7 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
memcpy(&attr->evpn_overlay, evpn,
sizeof(struct bgp_route_evpn));
}
- bgp_adj_in_set(dest, peer, attr, addpath_id);
+ bgp_adj_in_set(dest, peer, attr, addpath_id, &bgp_labels);
}
/* Update permitted loop count */
@@ -4447,7 +4782,8 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
if (pi && pi->attr->rmap_table_id != new_attr.rmap_table_id) {
if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED))
/* remove from RIB previous entry */
- bgp_zebra_withdraw(p, pi, bgp, afi, safi);
+ bgp_zebra_route_install(dest, pi, bgp, false, NULL,
+ false);
}
if (peer->sort == BGP_PEER_EBGP) {
@@ -4541,15 +4877,12 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
/* Same attribute comes in. */
if (!CHECK_FLAG(pi->flags, BGP_PATH_REMOVED) && same_attr &&
- (!has_valid_label ||
- (bgp_path_info_extra_get(pi) &&
- bgp_labels_same((const mpls_label_t *)pi->extra->label,
- pi->extra->num_labels, label,
- num_labels)))) {
- if (CHECK_FLAG(bgp->af_flags[afi][safi],
- BGP_CONFIG_DAMPENING)
- && peer->sort == BGP_PEER_EBGP
- && CHECK_FLAG(pi->flags, BGP_PATH_HISTORY)) {
+ (!bgp_labels.num_labels ||
+ bgp_path_info_labels_same(pi, bgp_labels.label,
+ bgp_labels.num_labels))) {
+ if (get_active_bdc_from_pi(pi, afi, safi) &&
+ peer->sort == BGP_PEER_EBGP &&
+ CHECK_FLAG(pi->flags, BGP_PATH_HISTORY)) {
if (bgp_debug_update(peer, p, NULL, 1)) {
bgp_debug_rdpfxpath2str(
afi, safi, prd, p, label,
@@ -4564,7 +4897,7 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
!= BGP_DAMP_SUPPRESSED) {
bgp_aggregate_increment(bgp, p, pi, afi,
safi);
- bgp_process(bgp, dest, afi, safi);
+ bgp_process(bgp, dest, pi, afi, safi);
}
} else /* Duplicate - odd */
{
@@ -4592,7 +4925,7 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
bgp_path_info_unset_flag(
dest, pi, BGP_PATH_STALE);
bgp_dest_set_defer_flag(dest, false);
- bgp_process(bgp, dest, afi, safi);
+ bgp_process(bgp, dest, pi, afi, safi);
}
}
@@ -4650,11 +4983,11 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
bgp_path_info_set_flag(dest, pi, BGP_PATH_ATTR_CHANGED);
/* Update bgp route dampening information. */
- if (CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)
- && peer->sort == BGP_PEER_EBGP) {
+ if (get_active_bdc_from_pi(pi, afi, safi) &&
+ peer->sort == BGP_PEER_EBGP) {
/* This is implicit withdraw so we should update
- dampening
- information. */
+ * dampening information.
+ */
if (!CHECK_FLAG(pi->flags, BGP_PATH_HISTORY))
bgp_damp_withdraw(pi, dest, afi, safi, 1);
}
@@ -4728,17 +5061,11 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
pi->attr = attr_new;
/* Update MPLS label */
- if (has_valid_label) {
- extra = bgp_path_info_extra_get(pi);
- if (!bgp_labels_same((const mpls_label_t *)extra->label,
- extra->num_labels, label,
- num_labels)) {
- memcpy(&extra->label, label,
- num_labels * sizeof(mpls_label_t));
- extra->num_labels = num_labels;
- }
- if (!(afi == AFI_L2VPN && safi == SAFI_EVPN))
- bgp_set_valid_label(&extra->label[0]);
+ if (!bgp_path_info_labels_same(pi, &bgp_labels.label[0],
+ bgp_labels.num_labels)) {
+ bgp_path_info_extra_get(pi);
+ bgp_labels_unintern(&pi->extra->labels);
+ pi->extra->labels = bgp_labels_intern(&bgp_labels);
}
#ifdef ENABLE_BGP_VNC
@@ -4765,8 +5092,8 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
#endif
/* Update bgp route dampening information. */
- if (CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)
- && peer->sort == BGP_PEER_EBGP) {
+ if (get_active_bdc_from_pi(pi, afi, safi) &&
+ peer->sort == BGP_PEER_EBGP) {
/* Now we do normal update dampening. */
ret = bgp_damp_update(pi, dest, afi, safi);
if (ret == BGP_DAMP_SUPPRESSED) {
@@ -4882,7 +5209,7 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
/* Process change. */
bgp_aggregate_increment(bgp, p, pi, afi, safi);
- bgp_process(bgp, dest, afi, safi);
+ bgp_process(bgp, dest, pi, afi, safi);
bgp_dest_unlock_node(dest);
if (SAFI_UNICAST == safi
@@ -4929,17 +5256,8 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
new = info_make(type, sub_type, 0, peer, attr_new, dest);
/* Update MPLS label */
- if (has_valid_label) {
- extra = bgp_path_info_extra_get(new);
- if (!bgp_labels_same((const mpls_label_t *)extra->label,
- extra->num_labels, label, num_labels)) {
- memcpy(&extra->label, label,
- num_labels * sizeof(mpls_label_t));
- extra->num_labels = num_labels;
- }
- if (!(afi == AFI_L2VPN && safi == SAFI_EVPN))
- bgp_set_valid_label(&extra->label[0]);
- }
+ bgp_path_info_extra_get(new);
+ new->extra->labels = bgp_labels_intern(&bgp_labels);
/* Nexthop reachability check. */
if (((afi == AFI_IP || afi == AFI_IP6) &&
@@ -5027,7 +5345,7 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
hook_call(bgp_process, bgp, afi, safi, dest, peer, false);
/* Process change. */
- bgp_process(bgp, dest, afi, safi);
+ bgp_process(bgp, dest, new, afi, safi);
if (SAFI_UNICAST == safi
&& (bgp->inst_type == BGP_INSTANCE_TYPE_VRF
@@ -5120,7 +5438,7 @@ filtered:
void bgp_withdraw(struct peer *peer, const struct prefix *p,
uint32_t addpath_id, 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)
+ uint8_t num_labels, struct bgp_route_evpn *evpn)
{
struct bgp *bgp;
char pfx_buf[BGP_PRD_PATH_STRLEN];
@@ -5347,18 +5665,16 @@ static void bgp_soft_reconfig_table_update(struct peer *peer,
safi_t safi, struct prefix_rd *prd)
{
struct bgp_path_info *pi;
- uint32_t num_labels = 0;
- mpls_label_t *label_pnt = NULL;
+ uint8_t num_labels;
+ mpls_label_t *label_pnt;
struct bgp_route_evpn evpn;
for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next)
if (pi->peer == peer)
break;
- if (pi && pi->extra)
- num_labels = pi->extra->num_labels;
- if (num_labels)
- label_pnt = &pi->extra->label[0];
+ num_labels = ain->labels ? ain->labels->num_labels : 0;
+ label_pnt = num_labels ? &ain->labels->label[0] : NULL;
if (pi)
memcpy(&evpn, bgp_attr_get_evpn_overlay(pi->attr),
sizeof(evpn));
@@ -5598,7 +5914,7 @@ static wq_item_status bgp_clear_route_node(struct work_queue *wq, void *data)
struct bgp_clear_node_queue *cnq = data;
struct bgp_dest *dest = cnq->dest;
struct peer *peer = wq->spec.data;
- struct bgp_path_info *pi;
+ struct bgp_path_info *pi, *next;
struct bgp *bgp;
afi_t afi = bgp_dest_table(dest)->afi;
safi_t safi = bgp_dest_table(dest)->safi;
@@ -5609,7 +5925,8 @@ static wq_item_status bgp_clear_route_node(struct work_queue *wq, void *data)
/* It is possible that we have multiple paths for a prefix from a peer
* if that peer is using AddPath.
*/
- for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) {
+ for (pi = bgp_dest_get_bgp_path_info(dest);
+ (pi != NULL) && (next = pi->next, 1); pi = next) {
if (pi->peer != peer)
continue;
@@ -5871,7 +6188,7 @@ void bgp_clear_adj_in(struct peer *peer, afi_t afi, safi_t safi)
void bgp_clear_stale_route(struct peer *peer, afi_t afi, safi_t safi)
{
struct bgp_dest *dest;
- struct bgp_path_info *pi;
+ struct bgp_path_info *pi, *next;
struct bgp_table *table;
if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP || safi == SAFI_EVPN) {
@@ -5886,8 +6203,9 @@ void bgp_clear_stale_route(struct peer *peer, afi_t afi, safi_t safi)
for (rm = bgp_table_top(table); rm;
rm = bgp_route_next(rm))
- for (pi = bgp_dest_get_bgp_path_info(rm); pi;
- pi = pi->next) {
+ for (pi = bgp_dest_get_bgp_path_info(rm);
+ (pi != NULL) && (next = pi->next, 1);
+ pi = next) {
if (pi->peer != peer)
continue;
if (CHECK_FLAG(
@@ -5920,8 +6238,8 @@ void bgp_clear_stale_route(struct peer *peer, afi_t afi, safi_t safi)
} else {
for (dest = bgp_table_top(peer->bgp->rib[afi][safi]); dest;
dest = bgp_route_next(dest))
- for (pi = bgp_dest_get_bgp_path_info(dest); pi;
- pi = pi->next) {
+ for (pi = bgp_dest_get_bgp_path_info(dest);
+ (pi != NULL) && (next = pi->next, 1); pi = next) {
if (pi->peer != peer)
continue;
if (CHECK_FLAG(peer->af_sflags[afi][safi],
@@ -6024,7 +6342,8 @@ void bgp_set_stale_route(struct peer *peer, afi_t afi, safi_t safi)
bool bgp_outbound_policy_exists(struct peer *peer, struct bgp_filter *filter)
{
- if (peer->sort == BGP_PEER_IBGP)
+ if (peer->sort == BGP_PEER_CONFED || peer->sort == BGP_PEER_IBGP ||
+ peer->sub_sort == BGP_PEER_EBGP_OAD)
return true;
if (peer->sort == BGP_PEER_EBGP &&
@@ -6037,7 +6356,8 @@ bool bgp_outbound_policy_exists(struct peer *peer, struct bgp_filter *filter)
bool bgp_inbound_policy_exists(struct peer *peer, struct bgp_filter *filter)
{
- if (peer->sort == BGP_PEER_IBGP)
+ if (peer->sort == BGP_PEER_CONFED || peer->sort == BGP_PEER_IBGP ||
+ peer->sub_sort == BGP_PEER_EBGP_OAD)
return true;
if (peer->sort == BGP_PEER_EBGP
@@ -6073,8 +6393,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(p, pi, bgp, afi,
- safi);
+ bgp_zebra_withdraw_actual(dest, pi, bgp);
}
dest = bgp_path_info_reap(dest, pi);
@@ -6369,10 +6688,11 @@ void bgp_static_update(struct bgp *bgp, const struct prefix *p,
route_map_result_t ret;
#ifdef ENABLE_BGP_VNC
int vnc_implicit_withdraw = 0;
- mpls_label_t label = 0;
+ mpls_label_t label = MPLS_INVALID_LABEL;
#endif
- uint32_t num_labels = 0;
+ uint8_t num_labels = 0;
struct bgp *bgp_nexthop = bgp;
+ struct bgp_labels labels = {};
assert(bgp_static);
@@ -6522,9 +6842,9 @@ void bgp_static_update(struct bgp *bgp, const struct prefix *p,
bgp, p, pi);
}
} else {
- if (pi->extra)
+ if (bgp_path_info_num_labels(pi))
label = decode_label(
- &pi->extra->label[0]);
+ &pi->extra->labels->label[0]);
}
#endif
if (pi->extra && pi->extra->vrfleak->bgp_orig)
@@ -6535,7 +6855,7 @@ void bgp_static_update(struct bgp *bgp, const struct prefix *p,
/* Process change. */
bgp_aggregate_increment(bgp, p, pi, afi, safi);
- bgp_process(bgp, dest, afi, safi);
+ bgp_process(bgp, dest, pi, afi, safi);
if (SAFI_MPLS_VPN == safi &&
bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT) {
@@ -6573,8 +6893,9 @@ void bgp_static_update(struct bgp *bgp, const struct prefix *p,
SET_FLAG(new->flags, BGP_PATH_VALID);
bgp_path_info_extra_get(new);
if (num_labels) {
- new->extra->label[0] = bgp_static->label;
- new->extra->num_labels = num_labels;
+ labels.num_labels = num_labels;
+ labels.label[0] = bgp_static->label;
+ new->extra->labels = bgp_labels_intern(&labels);
}
#ifdef ENABLE_BGP_VNC
label = decode_label(&bgp_static->label);
@@ -6593,7 +6914,7 @@ void bgp_static_update(struct bgp *bgp, const struct prefix *p,
bgp_dest_unlock_node(dest);
/* Process change. */
- bgp_process(bgp, dest, afi, safi);
+ bgp_process(bgp, dest, new, afi, safi);
if (SAFI_UNICAST == safi &&
(bgp->inst_type == BGP_INSTANCE_TYPE_VRF ||
@@ -6632,6 +6953,7 @@ void bgp_static_withdraw(struct bgp *bgp, const struct prefix *p, afi_t afi,
/* Withdraw static BGP route from routing table. */
if (pi) {
+ SET_FLAG(pi->flags, BGP_PATH_UNSORTED);
#ifdef ENABLE_BGP_VNC
if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP)
rfapiProcessWithdraw(pi->peer, NULL, p, prd, pi->attr,
@@ -6650,7 +6972,7 @@ void bgp_static_withdraw(struct bgp *bgp, const struct prefix *p, afi_t afi,
bgp_aggregate_decrement(bgp, p, pi, afi, safi);
bgp_unlink_nexthop(pi);
bgp_path_info_delete(dest, pi);
- bgp_process(bgp, dest, afi, safi);
+ bgp_process(bgp, dest, pi, afi, safi);
}
/* Unlock bgp_node_lookup. */
@@ -7055,7 +7377,7 @@ static void bgp_purge_af_static_redist_routes(struct bgp *bgp, afi_t afi,
safi);
bgp_unlink_nexthop(pi);
bgp_path_info_delete(dest, pi);
- bgp_process(bgp, dest, afi, safi);
+ bgp_process(bgp, dest, pi, afi, safi);
}
}
}
@@ -7418,8 +7740,10 @@ static void bgp_aggregate_install(
/*
* Mark the old as unusable
*/
- if (pi)
+ if (pi) {
bgp_path_info_delete(dest, pi);
+ bgp_process(bgp, dest, pi, afi, safi);
+ }
attr = bgp_attr_aggregate_intern(
bgp, origin, aspath, community, ecommunity, lcommunity,
@@ -7444,7 +7768,7 @@ static void bgp_aggregate_install(
SET_FLAG(new->flags, BGP_PATH_VALID);
bgp_path_info_add(dest, new);
- bgp_process(bgp, dest, afi, safi);
+ bgp_process(bgp, dest, new, afi, safi);
} else {
uninstall_aggregate_route:
for (pi = orig; pi; pi = pi->next)
@@ -7456,7 +7780,7 @@ static void bgp_aggregate_install(
/* Withdraw static BGP route from routing table. */
if (pi) {
bgp_path_info_delete(dest, pi);
- bgp_process(bgp, dest, afi, safi);
+ bgp_process(bgp, dest, pi, afi, safi);
}
}
@@ -7542,7 +7866,6 @@ void bgp_aggregate_toggle_suppressed(struct bgp_aggregate *aggregate,
const struct prefix *dest_p;
struct bgp_dest *dest, *top;
struct bgp_path_info *pi;
- bool toggle_suppression;
/* We've found a different MED we must revert any suppressed routes. */
top = bgp_node_get(table, p);
@@ -7552,7 +7875,6 @@ void bgp_aggregate_toggle_suppressed(struct bgp_aggregate *aggregate,
if (dest_p->prefixlen <= p->prefixlen)
continue;
- toggle_suppression = false;
for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) {
if (BGP_PATH_HOLDDOWN(pi))
continue;
@@ -7563,17 +7885,14 @@ void bgp_aggregate_toggle_suppressed(struct bgp_aggregate *aggregate,
if (suppress) {
/* Suppress route if not suppressed already. */
if (aggr_suppress_path(aggregate, pi))
- toggle_suppression = true;
+ bgp_process(bgp, dest, pi, afi, safi);
continue;
}
/* Install route if there is no more suppression. */
if (aggr_unsuppress_path(aggregate, pi))
- toggle_suppression = true;
+ bgp_process(bgp, dest, pi, afi, safi);
}
-
- if (toggle_suppression)
- bgp_process(bgp, dest, afi, safi);
}
bgp_dest_unlock_node(top);
}
@@ -7632,7 +7951,6 @@ bool bgp_aggregate_route(struct bgp *bgp, const struct prefix *p, afi_t afi,
struct ecommunity *ecommunity = NULL;
struct lcommunity *lcommunity = NULL;
struct bgp_path_info *pi;
- unsigned long match = 0;
uint8_t atomic_aggregate = 0;
/* If the bgp instance is being deleted or self peer is deleted
@@ -7682,8 +8000,6 @@ bool bgp_aggregate_route(struct bgp *bgp, const struct prefix *p, afi_t afi,
if (!bgp_check_advertise(bgp, dest, safi))
continue;
- match = 0;
-
for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) {
if (BGP_PATH_HOLDDOWN(pi))
continue;
@@ -7707,7 +8023,7 @@ bool bgp_aggregate_route(struct bgp *bgp, const struct prefix *p, afi_t afi,
if (aggregate->summary_only
&& AGGREGATE_MED_VALID(aggregate)) {
if (aggr_suppress_path(aggregate, pi))
- match++;
+ bgp_process(bgp, dest, pi, afi, safi);
}
/*
@@ -7723,7 +8039,7 @@ bool bgp_aggregate_route(struct bgp *bgp, const struct prefix *p, afi_t afi,
&& AGGREGATE_MED_VALID(aggregate)
&& aggr_suppress_map_test(bgp, aggregate, pi)) {
if (aggr_suppress_path(aggregate, pi))
- match++;
+ bgp_process(bgp, dest, pi, afi, safi);
}
aggregate->count++;
@@ -7784,8 +8100,6 @@ bool bgp_aggregate_route(struct bgp *bgp, const struct prefix *p, afi_t afi,
aggregate,
bgp_attr_get_lcommunity(pi->attr));
}
- if (match)
- bgp_process(bgp, dest, afi, safi);
}
if (aggregate->as_set) {
bgp_compute_aggregate_aspath_val(aggregate);
@@ -7845,7 +8159,6 @@ void bgp_aggregate_delete(struct bgp *bgp, const struct prefix *p, afi_t afi,
struct bgp_dest *top;
struct bgp_dest *dest;
struct bgp_path_info *pi;
- unsigned long match;
table = bgp->rib[afi][safi];
@@ -7857,7 +8170,6 @@ void bgp_aggregate_delete(struct bgp *bgp, const struct prefix *p, afi_t afi,
if (dest_p->prefixlen <= p->prefixlen)
continue;
- match = 0;
for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) {
if (BGP_PATH_HOLDDOWN(pi))
@@ -7875,10 +8187,11 @@ void bgp_aggregate_delete(struct bgp *bgp, const struct prefix *p, afi_t afi,
if (pi->extra && pi->extra->aggr_suppressors &&
listcount(pi->extra->aggr_suppressors)) {
if (aggr_unsuppress_path(aggregate, pi))
- match++;
+ bgp_process(bgp, dest, pi, afi, safi);
}
- aggregate->count--;
+ if (aggregate->count > 0)
+ aggregate->count--;
if (pi->attr->origin == BGP_ORIGIN_INCOMPLETE)
aggregate->incomplete_origin_count--;
@@ -7917,10 +8230,6 @@ void bgp_aggregate_delete(struct bgp *bgp, const struct prefix *p, afi_t afi,
pi->attr));
}
}
-
- /* If this node was suppressed, process the change. */
- if (match)
- bgp_process(bgp, dest, afi, safi);
}
if (aggregate->as_set) {
aspath_free(aggregate->aspath);
@@ -8069,7 +8378,6 @@ static void bgp_remove_route_from_aggregate(struct bgp *bgp, afi_t afi,
struct community *community = NULL;
struct ecommunity *ecommunity = NULL;
struct lcommunity *lcommunity = NULL;
- unsigned long match = 0;
/* If the bgp instance is being deleted or self peer is deleted
* then do not create aggregate route
@@ -8086,12 +8394,12 @@ static void bgp_remove_route_from_aggregate(struct bgp *bgp, afi_t afi,
if (aggregate->summary_only && AGGREGATE_MED_VALID(aggregate))
if (aggr_unsuppress_path(aggregate, pi))
- match++;
+ bgp_process(bgp, pi->net, pi, afi, safi);
if (aggregate->suppress_map_name && AGGREGATE_MED_VALID(aggregate)
&& aggr_suppress_map_test(bgp, aggregate, pi))
if (aggr_unsuppress_path(aggregate, pi))
- match++;
+ bgp_process(bgp, pi->net, pi, afi, safi);
/*
* This must be called after `summary`, `suppress-map` check to avoid
@@ -8133,10 +8441,6 @@ static void bgp_remove_route_from_aggregate(struct bgp *bgp, afi_t afi,
aggregate, bgp_attr_get_lcommunity(pi->attr));
}
- /* If this node was suppressed, process the change. */
- if (match)
- bgp_process(bgp, pi->net, afi, safi);
-
origin = BGP_ORIGIN_IGP;
if (aggregate->incomplete_origin_count > 0)
origin = BGP_ORIGIN_INCOMPLETE;
@@ -8594,6 +8898,7 @@ void bgp_redistribute_add(struct bgp *bgp, struct prefix *p,
afi_t afi;
route_map_result_t ret;
struct bgp_redist *red;
+ struct interface *ifp;
if (CHECK_FLAG(bgp->flags, BGP_FLAG_DELETE_IN_PROGRESS) ||
bgp->peer_self == NULL)
@@ -8653,6 +8958,11 @@ void bgp_redistribute_add(struct bgp *bgp, struct prefix *p,
}
attr.nh_type = nhtype;
attr.nh_ifindex = ifindex;
+ ifp = if_lookup_by_index(ifindex, bgp->vrf_id);
+ if (ifp && if_is_operative(ifp))
+ SET_FLAG(attr.nh_flags, BGP_ATTR_NH_IF_OPERSTATE);
+ else
+ UNSET_FLAG(attr.nh_flags, BGP_ATTR_NH_IF_OPERSTATE);
attr.med = metric;
attr.distance = distance;
@@ -8740,7 +9050,7 @@ void bgp_redistribute_add(struct bgp *bgp, struct prefix *p,
/* Process change. */
bgp_aggregate_increment(bgp, p, bpi, afi,
SAFI_UNICAST);
- bgp_process(bgp, bn, afi, SAFI_UNICAST);
+ bgp_process(bgp, bn, bpi, afi, SAFI_UNICAST);
bgp_dest_unlock_node(bn);
aspath_unintern(&attr.aspath);
@@ -8763,7 +9073,7 @@ void bgp_redistribute_add(struct bgp *bgp, struct prefix *p,
bgp_path_info_add(bn, new);
bgp_dest_unlock_node(bn);
SET_FLAG(bn->flags, BGP_NODE_FIB_INSTALLED);
- bgp_process(bgp, bn, afi, SAFI_UNICAST);
+ bgp_process(bgp, bn, new, afi, SAFI_UNICAST);
if ((bgp->inst_type == BGP_INSTANCE_TYPE_VRF)
|| (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)) {
@@ -8804,7 +9114,7 @@ void bgp_redistribute_delete(struct bgp *bgp, struct prefix *p, uint8_t type,
}
bgp_aggregate_decrement(bgp, p, pi, afi, SAFI_UNICAST);
bgp_path_info_delete(dest, pi);
- bgp_process(bgp, dest, afi, SAFI_UNICAST);
+ bgp_process(bgp, dest, pi, afi, SAFI_UNICAST);
}
bgp_dest_unlock_node(dest);
}
@@ -8838,7 +9148,7 @@ void bgp_redistribute_withdraw(struct bgp *bgp, afi_t afi, int type,
bgp_path_info_delete(dest, pi);
if (!CHECK_FLAG(bgp->flags,
BGP_FLAG_DELETE_IN_PROGRESS))
- bgp_process(bgp, dest, afi, SAFI_UNICAST);
+ bgp_process(bgp, dest, pi, afi, SAFI_UNICAST);
else {
dest = bgp_path_info_reap(dest, pi);
assert(dest);
@@ -8984,6 +9294,9 @@ static void route_vty_short_status_out(struct vty *vty,
if (path->extra && bgp_path_suppressed(path))
json_object_boolean_true_add(json_path, "suppressed");
+ if (CHECK_FLAG(path->flags, BGP_PATH_UNSORTED))
+ json_object_boolean_true_add(json_path, "unsorted");
+
if (CHECK_FLAG(path->flags, BGP_PATH_VALID)
&& !CHECK_FLAG(path->flags, BGP_PATH_HISTORY))
json_object_boolean_true_add(json_path, "valid");
@@ -9046,6 +9359,8 @@ static void route_vty_short_status_out(struct vty *vty,
/* Selected */
if (CHECK_FLAG(path->flags, BGP_PATH_HISTORY))
vty_out(vty, "h");
+ else if (CHECK_FLAG(path->flags, BGP_PATH_UNSORTED))
+ vty_out(vty, "u");
else if (CHECK_FLAG(path->flags, BGP_PATH_DAMPED))
vty_out(vty, "d");
else if (CHECK_FLAG(path->flags, BGP_PATH_SELECTED))
@@ -9061,6 +9376,9 @@ static void route_vty_short_status_out(struct vty *vty,
vty_out(vty, "i");
else
vty_out(vty, " ");
+
+ /* adding space between next column */
+ vty_out(vty, " ");
}
static char *bgp_nexthop_hostname(struct peer *peer,
@@ -9341,10 +9659,8 @@ void route_vty_out(struct vty *vty, const struct prefix *p,
json_object_string_add(json_nexthop_ll, "scope",
"link-local");
- if ((IPV6_ADDR_CMP(&attr->mp_nexthop_global,
- &attr->mp_nexthop_local)
- != 0)
- && !attr->mp_nexthop_prefer_global)
+ if (!CHECK_FLAG(attr->nh_flags,
+ BGP_ATTR_NH_MP_PREFER_GLOBAL))
json_object_boolean_true_add(
json_nexthop_ll, "used");
else
@@ -9356,10 +9672,11 @@ void route_vty_out(struct vty *vty, const struct prefix *p,
} else {
/* Display LL if LL/Global both in table unless
* prefer-global is set */
- if (((attr->mp_nexthop_len
- == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL)
- && !attr->mp_nexthop_prefer_global)
- || (path->peer->conf_if)) {
+ if (((attr->mp_nexthop_len ==
+ BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) &&
+ !CHECK_FLAG(attr->nh_flags,
+ BGP_ATTR_NH_MP_PREFER_GLOBAL)) ||
+ (path->peer->conf_if)) {
if (path->peer->conf_if) {
len = vty_out(vty, "%s",
path->peer->conf_if);
@@ -9764,8 +10081,8 @@ void route_vty_out_tag(struct vty *vty, const struct prefix *p,
}
}
- if (bgp_is_valid_label(&path->extra->label[0])) {
- label = decode_label(&path->extra->label[0]);
+ if (bgp_path_info_has_valid_label(path)) {
+ label = decode_label(&path->extra->labels->label[0]);
if (json) {
json_object_int_add(json_out, "notag", label);
json_object_array_add(json, json_out);
@@ -10155,7 +10472,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
json_object *json_paths)
{
char buf[INET6_ADDRSTRLEN];
- char tag_buf[30];
+ char vni_buf[30] = {};
struct attr *attr = path->attr;
time_t tbuf;
char timebuf[32];
@@ -10163,6 +10480,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
json_object *json_cluster_list = NULL;
json_object *json_cluster_list_list = NULL;
json_object *json_ext_community = NULL;
+ json_object *json_ext_ipv6_community = NULL;
json_object *json_last_update = NULL;
json_object *json_pmsi = NULL;
json_object *json_nexthop_global = NULL;
@@ -10187,7 +10505,6 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
uint32_t bos = 0;
uint32_t exp = 0;
mpls_label_t label = MPLS_INVALID_LABEL;
- tag_buf[0] = '\0';
struct bgp_path_info *bpi_ultimate =
bgp_get_imported_bpi_ultimate(path);
@@ -10197,26 +10514,22 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
json_nexthop_global = json_object_new_object();
}
+ if (bgp_path_info_num_labels(path)) {
+ bgp_evpn_label2str(path->extra->labels->label,
+ path->extra->labels->num_labels, vni_buf,
+ sizeof(vni_buf));
+ }
+
if (safi == SAFI_EVPN) {
if (!json_paths)
vty_out(vty, " Route %pFX", p);
- }
- if (path->extra) {
- if (path->extra && path->extra->num_labels) {
- bgp_evpn_label2str(path->extra->label,
- path->extra->num_labels, tag_buf,
- sizeof(tag_buf));
- }
- if (safi == SAFI_EVPN) {
- if (!json_paths) {
- if (tag_buf[0] != '\0')
- vty_out(vty, " VNI %s", tag_buf);
- } else {
- if (tag_buf[0])
- json_object_string_add(json_path, "vni",
- tag_buf);
- }
+ if (vni_buf[0]) {
+ if (json_paths)
+ json_object_string_add(json_path, "vni",
+ vni_buf);
+ else
+ vty_out(vty, " VNI %s", vni_buf);
}
}
@@ -10256,7 +10569,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
vty_out(vty, ":%pFX, VNI %s",
(struct prefix_evpn *)
bgp_dest_get_prefix(dest),
- tag_buf);
+ vni_buf);
if (CHECK_FLAG(attr->es_flags, ATTR_ES_L3_NHG))
vty_out(vty, ", L3NHG %s",
CHECK_FLAG(
@@ -10612,7 +10925,8 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
json_object_boolean_true_add(json_nexthop_ll,
"accessible");
- if (!attr->mp_nexthop_prefer_global)
+ if (!CHECK_FLAG(attr->nh_flags,
+ BGP_ATTR_NH_MP_PREFER_GLOBAL))
json_object_boolean_true_add(json_nexthop_ll,
"used");
else
@@ -10622,7 +10936,8 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
vty_out(vty, " (%s) %s\n",
inet_ntop(AF_INET6, &attr->mp_nexthop_local,
buf, INET6_ADDRSTRLEN),
- attr->mp_nexthop_prefer_global
+ CHECK_FLAG(attr->nh_flags,
+ BGP_ATTR_NH_MP_PREFER_GLOBAL)
? "(prefer-global)"
: "(used)");
}
@@ -10869,6 +11184,21 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
}
}
+ if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_IPV6_EXT_COMMUNITIES)) {
+ if (json_paths) {
+ json_ext_ipv6_community = json_object_new_object();
+ json_object_string_add(json_ext_ipv6_community, "string",
+ bgp_attr_get_ipv6_ecommunity(attr)
+ ->str);
+ json_object_object_add(json_path,
+ "extendedIpv6Community",
+ json_ext_ipv6_community);
+ } else {
+ vty_out(vty, " Extended IPv6 Community: %s\n",
+ bgp_attr_get_ipv6_ecommunity(attr)->str);
+ }
+ }
+
/* Line 6 display Large community */
if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES)) {
if (json_paths) {
@@ -10948,13 +11278,13 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
}
if (path->extra && path->extra->damp_info)
- bgp_damp_info_vty(vty, path, afi, safi, json_path);
+ bgp_damp_info_vty(vty, bgp, path, afi, safi, json_path);
/* Remote Label */
- if (path->extra && bgp_is_valid_label(&path->extra->label[0])
- && (safi != SAFI_EVPN && !is_route_parent_evpn(path))) {
- mpls_lse_decode(path->extra->label[0], &label, &ttl, &exp,
- &bos);
+ if (bgp_path_info_has_valid_label(path) &&
+ (safi != SAFI_EVPN && !is_route_parent_evpn(path))) {
+ mpls_lse_decode(path->extra->labels->label[0], &label, &ttl,
+ &exp, &bos);
if (json_paths)
json_object_int_add(json_path, "remoteLabel", label);
@@ -13686,21 +14016,23 @@ enum bgp_pcounts {
PCOUNT_COUNTED,
PCOUNT_BPATH_SELECTED,
PCOUNT_PFCNT, /* the figure we display to users */
+ PCOUNT_UNSORTED,
PCOUNT_MAX,
};
static const char *const pcount_strs[] = {
- [PCOUNT_ADJ_IN] = "Adj-in",
- [PCOUNT_DAMPED] = "Damped",
- [PCOUNT_REMOVED] = "Removed",
- [PCOUNT_HISTORY] = "History",
- [PCOUNT_STALE] = "Stale",
- [PCOUNT_VALID] = "Valid",
- [PCOUNT_ALL] = "All RIB",
- [PCOUNT_COUNTED] = "PfxCt counted",
- [PCOUNT_BPATH_SELECTED] = "PfxCt Best Selected",
- [PCOUNT_PFCNT] = "Useable",
- [PCOUNT_MAX] = NULL,
+ [PCOUNT_ADJ_IN] = "Adj-in",
+ [PCOUNT_DAMPED] = "Damped",
+ [PCOUNT_REMOVED] = "Removed",
+ [PCOUNT_HISTORY] = "History",
+ [PCOUNT_STALE] = "Stale",
+ [PCOUNT_VALID] = "Valid",
+ [PCOUNT_ALL] = "All RIB",
+ [PCOUNT_COUNTED] = "PfxCt counted",
+ [PCOUNT_BPATH_SELECTED] = "PfxCt Best Selected",
+ [PCOUNT_PFCNT] = "Useable",
+ [PCOUNT_UNSORTED] = "Unsorted",
+ [PCOUNT_MAX] = NULL,
};
struct peer_pcounts {
@@ -13741,6 +14073,8 @@ static void bgp_peer_count_proc(struct bgp_dest *rn, struct peer_pcounts *pc)
pc->count[PCOUNT_PFCNT]++;
if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED))
pc->count[PCOUNT_BPATH_SELECTED]++;
+ if (CHECK_FLAG(pi->flags, BGP_PATH_UNSORTED))
+ pc->count[PCOUNT_UNSORTED]++;
if (CHECK_FLAG(pi->flags, BGP_PATH_COUNTED)) {
pc->count[PCOUNT_COUNTED]++;
@@ -15496,9 +15830,8 @@ static int bgp_clear_damp_route(struct vty *vty, const char *view_name,
while (pi) {
if (pi->extra && pi->extra->damp_info) {
pi_temp = pi->next;
- bgp_damp_info_free(
- pi->extra->damp_info,
- 1, afi, safi);
+ bgp_damp_info_free(pi->extra->damp_info,
+ NULL, 1);
pi = pi_temp;
} else
pi = pi->next;
@@ -15509,26 +15842,38 @@ static int bgp_clear_damp_route(struct vty *vty, const char *view_name,
}
} else {
dest = bgp_node_match(bgp->rib[afi][safi], &match);
- if (dest != NULL) {
- const struct prefix *dest_p = bgp_dest_get_prefix(dest);
+ if (!dest)
+ return CMD_SUCCESS;
- if (!prefix_check
- || dest_p->prefixlen == match.prefixlen) {
- pi = bgp_dest_get_bgp_path_info(dest);
- while (pi) {
- if (pi->extra && pi->extra->damp_info) {
- pi_temp = pi->next;
- bgp_damp_info_free(
- pi->extra->damp_info,
- 1, afi, safi);
- pi = pi_temp;
- } else
- pi = pi->next;
- }
+ const struct prefix *dest_p = bgp_dest_get_prefix(dest);
+
+ if (prefix_check || dest_p->prefixlen != match.prefixlen)
+ return CMD_SUCCESS;
+
+ pi = bgp_dest_get_bgp_path_info(dest);
+ while (pi) {
+ if (!(pi->extra && pi->extra->damp_info)) {
+ pi = pi->next;
+ continue;
}
- bgp_dest_unlock_node(dest);
+ pi_temp = pi->next;
+ struct bgp_damp_info *bdi = pi->extra->damp_info;
+
+ if (bdi->lastrecord != BGP_RECORD_UPDATE)
+ continue;
+
+ bgp_aggregate_increment(bgp,
+ bgp_dest_get_prefix(bdi->dest),
+ bdi->path, bdi->afi, bdi->safi);
+ bgp_process(bgp, bdi->dest, bdi->path, bdi->afi,
+ bdi->safi);
+
+ bgp_damp_info_free(pi->extra->damp_info, NULL, 1);
+ pi = pi_temp;
}
+
+ bgp_dest_unlock_node(dest);
}
return CMD_SUCCESS;
@@ -15542,7 +15887,9 @@ DEFUN (clear_ip_bgp_dampening,
BGP_STR
"Clear route flap dampening information\n")
{
- bgp_damp_info_clean(AFI_IP, SAFI_UNICAST);
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
+ bgp_damp_info_clean(bgp, &bgp->damp[AFI_IP][SAFI_UNICAST], AFI_IP,
+ SAFI_UNICAST);
return CMD_SUCCESS;
}
diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h
index 2929c75..89449ac 100644
--- a/bgpd/bgp_route.h
+++ b/bgpd/bgp_route.h
@@ -59,20 +59,15 @@ enum bgp_show_adj_route_type {
#define BGP_SHOW_SCODE_HEADER \
"Status codes: s suppressed, d damped, " \
- "h history, * valid, > best, = multipath,\n" \
+ "h history, u unsorted, * valid, > best, = multipath,\n" \
" i internal, r RIB-failure, S Stale, R Removed\n"
#define BGP_SHOW_OCODE_HEADER \
"Origin codes: i - IGP, e - EGP, ? - incomplete\n"
#define BGP_SHOW_NCODE_HEADER "Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self\n"
#define BGP_SHOW_RPKI_HEADER \
"RPKI validation codes: V valid, I invalid, N Not found\n\n"
-#define BGP_SHOW_HEADER " Network Next Hop Metric LocPrf Weight Path\n"
-#define BGP_SHOW_HEADER_WIDE " Network Next Hop Metric LocPrf Weight Path\n"
-
-/* Maximum number of labels we can process or send with a prefix. We
- * really do only 1 for MPLS (BGP-LU) but we can do 2 for EVPN-VxLAN.
- */
-#define BGP_MAX_LABELS 2
+#define BGP_SHOW_HEADER " Network Next Hop Metric LocPrf Weight Path\n"
+#define BGP_SHOW_HEADER_WIDE " Network Next Hop Metric LocPrf Weight Path\n"
/* Maximum number of sids we can process or send with a prefix. */
#define BGP_MAX_SIDS 6
@@ -237,8 +232,7 @@ struct bgp_path_info_extra {
uint32_t igpmetric;
/* MPLS label(s) - VNI(s) for EVPN-VxLAN */
- mpls_label_t label[BGP_MAX_LABELS];
- uint32_t num_labels;
+ struct bgp_labels *labels;
/* timestamp of the rib installation */
time_t bgp_rib_uptime;
@@ -327,6 +321,7 @@ struct bgp_path_info {
#define BGP_PATH_ACCEPT_OWN (1 << 16)
#define BGP_PATH_MPLSVPN_LABEL_NH (1 << 17)
#define BGP_PATH_MPLSVPN_NH_LABEL_BIND (1 << 18)
+#define BGP_PATH_UNSORTED (1 << 19)
/* BGP route type. This can be static, RIP, OSPF, BGP etc. */
uint8_t type;
@@ -345,6 +340,8 @@ struct bgp_path_info {
unsigned short instance;
+ enum bgp_path_selection_reason reason;
+
/* Addpath identifiers */
uint32_t addpath_rx_id;
struct bgp_addpath_info_data tx_addpath;
@@ -750,12 +747,16 @@ extern void bgp_path_info_delete(struct bgp_dest *dest,
struct bgp_path_info *pi);
extern struct bgp_path_info_extra *
bgp_path_info_extra_get(struct bgp_path_info *path);
+extern bool bgp_path_info_has_valid_label(const struct bgp_path_info *path);
+extern uint8_t bgp_path_info_num_labels(const struct bgp_path_info *pi);
extern void bgp_path_info_set_flag(struct bgp_dest *dest,
struct bgp_path_info *path, uint32_t flag);
extern void bgp_path_info_unset_flag(struct bgp_dest *dest,
struct bgp_path_info *path, uint32_t flag);
extern void bgp_path_info_path_with_addpath_rx_str(struct bgp_path_info *pi,
char *buf, size_t buf_len);
+extern bool bgp_path_info_labels_same(const struct bgp_path_info *bpi,
+ const mpls_label_t *label, uint32_t n);
extern int bgp_nlri_parse_ip(struct peer *, struct attr *, struct bgp_nlri *);
@@ -792,16 +793,17 @@ extern void 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,
+ uint8_t num_labels, int soft_reconfig,
struct bgp_route_evpn *evpn);
extern void bgp_withdraw(struct peer *peer, const struct prefix *p,
uint32_t addpath_id, afi_t afi, safi_t safi, int type,
int sub_type, struct prefix_rd *prd,
- mpls_label_t *label, uint32_t num_labels,
+ mpls_label_t *label, uint8_t num_labels,
struct bgp_route_evpn *evpn);
/* for bgp_nexthop and bgp_damp */
-extern void bgp_process(struct bgp *, struct bgp_dest *, afi_t, safi_t);
+extern void bgp_process(struct bgp *bgp, struct bgp_dest *dest,
+ struct bgp_path_info *pi, afi_t afi, safi_t safi);
/*
* Add an end-of-initial-update marker to the process queue. This is just a
diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c
index dbc3d64..97ae92c 100644
--- a/bgpd/bgp_routemap.c
+++ b/bgpd/bgp_routemap.c
@@ -1056,7 +1056,7 @@ static enum route_map_cmd_result_t
route_match_vni(void *rule, const struct prefix *prefix, void *object)
{
vni_t vni = 0;
- unsigned int label_cnt = 0;
+ unsigned int label_cnt;
struct bgp_path_info *path = NULL;
struct prefix_evpn *evp = (struct prefix_evpn *) prefix;
@@ -1081,13 +1081,10 @@ route_match_vni(void *rule, const struct prefix *prefix, void *object)
&& evp->prefix.route_type != BGP_EVPN_IP_PREFIX_ROUTE))
return RMAP_NOOP;
- if (path->extra == NULL)
- return RMAP_NOMATCH;
-
- for (;
- label_cnt < BGP_MAX_LABELS && label_cnt < path->extra->num_labels;
+ for (label_cnt = 0; label_cnt < BGP_MAX_LABELS &&
+ label_cnt < bgp_path_info_num_labels(path);
label_cnt++) {
- if (vni == label2vni(&path->extra->label[label_cnt]))
+ if (vni == label2vni(&path->extra->labels->label[label_cnt]))
return RMAP_MATCH;
}
@@ -1944,7 +1941,6 @@ route_set_srte_color(void *rule, const struct prefix *prefix, void *object)
path = object;
path->attr->srte_color = *srte_color;
- path->attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_SRTE_COLOR);
return RMAP_OKAY;
}
@@ -2326,7 +2322,7 @@ static const struct route_map_rule_cmd route_set_aspath_prepend_cmd = {
static void *route_aspath_exclude_compile(const char *arg)
{
struct aspath_exclude *ase;
- struct aspath_exclude_list *ael;
+ struct as_list *aux_aslist;
const char *str = arg;
static const char asp_acl[] = "as-path-access-list";
@@ -2338,44 +2334,37 @@ static void *route_aspath_exclude_compile(const char *arg)
while (*str == ' ')
str++;
ase->exclude_aspath_acl_name = XSTRDUP(MTYPE_TMP, str);
- ase->exclude_aspath_acl = as_list_lookup(str);
+ aux_aslist = as_list_lookup(str);
+ if (!aux_aslist)
+ /* new orphan filter */
+ as_exclude_set_orphan(ase);
+ else
+ as_list_list_add_head(&aux_aslist->exclude_rule, ase);
+
+ ase->exclude_aspath_acl = aux_aslist;
} else
ase->aspath = aspath_str2aspath(str, bgp_get_asnotation(NULL));
- if (ase->exclude_aspath_acl) {
- ael = XCALLOC(MTYPE_ROUTE_MAP_COMPILED,
- sizeof(struct aspath_exclude_list));
- ael->bp_as_excl = ase;
- ael->next = ase->exclude_aspath_acl->exclude_list;
- ase->exclude_aspath_acl->exclude_list = ael;
- }
-
return ase;
}
static void route_aspath_exclude_free(void *rule)
{
struct aspath_exclude *ase = rule;
- struct aspath_exclude_list *cur_ael = NULL;
- struct aspath_exclude_list *prev_ael = NULL;
+ struct as_list *acl;
+
+ /* manage references to that rule*/
+ if (ase->exclude_aspath_acl) {
+ acl = ase->exclude_aspath_acl;
+ as_list_list_del(&acl->exclude_rule, ase);
+ } else {
+ /* no ref to acl, this aspath exclude is orphan */
+ as_exclude_remove_orphan(ase);
+ }
aspath_free(ase->aspath);
if (ase->exclude_aspath_acl_name)
XFREE(MTYPE_TMP, ase->exclude_aspath_acl_name);
- if (ase->exclude_aspath_acl)
- cur_ael = ase->exclude_aspath_acl->exclude_list;
- while (cur_ael) {
- if (cur_ael->bp_as_excl == ase) {
- if (prev_ael)
- prev_ael->next = cur_ael->next;
- else
- ase->exclude_aspath_acl->exclude_list = NULL;
- XFREE(MTYPE_ROUTE_MAP_COMPILED, cur_ael);
- break;
- }
- prev_ael = cur_ael;
- cur_ael = cur_ael->next;
- }
XFREE(MTYPE_ROUTE_MAP_COMPILED, ase);
}
@@ -2410,16 +2399,10 @@ route_set_aspath_exclude(void *rule, const struct prefix *dummy, void *object)
else if (ase->exclude_all)
path->attr->aspath = aspath_filter_exclude_all(new_path);
- else if (ase->exclude_aspath_acl_name) {
- if (!ase->exclude_aspath_acl)
- ase->exclude_aspath_acl =
- as_list_lookup(ase->exclude_aspath_acl_name);
- if (ase->exclude_aspath_acl)
- path->attr->aspath =
- aspath_filter_exclude_acl(new_path,
- ase->exclude_aspath_acl);
- }
-
+ else if (ase->exclude_aspath_acl)
+ path->attr->aspath =
+ aspath_filter_exclude_acl(new_path,
+ ase->exclude_aspath_acl);
return RMAP_OKAY;
}
@@ -3196,7 +3179,7 @@ struct rmap_ecomm_lb_set {
#define RMAP_ECOMM_LB_SET_CUMUL 2
#define RMAP_ECOMM_LB_SET_NUM_MPATH 3
bool non_trans;
- uint32_t bw;
+ uint64_t bw;
};
static enum route_map_cmd_result_t
@@ -3206,8 +3189,7 @@ route_set_ecommunity_lb(void *rule, const struct prefix *prefix, void *object)
struct bgp_path_info *path;
struct peer *peer;
struct ecommunity ecom_lb = {0};
- struct ecommunity_val lb_eval;
- uint32_t bw_bytes = 0;
+ uint64_t bw_bytes = 0;
uint16_t mpath_count = 0;
struct ecommunity *new_ecom;
struct ecommunity *old_ecom;
@@ -3221,13 +3203,13 @@ route_set_ecommunity_lb(void *rule, const struct prefix *prefix, void *object)
/* Build link bandwidth extended community */
as = (peer->bgp->as > BGP_AS_MAX) ? BGP_AS_TRANS : peer->bgp->as;
if (rels->lb_type == RMAP_ECOMM_LB_SET_VALUE) {
- bw_bytes = ((uint64_t)rels->bw * 1000 * 1000) / 8;
+ bw_bytes = (rels->bw * 1000 * 1000) / 8;
} else if (rels->lb_type == RMAP_ECOMM_LB_SET_CUMUL) {
/* process this only for the best path. */
if (!CHECK_FLAG(path->flags, BGP_PATH_SELECTED))
return RMAP_OKAY;
- bw_bytes = (uint32_t)bgp_path_info_mpath_cumbw(path);
+ bw_bytes = bgp_path_info_mpath_cumbw(path);
if (!bw_bytes)
return RMAP_OKAY;
@@ -3237,31 +3219,53 @@ route_set_ecommunity_lb(void *rule, const struct prefix *prefix, void *object)
if (!CHECK_FLAG(path->flags, BGP_PATH_SELECTED))
return RMAP_OKAY;
- bw_bytes = ((uint64_t)peer->bgp->lb_ref_bw * 1000 * 1000) / 8;
+ bw_bytes = (peer->bgp->lb_ref_bw * 1000 * 1000) / 8;
mpath_count = bgp_path_info_mpath_count(path) + 1;
bw_bytes *= mpath_count;
}
- encode_lb_extcomm(as, bw_bytes, rels->non_trans, &lb_eval,
- CHECK_FLAG(peer->flags,
- PEER_FLAG_DISABLE_LINK_BW_ENCODING_IEEE));
+ if (CHECK_FLAG(peer->flags, PEER_FLAG_EXTENDED_LINK_BANDWIDTH)) {
+ struct ecommunity_val_ipv6 lb_eval;
- /* add to route or merge with existing */
- old_ecom = bgp_attr_get_ecommunity(path->attr);
- if (old_ecom) {
- new_ecom = ecommunity_dup(old_ecom);
- ecommunity_add_val(new_ecom, &lb_eval, true, true);
- if (!old_ecom->refcnt)
- ecommunity_free(&old_ecom);
+ encode_lb_extended_extcomm(as, bw_bytes, rels->non_trans,
+ &lb_eval);
+
+ old_ecom = bgp_attr_get_ipv6_ecommunity(path->attr);
+ if (old_ecom) {
+ new_ecom = ecommunity_dup(old_ecom);
+ ecommunity_add_val_ipv6(new_ecom, &lb_eval, true, true);
+ if (!old_ecom->refcnt)
+ ecommunity_free(&old_ecom);
+ } else {
+ ecom_lb.size = 1;
+ ecom_lb.unit_size = IPV6_ECOMMUNITY_SIZE;
+ ecom_lb.val = (uint8_t *)lb_eval.val;
+ new_ecom = ecommunity_dup(&ecom_lb);
+ }
+
+ bgp_attr_set_ipv6_ecommunity(path->attr, new_ecom);
} else {
- ecom_lb.size = 1;
- ecom_lb.unit_size = ECOMMUNITY_SIZE;
- ecom_lb.val = (uint8_t *)lb_eval.val;
- new_ecom = ecommunity_dup(&ecom_lb);
- }
+ struct ecommunity_val lb_eval;
+
+ encode_lb_extcomm(as, bw_bytes, rels->non_trans, &lb_eval,
+ CHECK_FLAG(peer->flags,
+ PEER_FLAG_DISABLE_LINK_BW_ENCODING_IEEE));
+
+ old_ecom = bgp_attr_get_ecommunity(path->attr);
+ if (old_ecom) {
+ new_ecom = ecommunity_dup(old_ecom);
+ ecommunity_add_val(new_ecom, &lb_eval, true, true);
+ if (!old_ecom->refcnt)
+ ecommunity_free(&old_ecom);
+ } else {
+ ecom_lb.size = 1;
+ ecom_lb.unit_size = ECOMMUNITY_SIZE;
+ ecom_lb.val = (uint8_t *)lb_eval.val;
+ new_ecom = ecommunity_dup(&ecom_lb);
+ }
- /* new_ecom will be intern()'d or attr_flush()'d in call stack */
- bgp_attr_set_ecommunity(path->attr, new_ecom);
+ bgp_attr_set_ecommunity(path->attr, new_ecom);
+ }
/* Mark that route-map has set link bandwidth; used in attribute
* setting decisions.
@@ -3275,7 +3279,7 @@ static void *route_set_ecommunity_lb_compile(const char *arg)
{
struct rmap_ecomm_lb_set *rels;
uint8_t lb_type;
- uint32_t bw = 0;
+ uint64_t bw = 0;
char bw_str[40] = {0};
char *p, *str;
bool non_trans = false;
@@ -3317,13 +3321,8 @@ static enum route_map_cmd_result_t
route_set_ecommunity_color(void *rule, const struct prefix *prefix,
void *object)
{
- struct bgp_path_info *path;
-
- path = object;
-
route_set_ecommunity(rule, prefix, object);
- path->attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_SRTE_COLOR);
return RMAP_OKAY;
}
@@ -3953,11 +3952,11 @@ route_set_ipv6_nexthop_prefer_global(void *rule, const struct prefix *prefix,
if (CHECK_FLAG(peer->rmap_type, PEER_RMAP_TYPE_IN)
|| CHECK_FLAG(peer->rmap_type, PEER_RMAP_TYPE_IMPORT)) {
/* Set next hop preference to global */
- path->attr->mp_nexthop_prefer_global = true;
+ SET_FLAG(path->attr->nh_flags, BGP_ATTR_NH_MP_PREFER_GLOBAL);
SET_FLAG(path->attr->rmap_change_flags,
BATTR_RMAP_IPV6_PREFER_GLOBAL_CHANGED);
} else {
- path->attr->mp_nexthop_prefer_global = false;
+ UNSET_FLAG(path->attr->nh_flags, BGP_ATTR_NH_MP_PREFER_GLOBAL);
SET_FLAG(path->attr->rmap_change_flags,
BATTR_RMAP_IPV6_PREFER_GLOBAL_CHANGED);
}
@@ -6880,7 +6879,7 @@ DEFUN_YANG(no_set_ecommunity_none, no_set_ecommunity_none_cmd,
DEFUN_YANG (set_ecommunity_lb,
set_ecommunity_lb_cmd,
- "set extcommunity bandwidth <(1-25600)|cumulative|num-multipaths> [non-transitive]",
+ "set extcommunity bandwidth <(1-4294967295)|cumulative|num-multipaths> [non-transitive]",
SET_STR
"BGP extended community attribute\n"
"Link bandwidth extended community\n"
@@ -6934,7 +6933,7 @@ DEFUN_YANG (set_ecommunity_lb,
DEFUN_YANG (no_set_ecommunity_lb,
no_set_ecommunity_lb_cmd,
- "no set extcommunity bandwidth <(1-25600)|cumulative|num-multipaths> [non-transitive]",
+ "no set extcommunity bandwidth <(1-4294967295)|cumulative|num-multipaths> [non-transitive]",
NO_STR
SET_STR
"BGP extended community attribute\n"
diff --git a/bgpd/bgp_routemap_nb_config.c b/bgpd/bgp_routemap_nb_config.c
index c1d6ee1..15c32ea 100644
--- a/bgpd/bgp_routemap_nb_config.c
+++ b/bgpd/bgp_routemap_nb_config.c
@@ -2937,7 +2937,7 @@ lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_finish(
struct routemap_hook_context *rhc;
enum ecommunity_lb_type lb_type;
char str[VTY_BUFSIZ];
- uint16_t bandwidth;
+ uint32_t bandwidth;
int ret;
/* Add configuration. */
@@ -2951,8 +2951,8 @@ lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_finish(
switch (lb_type) {
case EXPLICIT_BANDWIDTH:
- bandwidth = yang_dnode_get_uint16(args->dnode, "bandwidth");
- snprintf(str, sizeof(str), "%d", bandwidth);
+ bandwidth = yang_dnode_get_uint32(args->dnode, "bandwidth");
+ snprintf(str, sizeof(str), "%u", bandwidth);
break;
case CUMULATIVE_BANDWIDTH:
snprintf(str, sizeof(str), "%s", "cumulative");
diff --git a/bgpd/bgp_rpki.c b/bgpd/bgp_rpki.c
index 22f78fb..a487f49 100644
--- a/bgpd/bgp_rpki.c
+++ b/bgpd/bgp_rpki.c
@@ -29,6 +29,7 @@
#include "bgpd/bgpd.h"
#include "bgpd/bgp_table.h"
#include "bgp_advertise.h"
+#include "bgp_label.h"
#include "bgpd/bgp_debug.h"
#include "bgpd/bgp_attr.h"
#include "bgpd/bgp_aspath.h"
@@ -656,17 +657,16 @@ static void revalidate_bgp_node(struct bgp_dest *bgp_dest, afi_t afi,
safi_t safi)
{
struct bgp_adj_in *ain;
+ mpls_label_t *label;
+ uint8_t num_labels;
for (ain = bgp_dest->adj_in; ain; ain = ain->next) {
struct bgp_path_info *path =
bgp_dest_get_bgp_path_info(bgp_dest);
- mpls_label_t *label = NULL;
- uint32_t num_labels = 0;
- if (path && path->extra) {
- label = path->extra->label;
- num_labels = path->extra->num_labels;
- }
+ num_labels = bgp_path_info_num_labels(path);
+ label = num_labels ? path->extra->labels->label : NULL;
+
(void)bgp_update(ain->peer, bgp_dest_get_prefix(bgp_dest),
ain->addpath_rx_id, ain->attr, afi, safi,
ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL, label,
@@ -1082,7 +1082,7 @@ static void print_prefix_table(struct vty *vty, struct rpki_vrf *rpki_vrf,
unsigned int number_of_ipv4_prefixes = 0;
unsigned int number_of_ipv6_prefixes = 0;
- struct rtr_mgr_group *group = get_connected_group(rpki_vrf);
+ struct rtr_mgr_group *group;
json_object *json_records = NULL;
if (!rpki_vrf)
@@ -1621,7 +1621,7 @@ static int bgp_rpki_write_vrf(struct vty *vty, struct vrf *vrf)
#endif
case TCP:
tcp_config = cache->tr_config.tcp_config;
- vty_out(vty, "%s rpki cache %s %s ", sep,
+ vty_out(vty, "%s rpki cache tcp %s %s ", sep,
tcp_config->host, tcp_config->port);
if (tcp_config->bindaddr)
vty_out(vty, "source %s ",
@@ -1630,7 +1630,7 @@ static int bgp_rpki_write_vrf(struct vty *vty, struct vrf *vrf)
#if defined(FOUND_SSH)
case SSH:
ssh_config = cache->tr_config.ssh_config;
- vty_out(vty, "%s rpki cache %s %u %s %s %s ", sep,
+ vty_out(vty, "%s rpki cache ssh %s %u %s %s %s ", sep,
ssh_config->host, ssh_config->port,
ssh_config->username,
ssh_config->client_privkey_path,
@@ -1918,8 +1918,11 @@ DEFUN (no_rpki_retry_interval,
return CMD_SUCCESS;
}
+#if CONFDATE > 20240916
+CPP_NOTICE("Remove rpki_cache_cmd")
+#endif
DEFPY(rpki_cache, rpki_cache_cmd,
- "rpki cache <A.B.C.D|WORD> <TCPPORT|(1-65535)$sshport SSH_UNAME SSH_PRIVKEY [SERVER_PUBKEY]> [source <A.B.C.D>$bindaddr] preference (1-255)",
+ "rpki cache <A.B.C.D|WORD> <TCPPORT|(1-65535)$sshport SSH_UNAME SSH_PRIVKEY [KNOWN_HOSTS_PATH]> [source <A.B.C.D>$bindaddr] preference (1-255)",
RPKI_OUTPUT_STRING
"Install a cache server to current group\n"
"IP address of cache server\n"
@@ -1928,7 +1931,7 @@ DEFPY(rpki_cache, rpki_cache_cmd,
"SSH port number\n"
"SSH user name\n"
"Path to own SSH private key\n"
- "Path to Public key of cache server\n"
+ "Path to the known hosts file\n"
"Configure source IP address of RPKI connection\n"
"Define a Source IP Address\n"
"Preference of the cache server\n"
@@ -1967,7 +1970,7 @@ DEFPY(rpki_cache, rpki_cache_cmd,
if (ssh_uname) {
#if defined(FOUND_SSH)
return_value = add_ssh_cache(rpki_vrf, cache, sshport, ssh_uname,
- ssh_privkey, server_pubkey,
+ ssh_privkey, known_hosts_path,
preference, bindaddr_str);
#else
return_value = SUCCESS;
@@ -1990,19 +1993,143 @@ DEFPY(rpki_cache, rpki_cache_cmd,
return CMD_SUCCESS;
}
+DEFPY(rpki_cache_tcp, rpki_cache_tcp_cmd,
+ "rpki cache tcp <A.B.C.D|WORD>$cache TCPPORT [source <A.B.C.D>$bindaddr] preference (1-255)",
+ RPKI_OUTPUT_STRING
+ "Install a cache server to current group\n"
+ "Use TCP\n"
+ "IP address of cache server\n"
+ "Hostname of cache server\n"
+ "TCP port number\n"
+ "Configure source IP address of RPKI connection\n"
+ "Define a Source IP Address\n"
+ "Preference of the cache server\n"
+ "Preference value\n")
+{
+ int return_value;
+ struct listnode *cache_node;
+ struct cache *current_cache;
+ struct rpki_vrf *rpki_vrf;
+ bool init;
+
+ if (vty->node == RPKI_VRF_NODE)
+ rpki_vrf = VTY_GET_CONTEXT_SUB(rpki_vrf);
+ else
+ rpki_vrf = VTY_GET_CONTEXT(rpki_vrf);
+
+ if (!rpki_vrf)
+ return CMD_WARNING_CONFIG_FAILED;
+
+ if (!rpki_vrf || !rpki_vrf->cache_list)
+ return CMD_WARNING;
+
+ init = !!list_isempty(rpki_vrf->cache_list);
+
+ for (ALL_LIST_ELEMENTS_RO(rpki_vrf->cache_list, cache_node,
+ current_cache)) {
+ if (current_cache->preference == preference) {
+ vty_out(vty,
+ "Cache with preference %ld is already configured\n",
+ preference);
+ return CMD_WARNING;
+ }
+ }
+
+ return_value = add_tcp_cache(rpki_vrf, cache, tcpport, preference,
+ bindaddr_str);
+
+ if (return_value == ERROR) {
+ vty_out(vty, "Could not create new rpki cache\n");
+ return CMD_WARNING;
+ }
+
+ if (init)
+ start(rpki_vrf);
+
+ return CMD_SUCCESS;
+}
+
+DEFPY(rpki_cache_ssh, rpki_cache_ssh_cmd,
+ "rpki cache ssh <A.B.C.D|WORD>$cache (1-65535)$sshport SSH_UNAME SSH_PRIVKEY [KNOWN_HOSTS_PATH] [source <A.B.C.D>$bindaddr] preference (1-255)",
+ RPKI_OUTPUT_STRING
+ "Install a cache server to current group\n"
+ "Use SSH\n"
+ "IP address of cache server\n"
+ "Hostname of cache server\n"
+ "SSH port number\n"
+ "SSH user name\n"
+ "Path to own SSH private key\n"
+ "Path to the known hosts file\n"
+ "Configure source IP address of RPKI connection\n"
+ "Define a Source IP Address\n"
+ "Preference of the cache server\n"
+ "Preference value\n")
+{
+ int return_value;
+ struct listnode *cache_node;
+ struct cache *current_cache;
+ struct rpki_vrf *rpki_vrf;
+ bool init;
+
+ if (vty->node == RPKI_VRF_NODE)
+ rpki_vrf = VTY_GET_CONTEXT_SUB(rpki_vrf);
+ else
+ rpki_vrf = VTY_GET_CONTEXT(rpki_vrf);
+
+ if (!rpki_vrf)
+ return CMD_WARNING_CONFIG_FAILED;
+
+ if (!rpki_vrf || !rpki_vrf->cache_list)
+ return CMD_WARNING;
+
+ init = !!list_isempty(rpki_vrf->cache_list);
+
+ for (ALL_LIST_ELEMENTS_RO(rpki_vrf->cache_list, cache_node,
+ current_cache)) {
+ if (current_cache->preference == preference) {
+ vty_out(vty,
+ "Cache with preference %ld is already configured\n",
+ preference);
+ return CMD_WARNING;
+ }
+ }
+
+#if defined(FOUND_SSH)
+ return_value = add_ssh_cache(rpki_vrf, cache, sshport, ssh_uname,
+ ssh_privkey, known_hosts_path, preference,
+ bindaddr_str);
+#else
+ return_value = SUCCESS;
+ vty_out(vty,
+ "ssh sockets are not supported. Please recompile rtrlib and frr with ssh support. If you want to use it\n");
+#endif
+
+ if (return_value == ERROR) {
+ vty_out(vty, "Could not create new rpki cache\n");
+ return CMD_WARNING;
+ }
+
+ if (init)
+ start(rpki_vrf);
+
+ return CMD_SUCCESS;
+}
+
DEFPY (no_rpki_cache,
no_rpki_cache_cmd,
- "no rpki cache <A.B.C.D|WORD> <TCPPORT|(1-65535)$sshport SSH_UNAME SSH_PRIVKEY [SERVER_PUBKEY]> [source <A.B.C.D>$bindaddr] preference (1-255)",
+ "no rpki cache <tcp|ssh> <A.B.C.D|WORD> <TCPPORT|(1-65535)$sshport SSH_UNAME SSH_PRIVKEY [KNOWN_HOSTS_PATH]> [source <A.B.C.D>$bindaddr] preference (1-255)",
NO_STR
RPKI_OUTPUT_STRING
"Install a cache server to current group\n"
+ "Use TCP\n"
+ "Use SSH\n"
"IP address of cache server\n"
"Hostname of cache server\n"
"TCP port number\n"
"SSH port number\n"
"SSH user name\n"
"Path to own SSH private key\n"
- "Path to Public key of cache server\n"
+ "Path to the known hosts file\n"
"Configure source IP address of RPKI connection\n"
"Define a Source IP Address\n"
"Preference of the cache server\n"
@@ -2088,16 +2215,18 @@ DEFPY (show_rpki_prefix_table,
DEFPY (show_rpki_as_number,
show_rpki_as_number_cmd,
- "show rpki as-number ASNUM$by_asn [vrf NAME$vrfname] [json$uj]",
+ "show rpki as-number <0$zero|ASNUM$by_asn> [vrf NAME$vrfname] [json$uj]",
SHOW_STR
RPKI_OUTPUT_STRING
"Lookup by ASN in prefix table\n"
+ "AS Number of 0, see RFC-7607\n"
"AS Number\n"
VRF_CMD_HELP_STR
JSON_STR)
{
struct json_object *json = NULL;
struct rpki_vrf *rpki_vrf;
+ as_t as;
if (uj)
json = json_object_new_object();
@@ -2118,18 +2247,24 @@ DEFPY (show_rpki_as_number,
return CMD_WARNING;
}
- print_prefix_table_by_asn(vty, by_asn, rpki_vrf, json);
+ if (zero)
+ as = 0;
+ else
+ as = by_asn;
+
+ print_prefix_table_by_asn(vty, as, rpki_vrf, json);
return CMD_SUCCESS;
}
DEFPY (show_rpki_prefix,
show_rpki_prefix_cmd,
- "show rpki prefix <A.B.C.D/M|X:X::X:X/M> [ASNUM$asn] [vrf NAME$vrfname] [json$uj]",
+ "show rpki prefix <A.B.C.D/M|X:X::X:X/M> [0$zero|ASNUM$asn] [vrf NAME$vrfname] [json$uj]",
SHOW_STR
RPKI_OUTPUT_STRING
"Lookup IP prefix and optionally ASN in prefix table\n"
"IPv4 prefix\n"
"IPv6 prefix\n"
+ "AS Number of 0, see RFC-7607\n"
"AS Number\n"
VRF_CMD_HELP_STR
JSON_STR)
@@ -2138,6 +2273,7 @@ DEFPY (show_rpki_prefix,
json_object *json_records = NULL;
enum asnotation_mode asnotation;
struct rpki_vrf *rpki_vrf;
+ as_t as;
if (uj)
json = json_object_new_object();
@@ -2153,6 +2289,11 @@ DEFPY (show_rpki_prefix,
return CMD_WARNING;
}
+ if (zero)
+ as = 0;
+ else
+ as = asn;
+
struct lrtr_ip_addr addr;
char addr_str[INET6_ADDRSTRLEN];
size_t addr_len = strchr(prefix_str, '/') - prefix_str;
@@ -2174,7 +2315,7 @@ DEFPY (show_rpki_prefix,
enum pfxv_state result;
if (pfx_table_validate_r(rpki_vrf->rtr_config->pfx_table, &matches,
- &match_count, asn, &addr, prefix->prefixlen,
+ &match_count, as, &addr, prefix->prefixlen,
&result) != PFX_SUCCESS) {
if (json) {
json_object_string_add(json, "error", "Prefix lookup failed.");
@@ -2198,7 +2339,7 @@ DEFPY (show_rpki_prefix,
const struct pfx_record *record = &matches[i];
if (record->max_len >= prefix->prefixlen &&
- ((asn != 0 && (uint32_t)asn == record->asn) || asn == 0)) {
+ ((as != 0 && (uint32_t)as == record->asn) || asn == 0)) {
print_record(&matches[i], vty, json_records,
asnotation);
}
@@ -2243,10 +2384,16 @@ DEFPY (show_rpki_cache_server,
if (cache->type == TCP) {
if (!json) {
vty_out(vty,
- "host: %s port: %s, preference: %hhu\n",
+ "host: %s port: %s, preference: %hhu, protocol: tcp",
cache->tr_config.tcp_config->host,
cache->tr_config.tcp_config->port,
cache->preference);
+ if (cache->tr_config.tcp_config->bindaddr)
+ vty_out(vty, ", source: %s\n",
+ cache->tr_config.tcp_config
+ ->bindaddr);
+ else
+ vty_out(vty, "\n");
} else {
json_server = json_object_new_object();
json_object_string_add(json_server, "mode",
@@ -2259,6 +2406,12 @@ DEFPY (show_rpki_cache_server,
cache->tr_config.tcp_config->port);
json_object_int_add(json_server, "preference",
cache->preference);
+ if (cache->tr_config.tcp_config->bindaddr)
+ json_object_string_add(json_server,
+ "source",
+ cache->tr_config
+ .tcp_config
+ ->bindaddr);
json_object_array_add(json_servers,
json_server);
}
@@ -2267,7 +2420,7 @@ DEFPY (show_rpki_cache_server,
} else if (cache->type == SSH) {
if (!json) {
vty_out(vty,
- "host: %s port: %d username: %s server_hostkey_path: %s client_privkey_path: %s, preference: %hhu\n",
+ "host: %s, port: %d, username: %s, server_hostkey_path: %s, client_privkey_path: %s, preference: %hhu, protocol: ssh",
cache->tr_config.ssh_config->host,
cache->tr_config.ssh_config->port,
cache->tr_config.ssh_config->username,
@@ -2276,6 +2429,12 @@ DEFPY (show_rpki_cache_server,
cache->tr_config.ssh_config
->client_privkey_path,
cache->preference);
+ if (cache->tr_config.ssh_config->bindaddr)
+ vty_out(vty, ", source: %s\n",
+ cache->tr_config.ssh_config
+ ->bindaddr);
+ else
+ vty_out(vty, "\n");
} else {
json_server = json_object_new_object();
json_object_string_add(json_server, "mode",
@@ -2299,6 +2458,12 @@ DEFPY (show_rpki_cache_server,
->client_privkey_path);
json_object_int_add(json_server, "preference",
cache->preference);
+ if (cache->tr_config.ssh_config->bindaddr)
+ json_object_string_add(json_server,
+ "source",
+ cache->tr_config
+ .ssh_config
+ ->bindaddr);
json_object_array_add(json_servers,
json_server);
}
@@ -2651,6 +2816,8 @@ static void install_cli_commands(void)
install_element(RPKI_NODE, &no_rpki_retry_interval_cmd);
/* Install rpki cache commands */
+ install_element(RPKI_NODE, &rpki_cache_tcp_cmd);
+ install_element(RPKI_NODE, &rpki_cache_ssh_cmd);
install_element(RPKI_NODE, &rpki_cache_cmd);
install_element(RPKI_NODE, &no_rpki_cache_cmd);
@@ -2673,6 +2840,8 @@ static void install_cli_commands(void)
install_element(RPKI_VRF_NODE, &no_rpki_retry_interval_cmd);
/* Install rpki cache commands */
+ install_element(RPKI_VRF_NODE, &rpki_cache_tcp_cmd);
+ install_element(RPKI_VRF_NODE, &rpki_cache_ssh_cmd);
install_element(RPKI_VRF_NODE, &rpki_cache_cmd);
install_element(RPKI_VRF_NODE, &no_rpki_cache_cmd);
diff --git a/bgpd/bgp_snmp_bgp4v2.c b/bgpd/bgp_snmp_bgp4v2.c
index 0c8ed33..7036910 100644
--- a/bgpd/bgp_snmp_bgp4v2.c
+++ b/bgpd/bgp_snmp_bgp4v2.c
@@ -853,7 +853,8 @@ static uint8_t *bgp4v2PathAttrTable(struct variable *v, oid name[],
case BGP_ATTR_NHLEN_IPV6_GLOBAL:
return SNMP_INTEGER(2);
case BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL:
- if (path->attr->mp_nexthop_prefer_global)
+ if (CHECK_FLAG(path->attr->nh_flags,
+ BGP_ATTR_NH_MP_PREFER_GLOBAL))
return SNMP_INTEGER(2);
else
return SNMP_INTEGER(4);
@@ -867,7 +868,8 @@ static uint8_t *bgp4v2PathAttrTable(struct variable *v, oid name[],
case BGP_ATTR_NHLEN_IPV6_GLOBAL:
return SNMP_IP6ADDRESS(path->attr->mp_nexthop_global);
case BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL:
- if (path->attr->mp_nexthop_prefer_global)
+ if (CHECK_FLAG(path->attr->nh_flags,
+ BGP_ATTR_NH_MP_PREFER_GLOBAL))
return SNMP_IP6ADDRESS(
path->attr->mp_nexthop_global);
else
diff --git a/bgpd/bgp_table.c b/bgpd/bgp_table.c
index 8465ada..781909b 100644
--- a/bgpd/bgp_table.c
+++ b/bgpd/bgp_table.c
@@ -239,7 +239,11 @@ static ssize_t printfrr_bd(struct fbuf *buf, struct printfrr_eargs *ea,
if (!dest)
return bputs(buf, "(null)");
+#if !defined(DEV_BUILD)
/* need to get the real length even if buffer too small */
prefix2str(p, cbuf, sizeof(cbuf));
return bputs(buf, cbuf);
+#else
+ return bprintfrr(buf, "%s(%p)", prefix2str(p, cbuf, sizeof(cbuf)), dest);
+#endif
}
diff --git a/bgpd/bgp_table.h b/bgpd/bgp_table.h
index 5b4c3be..130f5ca 100644
--- a/bgpd/bgp_table.h
+++ b/bgpd/bgp_table.h
@@ -76,6 +76,11 @@ struct bgp_dest {
STAILQ_ENTRY(bgp_dest) pq;
+ struct zebra_announce_item zai;
+ struct bgp_path_info *za_bgp_pi;
+ struct bgpevpn *za_vpn;
+ bool za_is_sync;
+
uint64_t version;
mpls_label_t local_label;
@@ -91,12 +96,16 @@ struct bgp_dest {
#define BGP_NODE_LABEL_REQUESTED (1 << 7)
#define BGP_NODE_SOFT_RECONFIG (1 << 8)
#define BGP_NODE_PROCESS_CLEAR (1 << 9)
+#define BGP_NODE_SCHEDULE_FOR_INSTALL (1 << 10)
+#define BGP_NODE_SCHEDULE_FOR_DELETE (1 << 11)
struct bgp_addpath_node_data tx_addpath;
enum bgp_path_selection_reason reason;
};
+DECLARE_LIST(zebra_announce, struct bgp_dest, zai);
+
extern void bgp_delete_listnode(struct bgp_dest *dest);
/*
* bgp_table_iter_t
diff --git a/bgpd/bgp_trace.c b/bgpd/bgp_trace.c
index 02afbeb..af45e7a 100644
--- a/bgpd/bgp_trace.c
+++ b/bgpd/bgp_trace.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
#define TRACEPOINT_CREATE_PROBES
#define TRACEPOINT_DEFINE
diff --git a/bgpd/bgp_updgrp.c b/bgpd/bgp_updgrp.c
index d13515a..124e7a3 100644
--- a/bgpd/bgp_updgrp.c
+++ b/bgpd/bgp_updgrp.c
@@ -145,11 +145,12 @@ static void conf_copy(struct peer *dst, struct peer *src, afi_t afi,
dst->addpath_type[afi][safi] = src->addpath_type[afi][safi];
dst->addpath_best_selected[afi][safi] =
src->addpath_best_selected[afi][safi];
+ dst->addpath_paths_limit[afi][safi] =
+ src->addpath_paths_limit[afi][safi];
dst->local_as = src->local_as;
dst->change_local_as = src->change_local_as;
dst->shared_network = src->shared_network;
dst->local_role = src->local_role;
- dst->as_path_loop_detection = src->as_path_loop_detection;
if (src->soo[afi][safi]) {
ecommunity_free(&dst->soo[afi][safi]);
@@ -348,6 +349,8 @@ static unsigned int updgrp_hash_key_make(const void *p)
key = jhash_1word((flags & PEER_UPDGRP_AF_FLAGS), key);
key = jhash_1word((uint32_t)peer->addpath_type[afi][safi], key);
key = jhash_1word(peer->addpath_best_selected[afi][safi], key);
+ key = jhash_1word(peer->addpath_paths_limit[afi][safi].receive, key);
+ key = jhash_1word(peer->addpath_paths_limit[afi][safi].send, key);
key = jhash_1word((peer->cap & PEER_UPDGRP_CAP_FLAGS), key);
key = jhash_1word((peer->af_cap[afi][safi] & PEER_UPDGRP_AF_CAP_FLAGS),
key);
@@ -356,9 +359,12 @@ static unsigned int updgrp_hash_key_make(const void *p)
key = jhash_1word(peer->max_packet_size, key);
key = jhash_1word(peer->pmax_out[afi][safi], key);
- if (peer->as_path_loop_detection)
- key = jhash_2words(peer->as, peer->as_path_loop_detection, key);
+ if (CHECK_FLAG(peer->flags, PEER_FLAG_AS_LOOP_DETECTION))
+ key = jhash_2words(peer->as,
+ CHECK_FLAG(peer->flags,
+ PEER_FLAG_AS_LOOP_DETECTION),
+ key);
if (peer->group)
key = jhash_1word(jhash(peer->group->name,
strlen(peer->group->name), SEED1),
@@ -439,7 +445,7 @@ static unsigned int updgrp_hash_key_make(const void *p)
key = jhash_1word((peer->flags & PEER_FLAG_AIGP), key);
if (peer->soo[afi][safi]) {
- char *soo_str = ecommunity_str(peer->soo[afi][safi]);
+ const char *soo_str = ecommunity_str(peer->soo[afi][safi]);
key = jhash_1word(jhash(soo_str, strlen(soo_str), SEED1), key);
}
@@ -460,7 +466,11 @@ static unsigned int updgrp_hash_key_make(const void *p)
CHECK_FLAG(peer->af_cap[afi][safi],
PEER_UPDGRP_AF_CAP_FLAGS),
peer->v_routeadv, peer->change_local_as,
- peer->as_path_loop_detection);
+ !!CHECK_FLAG(peer->flags,
+ PEER_FLAG_AS_LOOP_DETECTION));
+ zlog_debug("%pBP Update Group Hash: addpath paths-limit: (send %u, receive %u)",
+ peer, peer->addpath_paths_limit[afi][safi].send,
+ peer->addpath_paths_limit[afi][safi].receive);
zlog_debug(
"%pBP Update Group Hash: max packet size: %u pmax_out: %u Peer Group: %s rmap out: %s",
peer, peer->max_packet_size, peer->pmax_out[afi][safi],
@@ -1722,18 +1732,6 @@ static int update_group_walkcb(struct hash_bucket *bucket, void *arg)
return ret;
}
-static int update_group_periodic_merge_walkcb(struct update_group *updgrp,
- void *arg)
-{
- struct update_subgroup *subgrp;
- struct update_subgroup *tmp_subgrp;
- const char *reason = arg;
-
- UPDGRP_FOREACH_SUBGRP_SAFE (updgrp, subgrp, tmp_subgrp)
- update_subgroup_check_merge(subgrp, reason);
- return UPDWALK_CONTINUE;
-}
-
/********************
* PUBLIC FUNCTIONS
********************/
@@ -2072,14 +2070,6 @@ void update_group_walk(struct bgp *bgp, updgrp_walkcb cb, void *ctx)
}
}
-void update_group_periodic_merge(struct bgp *bgp)
-{
- char reason[] = "periodic merge check";
-
- update_group_walk(bgp, update_group_periodic_merge_walkcb,
- (void *)reason);
-}
-
static int
update_group_default_originate_route_map_walkcb(struct update_group *updgrp,
void *arg)
diff --git a/bgpd/bgp_updgrp.h b/bgpd/bgp_updgrp.h
index 5e8b537..d0fd226 100644
--- a/bgpd/bgp_updgrp.h
+++ b/bgpd/bgp_updgrp.h
@@ -369,7 +369,6 @@ extern void update_group_policy_update(struct bgp *bgp,
extern void update_group_af_walk(struct bgp *bgp, afi_t afi, safi_t safi,
updgrp_walkcb cb, void *ctx);
extern void update_group_walk(struct bgp *bgp, updgrp_walkcb cb, void *ctx);
-extern void update_group_periodic_merge(struct bgp *bgp);
extern void
update_group_refresh_default_originate_route_map(struct event *thread);
extern void update_group_start_advtimer(struct bgp *bgp);
diff --git a/bgpd/bgp_updgrp_adv.c b/bgpd/bgp_updgrp_adv.c
index 9d62265..250378a 100644
--- a/bgpd/bgp_updgrp_adv.c
+++ b/bgpd/bgp_updgrp_adv.c
@@ -78,6 +78,8 @@ static inline struct bgp_adj_out *adj_lookup(struct bgp_dest *dest,
static void adj_free(struct bgp_adj_out *adj)
{
+ bgp_labels_unintern(&adj->labels);
+
TAILQ_REMOVE(&(adj->subgroup->adjq), adj, subgrp_adj_train);
SUBGRP_DECR_STAT(adj->subgroup, adj_count);
@@ -97,13 +99,19 @@ subgrp_announce_addpath_best_selected(struct bgp_dest *dest,
enum bgp_path_selection_reason reason;
char pfx_buf[PREFIX2STR_BUFFER] = {};
int paths_eq = 0;
- int best_path_count = 0;
struct list *list = list_new();
struct bgp_path_info *pi = NULL;
+ uint16_t paths_count = 0;
+ uint16_t paths_limit = peer->addpath_paths_limit[afi][safi].receive;
if (peer->addpath_type[afi][safi] == BGP_ADDPATH_BEST_SELECTED) {
- while (best_path_count++ <
- peer->addpath_best_selected[afi][safi]) {
+ paths_limit =
+ paths_limit
+ ? MIN(paths_limit,
+ peer->addpath_best_selected[afi][safi])
+ : peer->addpath_best_selected[afi][safi];
+
+ while (paths_count++ < paths_limit) {
struct bgp_path_info *exist = NULL;
for (pi = bgp_dest_get_bgp_path_info(dest); pi;
@@ -139,8 +147,26 @@ subgrp_announce_addpath_best_selected(struct bgp_dest *dest,
subgroup_process_announce_selected(
subgrp, NULL, dest, afi, safi, id);
} else {
- subgroup_process_announce_selected(subgrp, pi, dest,
- afi, safi, id);
+ /* No Paths-Limit involved */
+ if (!paths_limit) {
+ subgroup_process_announce_selected(subgrp, pi,
+ dest, afi,
+ safi, id);
+ continue;
+ }
+
+ /* If we have Paths-Limit capability, we MUST
+ * not send more than the number of paths expected
+ * by the peer.
+ */
+ if (paths_count++ < paths_limit)
+ subgroup_process_announce_selected(subgrp, pi,
+ dest, afi,
+ safi, id);
+ else
+ subgroup_process_announce_selected(subgrp, NULL,
+ dest, afi,
+ safi, id);
}
}
@@ -509,7 +535,7 @@ bool bgp_adj_out_set_subgroup(struct bgp_dest *dest,
struct peer *adv_peer;
struct peer_af *paf;
struct bgp *bgp;
- uint32_t attr_hash = attrhash_key_make(attr);
+ uint32_t attr_hash = 0;
peer = SUBGRP_PEER(subgrp);
afi = SUBGRP_AFI(subgrp);
@@ -544,9 +570,13 @@ bool bgp_adj_out_set_subgroup(struct bgp_dest *dest,
* the route wasn't changed actually.
* Do not suppress BGP UPDATES for route-refresh.
*/
- if (CHECK_FLAG(bgp->flags, BGP_FLAG_SUPPRESS_DUPLICATES)
- && !CHECK_FLAG(subgrp->sflags, SUBGRP_STATUS_FORCE_UPDATES)
- && adj->attr_hash == attr_hash) {
+ if (likely(CHECK_FLAG(bgp->flags, BGP_FLAG_SUPPRESS_DUPLICATES)))
+ attr_hash = attrhash_key_make(attr);
+
+ if (!CHECK_FLAG(subgrp->sflags, SUBGRP_STATUS_FORCE_UPDATES) &&
+ attr_hash && adj->attr_hash == attr_hash &&
+ bgp_labels_cmp(path->extra ? path->extra->labels : NULL,
+ adj->labels)) {
if (BGP_DEBUG(update, UPDATE_OUT)) {
char attr_str[BUFSIZ] = {0};
@@ -588,6 +618,10 @@ bool bgp_adj_out_set_subgroup(struct bgp_dest *dest,
adv->baa = bgp_advertise_attr_intern(subgrp->hash, attr);
adv->adj = adj;
adj->attr_hash = attr_hash;
+ if (path->extra)
+ adj->labels = bgp_labels_intern(path->extra->labels);
+ else
+ adj->labels = NULL;
/* Add new advertisement to advertisement attribute list. */
bgp_advertise_add(adv->baa, adv);
diff --git a/bgpd/bgp_updgrp_packet.c b/bgpd/bgp_updgrp_packet.c
index 7502bf2..6e30d4f 100644
--- a/bgpd/bgp_updgrp_packet.c
+++ b/bgpd/bgp_updgrp_packet.c
@@ -523,11 +523,13 @@ struct stream *bpacket_reformat_for_peer(struct bpacket *pkt,
gnh_modified = 1;
}
- if (IN6_IS_ADDR_UNSPECIFIED(mod_v6nhg)) {
- if (peer->nexthop.v4.s_addr != INADDR_ANY) {
- ipv4_to_ipv4_mapped_ipv6(mod_v6nhg,
- peer->nexthop.v4);
- }
+ if (peer->nexthop.v4.s_addr != INADDR_ANY &&
+ (IN6_IS_ADDR_UNSPECIFIED(mod_v6nhg) ||
+ (IN6_IS_ADDR_LINKLOCAL(mod_v6nhg) &&
+ peer->connection->su.sa.sa_family == AF_INET6 &&
+ paf->afi == AFI_IP))) {
+ ipv4_to_ipv4_mapped_ipv6(mod_v6nhg, peer->nexthop.v4);
+ gnh_modified = 1;
}
if (IS_MAPPED_IPV6(&peer->nexthop.v6_global)) {
@@ -665,7 +667,7 @@ struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp)
uint32_t addpath_tx_id = 0;
struct prefix_rd *prd = NULL;
mpls_label_t label = MPLS_INVALID_LABEL, *label_pnt = NULL;
- uint32_t num_labels = 0;
+ uint8_t num_labels = 0;
if (!subgrp)
return NULL;
@@ -812,9 +814,12 @@ struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp)
path);
label_pnt = &label;
num_labels = 1;
- } else if (path && path->extra) {
- label_pnt = &path->extra->label[0];
- num_labels = path->extra->num_labels;
+ } else {
+ num_labels = bgp_path_info_num_labels(path);
+ label_pnt =
+ num_labels
+ ? &path->extra->labels->label[0]
+ : NULL;
}
if (stream_empty(snlri))
@@ -1081,7 +1086,7 @@ void subgroup_default_update_packet(struct update_subgroup *subgrp,
struct bpacket_attr_vec_arr vecarr;
bool addpath_capable = false;
mpls_label_t label = MPLS_LABEL_IMPLICIT_NULL;
- uint32_t num_labels = 0;
+ uint8_t num_labels = 0;
if (DISABLE_BGP_ANNOUNCE)
return;
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index 9530a66..1a87799 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -126,6 +126,10 @@ FRR_CFG_DEFAULT_BOOL(BGP_SOFT_VERSION_CAPABILITY,
{ .val_bool = true, .match_profile = "datacenter", },
{ .val_bool = false },
);
+FRR_CFG_DEFAULT_BOOL(BGP_DYNAMIC_CAPABILITY,
+ { .val_bool = true, .match_profile = "datacenter", },
+ { .val_bool = false },
+);
FRR_CFG_DEFAULT_BOOL(BGP_ENFORCE_FIRST_AS,
{ .val_bool = false, .match_version = "< 9.1", },
{ .val_bool = true },
@@ -623,6 +627,9 @@ int bgp_get_vty(struct bgp **bgp, as_t *as, const char *name,
if (DFLT_BGP_SOFT_VERSION_CAPABILITY)
SET_FLAG((*bgp)->flags,
BGP_FLAG_SOFT_VERSION_CAPABILITY);
+ if (DFLT_BGP_DYNAMIC_CAPABILITY)
+ SET_FLAG((*bgp)->flags,
+ BGP_FLAG_DYNAMIC_CAPABILITY);
if (DFLT_BGP_ENFORCE_FIRST_AS)
SET_FLAG((*bgp)->flags, BGP_FLAG_ENFORCE_FIRST_AS);
@@ -1694,6 +1701,10 @@ DEFUN (no_router_bgp,
for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, tmp_bgp)) {
if (tmp_bgp->inst_type != BGP_INSTANCE_TYPE_VRF)
continue;
+
+ if (CHECK_FLAG(tmp_bgp->vrf_flags, BGP_VRF_AUTO))
+ bgp_delete(tmp_bgp);
+
if (CHECK_FLAG(
tmp_bgp->af_flags[AFI_IP]
[SAFI_UNICAST],
@@ -1753,10 +1764,10 @@ DEFPY (bgp_session_dscp,
bgp_session_dscp_cmd,
"bgp session-dscp (0-63)$dscp",
BGP_STR
- "Override default (C6) bgp TCP session DSCP value\n"
- "Manually configured dscp parameter\n")
+ "Override default (CS6) DSCP for BGP connections\n"
+ "Manually configured DSCP value\n")
{
- bm->tcp_dscp = dscp << 2;
+ bm->ip_tos = dscp << 2;
return CMD_SUCCESS;
}
@@ -1766,10 +1777,10 @@ DEFPY (no_bgp_session_dscp,
"no bgp session-dscp [(0-63)]",
NO_STR
BGP_STR
- "Override default (C6) bgp TCP session DSCP value\n"
- "Manually configured dscp parameter\n")
+ "Override default (CS6) DSCP for BGP connections\n"
+ "Manually configured DSCP value\n")
{
- bm->tcp_dscp = IPTOS_PREC_INTERNETCONTROL;
+ bm->ip_tos = IPTOS_PREC_INTERNETCONTROL;
return CMD_SUCCESS;
}
@@ -3028,14 +3039,17 @@ DEFUN (bgp_graceful_restart,
VTY_DECLVAR_CONTEXT(bgp, bgp);
ret = bgp_gr_update_all(bgp, GLOBAL_GR_CMD);
-
- VTY_BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(bgp, bgp->peer,
- ret);
+ if (ret == BGP_GR_SUCCESS) {
+ VTY_BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(bgp,
+ bgp->peer,
+ ret);
+ vty_out(vty,
+ "Graceful restart configuration changed, reset all peers to take effect\n");
+ }
if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
zlog_debug("[BGP_GR] bgp_graceful_restart_cmd : END ");
- vty_out(vty,
- "Graceful restart configuration changed, reset all peers to take effect\n");
+
return bgp_vty_return(vty, ret);
}
@@ -3055,14 +3069,16 @@ DEFUN (no_bgp_graceful_restart,
int ret = BGP_GR_FAILURE;
ret = bgp_gr_update_all(bgp, NO_GLOBAL_GR_CMD);
-
- VTY_BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(bgp, bgp->peer,
- ret);
+ if (ret == BGP_GR_SUCCESS) {
+ VTY_BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(bgp,
+ bgp->peer,
+ ret);
+ vty_out(vty,
+ "Graceful restart configuration changed, reset all peers to take effect\n");
+ }
if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
zlog_debug("[BGP_GR] no_bgp_graceful_restart_cmd : END ");
- vty_out(vty,
- "Graceful restart configuration changed, reset all peers to take effect\n");
return bgp_vty_return(vty, ret);
}
@@ -3270,24 +3286,25 @@ DEFUN (bgp_graceful_restart_disable,
VTY_DECLVAR_CONTEXT(bgp, bgp);
ret = bgp_gr_update_all(bgp, GLOBAL_DISABLE_CMD);
+ if (ret == BGP_GR_SUCCESS) {
+ VTY_BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(bgp,
+ bgp->peer,
+ ret);
+ vty_out(vty,
+ "Graceful restart configuration changed, reset all peers to take effect\n");
- VTY_BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(bgp,
- bgp->peer, ret);
+ for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
+ bgp_capability_send(peer, AFI_IP, SAFI_UNICAST,
+ CAPABILITY_CODE_RESTART,
+ CAPABILITY_ACTION_UNSET);
+ bgp_capability_send(peer, AFI_IP, SAFI_UNICAST,
+ CAPABILITY_CODE_LLGR,
+ CAPABILITY_ACTION_UNSET);
+ }
+ }
if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
- zlog_debug(
- "[BGP_GR] bgp_graceful_restart_disable_cmd : END ");
- vty_out(vty,
- "Graceful restart configuration changed, reset all peers to take effect\n");
-
- for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
- bgp_capability_send(peer, AFI_IP, SAFI_UNICAST,
- CAPABILITY_CODE_RESTART,
- CAPABILITY_ACTION_UNSET);
- bgp_capability_send(peer, AFI_IP, SAFI_UNICAST,
- CAPABILITY_CODE_LLGR,
- CAPABILITY_ACTION_UNSET);
- }
+ zlog_debug("[BGP_GR] bgp_graceful_restart_disable_cmd : END ");
return bgp_vty_return(vty, ret);
}
@@ -3309,15 +3326,17 @@ DEFUN (no_bgp_graceful_restart_disable,
int ret = BGP_GR_FAILURE;
ret = bgp_gr_update_all(bgp, NO_GLOBAL_DISABLE_CMD);
-
- VTY_BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(bgp, bgp->peer,
- ret);
+ if (ret == BGP_GR_SUCCESS) {
+ VTY_BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(bgp,
+ bgp->peer,
+ ret);
+ vty_out(vty,
+ "Graceful restart configuration changed, reset all peers to take effect\n");
+ }
if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
zlog_debug(
"[BGP_GR] no_bgp_graceful_restart_disable_cmd : END ");
- vty_out(vty,
- "Graceful restart configuration changed, reset all peers to take effect\n");
return bgp_vty_return(vty, ret);
}
@@ -3332,7 +3351,7 @@ DEFUN (bgp_neighbor_graceful_restart_set,
{
int idx_peer = 1;
struct peer *peer;
- int ret = BGP_GR_FAILURE;
+ int result = BGP_GR_FAILURE, ret = BGP_GR_SUCCESS;
VTY_BGP_GR_DEFINE_LOOP_VARIABLE;
@@ -3344,18 +3363,23 @@ DEFUN (bgp_neighbor_graceful_restart_set,
if (!peer)
return CMD_WARNING_CONFIG_FAILED;
- ret = bgp_neighbor_graceful_restart(peer, PEER_GR_CMD);
-
- VTY_BGP_GR_ROUTER_DETECT(bgp, peer, peer->bgp->peer);
- VTY_SEND_BGP_GR_CAPABILITY_TO_ZEBRA(peer->bgp, ret);
+ result = bgp_neighbor_graceful_restart(peer, PEER_GR_CMD);
+ if (result == BGP_GR_SUCCESS) {
+ VTY_BGP_GR_ROUTER_DETECT(bgp, peer, peer->bgp->peer);
+ VTY_SEND_BGP_GR_CAPABILITY_TO_ZEBRA(peer->bgp, ret);
+ vty_out(vty,
+ "Graceful restart configuration changed, reset this peer to take effect\n");
+ }
if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
zlog_debug(
"[BGP_GR] bgp_neighbor_graceful_restart_set_cmd : END ");
- vty_out(vty,
- "Graceful restart configuration changed, reset this peer to take effect\n");
- return bgp_vty_return(vty, ret);
+ if (ret != BGP_GR_SUCCESS)
+ vty_out(vty,
+ "As part of configuring graceful-restart, capability send to zebra failed\n");
+
+ return bgp_vty_return(vty, result);
}
DEFUN (no_bgp_neighbor_graceful_restart,
@@ -3368,7 +3392,7 @@ DEFUN (no_bgp_neighbor_graceful_restart,
)
{
int idx_peer = 2;
- int ret = BGP_GR_FAILURE;
+ int result = BGP_GR_FAILURE, ret = BGP_GR_SUCCESS;
struct peer *peer;
VTY_BGP_GR_DEFINE_LOOP_VARIABLE;
@@ -3381,18 +3405,23 @@ DEFUN (no_bgp_neighbor_graceful_restart,
zlog_debug(
"[BGP_GR] no_bgp_neighbor_graceful_restart_set_cmd : START ");
- ret = bgp_neighbor_graceful_restart(peer, NO_PEER_GR_CMD);
-
- VTY_BGP_GR_ROUTER_DETECT(bgp, peer, peer->bgp->peer);
- VTY_SEND_BGP_GR_CAPABILITY_TO_ZEBRA(peer->bgp, ret);
+ result = bgp_neighbor_graceful_restart(peer, NO_PEER_GR_CMD);
+ if (ret == BGP_GR_SUCCESS) {
+ VTY_BGP_GR_ROUTER_DETECT(bgp, peer, peer->bgp->peer);
+ VTY_SEND_BGP_GR_CAPABILITY_TO_ZEBRA(peer->bgp, ret);
+ vty_out(vty,
+ "Graceful restart configuration changed, reset this peer to take effect\n");
+ }
if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
zlog_debug(
"[BGP_GR] no_bgp_neighbor_graceful_restart_set_cmd : END ");
- vty_out(vty,
- "Graceful restart configuration changed, reset this peer to take effect\n");
- return bgp_vty_return(vty, ret);
+ if (ret != BGP_GR_SUCCESS)
+ vty_out(vty,
+ "As part of configuring graceful-restart, capability send to zebra failed\n");
+
+ return bgp_vty_return(vty, result);
}
DEFUN (bgp_neighbor_graceful_restart_helper_set,
@@ -3420,15 +3449,16 @@ DEFUN (bgp_neighbor_graceful_restart_helper_set,
ret = bgp_neighbor_graceful_restart(peer, PEER_HELPER_CMD);
-
- VTY_BGP_GR_ROUTER_DETECT(bgp, peer, peer->bgp->peer);
- VTY_SEND_BGP_GR_CAPABILITY_TO_ZEBRA(peer->bgp, ret);
+ if (ret == BGP_GR_SUCCESS) {
+ VTY_BGP_GR_ROUTER_DETECT(bgp, peer, peer->bgp->peer);
+ VTY_SEND_BGP_GR_CAPABILITY_TO_ZEBRA(peer->bgp, ret);
+ vty_out(vty,
+ "Graceful restart configuration changed, reset this peer to take effect\n");
+ }
if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
zlog_debug(
"[BGP_GR] bgp_neighbor_graceful_restart_helper_set_cmd : END ");
- vty_out(vty,
- "Graceful restart configuration changed, reset this peer to take effect\n");
return bgp_vty_return(vty, ret);
}
@@ -3457,15 +3487,16 @@ DEFUN (no_bgp_neighbor_graceful_restart_helper,
"[BGP_GR] no_bgp_neighbor_graceful_restart_helper_set_cmd : START ");
ret = bgp_neighbor_graceful_restart(peer, NO_PEER_HELPER_CMD);
-
- VTY_BGP_GR_ROUTER_DETECT(bgp, peer, peer->bgp->peer);
- VTY_SEND_BGP_GR_CAPABILITY_TO_ZEBRA(peer->bgp, ret);
+ if (ret == BGP_GR_SUCCESS) {
+ VTY_BGP_GR_ROUTER_DETECT(bgp, peer, peer->bgp->peer);
+ VTY_SEND_BGP_GR_CAPABILITY_TO_ZEBRA(peer->bgp, ret);
+ vty_out(vty,
+ "Graceful restart configuration changed, reset this peer to take effect\n");
+ }
if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
zlog_debug(
"[BGP_GR] no_bgp_neighbor_graceful_restart_helper_set_cmd : END ");
- vty_out(vty,
- "Graceful restart configuration changed, reset this peer to take effect\n");
return bgp_vty_return(vty, ret);
}
@@ -3493,18 +3524,19 @@ DEFUN (bgp_neighbor_graceful_restart_disable_set,
return CMD_WARNING_CONFIG_FAILED;
ret = bgp_neighbor_graceful_restart(peer, PEER_DISABLE_CMD);
+ if (ret == BGP_GR_SUCCESS) {
+ if (peer->bgp->t_startup)
+ bgp_peer_gr_flags_update(peer);
- if (peer->bgp->t_startup)
- bgp_peer_gr_flags_update(peer);
-
- VTY_BGP_GR_ROUTER_DETECT(bgp, peer, peer->bgp->peer);
- VTY_SEND_BGP_GR_CAPABILITY_TO_ZEBRA(peer->bgp, ret);
+ VTY_BGP_GR_ROUTER_DETECT(bgp, peer, peer->bgp->peer);
+ VTY_SEND_BGP_GR_CAPABILITY_TO_ZEBRA(peer->bgp, ret);
+ vty_out(vty,
+ "Graceful restart configuration changed, reset this peer to take effect\n");
+ }
if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
zlog_debug(
"[BGP_GR]bgp_neighbor_graceful_restart_disable_set_cmd : END ");
- vty_out(vty,
- "Graceful restart configuration changed, reset this peer to take effect\n");
return bgp_vty_return(vty, ret);
}
@@ -3533,15 +3565,16 @@ DEFUN (no_bgp_neighbor_graceful_restart_disable,
"[BGP_GR] no_bgp_neighbor_graceful_restart_disable_set_cmd : START ");
ret = bgp_neighbor_graceful_restart(peer, NO_PEER_DISABLE_CMD);
-
- VTY_BGP_GR_ROUTER_DETECT(bgp, peer, peer->bgp->peer);
- VTY_SEND_BGP_GR_CAPABILITY_TO_ZEBRA(peer->bgp, ret);
+ if (ret == BGP_GR_SUCCESS) {
+ VTY_BGP_GR_ROUTER_DETECT(bgp, peer, peer->bgp->peer);
+ VTY_SEND_BGP_GR_CAPABILITY_TO_ZEBRA(peer->bgp, ret);
+ vty_out(vty,
+ "Graceful restart configuration changed, reset this peer to take effect\n");
+ }
if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
zlog_debug(
"[BGP_GR] no_bgp_neighbor_graceful_restart_disable_set_cmd : END ");
- vty_out(vty,
- "Graceful restart configuration changed, reset this peer to take effect\n");
return bgp_vty_return(vty, ret);
}
@@ -4298,6 +4331,24 @@ DEFPY (bgp_default_software_version_capability,
return CMD_SUCCESS;
}
+DEFPY (bgp_default_dynamic_capability,
+ bgp_default_dynamic_capability_cmd,
+ "[no] bgp default dynamic-capability",
+ NO_STR
+ BGP_STR
+ "Configure BGP defaults\n"
+ "Advertise dynamic capability for all neighbors\n")
+{
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
+
+ if (no)
+ UNSET_FLAG(bgp->flags, BGP_FLAG_DYNAMIC_CAPABILITY);
+ else
+ SET_FLAG(bgp->flags, BGP_FLAG_DYNAMIC_CAPABILITY);
+
+ return CMD_SUCCESS;
+}
+
/* "bgp network import-check" configuration. */
DEFUN (bgp_network_import_check,
bgp_network_import_check_cmd,
@@ -4315,6 +4366,9 @@ DEFUN (bgp_network_import_check,
return CMD_SUCCESS;
}
+#if CONFDATE > 20241013
+CPP_NOTICE("Drop `bgp network import-check exact` command")
+#endif
ALIAS_HIDDEN(bgp_network_import_check, bgp_network_import_check_exact_cmd,
"bgp network import-check exact",
BGP_STR
@@ -5077,6 +5131,8 @@ DEFUN (no_neighbor,
struct peer_group *group;
struct peer *peer;
struct peer *other;
+ afi_t afi;
+ int lr_count;
ret = str2sockunion(argv[idx_peer]->arg, &su);
if (ret < 0) {
@@ -5094,6 +5150,15 @@ DEFUN (no_neighbor,
group = peer_group_lookup(bgp, argv[idx_peer]->arg);
if (group) {
+ for (afi = AFI_IP; afi < AFI_MAX; afi++) {
+ lr_count = listcount(group->listen_range[afi]);
+ if (lr_count) {
+ vty_out(vty,
+ "%%Peer-group %s is attached to %d listen-range(s), delete them first\n",
+ group->name, lr_count);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+ }
peer_group_notify_unconfig(group);
peer_group_delete(group);
} else {
@@ -5171,9 +5236,20 @@ DEFUN (no_neighbor_peer_group,
VTY_DECLVAR_CONTEXT(bgp, bgp);
int idx_word = 2;
struct peer_group *group;
+ afi_t afi;
+ int lr_count;
group = peer_group_lookup(bgp, argv[idx_word]->arg);
if (group) {
+ for (afi = AFI_IP; afi < AFI_MAX; afi++) {
+ lr_count = listcount(group->listen_range[afi]);
+ if (lr_count) {
+ vty_out(vty,
+ "%%Peer-group %s is attached to %d listen-range(s), delete them first\n",
+ group->name, lr_count);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+ }
peer_group_notify_unconfig(group);
peer_group_delete(group);
} else {
@@ -7073,6 +7149,26 @@ DEFUN (no_neighbor_disable_connected_check,
PEER_FLAG_DISABLE_CONNECTED_CHECK);
}
+DEFPY(neighbor_extended_link_bw,
+ neighbor_extended_link_bw_cmd,
+ "[no] neighbor <A.B.C.D|X:X::X:X|WORD>$neighbor extended-link-bandwidth",
+ NO_STR
+ NEIGHBOR_STR
+ NEIGHBOR_ADDR_STR2
+ "Send Extended (64-bit) version of encoding for Link-Bandwidth\n")
+{
+ int ret;
+
+ if (no)
+ ret = peer_flag_unset_vty(vty, neighbor,
+ PEER_FLAG_EXTENDED_LINK_BANDWIDTH);
+ else
+ ret = peer_flag_set_vty(vty, neighbor,
+ PEER_FLAG_EXTENDED_LINK_BANDWIDTH);
+
+ return ret;
+}
+
/* disable-link-bw-encoding-ieee */
DEFUN(neighbor_disable_link_bw_encoding_ieee,
neighbor_disable_link_bw_encoding_ieee_cmd,
@@ -9198,15 +9294,64 @@ DEFPY(
NEIGHBOR_ADDR_STR2
"Detect AS loops before sending to neighbor\n")
{
+ return peer_flag_set_vty(vty, neighbor, PEER_FLAG_AS_LOOP_DETECTION);
+}
+
+DEFPY (neighbor_addpath_paths_limit,
+ neighbor_addpath_paths_limit_cmd,
+ "neighbor <A.B.C.D|X:X::X:X|WORD>$neighbor addpath-rx-paths-limit (1-65535)$paths_limit",
+ NEIGHBOR_STR
+ NEIGHBOR_ADDR_STR2
+ "Paths Limit for Addpath to receive from the peer\n"
+ "Maximum number of paths\n")
+{
struct peer *peer;
+ afi_t afi = bgp_node_afi(vty);
+ safi_t safi = bgp_node_safi(vty);
+ int ret;
peer = peer_and_group_lookup_vty(vty, neighbor);
if (!peer)
return CMD_WARNING_CONFIG_FAILED;
- peer->as_path_loop_detection = true;
+ ret = peer_af_flag_set_vty(vty, neighbor, afi, safi,
+ PEER_FLAG_ADDPATH_RX_PATHS_LIMIT);
- return CMD_SUCCESS;
+ peer->addpath_paths_limit[afi][safi].send = paths_limit;
+
+ bgp_capability_send(peer, afi, safi, CAPABILITY_CODE_PATHS_LIMIT,
+ CAPABILITY_ACTION_SET);
+
+ return ret;
+}
+
+DEFPY (no_neighbor_addpath_paths_limit,
+ no_neighbor_addpath_paths_limit_cmd,
+ "no neighbor <A.B.C.D|X:X::X:X|WORD>$neighbor addpath-rx-paths-limit [(1-65535)]",
+ NO_STR
+ NEIGHBOR_STR
+ NEIGHBOR_ADDR_STR2
+ "Paths Limit for Addpath to receive from the peer\n"
+ "Maximum number of paths\n")
+{
+ struct peer *peer;
+ afi_t afi = bgp_node_afi(vty);
+ safi_t safi = bgp_node_safi(vty);
+ int ret;
+
+ peer = peer_and_group_lookup_vty(vty, neighbor);
+ if (!peer)
+ return CMD_WARNING_CONFIG_FAILED;
+
+ ret = peer_af_flag_unset_vty(vty, neighbor, afi, safi,
+ PEER_FLAG_ADDPATH_RX_PATHS_LIMIT);
+
+ peer->addpath_paths_limit[afi][safi].send = 0;
+
+ bgp_capability_send(peer, afi, safi, CAPABILITY_CODE_PATHS_LIMIT,
+ CAPABILITY_ACTION_SET);
+
+ return ret;
}
DEFPY(
@@ -9218,15 +9363,7 @@ DEFPY(
NEIGHBOR_ADDR_STR2
"Detect AS loops before sending to neighbor\n")
{
- struct peer *peer;
-
- peer = peer_and_group_lookup_vty(vty, neighbor);
- if (!peer)
- return CMD_WARNING_CONFIG_FAILED;
-
- peer->as_path_loop_detection = false;
-
- return CMD_SUCCESS;
+ return peer_flag_unset_vty(vty, neighbor, PEER_FLAG_AS_LOOP_DETECTION);
}
DEFPY(neighbor_path_attribute_discard,
@@ -9343,6 +9480,92 @@ DEFPY(no_neighbor_path_attribute_treat_as_withdraw,
return CMD_SUCCESS;
}
+DEFPY(neighbor_damp,
+ neighbor_damp_cmd,
+ "neighbor <A.B.C.D|X:X::X:X|WORD>$neighbor dampening [(1-45)$half [(1-20000)$reuse (1-20000)$suppress (1-255)$max]]",
+ NEIGHBOR_STR
+ NEIGHBOR_ADDR_STR2
+ "Enable neighbor route-flap dampening\n"
+ "Half-life time for the penalty\n"
+ "Value to start reusing a route\n"
+ "Value to start suppressing a route\n"
+ "Maximum duration to suppress a stable route\n")
+{
+ struct peer *peer = peer_and_group_lookup_vty(vty, neighbor);
+
+ if (!peer)
+ return CMD_WARNING_CONFIG_FAILED;
+ if (!half)
+ half = DEFAULT_HALF_LIFE;
+ if (!reuse) {
+ reuse = DEFAULT_REUSE;
+ suppress = DEFAULT_SUPPRESS;
+ max = half * 4;
+ }
+ if (suppress < reuse) {
+ vty_out(vty, "Suppress value cannot be less than reuse value\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+ bgp_peer_damp_enable(peer, bgp_node_afi(vty), bgp_node_safi(vty),
+ half * 60, reuse, suppress, max * 60);
+ return CMD_SUCCESS;
+}
+
+DEFPY(no_neighbor_damp,
+ no_neighbor_damp_cmd,
+ "no neighbor <A.B.C.D|X:X::X:X|WORD>$neighbor dampening [HALF [REUSE SUPPRESS MAX]]",
+ NO_STR
+ NEIGHBOR_STR
+ NEIGHBOR_ADDR_STR2
+ "Enable neighbor route-flap dampening\n"
+ "Half-life time for the penalty\n"
+ "Value to start reusing a route\n"
+ "Value to start suppressing a route\n"
+ "Maximum duration to suppress a stable route\n")
+{
+ struct peer *peer = peer_and_group_lookup_vty(vty, neighbor);
+
+ if (!peer)
+ return CMD_WARNING_CONFIG_FAILED;
+ bgp_peer_damp_disable(peer, bgp_node_afi(vty), bgp_node_safi(vty));
+ return CMD_SUCCESS;
+}
+
+DEFPY (show_ip_bgp_neighbor_damp_param,
+ show_ip_bgp_neighbor_damp_param_cmd,
+ "show [ip] bgp [<ipv4|ipv6> [unicast]] neighbors <A.B.C.D|X:X::X:X|WORD>$neighbor dampening parameters [json]$json",
+ SHOW_STR
+ IP_STR
+ BGP_STR
+ BGP_AFI_HELP_STR
+ "Address Family modifier\n"
+ NEIGHBOR_STR
+ NEIGHBOR_ADDR_STR2
+ "Neighbor route-flap dampening information\n"
+ "Display detail of configured dampening parameters\n"
+ JSON_STR)
+{
+ bool use_json = false;
+ int idx = 0;
+ afi_t afi = AFI_IP;
+ safi_t safi = SAFI_UNICAST;
+ struct peer *peer;
+
+ if (argv_find(argv, argc, "ip", &idx))
+ afi = AFI_IP;
+ if (argv_find(argv, argc, "ipv4", &idx))
+ afi = AFI_IP;
+ if (argv_find(argv, argc, "ipv6", &idx))
+ afi = AFI_IP6;
+ peer = peer_and_group_lookup_vty(vty, neighbor);
+ if (!peer)
+ return CMD_WARNING;
+ if (json)
+ use_json = true;
+ bgp_show_peer_dampening_parameters(vty, peer, afi, safi, use_json);
+ return CMD_SUCCESS;
+}
+
static int set_ecom_list(struct vty *vty, int argc, struct cmd_token **argv,
struct ecommunity **list, bool is_rt6)
{
@@ -9628,8 +9851,6 @@ DEFPY (af_label_vpn_export,
BGP_VPN_POLICY_TOVPN_LABEL_AUTO);
/* fetch a label */
bgp->vpn_policy[afi].tovpn_label = MPLS_LABEL_NONE;
- bgp_lp_get(LP_TYPE_VRF, &bgp->vpn_policy[afi],
- vpn_leak_label_callback);
} else {
bgp->vpn_policy[afi].tovpn_label = label;
UNSET_FLAG(bgp->vpn_policy[afi].flags,
@@ -10218,12 +10439,20 @@ DEFPY(bgp_imexport_vrf, bgp_imexport_vrf_cmd,
vrf_bgp = bgp_lookup_by_name(import_name);
if (!vrf_bgp) {
- if (strcmp(import_name, VRF_DEFAULT_NAME) == 0)
+ if (strcmp(import_name, VRF_DEFAULT_NAME) == 0) {
vrf_bgp = bgp_default;
- else
+ } else {
/* Auto-create assuming the same AS */
ret = bgp_get_vty(&vrf_bgp, &as, import_name, bgp_type,
NULL, ASNOTATION_UNDEFINED);
+
+ /* Auto created VRF instances should be marked
+ * properly, otherwise we have a state after bgpd
+ * restart where VRF instance has default VRF's ASN.
+ */
+ SET_FLAG(vrf_bgp->vrf_flags, BGP_VRF_AUTO);
+ }
+
if (ret) {
vty_out(vty,
"VRF %s is not configured as a bgp instance\n",
@@ -10672,7 +10901,10 @@ static int bgp_clear_prefix(struct vty *vty, const char *view_name,
if (rm_p->prefixlen == match.prefixlen) {
SET_FLAG(rm->flags,
BGP_NODE_USER_CLEAR);
- bgp_process(bgp, rm, afi, safi);
+ bgp_process(bgp, rm,
+ bgp_dest_get_bgp_path_info(
+ rm),
+ afi, safi);
}
bgp_dest_unlock_node(rm);
}
@@ -10684,7 +10916,9 @@ static int bgp_clear_prefix(struct vty *vty, const char *view_name,
if (dest_p->prefixlen == match.prefixlen) {
SET_FLAG(dest->flags, BGP_NODE_USER_CLEAR);
- bgp_process(bgp, dest, afi, safi);
+ bgp_process(bgp, dest,
+ bgp_dest_get_bgp_path_info(dest),
+ afi, safi);
}
bgp_dest_unlock_node(dest);
}
@@ -11439,10 +11673,9 @@ static void bgp_show_peer_reset(struct vty * vty, struct peer *peer,
BGP_NOTIFY_CEASE_HARD_RESET)
: "");
} else {
- vty_out(vty, " %s (%s)\n",
+ vty_out(vty, " %s (%s)\n",
peer_down_str[(int)peer->last_reset],
- peer->soft_version ? peer->soft_version
- : "n/a");
+ peer->soft_version ? peer->soft_version : "n/a");
}
}
}
@@ -12392,6 +12625,9 @@ static void bgp_show_all_instances_summary_vty(struct vty *vty, afi_t afi,
vty_out(vty, "{\n");
for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) {
+ if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_AUTO))
+ continue;
+
nbr_output = true;
if (use_json) {
if (!is_first)
@@ -12684,7 +12920,7 @@ static void bgp_show_neighbor_graceful_restart_remote_mode(struct vty *vty,
if (json)
json_object_string_add(json, "remoteGrMode", mode);
else
- vty_out(vty, "%s\n", mode);
+ vty_out(vty, "%s", mode);
}
static void bgp_show_neighbor_graceful_restart_local_mode(struct vty *vty,
@@ -12716,7 +12952,7 @@ static void bgp_show_neighbor_graceful_restart_local_mode(struct vty *vty,
if (json)
json_object_string_add(json, "localGrMode", mode);
else
- vty_out(vty, "%s\n", mode);
+ vty_out(vty, "%s", mode);
}
static void bgp_show_neighbor_graceful_restart_capability_per_afi_safi(
@@ -14070,33 +14306,28 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
CHECK_FLAG(
p->af_cap[afi][safi],
PEER_CAP_ADDPATH_AF_TX_RCV)) {
- if (CHECK_FLAG(
- p->af_cap[afi]
- [safi],
- PEER_CAP_ADDPATH_AF_TX_ADV) &&
- CHECK_FLAG(
- p->af_cap[afi]
- [safi],
- PEER_CAP_ADDPATH_AF_TX_RCV))
- json_object_boolean_true_add(
- json_sub,
- "txAdvertisedAndReceived");
- else if (
- CHECK_FLAG(
- p->af_cap[afi]
- [safi],
- PEER_CAP_ADDPATH_AF_TX_ADV))
- json_object_boolean_true_add(
- json_sub,
- "txAdvertised");
- else if (
- CHECK_FLAG(
- p->af_cap[afi]
- [safi],
- PEER_CAP_ADDPATH_AF_TX_RCV))
- json_object_boolean_true_add(
- json_sub,
- "txReceived");
+ json_object_boolean_add(
+ json_sub,
+ "txAdvertisedAndReceived",
+ CHECK_FLAG(p->af_cap[afi]
+ [safi],
+ PEER_CAP_ADDPATH_AF_TX_ADV) &&
+ CHECK_FLAG(
+ p->af_cap[afi]
+ [safi],
+ PEER_CAP_ADDPATH_AF_TX_RCV));
+
+ json_object_boolean_add(
+ json_sub, "txAdvertised",
+ CHECK_FLAG(p->af_cap[afi]
+ [safi],
+ PEER_CAP_ADDPATH_AF_TX_ADV));
+
+ json_object_boolean_add(
+ json_sub, "txReceived",
+ CHECK_FLAG(p->af_cap[afi]
+ [safi],
+ PEER_CAP_ADDPATH_AF_TX_RCV));
}
if (CHECK_FLAG(
@@ -14105,33 +14336,28 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
CHECK_FLAG(
p->af_cap[afi][safi],
PEER_CAP_ADDPATH_AF_RX_RCV)) {
- if (CHECK_FLAG(
- p->af_cap[afi]
- [safi],
- PEER_CAP_ADDPATH_AF_RX_ADV) &&
- CHECK_FLAG(
- p->af_cap[afi]
- [safi],
- PEER_CAP_ADDPATH_AF_RX_RCV))
- json_object_boolean_true_add(
- json_sub,
- "rxAdvertisedAndReceived");
- else if (
- CHECK_FLAG(
- p->af_cap[afi]
- [safi],
- PEER_CAP_ADDPATH_AF_RX_ADV))
- json_object_boolean_true_add(
- json_sub,
- "rxAdvertised");
- else if (
- CHECK_FLAG(
- p->af_cap[afi]
- [safi],
- PEER_CAP_ADDPATH_AF_RX_RCV))
- json_object_boolean_true_add(
- json_sub,
- "rxReceived");
+ json_object_boolean_add(
+ json_sub,
+ "rxAdvertisedAndReceived",
+ CHECK_FLAG(p->af_cap[afi]
+ [safi],
+ PEER_CAP_ADDPATH_AF_RX_ADV) &&
+ CHECK_FLAG(
+ p->af_cap[afi]
+ [safi],
+ PEER_CAP_ADDPATH_AF_RX_RCV));
+
+ json_object_boolean_add(
+ json_sub, "rxAdvertised",
+ CHECK_FLAG(p->af_cap[afi]
+ [safi],
+ PEER_CAP_ADDPATH_AF_RX_ADV));
+
+ json_object_boolean_add(
+ json_sub, "rxReceived",
+ CHECK_FLAG(p->af_cap[afi]
+ [safi],
+ PEER_CAP_ADDPATH_AF_RX_RCV));
}
if (CHECK_FLAG(
@@ -14157,6 +14383,86 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
json_add);
}
+ /* Paths-Limit */
+ if (CHECK_FLAG(p->cap, PEER_CAP_PATHS_LIMIT_RCV) ||
+ CHECK_FLAG(p->cap, PEER_CAP_PATHS_LIMIT_ADV)) {
+ json_object *json_add = NULL;
+ const char *print_store;
+
+ json_add = json_object_new_object();
+
+ FOREACH_AFI_SAFI (afi, safi) {
+ json_object *json_sub = NULL;
+
+ json_sub = json_object_new_object();
+ print_store = get_afi_safi_str(afi, safi,
+ true);
+
+ if (CHECK_FLAG(p->af_cap[afi][safi],
+ PEER_CAP_PATHS_LIMIT_AF_ADV) ||
+ CHECK_FLAG(p->af_cap[afi][safi],
+ PEER_CAP_PATHS_LIMIT_AF_RCV)) {
+ if (CHECK_FLAG(p->af_cap[afi][safi],
+ PEER_CAP_PATHS_LIMIT_AF_ADV) &&
+ CHECK_FLAG(p->af_cap[afi][safi],
+ PEER_CAP_PATHS_LIMIT_AF_RCV)) {
+ json_object_boolean_true_add(
+ json_sub,
+ "advertisedAndReceived");
+ json_object_int_add(
+ json_sub,
+ "advertisedPathsLimit",
+ p->addpath_paths_limit
+ [afi][safi]
+ .send);
+ json_object_int_add(
+ json_sub,
+ "receivedPathsLimit",
+ p->addpath_paths_limit
+ [afi][safi]
+ .receive);
+ } else if (CHECK_FLAG(p->af_cap[afi]
+ [safi],
+ PEER_CAP_PATHS_LIMIT_AF_ADV)) {
+ json_object_boolean_true_add(
+ json_sub,
+ "advertised");
+ json_object_int_add(
+ json_sub,
+ "advertisedPathsLimit",
+ p->addpath_paths_limit
+ [afi][safi]
+ .send);
+ } else if (CHECK_FLAG(p->af_cap[afi]
+ [safi],
+ PEER_CAP_PATHS_LIMIT_AF_RCV)) {
+ json_object_boolean_true_add(
+ json_sub,
+ "received");
+ json_object_int_add(
+ json_sub,
+ "receivedPathsLimit",
+ p->addpath_paths_limit
+ [afi][safi]
+ .receive);
+ }
+ }
+
+ if (CHECK_FLAG(p->af_cap[afi][safi],
+ PEER_CAP_PATHS_LIMIT_AF_ADV) ||
+ CHECK_FLAG(p->af_cap[afi][safi],
+ PEER_CAP_PATHS_LIMIT_AF_RCV))
+ json_object_object_add(json_add,
+ print_store,
+ json_sub);
+ else
+ json_object_free(json_sub);
+ }
+
+ json_object_object_add(json_cap, "pathsLimit",
+ json_add);
+ }
+
/* Dynamic */
if (CHECK_FLAG(p->cap, PEER_CAP_DYNAMIC_RCV) ||
CHECK_FLAG(p->cap, PEER_CAP_DYNAMIC_ADV)) {
@@ -14610,6 +14916,47 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
}
}
+ /* Paths-Limit */
+ if (CHECK_FLAG(p->cap, PEER_CAP_PATHS_LIMIT_RCV) ||
+ CHECK_FLAG(p->cap, PEER_CAP_PATHS_LIMIT_ADV)) {
+ vty_out(vty, " Paths-Limit:\n");
+
+ FOREACH_AFI_SAFI (afi, safi) {
+ if (CHECK_FLAG(p->af_cap[afi][safi],
+ PEER_CAP_PATHS_LIMIT_AF_ADV) ||
+ CHECK_FLAG(p->af_cap[afi][safi],
+ PEER_CAP_PATHS_LIMIT_AF_RCV)) {
+ vty_out(vty, " %s: ",
+ get_afi_safi_str(afi,
+ safi,
+ false));
+
+ if (CHECK_FLAG(p->af_cap[afi][safi],
+ PEER_CAP_PATHS_LIMIT_AF_ADV))
+ vty_out(vty,
+ "advertised (%u)",
+ p->addpath_paths_limit
+ [afi][safi]
+ .send);
+
+ if (CHECK_FLAG(p->af_cap[afi][safi],
+ PEER_CAP_PATHS_LIMIT_AF_RCV))
+ vty_out(vty,
+ "%sreceived (%u)",
+ CHECK_FLAG(p->af_cap[afi]
+ [safi],
+ PEER_CAP_PATHS_LIMIT_AF_ADV)
+ ? " and "
+ : "",
+ p->addpath_paths_limit
+ [afi][safi]
+ .receive);
+
+ vty_out(vty, "\n");
+ }
+ }
+ }
+
/* Dynamic */
if (CHECK_FLAG(p->cap, PEER_CAP_DYNAMIC_RCV) ||
CHECK_FLAG(p->cap, PEER_CAP_DYNAMIC_ADV)) {
@@ -15662,6 +16009,9 @@ static void bgp_show_all_instances_neighbors_vty(struct vty *vty,
vty_out(vty, "{\n");
for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) {
+ if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_AUTO))
+ continue;
+
nbr_output = true;
if (use_json) {
if (!(json = json_object_new_object())) {
@@ -16221,6 +16571,9 @@ static int bgp_show_all_instance_route_leak_vty(struct vty *vty, afi_t afi,
if (bgp->inst_type != BGP_INSTANCE_TYPE_DEFAULT)
vrf_name = bgp->name;
+ if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_AUTO))
+ continue;
+
if (use_json) {
json_vrf = json_object_new_object();
} else {
@@ -16311,6 +16664,9 @@ static void bgp_show_all_instances_updgrps_vty(struct vty *vty, afi_t afi,
struct bgp *bgp;
for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) {
+ if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_AUTO))
+ continue;
+
if (!uj)
vty_out(vty, "\nInstance %s:\n",
(bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)
@@ -17512,6 +17868,76 @@ DEFUN (bgp_redistribute_ipv6_rmap_metric,
return bgp_redistribute_set(bgp, AFI_IP6, type, 0, changed);
}
+DEFPY(bgp_redistribute_ipv6_table, bgp_redistribute_ipv6_table_cmd,
+ "redistribute table-direct (1-65535)$table_id [{metric$metric (0-4294967295)$metric_val|route-map WORD$rmap}]",
+ "Redistribute information from another routing protocol\n"
+ "Non-main Kernel Routing Table - Direct\n"
+ "Table ID\n"
+ "Metric for redistributed routes\n"
+ "Default metric\n"
+ "Route map reference\n"
+ "Pointer to route-map entries\n")
+{
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
+ bool changed = false;
+ struct route_map *route_map = NULL;
+ struct bgp_redist *red;
+
+ if (rmap)
+ route_map = route_map_lookup_warn_noexist(vty, rmap);
+
+ if (bgp->vrf_id != VRF_DEFAULT) {
+ vty_out(vty,
+ "%% Only default BGP instance can use 'table-direct'\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+ if (table_id == RT_TABLE_MAIN || table_id == RT_TABLE_LOCAL) {
+ vty_out(vty,
+ "%% 'table-direct', can not use %lu routing table\n",
+ table_id);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ red = bgp_redist_add(bgp, AFI_IP6, ZEBRA_ROUTE_TABLE_DIRECT, table_id);
+ if (rmap)
+ changed = bgp_redistribute_rmap_set(red, rmap, route_map);
+ if (metric)
+ changed |= bgp_redistribute_metric_set(bgp, red, AFI_IP6,
+ ZEBRA_ROUTE_TABLE_DIRECT,
+ metric_val);
+ return bgp_redistribute_set(bgp, AFI_IP6, ZEBRA_ROUTE_TABLE_DIRECT,
+ table_id, changed);
+}
+
+DEFPY(no_bgp_redistribute_ipv6_table, no_bgp_redistribute_ipv6_table_cmd,
+ "no redistribute table-direct (1-65535)$table_id [{metric (0-4294967295)|route-map WORD}]",
+ NO_STR
+ "Redistribute information from another routing protocol\n"
+ "Non-main Kernel Routing Table - Direct\n"
+ "Table ID\n"
+ "Metric for redistributed routes\n"
+ "Default metric\n"
+ "Route map reference\n"
+ "Pointer to route-map entries\n")
+{
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
+
+ if (bgp->vrf_id != VRF_DEFAULT) {
+ vty_out(vty,
+ "%% Only default BGP instance can use 'table-direct'\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+ if (table_id == RT_TABLE_MAIN || table_id == RT_TABLE_LOCAL) {
+ vty_out(vty,
+ "%% 'table-direct', can not use %lu routing table\n",
+ table_id);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ bgp_redistribute_unset(bgp, AFI_IP6, ZEBRA_ROUTE_TABLE_DIRECT, table_id);
+ return CMD_SUCCESS;
+}
+
DEFUN (bgp_redistribute_ipv6_metric_rmap,
bgp_redistribute_ipv6_metric_rmap_cmd,
"redistribute " FRR_IP6_REDIST_STR_BGPD " metric (0-4294967295) route-map RMAP_NAME",
@@ -18172,6 +18598,9 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp,
vty_out(vty, " neighbor %s disable-link-bw-encoding-ieee\n",
addr);
+ if (peergroup_flag_check(peer, PEER_FLAG_EXTENDED_LINK_BANDWIDTH))
+ vty_out(vty, " neighbor %s extended-link-bandwidth\n", addr);
+
/* extended-optional-parameters */
if (peergroup_flag_check(peer, PEER_FLAG_EXTENDED_OPT_PARAMS))
vty_out(vty, " neighbor %s extended-optional-parameters\n",
@@ -18231,9 +18660,15 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp,
vty_out(vty, " neighbor %s timers delayopen %u\n", addr,
peer->bgp->default_delayopen);
- /* capability dynamic */
- if (peergroup_flag_check(peer, PEER_FLAG_DYNAMIC_CAPABILITY))
- vty_out(vty, " neighbor %s capability dynamic\n", addr);
+ /* capability software-version */
+ if (CHECK_FLAG(bgp->flags, BGP_FLAG_DYNAMIC_CAPABILITY)) {
+ if (!peergroup_flag_check(peer, PEER_FLAG_DYNAMIC_CAPABILITY))
+ vty_out(vty, " no neighbor %s capability dynamic\n",
+ addr);
+ } else {
+ if (peergroup_flag_check(peer, PEER_FLAG_DYNAMIC_CAPABILITY))
+ vty_out(vty, " neighbor %s capability dynamic\n", addr);
+ }
/* capability extended-nexthop */
if (peergroup_flag_check(peer, PEER_FLAG_CAPABILITY_ENHE)) {
@@ -18282,7 +18717,7 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp,
vty_out(vty, " neighbor %s strict-capability-match\n", addr);
/* Sender side AS path loop detection. */
- if (peer->as_path_loop_detection)
+ if (peergroup_flag_check(peer, PEER_FLAG_AS_LOOP_DETECTION))
vty_out(vty, " neighbor %s sender-as-path-loop-detection\n",
addr);
@@ -18404,6 +18839,11 @@ static void bgp_config_write_peer_af(struct vty *vty, struct bgp *bgp,
if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_DISABLE_ADDPATH_RX))
vty_out(vty, " neighbor %s disable-addpath-rx\n", addr);
+ if (CHECK_FLAG(peer->af_flags[afi][safi],
+ PEER_FLAG_ADDPATH_RX_PATHS_LIMIT))
+ vty_out(vty, " neighbor %s addpath-rx-paths-limit %u\n", addr,
+ peer->addpath_paths_limit[afi][safi].send);
+
/* ORF capability. */
if (peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_ORF_PREFIX_SM)
|| peergroup_af_flag_check(peer, afi, safi,
@@ -18679,7 +19119,16 @@ static void bgp_config_write_family(struct vty *vty, struct bgp *bgp, afi_t afi,
/* BGP flag dampening. */
if (CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING))
- bgp_config_write_damp(vty, afi, safi);
+ bgp_config_write_damp(vty, bgp, afi, safi);
+ for (ALL_LIST_ELEMENTS_RO(bgp->group, node, group))
+ if (peer_af_flag_check(group->conf, afi, safi,
+ PEER_FLAG_CONFIG_DAMPENING))
+ bgp_config_write_peer_damp(vty, group->conf, afi, safi);
+ for (ALL_LIST_ELEMENTS_RO(bgp->peer, node, peer))
+ if (CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE) &&
+ peer_af_flag_check(peer, afi, safi,
+ PEER_FLAG_CONFIG_DAMPENING))
+ bgp_config_write_peer_damp(vty, peer, afi, safi);
for (ALL_LIST_ELEMENTS(bgp->group, node, nnode, group))
bgp_config_write_peer_af(vty, bgp, group->conf, afi, safi);
@@ -18765,9 +19214,9 @@ int bgp_config_write(struct vty *vty)
if (CHECK_FLAG(bm->flags, BM_FLAG_SEND_EXTRA_DATA_TO_ZEBRA))
vty_out(vty, "bgp send-extra-data zebra\n");
- /* BGP session DSCP value */
- if (bm->tcp_dscp != IPTOS_PREC_INTERNETCONTROL)
- vty_out(vty, "bgp session-dscp %u\n", bm->tcp_dscp >> 2);
+ /* DSCP value for outgoing packets in BGP connections */
+ if (bm->ip_tos != IPTOS_PREC_INTERNETCONTROL)
+ vty_out(vty, "bgp session-dscp %u\n", bm->ip_tos >> 2);
/* BGP InQ limit */
if (bm->inq_limit != BM_DEFAULT_Q_LIMIT)
@@ -18919,6 +19368,15 @@ int bgp_config_write(struct vty *vty)
? ""
: "no ");
+ if (!!CHECK_FLAG(bgp->flags, BGP_FLAG_DYNAMIC_CAPABILITY) !=
+ SAVE_BGP_DYNAMIC_CAPABILITY)
+ vty_out(vty,
+ " %sbgp default dynamic-capability\n",
+ CHECK_FLAG(bgp->flags,
+ BGP_FLAG_DYNAMIC_CAPABILITY)
+ ? ""
+ : "no ");
+
/* BGP default subgroup-pkt-queue-max. */
if (bgp->default_subgroup_pkt_queue_max
!= BGP_DEFAULT_SUBGROUP_PKT_QUEUE_MAX)
@@ -19967,6 +20425,9 @@ void bgp_vty_init(void)
/* bgp default software-version-capability */
install_element(BGP_NODE, &bgp_default_software_version_capability_cmd);
+ /* bgp default dynamic-capability */
+ install_element(BGP_NODE, &bgp_default_dynamic_capability_cmd);
+
/* "bgp default subgroup-pkt-queue-max" commands. */
install_element(BGP_NODE, &bgp_default_subgroup_pkt_queue_max_cmd);
install_element(BGP_NODE, &no_bgp_default_subgroup_pkt_queue_max_cmd);
@@ -20565,6 +21026,26 @@ void bgp_vty_init(void)
install_element(BGP_VPNV6_NODE,
&no_neighbor_addpath_tx_bestpath_per_as_cmd);
+ /* "neighbor addpath-rx-paths-limit" commands.*/
+ install_element(BGP_NODE, &neighbor_addpath_paths_limit_cmd);
+ install_element(BGP_NODE, &no_neighbor_addpath_paths_limit_cmd);
+ install_element(BGP_IPV4_NODE, &neighbor_addpath_paths_limit_cmd);
+ install_element(BGP_IPV4_NODE, &no_neighbor_addpath_paths_limit_cmd);
+ install_element(BGP_IPV4M_NODE, &neighbor_addpath_paths_limit_cmd);
+ install_element(BGP_IPV4M_NODE, &no_neighbor_addpath_paths_limit_cmd);
+ install_element(BGP_IPV4L_NODE, &neighbor_addpath_paths_limit_cmd);
+ install_element(BGP_IPV4L_NODE, &no_neighbor_addpath_paths_limit_cmd);
+ install_element(BGP_IPV6_NODE, &neighbor_addpath_paths_limit_cmd);
+ install_element(BGP_IPV6_NODE, &no_neighbor_addpath_paths_limit_cmd);
+ install_element(BGP_IPV6M_NODE, &neighbor_addpath_paths_limit_cmd);
+ install_element(BGP_IPV6M_NODE, &no_neighbor_addpath_paths_limit_cmd);
+ install_element(BGP_IPV6L_NODE, &neighbor_addpath_paths_limit_cmd);
+ install_element(BGP_IPV6L_NODE, &no_neighbor_addpath_paths_limit_cmd);
+ install_element(BGP_VPNV4_NODE, &neighbor_addpath_paths_limit_cmd);
+ install_element(BGP_VPNV4_NODE, &no_neighbor_addpath_paths_limit_cmd);
+ install_element(BGP_VPNV6_NODE, &neighbor_addpath_paths_limit_cmd);
+ install_element(BGP_VPNV6_NODE, &no_neighbor_addpath_paths_limit_cmd);
+
/* "neighbor sender-as-path-loop-detection" commands. */
install_element(BGP_NODE, &neighbor_aspath_loop_detection_cmd);
install_element(BGP_NODE, &no_neighbor_aspath_loop_detection_cmd);
@@ -20641,6 +21122,9 @@ void bgp_vty_init(void)
install_element(BGP_NODE,
&no_neighbor_disable_link_bw_encoding_ieee_cmd);
+
+ install_element(BGP_NODE, &neighbor_extended_link_bw_cmd);
+
/* "neighbor extended-optional-parameters" commands. */
install_element(BGP_NODE, &neighbor_extended_optional_parameters_cmd);
install_element(BGP_NODE,
@@ -20967,6 +21451,15 @@ void bgp_vty_init(void)
install_element(BGP_VPNV6_NODE,
&neighbor_maximum_prefix_threshold_restart_cmd);
install_element(BGP_VPNV6_NODE, &no_neighbor_maximum_prefix_cmd);
+ install_element(BGP_EVPN_NODE, &neighbor_maximum_prefix_cmd);
+ install_element(BGP_EVPN_NODE, &neighbor_maximum_prefix_threshold_cmd);
+ install_element(BGP_EVPN_NODE, &neighbor_maximum_prefix_warning_cmd);
+ install_element(BGP_EVPN_NODE,
+ &neighbor_maximum_prefix_threshold_warning_cmd);
+ install_element(BGP_EVPN_NODE, &neighbor_maximum_prefix_restart_cmd);
+ install_element(BGP_EVPN_NODE,
+ &neighbor_maximum_prefix_threshold_restart_cmd);
+ install_element(BGP_EVPN_NODE, &no_neighbor_maximum_prefix_cmd);
/* "neighbor allowas-in" */
install_element(BGP_NODE, &neighbor_allowas_in_hidden_cmd);
@@ -21014,6 +21507,23 @@ void bgp_vty_init(void)
install_element(BGP_EVPN_NODE, &neighbor_soo_cmd);
install_element(BGP_EVPN_NODE, &no_neighbor_soo_cmd);
+ /* "neighbor dampening" commands. */
+ install_element(BGP_NODE, &neighbor_damp_cmd);
+ install_element(BGP_NODE, &no_neighbor_damp_cmd);
+ install_element(BGP_IPV4_NODE, &neighbor_damp_cmd);
+ install_element(BGP_IPV4_NODE, &no_neighbor_damp_cmd);
+ install_element(BGP_IPV4M_NODE, &neighbor_damp_cmd);
+ install_element(BGP_IPV4M_NODE, &no_neighbor_damp_cmd);
+ install_element(BGP_IPV4L_NODE, &neighbor_damp_cmd);
+ install_element(BGP_IPV4L_NODE, &no_neighbor_damp_cmd);
+ install_element(BGP_IPV6_NODE, &neighbor_damp_cmd);
+ install_element(BGP_IPV6_NODE, &no_neighbor_damp_cmd);
+ install_element(BGP_IPV6M_NODE, &neighbor_damp_cmd);
+ install_element(BGP_IPV6M_NODE, &no_neighbor_damp_cmd);
+ install_element(BGP_IPV6L_NODE, &neighbor_damp_cmd);
+ install_element(BGP_IPV6L_NODE, &no_neighbor_damp_cmd);
+ install_element(VIEW_NODE, &show_ip_bgp_neighbor_damp_param_cmd);
+
/* address-family commands. */
install_element(BGP_NODE, &address_family_ipv4_safi_cmd);
install_element(BGP_NODE, &address_family_ipv6_safi_cmd);
@@ -21117,6 +21627,8 @@ void bgp_vty_init(void)
install_element(BGP_IPV6_NODE, &bgp_redistribute_ipv6_metric_cmd);
install_element(BGP_IPV6_NODE, &bgp_redistribute_ipv6_rmap_metric_cmd);
install_element(BGP_IPV6_NODE, &bgp_redistribute_ipv6_metric_rmap_cmd);
+ install_element(BGP_IPV6_NODE, &bgp_redistribute_ipv6_table_cmd);
+ install_element(BGP_IPV6_NODE, &no_bgp_redistribute_ipv6_table_cmd);
/* import|export vpn [route-map RMAP_NAME] */
install_element(BGP_IPV4_NODE, &bgp_imexport_vpn_cmd);
@@ -21226,9 +21738,6 @@ static const char *community_direct_str(int direct)
static void community_list_perror(struct vty *vty, int ret)
{
switch (ret) {
- case COMMUNITY_LIST_ERR_CANT_FIND_LIST:
- vty_out(vty, "%% Can't find community-list\n");
- break;
case COMMUNITY_LIST_ERR_MALFORMED_VAL:
vty_out(vty, "%% Malformed community-list value\n");
break;
@@ -21338,16 +21847,11 @@ DEFUN (no_community_list_standard_all,
argv_find(argv, argc, "COMMUNITY_LIST_NAME", &idx);
cl_name_or_number = argv[idx]->arg;
- int ret = community_list_unset(bgp_clist, cl_name_or_number, str, seq,
- direct, style);
+ community_list_unset(bgp_clist, cl_name_or_number, str, seq, direct,
+ style);
XFREE(MTYPE_TMP, str);
- if (ret < 0) {
- community_list_perror(vty, ret);
- return CMD_WARNING_CONFIG_FAILED;
- }
-
return CMD_SUCCESS;
}
@@ -21451,16 +21955,11 @@ DEFUN (no_community_list_expanded_all,
argv_find(argv, argc, "COMMUNITY_LIST_NAME", &idx);
cl_name_or_number = argv[idx]->arg;
- int ret = community_list_unset(bgp_clist, cl_name_or_number, str, seq,
- direct, style);
+ community_list_unset(bgp_clist, cl_name_or_number, str, seq, direct,
+ style);
XFREE(MTYPE_TMP, str);
- if (ret < 0) {
- community_list_perror(vty, ret);
- return CMD_WARNING_CONFIG_FAILED;
- }
-
return CMD_SUCCESS;
}
@@ -21616,7 +22115,6 @@ static int lcommunity_list_set_vty(struct vty *vty, int argc,
static int lcommunity_list_unset_vty(struct vty *vty, int argc,
struct cmd_token **argv, int style)
{
- int ret;
int direct = 0;
char *str = NULL;
int idx = 0;
@@ -21649,18 +22147,13 @@ static int lcommunity_list_unset_vty(struct vty *vty, int argc,
argv_find(argv, argc, "LCOMMUNITY_LIST_NAME", &idx);
/* Unset community list. */
- ret = lcommunity_list_unset(bgp_clist, argv[idx]->arg, str, seq, direct,
- style);
+ lcommunity_list_unset(bgp_clist, argv[idx]->arg, str, seq, direct,
+ style);
/* Free temporary community list string allocated by
argv_concat(). */
XFREE(MTYPE_TMP, str);
- if (ret < 0) {
- community_list_perror(vty, ret);
- return CMD_WARNING_CONFIG_FAILED;
- }
-
return CMD_SUCCESS;
}
@@ -22057,16 +22550,11 @@ DEFUN (no_extcommunity_list_standard_all,
argv_find(argv, argc, "EXTCOMMUNITY_LIST_NAME", &idx);
cl_number_or_name = argv[idx]->arg;
- int ret = extcommunity_list_unset(bgp_clist, cl_number_or_name, str,
- seq, direct, style);
+ extcommunity_list_unset(bgp_clist, cl_number_or_name, str, seq, direct,
+ style);
XFREE(MTYPE_TMP, str);
- if (ret < 0) {
- community_list_perror(vty, ret);
- return CMD_WARNING_CONFIG_FAILED;
- }
-
return CMD_SUCCESS;
}
@@ -22122,16 +22610,11 @@ DEFUN (no_extcommunity_list_expanded_all,
argv_find(argv, argc, "EXTCOMMUNITY_LIST_NAME", &idx);
cl_number_or_name = argv[idx]->arg;
- int ret = extcommunity_list_unset(bgp_clist, cl_number_or_name, str,
- seq, direct, style);
+ extcommunity_list_unset(bgp_clist, cl_number_or_name, str, seq, direct,
+ style);
XFREE(MTYPE_TMP, str);
- if (ret < 0) {
- community_list_perror(vty, ret);
- return CMD_WARNING_CONFIG_FAILED;
- }
-
return CMD_SUCCESS;
}
diff --git a/bgpd/bgp_vty.h b/bgpd/bgp_vty.h
index 4955e4c..addd717 100644
--- a/bgpd/bgp_vty.h
+++ b/bgpd/bgp_vty.h
@@ -13,8 +13,6 @@ struct bgp;
#define BGP_INSTANCE_HELP_STR "BGP view\nBGP VRF\nView/VRF name\n"
#define BGP_INSTANCE_ALL_HELP_STR "BGP view\nBGP VRF\nAll Views/VRFs\n"
-#define BGP_AF_STR "Address Family\n"
-#define BGP_AF_MODIFIER_STR "Address Family modifier\n"
#define BGP_AFI_CMD_STR "<ipv4|ipv6>"
#define BGP_AFI_HELP_STR BGP_AF_STR BGP_AF_STR
#define BGP_SAFI_CMD_STR "<unicast|multicast|vpn>"
diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c
index fe29662..5bb177b 100644
--- a/bgpd/bgp_zebra.c
+++ b/bgpd/bgp_zebra.c
@@ -235,6 +235,14 @@ static int bgp_ifp_up(struct interface *ifp)
hook_call(bgp_vrf_status_changed, bgp, ifp);
bgp_nht_ifp_up(ifp);
+ if (bgp_get_default() && if_is_loopback(ifp)) {
+ vpn_leak_zebra_vrf_label_update(bgp, AFI_IP);
+ vpn_leak_zebra_vrf_label_update(bgp, AFI_IP6);
+ vpn_leak_zebra_vrf_sid_update(bgp, AFI_IP);
+ vpn_leak_zebra_vrf_sid_update(bgp, AFI_IP6);
+ vpn_leak_postchange_all();
+ }
+
return 0;
}
@@ -282,16 +290,25 @@ static int bgp_ifp_down(struct interface *ifp)
hook_call(bgp_vrf_status_changed, bgp, ifp);
bgp_nht_ifp_down(ifp);
+ if (bgp_get_default() && if_is_loopback(ifp)) {
+ vpn_leak_zebra_vrf_label_withdraw(bgp, AFI_IP);
+ vpn_leak_zebra_vrf_label_withdraw(bgp, AFI_IP6);
+ vpn_leak_zebra_vrf_sid_withdraw(bgp, AFI_IP);
+ vpn_leak_zebra_vrf_sid_withdraw(bgp, AFI_IP6);
+ vpn_leak_postchange_all();
+ }
+
return 0;
}
static int bgp_interface_address_add(ZAPI_CALLBACK_ARGS)
{
- struct connected *ifc;
+ struct connected *ifc, *connected;
struct bgp *bgp;
struct peer *peer;
struct prefix *addr;
struct listnode *node, *nnode;
+ bool v6_ll_in_nh_global;
afi_t afi;
safi_t safi;
@@ -309,56 +326,70 @@ static int bgp_interface_address_add(ZAPI_CALLBACK_ARGS)
if (!bgp)
return 0;
- if (if_is_operative(ifc->ifp)) {
- bgp_connected_add(bgp, ifc);
+ if (!if_is_operative(ifc->ifp))
+ return 0;
- /* If we have learnt of any neighbors on this interface,
- * check to kick off any BGP interface-based neighbors,
- * but only if this is a link-local address.
- */
- if (IN6_IS_ADDR_LINKLOCAL(&ifc->address->u.prefix6)
- && !list_isempty(ifc->ifp->nbr_connected))
- bgp_start_interface_nbrs(bgp, ifc->ifp);
- else {
- addr = ifc->address;
+ bgp_connected_add(bgp, ifc);
- for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
- if (addr->family == AF_INET)
- continue;
+ /* If we have learnt of any neighbors on this interface,
+ * check to kick off any BGP interface-based neighbors,
+ * but only if this is a link-local address.
+ */
+ if (IN6_IS_ADDR_LINKLOCAL(&ifc->address->u.prefix6) &&
+ !list_isempty(ifc->ifp->nbr_connected))
+ bgp_start_interface_nbrs(bgp, ifc->ifp);
+ else if (ifc->address->family == AF_INET6 &&
+ !IN6_IS_ADDR_LINKLOCAL(&ifc->address->u.prefix6)) {
+ addr = ifc->address;
- /*
- * If the Peer's interface name matches the
- * interface name for which BGP received the
- * update and if the received interface address
- * is a globalV6 and if the peer is currently
- * using a v4-mapped-v6 addr or a link local
- * address, then copy the Rxed global v6 addr
- * into peer's v6_global and send updates out
- * with new nexthop addr.
- */
- if ((peer->conf_if &&
- (strcmp(peer->conf_if, ifc->ifp->name) ==
- 0)) &&
- !IN6_IS_ADDR_LINKLOCAL(&addr->u.prefix6) &&
- ((IS_MAPPED_IPV6(
- &peer->nexthop.v6_global)) ||
- IN6_IS_ADDR_LINKLOCAL(
- &peer->nexthop.v6_global))) {
-
- if (bgp_debug_zebra(ifc->address)) {
- zlog_debug(
- "Update peer %pBP's current intf addr %pI6 and send updates",
- peer,
- &peer->nexthop
- .v6_global);
- }
- memcpy(&peer->nexthop.v6_global,
- &addr->u.prefix6,
- IPV6_MAX_BYTELEN);
- FOREACH_AFI_SAFI (afi, safi)
- bgp_announce_route(peer, afi,
- safi, true);
+ for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
+ v6_ll_in_nh_global = false;
+
+ if (IN6_IS_ADDR_LINKLOCAL(&peer->nexthop.v6_global)) {
+ frr_each (if_connected, ifc->ifp->connected,
+ connected) {
+ if (connected->address->family !=
+ AF_INET6)
+ continue;
+ if (!IPV6_ADDR_SAME(&connected->address
+ ->u.prefix6,
+ &peer->nexthop
+ .v6_global))
+ continue;
+ /* peer->nexthop.v6_global contains a link-local address
+ * that needs to be replaced by the global address.
+ */
+ v6_ll_in_nh_global = true;
+ break;
+ }
+ }
+
+ /*
+ * If the Peer's interface name matches the
+ * interface name for which BGP received the
+ * update and if the received interface address
+ * is a globalV6 and if the peer is currently
+ * using a v4-mapped-v6 addr or a link local
+ * address, then copy the Rxed global v6 addr
+ * into peer's v6_global and send updates out
+ * with new nexthop addr.
+ */
+ if (v6_ll_in_nh_global ||
+ (peer->conf_if &&
+ strcmp(peer->conf_if, ifc->ifp->name) == 0 &&
+ (IS_MAPPED_IPV6(&peer->nexthop.v6_global) ||
+ IN6_IS_ADDR_LINKLOCAL(&peer->nexthop.v6_global)))) {
+ if (bgp_debug_zebra(ifc->address)) {
+ zlog_debug("Update peer %pBP's current intf global addr from %pI6 to %pI6 and send updates",
+ peer,
+ &peer->nexthop.v6_global,
+ &addr->u.prefix6);
}
+ memcpy(&peer->nexthop.v6_global,
+ &addr->u.prefix6, IPV6_MAX_BYTELEN);
+ FOREACH_AFI_SAFI (afi, safi)
+ bgp_announce_route(peer, afi, safi,
+ true);
}
}
}
@@ -369,10 +400,14 @@ static int bgp_interface_address_add(ZAPI_CALLBACK_ARGS)
static int bgp_interface_address_delete(ZAPI_CALLBACK_ARGS)
{
struct listnode *node, *nnode;
- struct connected *ifc;
+ struct connected *ifc, *connected;
struct peer *peer;
struct bgp *bgp;
struct prefix *addr;
+ struct in6_addr *v6_global = NULL;
+ struct in6_addr *v6_local = NULL;
+ afi_t afi;
+ safi_t safi;
bgp = bgp_lookup_by_vrf_id(vrf_id);
@@ -391,7 +426,18 @@ static int bgp_interface_address_delete(ZAPI_CALLBACK_ARGS)
addr = ifc->address;
- if (bgp) {
+ if (bgp && addr->family == AF_INET6 &&
+ !IN6_IS_ADDR_LINKLOCAL(&addr->u.prefix6)) {
+ /* find another IPv6 global if possible and find the IPv6 link-local */
+ frr_each (if_connected, ifc->ifp->connected, connected) {
+ if (connected->address->family != AF_INET6)
+ continue;
+ if (IN6_IS_ADDR_LINKLOCAL(&connected->address->u.prefix6))
+ v6_local = &connected->address->u.prefix6;
+ else
+ v6_global = &connected->address->u.prefix6;
+ }
+
/*
* When we are using the v6 global as part of the peering
* nexthops and we are removing it, then we need to
@@ -400,17 +446,17 @@ static int bgp_interface_address_delete(ZAPI_CALLBACK_ARGS)
* we do not want the peering to bounce.
*/
for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
- afi_t afi;
- safi_t safi;
-
- if (addr->family == AF_INET)
- continue;
-
- if (!IN6_IS_ADDR_LINKLOCAL(&addr->u.prefix6)
- && memcmp(&peer->nexthop.v6_global,
- &addr->u.prefix6, 16)
- == 0) {
- memset(&peer->nexthop.v6_global, 0, 16);
+ if (IPV6_ADDR_SAME(&peer->nexthop.v6_global,
+ &addr->u.prefix6)) {
+ if (v6_global)
+ IPV6_ADDR_COPY(&peer->nexthop.v6_global,
+ v6_global);
+ else if (v6_local)
+ IPV6_ADDR_COPY(&peer->nexthop.v6_global,
+ v6_local);
+ else
+ memset(&peer->nexthop.v6_global, 0,
+ IPV6_MAX_BYTELEN);
FOREACH_AFI_SAFI (afi, safi)
bgp_announce_route(peer, afi, safi,
true);
@@ -927,7 +973,8 @@ bgp_path_info_to_ipv6_nexthop(struct bgp_path_info *path, ifindex_t *ifindex)
|| path->attr->mp_nexthop_len
== BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL) {
/* Check if route-map is set to prefer global over link-local */
- if (path->attr->mp_nexthop_prefer_global) {
+ if (CHECK_FLAG(path->attr->nh_flags,
+ BGP_ATTR_NH_MP_PREFER_GLOBAL)) {
nexthop = &path->attr->mp_nexthop_global;
if (IN6_IS_ADDR_LINKLOCAL(nexthop))
*ifindex = path->attr->nh_ifindex;
@@ -1194,7 +1241,7 @@ static bool update_ipv6nh_for_route_install(int nh_othervrf, struct bgp *nh_bgp,
}
static bool bgp_zebra_use_nhop_weighted(struct bgp *bgp, struct attr *attr,
- uint32_t *nh_weight)
+ uint64_t *nh_weight)
{
/* zero link-bandwidth and link-bandwidth not present are treated
* as the same situation.
@@ -1226,7 +1273,7 @@ static void bgp_zebra_announce_parse_nexthop(
struct bgp_path_info local_info;
struct bgp_path_info *mpinfo_cp = &local_info;
mpls_label_t *labels;
- uint32_t num_labels = 0;
+ uint8_t num_labels = 0;
mpls_label_t nh_label;
int nh_othervrf = 0;
bool nh_updated = false;
@@ -1254,9 +1301,7 @@ static void bgp_zebra_announce_parse_nexthop(
}
for (; mpinfo; mpinfo = bgp_path_info_mpath_next(mpinfo)) {
- labels = NULL;
- num_labels = 0;
- uint32_t nh_weight;
+ uint64_t nh_weight;
bool is_evpn;
bool is_parent_evpn;
@@ -1286,25 +1331,19 @@ static void bgp_zebra_announce_parse_nexthop(
&nh_weight))
continue;
}
- if (CHECK_FLAG(info->flags, BGP_PATH_SELECTED))
- api_nh = &api->nexthops[*valid_nh_count];
- else
- api_nh = &api->backup_nexthops[*valid_nh_count];
+ api_nh = &api->nexthops[*valid_nh_count];
- if (CHECK_FLAG(info->attr->flag,
- ATTR_FLAG_BIT(BGP_ATTR_SRTE_COLOR)))
- api_nh->srte_color = bgp_attr_get_color(info->attr);
+ api_nh->srte_color = bgp_attr_get_color(info->attr);
if (bgp_debug_zebra(&api->prefix)) {
- if (mpinfo->extra) {
+ if (bgp_path_info_num_labels(mpinfo)) {
zlog_debug("%s: p=%pFX, bgp_is_valid_label: %d",
__func__, p,
bgp_is_valid_label(
- &mpinfo->extra->label[0]));
+ &mpinfo->extra->labels
+ ->label[0]));
} else {
- zlog_debug(
- "%s: p=%pFX, extra is NULL, no label",
- __func__, p);
+ zlog_debug("%s: p=%pFX, no label", __func__, p);
}
}
@@ -1370,13 +1409,10 @@ static void bgp_zebra_announce_parse_nexthop(
mpinfo->peer->sort == BGP_PEER_CONFED))
*allow_recursion = true;
- if (mpinfo->extra) {
- labels = mpinfo->extra->label;
- num_labels = mpinfo->extra->num_labels;
- }
+ num_labels = bgp_path_info_num_labels(mpinfo);
+ labels = num_labels ? mpinfo->extra->labels->label : NULL;
- if (labels && (num_labels > 0) &&
- (is_evpn || bgp_is_valid_label(&labels[0]))) {
+ if (num_labels && (is_evpn || bgp_is_valid_label(&labels[0]))) {
enum lsp_types_t nh_label_type = ZEBRA_LSP_NONE;
if (is_evpn) {
@@ -1501,15 +1537,16 @@ static void bgp_debug_zebra_nh(struct zapi_route *api)
snprintf(eth_buf, sizeof(eth_buf), " RMAC %s",
prefix_mac2str(&api_nh->rmac, buf1,
sizeof(buf1)));
- zlog_debug(" nhop [%d]: %s if %u VRF %u wt %u %s %s %s", i + 1,
- nh_buf, api_nh->ifindex, api_nh->vrf_id,
+ zlog_debug(" nhop [%d]: %s if %u VRF %u wt %" PRIu64
+ " %s %s %s",
+ i + 1, nh_buf, api_nh->ifindex, api_nh->vrf_id,
api_nh->weight, label_buf, segs_buf, eth_buf);
}
}
-void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p,
- struct bgp_path_info *info, struct bgp *bgp, afi_t afi,
- safi_t safi)
+static enum zclient_send_status
+bgp_zebra_announce_actual(struct bgp_dest *dest, struct bgp_path_info *info,
+ struct bgp *bgp)
{
struct bgp_path_info *bpi_ultimate;
struct zapi_route api = { 0 };
@@ -1521,35 +1558,19 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p,
route_tag_t tag;
bool is_add;
uint32_t nhg_id = 0;
- uint32_t recursion_flag = 0;
-
- /*
- * BGP is installing this route and bgp has been configured
- * to suppress announcements until the route has been installed
- * let's set the fact that we expect this route to be installed
- */
- if (BGP_SUPPRESS_FIB_ENABLED(bgp))
- SET_FLAG(dest->flags, BGP_NODE_FIB_INSTALL_PENDING);
-
- /* Don't try to install if we're not connected to Zebra or Zebra doesn't
- * know of this instance.
- */
- if (!bgp_install_info_to_zebra(bgp))
- return;
-
- if (bgp->main_zebra_update_hold)
- return;
+ struct bgp_table *table = bgp_dest_table(dest);
+ const struct prefix *p = bgp_dest_get_prefix(dest);
- if (safi == SAFI_FLOWSPEC) {
- bgp_pbr_update_entry(bgp, bgp_dest_get_prefix(dest), info, afi,
- safi, true);
- return;
+ if (table->safi == SAFI_FLOWSPEC) {
+ bgp_pbr_update_entry(bgp, p, info, table->afi, table->safi,
+ true);
+ return ZCLIENT_SEND_SUCCESS;
}
/* Make Zebra API structure. */
api.vrf_id = bgp->vrf_id;
api.type = ZEBRA_ROUTE_BGP;
- api.safi = safi;
+ api.safi = table->safi;
api.prefix = *p;
SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
@@ -1579,15 +1600,15 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p,
api.tableid = info->attr->rmap_table_id;
}
- if (CHECK_FLAG(info->attr->flag, ATTR_FLAG_BIT(BGP_ATTR_SRTE_COLOR)))
+ if (info->attr->srte_color)
SET_FLAG(api.message, ZAPI_MESSAGE_SRTE);
/* Metric is currently based on the best-path only */
metric = info->attr->med;
bgp_zebra_announce_parse_nexthop(info, p, bgp, &api, &valid_nh_count,
- afi, safi, &nhg_id, &metric, &tag,
- &allow_recursion);
+ table->afi, table->safi, &nhg_id,
+ &metric, &tag, &allow_recursion);
is_add = (valid_nh_count || nhg_id) ? true : false;
@@ -1640,7 +1661,7 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p,
api.tag = tag;
}
- distance = bgp_distance_apply(p, info, afi, safi, bgp);
+ distance = bgp_distance_apply(p, info, table->afi, table->safi, bgp);
if (distance) {
SET_FLAG(api.message, ZAPI_MESSAGE_DISTANCE);
api.distance = distance;
@@ -1654,16 +1675,14 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p,
api.metric, api.tag, api.nexthop_num, nhg_id);
bgp_debug_zebra_nh(&api);
- if (CHECK_FLAG(api.flags, ZEBRA_FLAG_ALLOW_RECURSION))
- recursion_flag = 1;
-
zlog_debug("%s: %pFX: announcing to zebra (recursion %sset)",
- __func__, p, (recursion_flag ? "" : "NOT "));
+ __func__, p, (allow_recursion ? "" : "NOT "));
}
- zclient_route_send(is_add ? ZEBRA_ROUTE_ADD : ZEBRA_ROUTE_DELETE,
- zclient, &api);
+ return zclient_route_send(is_add ? ZEBRA_ROUTE_ADD : ZEBRA_ROUTE_DELETE,
+ zclient, &api);
}
+
/* Announce all routes of a table to zebra */
void bgp_zebra_announce_table(struct bgp *bgp, afi_t afi, safi_t safi)
{
@@ -1684,14 +1703,11 @@ void bgp_zebra_announce_table(struct bgp *bgp, afi_t afi, safi_t safi)
for (dest = bgp_table_top(table); dest; dest = bgp_route_next(dest))
for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next)
if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED) &&
-
(pi->type == ZEBRA_ROUTE_BGP
&& (pi->sub_type == BGP_ROUTE_NORMAL
|| pi->sub_type == BGP_ROUTE_IMPORTED)))
-
- bgp_zebra_announce(dest,
- bgp_dest_get_prefix(dest),
- pi, bgp, afi, safi);
+ bgp_zebra_route_install(dest, pi, bgp, true,
+ NULL, false);
}
/* Announce routes of any bgp subtype of a table to zebra */
@@ -1713,39 +1729,30 @@ void bgp_zebra_announce_table_all_subtypes(struct bgp *bgp, afi_t afi,
for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next)
if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED) &&
pi->type == ZEBRA_ROUTE_BGP)
- bgp_zebra_announce(dest,
- bgp_dest_get_prefix(dest),
- pi, bgp, afi, safi);
+ bgp_zebra_route_install(dest, pi, bgp, true,
+ NULL, false);
}
-void bgp_zebra_withdraw(const struct prefix *p, struct bgp_path_info *info,
- struct bgp *bgp, afi_t afi, safi_t safi)
+enum zclient_send_status bgp_zebra_withdraw_actual(struct bgp_dest *dest,
+ struct bgp_path_info *info,
+ struct bgp *bgp)
{
struct zapi_route api;
struct peer *peer;
+ struct bgp_table *table = bgp_dest_table(dest);
+ const struct prefix *p = bgp_dest_get_prefix(dest);
- /*
- * If we are withdrawing the route, we don't need to have this
- * flag set. So unset it.
- */
- UNSET_FLAG(info->net->flags, BGP_NODE_FIB_INSTALL_PENDING);
-
- /* Don't try to install if we're not connected to Zebra or Zebra doesn't
- * know of this instance.
- */
- if (!bgp_install_info_to_zebra(bgp))
- return;
-
- if (safi == SAFI_FLOWSPEC) {
+ if (table->safi == SAFI_FLOWSPEC) {
peer = info->peer;
- bgp_pbr_update_entry(peer->bgp, p, info, afi, safi, false);
- return;
+ bgp_pbr_update_entry(peer->bgp, p, info, table->afi,
+ table->safi, false);
+ return ZCLIENT_SEND_SUCCESS;
}
memset(&api, 0, sizeof(api));
api.vrf_id = bgp->vrf_id;
api.type = ZEBRA_ROUTE_BGP;
- api.safi = safi;
+ api.safi = table->safi;
api.prefix = *p;
if (info->attr->rmap_table_id) {
@@ -1757,7 +1764,218 @@ void bgp_zebra_withdraw(const struct prefix *p, struct bgp_path_info *info,
zlog_debug("Tx route delete VRF %u %pFX", bgp->vrf_id,
&api.prefix);
- zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api);
+ return zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api);
+}
+
+/*
+ * Walk the new Fifo list one by one and invoke bgp_zebra_announce/withdraw
+ * to install/withdraw the routes to zebra.
+ *
+ * If status = ZCLIENT_SEND_SUCCESS (Buffer empt)y i.e. Zebra is free to
+ * receive more incoming data, then pick the next item on the list and
+ * continue processing.
+ *
+ * If status = ZCLIENT_SEND_BUFFERED (Buffer pending) i.e. Zebra is busy,
+ * break and bail out of the function because once at some point when zebra
+ * is free, a callback is triggered which inturn call this same function and
+ * continue processing items on list.
+ */
+#define ZEBRA_ANNOUNCEMENTS_LIMIT 1000
+static void bgp_handle_route_announcements_to_zebra(struct event *e)
+{
+ bool is_evpn = false;
+ uint32_t count = 0;
+ struct bgp_dest *dest = NULL;
+ struct bgp_table *table = NULL;
+ enum zclient_send_status status = ZCLIENT_SEND_SUCCESS;
+ bool install;
+ const struct prefix_evpn *evp = NULL;
+
+ while (count < ZEBRA_ANNOUNCEMENTS_LIMIT) {
+ is_evpn = false;
+
+ dest = zebra_announce_pop(&bm->zebra_announce_head);
+
+ if (!dest)
+ break;
+
+ table = bgp_dest_table(dest);
+ install = CHECK_FLAG(dest->flags, BGP_NODE_SCHEDULE_FOR_INSTALL);
+ if (table->afi == AFI_L2VPN && table->safi == SAFI_EVPN) {
+ is_evpn = true;
+ evp = (const struct prefix_evpn *)bgp_dest_get_prefix(
+ dest);
+ }
+
+ if (BGP_DEBUG(zebra, ZEBRA))
+ zlog_debug("BGP %s route %pBD(%s) with dest %p and flags 0x%x to zebra",
+ install ? "announcing" : "withdrawing", dest,
+ table->bgp->name_pretty, dest, dest->flags);
+
+ if (install) {
+ if (is_evpn)
+ status =
+ evpn_zebra_install(table->bgp,
+ dest->za_vpn,
+ (const struct prefix_evpn
+ *)
+ bgp_dest_get_prefix(
+ dest),
+ dest->za_bgp_pi);
+ else
+ status = bgp_zebra_announce_actual(dest,
+ dest->za_bgp_pi,
+ table->bgp);
+ UNSET_FLAG(dest->flags, BGP_NODE_SCHEDULE_FOR_INSTALL);
+ } else {
+ if (is_evpn)
+ status = evpn_zebra_uninstall(
+ table->bgp, dest->za_vpn,
+ (const struct prefix_evpn *)
+ bgp_dest_get_prefix(dest),
+ dest->za_bgp_pi, false);
+ else
+ status = bgp_zebra_withdraw_actual(dest,
+ dest->za_bgp_pi,
+ table->bgp);
+
+ UNSET_FLAG(dest->flags, BGP_NODE_SCHEDULE_FOR_DELETE);
+ }
+
+ if (is_evpn && status == ZCLIENT_SEND_FAILURE)
+ flog_err(EC_BGP_EVPN_FAIL,
+ "%s (%u): Failed to %s EVPN %pFX %s route in VNI %u",
+ vrf_id_to_name(table->bgp->vrf_id),
+ table->bgp->vrf_id,
+ install ? "install" : "uninstall", evp,
+ evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE
+ ? "MACIP"
+ : "IMET",
+ dest->za_vpn->vni);
+
+ bgp_path_info_unlock(dest->za_bgp_pi);
+ dest->za_bgp_pi = NULL;
+ dest->za_vpn = NULL;
+ bgp_dest_unlock_node(dest);
+
+ if (status == ZCLIENT_SEND_BUFFERED)
+ break;
+
+ count++;
+ }
+
+ if (status != ZCLIENT_SEND_BUFFERED &&
+ zebra_announce_count(&bm->zebra_announce_head))
+ event_add_event(bm->master,
+ bgp_handle_route_announcements_to_zebra, NULL,
+ 0, &bm->t_bgp_zebra_route);
+}
+
+/*
+ * Callback function invoked when zclient_flush_data() receives a BUFFER_EMPTY
+ * i.e. zebra is free to receive more incoming data.
+ */
+static void bgp_zebra_buffer_write_ready(void)
+{
+ bgp_handle_route_announcements_to_zebra(NULL);
+}
+
+/*
+ * BGP is now keeping a list of dests with the dest having a pointer
+ * to the bgp_path_info that it will be working on.
+ * Here is the sequence of events that should happen:
+ *
+ * Current State New State Action
+ * ------------- --------- ------
+ * ---- Install Place dest on list, save pi, mark
+ * as going to be installed
+ * ---- Withdrawal Place dest on list, save pi, mark
+ * as going to be deleted
+ *
+ * Install Install Leave dest on list, release old pi,
+ * save new pi, mark as going to be
+ * Installed
+ * Install Withdrawal Leave dest on list, release old pi,
+ * save new pi, mark as going to be
+ * withdrawan, remove install flag
+ *
+ * Withdrawal Install Leave dest on list, release old pi,
+ * save new pi, mark as going to be
+ * installed.
+ * Withdrawal Withdrawal Leave dest on list, release old pi,
+ * save new pi, mark as going to be
+ * withdrawn.
+ */
+void bgp_zebra_route_install(struct bgp_dest *dest, struct bgp_path_info *info,
+ struct bgp *bgp, bool install, struct bgpevpn *vpn,
+ bool is_sync)
+{
+ bool is_evpn = false;
+ struct bgp_table *table = NULL;
+
+ table = bgp_dest_table(dest);
+ if (table && table->afi == AFI_L2VPN && table->safi == SAFI_EVPN)
+ is_evpn = true;
+
+ /*
+ * BGP is installing this route and bgp has been configured
+ * to suppress announcements until the route has been installed
+ * let's set the fact that we expect this route to be installed
+ */
+ if (install) {
+ if (BGP_SUPPRESS_FIB_ENABLED(bgp))
+ SET_FLAG(dest->flags, BGP_NODE_FIB_INSTALL_PENDING);
+
+ if (bgp->main_zebra_update_hold && !is_evpn)
+ return;
+ } else {
+ UNSET_FLAG(dest->flags, BGP_NODE_FIB_INSTALL_PENDING);
+ }
+
+ /*
+ * Don't try to install if we're not connected to Zebra or Zebra doesn't
+ * know of this instance.
+ */
+ if (!bgp_install_info_to_zebra(bgp) && !is_evpn)
+ return;
+
+ if (!CHECK_FLAG(dest->flags, BGP_NODE_SCHEDULE_FOR_INSTALL) &&
+ !CHECK_FLAG(dest->flags, BGP_NODE_SCHEDULE_FOR_DELETE)) {
+ zebra_announce_add_tail(&bm->zebra_announce_head, dest);
+ /*
+ * If neither flag is set and za_bgp_pi is not set then it is a bug
+ */
+ assert(!dest->za_bgp_pi);
+ bgp_path_info_lock(info);
+ bgp_dest_lock_node(dest);
+ dest->za_bgp_pi = info;
+ } else if (CHECK_FLAG(dest->flags, BGP_NODE_SCHEDULE_FOR_INSTALL)) {
+ assert(dest->za_bgp_pi);
+ bgp_path_info_unlock(dest->za_bgp_pi);
+ bgp_path_info_lock(info);
+ dest->za_bgp_pi = info;
+ } else if (CHECK_FLAG(dest->flags, BGP_NODE_SCHEDULE_FOR_DELETE)) {
+ assert(dest->za_bgp_pi);
+ bgp_path_info_unlock(dest->za_bgp_pi);
+ bgp_path_info_lock(info);
+ dest->za_bgp_pi = info;
+ }
+
+ if (is_evpn) {
+ dest->za_vpn = vpn;
+ dest->za_is_sync = is_sync;
+ }
+
+ if (install) {
+ UNSET_FLAG(dest->flags, BGP_NODE_SCHEDULE_FOR_DELETE);
+ SET_FLAG(dest->flags, BGP_NODE_SCHEDULE_FOR_INSTALL);
+ } else {
+ UNSET_FLAG(dest->flags, BGP_NODE_SCHEDULE_FOR_INSTALL);
+ SET_FLAG(dest->flags, BGP_NODE_SCHEDULE_FOR_DELETE);
+ }
+
+ event_add_event(bm->master, bgp_handle_route_announcements_to_zebra,
+ NULL, 0, &bm->t_bgp_zebra_route);
}
/* Withdraw all entries in a BGP instances RIB table from Zebra */
@@ -1778,8 +1996,8 @@ void bgp_zebra_withdraw_table_all_subtypes(struct bgp *bgp, afi_t afi, safi_t sa
for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) {
if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED)
&& (pi->type == ZEBRA_ROUTE_BGP))
- bgp_zebra_withdraw(bgp_dest_get_prefix(dest),
- pi, bgp, afi, safi);
+ bgp_zebra_route_install(dest, pi, bgp, false,
+ NULL, false);
}
}
}
@@ -1964,7 +2182,7 @@ bool bgp_redistribute_metric_set(struct bgp *bgp, struct bgp_redist *red,
bgp_path_info_set_flag(dest, pi,
BGP_PATH_ATTR_CHANGED);
- bgp_process(bgp, dest, afi, SAFI_UNICAST);
+ bgp_process(bgp, dest, pi, afi, SAFI_UNICAST);
}
}
}
@@ -3148,6 +3366,15 @@ static int bgp_ifp_create(struct interface *ifp)
bgp_update_interface_nbrs(bgp, ifp, ifp);
hook_call(bgp_vrf_status_changed, bgp, ifp);
+
+ if (bgp_get_default() && if_is_loopback(ifp)) {
+ vpn_leak_zebra_vrf_label_update(bgp, AFI_IP);
+ vpn_leak_zebra_vrf_label_update(bgp, AFI_IP6);
+ vpn_leak_zebra_vrf_sid_update(bgp, AFI_IP);
+ vpn_leak_zebra_vrf_sid_update(bgp, AFI_IP6);
+ vpn_leak_postchange_all();
+ }
+
return 0;
}
@@ -3452,6 +3679,7 @@ void bgp_zebra_init(struct event_loop *master, unsigned short instance)
zclient = zclient_new(master, &zclient_options_default, bgp_handlers,
array_size(bgp_handlers));
zclient_init(zclient, ZEBRA_ROUTE_BGP, 0, &bgpd_privs);
+ zclient->zebra_buffer_write_ready = bgp_zebra_buffer_write_ready;
zclient->zebra_connected = bgp_zebra_connected;
zclient->zebra_capabilities = bgp_zebra_capabilities;
zclient->nexthop_update = bgp_nexthop_update;
@@ -3892,8 +4120,7 @@ int bgp_zebra_srv6_manager_release_locator_chunk(const char *name)
void bgp_zebra_send_nexthop_label(int cmd, mpls_label_t label,
ifindex_t ifindex, vrf_id_t vrf_id,
enum lsp_types_t ltype, struct prefix *p,
- uint32_t num_labels,
- mpls_label_t out_labels[])
+ uint8_t num_labels, mpls_label_t out_labels[])
{
struct zapi_labels zl = {};
struct zapi_nexthop *znh;
diff --git a/bgpd/bgp_zebra.h b/bgpd/bgp_zebra.h
index 396c833..55a4185 100644
--- a/bgpd/bgp_zebra.h
+++ b/bgpd/bgp_zebra.h
@@ -28,13 +28,11 @@ extern void bgp_zebra_destroy(void);
extern int bgp_zebra_get_table_range(struct zclient *zc, uint32_t chunk_size,
uint32_t *start, uint32_t *end);
extern int bgp_if_update_all(void);
-extern void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p,
- struct bgp_path_info *path, struct bgp *bgp,
- afi_t afi, safi_t safi);
+extern void bgp_zebra_route_install(struct bgp_dest *dest,
+ struct bgp_path_info *path, struct bgp *bgp,
+ bool install, struct bgpevpn *vpn,
+ bool is_sync);
extern void bgp_zebra_announce_table(struct bgp *bgp, afi_t afi, safi_t safi);
-extern void bgp_zebra_withdraw(const struct prefix *p,
- struct bgp_path_info *path, struct bgp *bgp,
- afi_t afi, safi_t safi);
/* Announce routes of any bgp subtype of a table to zebra */
extern void bgp_zebra_announce_table_all_subtypes(struct bgp *bgp, afi_t afi,
@@ -122,9 +120,12 @@ extern int bgp_zebra_srv6_manager_release_locator_chunk(const char *name);
extern void bgp_zebra_send_nexthop_label(int cmd, mpls_label_t label,
ifindex_t index, vrf_id_t vrfid,
enum lsp_types_t ltype,
- struct prefix *p, uint32_t num_labels,
+ struct prefix *p, uint8_t num_labels,
mpls_label_t out_labels[]);
extern bool bgp_zebra_request_label_range(uint32_t base, uint32_t chunk_size,
bool label_auto);
extern void bgp_zebra_release_label_range(uint32_t start, uint32_t end);
+extern enum zclient_send_status
+bgp_zebra_withdraw_actual(struct bgp_dest *dest, struct bgp_path_info *info,
+ struct bgp *bgp);
#endif /* _QUAGGA_BGP_ZEBRA_H */
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index d6d874b..894226a 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -1377,7 +1377,7 @@ int bgp_global_gr_init(struct bgp *bgp)
/*GLOBAL_GR_cmd */ /*no_Global_GR_cmd*/
GLOBAL_GR, GLOBAL_INVALID,
/*GLOBAL_DISABLE_cmd*//*no_Global_Disable_cmd*/
- GLOBAL_INVALID, GLOBAL_HELPER
+ GLOBAL_DISABLE, GLOBAL_HELPER
},
/* GLOBAL_INVALID Mode */
{
@@ -1411,13 +1411,13 @@ int bgp_peer_gr_init(struct peer *peer)
/* Event-> */ /* PEER_DISABLE_CMD */ /* NO_PEER_DISABLE_CMD */
{PEER_DISABLE, bgp_peer_gr_action }, {PEER_INVALID, NULL },
/* Event-> */ /* PEER_HELPER_cmd */ /* NO_PEER_HELPER_CMD */
- { PEER_INVALID, NULL }, {PEER_GLOBAL_INHERIT,
+ { PEER_HELPER, NULL }, {PEER_GLOBAL_INHERIT,
bgp_peer_gr_action }
},
{
/* PEER_GR Mode */
/* Event-> */ /* PEER_GR_CMD */ /* NO_PEER_GR_CMD */
- { PEER_INVALID, NULL }, { PEER_GLOBAL_INHERIT,
+ { PEER_GR, NULL }, { PEER_GLOBAL_INHERIT,
bgp_peer_gr_action },
/* Event-> */ /* PEER_DISABLE_CMD */ /* NO_PEER_DISABLE_CMD */
{PEER_DISABLE, bgp_peer_gr_action }, { PEER_INVALID, NULL },
@@ -1429,7 +1429,7 @@ int bgp_peer_gr_init(struct peer *peer)
/* Event-> */ /* PEER_GR_CMD */ /* NO_PEER_GR_CMD */
{ PEER_GR, bgp_peer_gr_action }, { PEER_INVALID, NULL },
/* Event-> */ /* PEER_DISABLE_CMD */ /* NO_PEER_DISABLE_CMD */
- { PEER_INVALID, NULL }, { PEER_GLOBAL_INHERIT,
+ { PEER_DISABLE, NULL }, { PEER_GLOBAL_INHERIT,
bgp_peer_gr_action },
/* Event-> */ /* PEER_HELPER_cmd */ /* NO_PEER_HELPER_CMD */
{ PEER_HELPER, bgp_peer_gr_action }, { PEER_INVALID, NULL }
@@ -1550,6 +1550,8 @@ struct peer *peer_new(struct bgp *bgp)
PEER_FLAG_SEND_LARGE_COMMUNITY);
peer->addpath_type[afi][safi] = BGP_ADDPATH_NONE;
peer->addpath_best_selected[afi][safi] = 0;
+ peer->addpath_paths_limit[afi][safi].receive = 0;
+ peer->addpath_paths_limit[afi][safi].send = 0;
peer->soo[afi][safi] = NULL;
}
@@ -1565,6 +1567,9 @@ struct peer *peer_new(struct bgp *bgp)
if (CHECK_FLAG(bgp->flags, BGP_FLAG_SOFT_VERSION_CAPABILITY))
peer_flag_set(peer, PEER_FLAG_CAPABILITY_SOFT_VERSION);
+ if (CHECK_FLAG(bgp->flags, BGP_FLAG_DYNAMIC_CAPABILITY))
+ peer_flag_set(peer, PEER_FLAG_DYNAMIC_CAPABILITY);
+
SET_FLAG(peer->flags_invert, PEER_FLAG_CAPABILITY_FQDN);
SET_FLAG(peer->flags, PEER_FLAG_CAPABILITY_FQDN);
@@ -1646,6 +1651,8 @@ void peer_xfer_config(struct peer *peer_dst, struct peer *peer_src)
peer_dst->weight[afi][safi] = peer_src->weight[afi][safi];
peer_dst->addpath_type[afi][safi] =
peer_src->addpath_type[afi][safi];
+ peer_dst->addpath_paths_limit[afi][safi] =
+ peer_src->addpath_paths_limit[afi][safi];
}
for (afidx = BGP_AF_START; afidx < BGP_AF_MAX; afidx++) {
@@ -1869,21 +1876,31 @@ void bgp_peer_conf_if_to_su_update(struct peer_connection *connection)
void bgp_recalculate_afi_safi_bestpaths(struct bgp *bgp, afi_t afi, safi_t safi)
{
struct bgp_dest *dest, *ndest;
+ struct bgp_path_info *pi, *next;
struct bgp_table *table;
for (dest = bgp_table_top(bgp->rib[afi][safi]); dest;
dest = bgp_route_next(dest)) {
table = bgp_dest_get_bgp_table_info(dest);
- if (table != NULL) {
- /* Special handling for 2-level routing
- * tables. */
- if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP
- || safi == SAFI_EVPN) {
- for (ndest = bgp_table_top(table); ndest;
- ndest = bgp_route_next(ndest))
- bgp_process(bgp, ndest, afi, safi);
- } else
- bgp_process(bgp, dest, afi, safi);
+
+ if (!table)
+ continue;
+
+ /* Special handling for 2-level routing
+ * tables. */
+ if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP
+ || safi == SAFI_EVPN) {
+ for (ndest = bgp_table_top(table); ndest;
+ ndest = bgp_route_next(ndest)) {
+ for (pi = bgp_dest_get_bgp_path_info(ndest);
+ (pi != NULL) && (next = pi->next, 1);
+ pi = next)
+ bgp_process(bgp, ndest, pi, afi, safi);
+ }
+ } else {
+ for (pi = bgp_dest_get_bgp_path_info(dest);
+ (pi != NULL) && (next = pi->next, 1); pi = next)
+ bgp_process(bgp, dest, pi, afi, safi);
}
}
}
@@ -2691,6 +2708,14 @@ int peer_delete(struct peer *peer)
if (peer->bfd_config)
bgp_peer_remove_bfd_config(peer);
+ /* Delete peer route flap dampening configuration. This needs to happen
+ * before removing the peer from peer groups.
+ */
+ FOREACH_AFI_SAFI (afi, safi)
+ if (peer_af_flag_check(peer, afi, safi,
+ PEER_FLAG_CONFIG_DAMPENING))
+ bgp_peer_damp_disable(peer, afi, safi);
+
/* If this peer belongs to peer group, clear up the
relationship. */
if (peer->group) {
@@ -2938,6 +2963,13 @@ static void peer_group2peer_config_copy(struct peer_group *group,
SET_FLAG(peer->flags,
PEER_FLAG_CAPABILITY_SOFT_VERSION);
+ /* capability dynamic apply */
+ if (!CHECK_FLAG(peer->flags_override,
+ PEER_FLAG_DYNAMIC_CAPABILITY))
+ if (CHECK_FLAG(conf->flags, PEER_FLAG_DYNAMIC_CAPABILITY))
+ SET_FLAG(peer->flags,
+ PEER_FLAG_DYNAMIC_CAPABILITY);
+
/* password apply */
if (!CHECK_FLAG(peer->flags_override, PEER_FLAG_PASSWORD))
PEER_STR_ATTR_INHERIT(peer, group, password,
@@ -2992,9 +3024,21 @@ int peer_group_remote_as(struct bgp *bgp, const char *group_name, as_t *as,
peer_as_change(group->conf, *as, as_type, as_str);
for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
- if (((peer->as_type == AS_SPECIFIED) && peer->as != *as)
- || (peer->as_type != as_type))
+ if (((peer->as_type == AS_SPECIFIED) && peer->as != *as) ||
+ (peer->as_type != as_type)) {
peer_as_change(peer, *as, as_type, as_str);
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug("%s peer %s set to as_type %u curr status %s trigger BGP_Start",
+ __func__, peer->host, peer->as_type,
+ lookup_msg(bgp_status_msg,
+ peer->connection->status, NULL));
+ /* Start Peer FSM to form neighbor using new as,
+ * NOTE: the connection is triggered upon start
+ * timer expiry.
+ */
+ if (!BGP_PEER_START_SUPPRESSED(peer))
+ BGP_EVENT_ADD(peer->connection, BGP_Start);
+ }
}
return 0;
@@ -3089,7 +3133,7 @@ int peer_group_delete(struct peer_group *group)
int peer_group_remote_as_delete(struct peer_group *group)
{
- struct peer *peer, *other;
+ struct peer *peer;
struct listnode *node, *nnode;
if ((group->conf->as_type == AS_UNSPECIFIED)
@@ -3097,19 +3141,12 @@ int peer_group_remote_as_delete(struct peer_group *group)
return 0;
for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
- other = peer->doppelganger;
-
if (CHECK_FLAG(peer->flags, PEER_FLAG_CAPABILITY_ENHE))
bgp_zebra_terminate_radv(peer->bgp, peer);
- peer_delete(peer);
-
- if (other && other->connection->status != Deleted) {
- other->group = NULL;
- peer_delete(other);
- }
+ /* reset existing peer connection */
+ peer_as_change(peer, 0, AS_UNSPECIFIED, NULL);
}
- list_delete_all_node(group->peer);
group->conf->as = 0;
group->conf->as_type = AS_UNSPECIFIED;
@@ -3583,10 +3620,13 @@ struct bgp *bgp_lookup_by_name(const char *name)
struct bgp *bgp;
struct listnode *node, *nnode;
- for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp))
+ for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) {
+ if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_AUTO))
+ continue;
if ((bgp->name == NULL && name == NULL)
|| (bgp->name && name && strcmp(bgp->name, name) == 0))
return bgp;
+ }
return NULL;
}
@@ -3835,6 +3875,9 @@ void bgp_instance_down(struct bgp *bgp)
struct listnode *node;
struct listnode *next;
+ /* Cleanup evpn instance state */
+ bgp_evpn_instance_down(bgp);
+
/* Stop timers. */
if (bgp->t_rmap_def_originate_eval)
EVENT_OFF(bgp->t_rmap_def_originate_eval);
@@ -3869,10 +3912,35 @@ int bgp_delete(struct bgp *bgp)
afi_t afi;
safi_t safi;
int i;
+ struct bgp_dest *dest = NULL;
+ struct bgp_dest *dest_next = NULL;
+ struct bgp_table *dest_table = NULL;
struct graceful_restart_info *gr_info;
+ uint32_t cnt_before, cnt_after;
assert(bgp);
+ /*
+ * Iterate the pending dest list and remove all the dest pertaininig to
+ * the bgp under delete.
+ */
+ cnt_before = zebra_announce_count(&bm->zebra_announce_head);
+ for (dest = zebra_announce_first(&bm->zebra_announce_head); dest;
+ dest = dest_next) {
+ dest_next = zebra_announce_next(&bm->zebra_announce_head, dest);
+ dest_table = bgp_dest_table(dest);
+ if (dest_table->bgp == bgp) {
+ zebra_announce_del(&bm->zebra_announce_head, dest);
+ bgp_path_info_unlock(dest->za_bgp_pi);
+ bgp_dest_unlock_node(dest);
+ }
+ }
+
+ cnt_after = zebra_announce_count(&bm->zebra_announce_head);
+ if (BGP_DEBUG(zebra, ZEBRA))
+ zlog_debug("Zebra Announce Fifo cleanup count before %u and after %u during BGP %s deletion",
+ cnt_before, cnt_after, bgp->name_pretty);
+
bgp_soft_reconfig_table_task_cancel(bgp, NULL, NULL);
/* make sure we withdraw any exported routes */
@@ -3921,6 +3989,11 @@ int bgp_delete(struct bgp *bgp)
EVENT_OFF(gr_info->t_route_select);
}
+ /* Delete route flap dampening configuration */
+ FOREACH_AFI_SAFI (afi, safi) {
+ bgp_damp_disable(bgp, afi, safi);
+ }
+
if (BGP_DEBUG(zebra, ZEBRA)) {
if (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)
zlog_debug("Deleting Default VRF");
@@ -4385,6 +4458,11 @@ struct peer *peer_lookup_dynamic_neighbor(struct bgp *bgp, union sockunion *su)
zlog_debug("%s Dynamic Neighbor added, group %s count %d",
peer->host, group->name, dncount);
+ if (dncount == gbgp->dynamic_neighbors_limit) {
+ zlog_warn("Dynamic Neighbor %s added as last connection. Peer-group %s reached maximum listen limit %d",
+ peer->host, group->name,
+ gbgp->dynamic_neighbors_limit);
+ }
return peer;
}
@@ -4571,7 +4649,7 @@ static const struct peer_flag_action peer_flag_action_list[] = {
{PEER_FLAG_DONT_CAPABILITY, 0, peer_change_none},
{PEER_FLAG_OVERRIDE_CAPABILITY, 0, peer_change_none},
{PEER_FLAG_STRICT_CAP_MATCH, 0, peer_change_none},
- {PEER_FLAG_DYNAMIC_CAPABILITY, 0, peer_change_reset},
+ {PEER_FLAG_DYNAMIC_CAPABILITY, 0, peer_change_none},
{PEER_FLAG_DISABLE_CONNECTED_CHECK, 0, peer_change_reset},
{PEER_FLAG_CAPABILITY_ENHE, 0, peer_change_reset},
{PEER_FLAG_ENFORCE_FIRST_AS, 0, peer_change_reset_in},
@@ -4594,6 +4672,8 @@ static const struct peer_flag_action peer_flag_action_list[] = {
{PEER_FLAG_GRACEFUL_SHUTDOWN, 0, peer_change_none},
{PEER_FLAG_CAPABILITY_SOFT_VERSION, 0, peer_change_none},
{PEER_FLAG_CAPABILITY_FQDN, 0, peer_change_none},
+ {PEER_FLAG_AS_LOOP_DETECTION, 0, peer_change_none},
+ {PEER_FLAG_EXTENDED_LINK_BANDWIDTH, 0, peer_change_none},
{0, 0, 0}};
static const struct peer_flag_action peer_af_flag_action_list[] = {
@@ -4628,6 +4708,7 @@ static const struct peer_flag_action peer_af_flag_action_list[] = {
{PEER_FLAG_SOO, 0, peer_change_reset},
{PEER_FLAG_ACCEPT_OWN, 0, peer_change_reset},
{PEER_FLAG_SEND_EXT_COMMUNITY_RPKI, 1, peer_change_reset_out},
+ {PEER_FLAG_ADDPATH_RX_PATHS_LIMIT, 0, peer_change_none},
{0, 0, 0}};
/* Proper action set. */
@@ -4758,6 +4839,8 @@ void bgp_shutdown_enable(struct bgp *bgp, const char *msg)
/* iterate through peers of BGP instance */
for (ALL_LIST_ELEMENTS_RO(bgp->peer, node, peer)) {
+ peer->last_reset = PEER_DOWN_USER_SHUTDOWN;
+
/* continue, if peer is already in administrative shutdown. */
if (CHECK_FLAG(peer->flags, PEER_FLAG_SHUTDOWN))
continue;
@@ -4812,8 +4895,10 @@ void bgp_shutdown_disable(struct bgp *bgp)
/* clear the BGP instances shutdown flag */
UNSET_FLAG(bgp->flags, BGP_FLAG_SHUTDOWN);
- for (ALL_LIST_ELEMENTS_RO(bgp->peer, node, peer))
+ for (ALL_LIST_ELEMENTS_RO(bgp->peer, node, peer)) {
bgp_timer_set(peer->connection);
+ peer->last_reset = PEER_DOWN_WAITING_OPEN;
+ }
}
/* Change specified peer flag. */
@@ -4885,6 +4970,10 @@ static int peer_flag_modify(struct peer *peer, uint64_t flag, int set)
bgp_zebra_terminate_radv(peer->bgp, peer);
}
+ if (flag == PEER_FLAG_SHUTDOWN)
+ peer->last_reset = set ? PEER_DOWN_USER_SHUTDOWN
+ : PEER_DOWN_WAITING_OPEN;
+
/* Execute flag action on peer. */
if (action.type == peer_change_reset)
peer_flag_modify_action(peer, flag);
@@ -4920,6 +5009,10 @@ static int peer_flag_modify(struct peer *peer, uint64_t flag, int set)
set ? bgp_zebra_initiate_radv(member->bgp, member)
: bgp_zebra_terminate_radv(member->bgp, member);
+ if (flag == PEER_FLAG_SHUTDOWN)
+ member->last_reset = set ? PEER_DOWN_USER_SHUTDOWN
+ : PEER_DOWN_WAITING_OPEN;
+
/* Execute flag action on peer-group member. */
if (action.type == peer_change_reset)
peer_flag_modify_action(member, flag);
@@ -8298,6 +8391,8 @@ void bgp_master_init(struct event_loop *master, const int buffer_size,
memset(&bgp_master, 0, sizeof(bgp_master));
bm = &bgp_master;
+
+ zebra_announce_init(&bm->zebra_announce_head);
bm->bgp = list_new();
bm->listen_sockets = list_new();
bm->port = BGP_PORT_DEFAULT;
@@ -8311,11 +8406,12 @@ void bgp_master_init(struct event_loop *master, const int buffer_size,
bm->terminating = false;
bm->socket_buffer = buffer_size;
bm->wait_for_fib = false;
- bm->tcp_dscp = IPTOS_PREC_INTERNETCONTROL;
+ bm->ip_tos = IPTOS_PREC_INTERNETCONTROL;
bm->inq_limit = BM_DEFAULT_Q_LIMIT;
bm->outq_limit = BM_DEFAULT_Q_LIMIT;
bm->t_bgp_sync_label_manager = NULL;
bm->t_bgp_start_label_manager = NULL;
+ bm->t_bgp_zebra_route = NULL;
bgp_mac_init();
/* init the rd id space.
@@ -8482,6 +8578,7 @@ void bgp_init(unsigned short instance)
/* BGP inits. */
bgp_attr_init();
+ bgp_labels_init();
bgp_debug_init();
bgp_community_alias_init();
bgp_dump_init();
@@ -8566,6 +8663,7 @@ void bgp_terminate(void)
EVENT_OFF(bm->t_rmap_update);
EVENT_OFF(bm->t_bgp_sync_label_manager);
EVENT_OFF(bm->t_bgp_start_label_manager);
+ EVENT_OFF(bm->t_bgp_zebra_route);
bgp_mac_finish();
}
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index 0f69095..1f8cc53 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -18,6 +18,8 @@
#include "iana_afi.h"
#include "asn.h"
+PREDECL_LIST(zebra_announce);
+
/* For union sockunion. */
#include "queue.h"
#include "sockunion.h"
@@ -31,6 +33,7 @@
#include "bgp_addpath_types.h"
#include "bgp_nexthop.h"
#include "bgp_io.h"
+#include "bgp_damp.h"
#include "lib/bfd.h"
@@ -163,8 +166,8 @@ struct bgp_master {
bool terminating; /* global flag that sigint terminate seen */
- /* DSCP value for TCP sessions */
- uint8_t tcp_dscp;
+ /* TOS value for outgoing packets in BGP connections */
+ uint8_t ip_tos;
#define BM_DEFAULT_Q_LIMIT 10000
uint32_t inq_limit;
@@ -173,8 +176,13 @@ struct bgp_master {
struct event *t_bgp_sync_label_manager;
struct event *t_bgp_start_label_manager;
+ struct event *t_bgp_zebra_route;
+
bool v6_with_v4_nexthops;
+ /* To preserve ordering of installations into zebra across all Vrfs */
+ struct zebra_announce_head zebra_announce_head;
+
QOBJ_FIELDS;
};
DECLARE_QOBJ_TYPE(bgp_master);
@@ -471,7 +479,7 @@ struct bgp {
* factor (e.g., number of multipaths for the prefix)
* Value is in Mbps
*/
- uint32_t lb_ref_bw;
+ uint64_t lb_ref_bw;
#define BGP_LINK_BW_REF_BW 1
/* BGP flags. */
@@ -522,6 +530,8 @@ struct bgp {
#define BGP_FLAG_LU_IPV6_EXPLICIT_NULL (1ULL << 34)
#define BGP_FLAG_SOFT_VERSION_CAPABILITY (1ULL << 35)
#define BGP_FLAG_ENFORCE_FIRST_AS (1ULL << 36)
+#define BGP_FLAG_DYNAMIC_CAPABILITY (1ULL << 37)
+#define BGP_FLAG_VNI_DOWN (1ULL << 38)
/* BGP default address-families.
* New peers inherit enabled afi/safis from bgp instance.
@@ -825,6 +835,9 @@ struct bgp {
enum asnotation_mode asnotation;
+ /* BGP route flap dampening configuration */
+ struct bgp_damp_config damp[AFI_MAX][SAFI_MAX];
+
QOBJ_FIELDS;
};
DECLARE_QOBJ_TYPE(bgp);
@@ -1140,6 +1153,11 @@ struct llgr_info {
uint8_t flags;
};
+struct addpath_paths_limit {
+ uint16_t send;
+ uint16_t receive;
+};
+
struct peer_connection {
struct peer *peer;
@@ -1333,6 +1351,8 @@ struct peer {
#define PEER_CAP_ROLE_RCV (1ULL << 26) /* role received */
#define PEER_CAP_SOFT_VERSION_ADV (1ULL << 27)
#define PEER_CAP_SOFT_VERSION_RCV (1ULL << 28)
+#define PEER_CAP_PATHS_LIMIT_ADV (1U << 29)
+#define PEER_CAP_PATHS_LIMIT_RCV (1U << 30)
/* Capability flags (reset in bgp_stop) */
uint32_t af_cap[AFI_MAX][SAFI_MAX];
@@ -1351,6 +1371,8 @@ struct peer {
#define PEER_CAP_ENHE_AF_NEGO (1U << 14) /* Extended nexthop afi/safi negotiated */
#define PEER_CAP_LLGR_AF_ADV (1U << 15)
#define PEER_CAP_LLGR_AF_RCV (1U << 16)
+#define PEER_CAP_PATHS_LIMIT_AF_ADV (1U << 17)
+#define PEER_CAP_PATHS_LIMIT_AF_RCV (1U << 18)
/* Global configuration flags. */
/*
@@ -1461,6 +1483,8 @@ struct peer {
#define PEER_FLAG_GRACEFUL_SHUTDOWN (1ULL << 35)
#define PEER_FLAG_CAPABILITY_SOFT_VERSION (1ULL << 36)
#define PEER_FLAG_CAPABILITY_FQDN (1ULL << 37) /* fqdn capability */
+#define PEER_FLAG_AS_LOOP_DETECTION (1ULL << 38) /* as path loop detection */
+#define PEER_FLAG_EXTENDED_LINK_BANDWIDTH (1ULL << 39)
/*
*GR-Disabled mode means unset PEER_FLAG_GRACEFUL_RESTART
@@ -1488,6 +1512,9 @@ struct peer {
/* Last update packet sent time */
time_t pkt_stime[AFI_MAX][SAFI_MAX];
+ /* Peer / peer group route flap dampening configuration */
+ struct bgp_damp_config damp[AFI_MAX][SAFI_MAX];
+
/* Peer Per AF flags */
/*
* Please consult the comments for *flags_override*, *flags_invert* and
@@ -1528,6 +1555,8 @@ struct peer {
#define PEER_FLAG_DISABLE_ADDPATH_RX (1ULL << 27)
#define PEER_FLAG_SOO (1ULL << 28)
#define PEER_FLAG_SEND_EXT_COMMUNITY_RPKI (1ULL << 29)
+#define PEER_FLAG_ADDPATH_RX_PATHS_LIMIT (1ULL << 30)
+#define PEER_FLAG_CONFIG_DAMPENING (1U << 31)
#define PEER_FLAG_ACCEPT_OWN (1ULL << 63)
enum bgp_addpath_strat addpath_type[AFI_MAX][SAFI_MAX];
@@ -1647,6 +1676,8 @@ struct peer {
uint32_t stat_pfx_nh_invalid;
uint32_t stat_pfx_dup_withdraw;
uint32_t stat_upd_7606; /* RFC7606: treat-as-withdraw */
+ uint64_t stat_pfx_loc_rib; /* RFC7854 : Number of routes in Loc-RIB */
+ uint64_t stat_pfx_adj_rib_in; /* RFC7854 : Number of routes in Adj-RIBs-In */
/* BGP state count */
uint32_t established; /* Established */
@@ -1813,9 +1844,6 @@ struct peer {
char *hostname;
char *domainname;
- /* Sender side AS path loop detection. */
- bool as_path_loop_detection;
-
/* Extended Message Support */
uint16_t max_packet_size;
@@ -1845,6 +1873,9 @@ struct peer {
/* Add-Path Best selected paths number to advertise */
uint8_t addpath_best_selected[AFI_MAX][SAFI_MAX];
+ /* Add-Path Paths-Limit */
+ struct addpath_paths_limit addpath_paths_limit[AFI_MAX][SAFI_MAX];
+
QOBJ_FIELDS;
};
DECLARE_QOBJ_TYPE(peer);
@@ -1951,7 +1982,6 @@ struct bgp_nlri {
#define BGP_ATTR_LARGE_COMMUNITIES 32
#define BGP_ATTR_OTC 35
#define BGP_ATTR_PREFIX_SID 40
-#define BGP_ATTR_SRTE_COLOR 51
#ifdef ENABLE_BGP_VNC_ATTR
#define BGP_ATTR_VNC 255
#endif
@@ -1970,6 +2000,7 @@ struct bgp_nlri {
#define BGP_NOTIFY_FSM_ERR 5
#define BGP_NOTIFY_CEASE 6
#define BGP_NOTIFY_ROUTE_REFRESH_ERR 7
+#define BGP_NOTIFY_SEND_HOLD_ERR 8
/* Subcodes for BGP Finite State Machine Error */
#define BGP_NOTIFY_FSM_ERR_SUBCODE_UNSPECIFIC 0
diff --git a/bgpd/rfapi/rfapi.c b/bgpd/rfapi/rfapi.c
index 382af05..23e3eb4 100644
--- a/bgpd/rfapi/rfapi.c
+++ b/bgpd/rfapi/rfapi.c
@@ -463,7 +463,7 @@ void del_vnc_route(struct rfapi_descriptor *rfd,
bgp_aggregate_decrement(bgp, p, bpi, afi, safi);
bgp_path_info_delete(bn, bpi);
- bgp_process(bgp, bn, afi, safi);
+ bgp_process(bgp, bn, bpi, afi, safi);
} else {
vnc_zlog_debug_verbose(
"%s: Couldn't find route (safi=%d) at prefix %pFX",
@@ -549,6 +549,7 @@ void add_vnc_route(struct rfapi_descriptor *rfd, /* cookie, VPN UN addr, peer */
int flags)
{
afi_t afi; /* of the VN address */
+ struct bgp_labels bgp_labels = {};
struct bgp_path_info *new;
struct bgp_path_info *bpi;
struct bgp_dest *bn;
@@ -592,7 +593,7 @@ void add_vnc_route(struct rfapi_descriptor *rfd, /* cookie, VPN UN addr, peer */
}
}
- if (label)
+ if (label && *label != MPLS_INVALID_LABEL)
label_val = *label;
else
label_val = MPLS_LABEL_IMPLICIT_NULL;
@@ -1001,7 +1002,7 @@ void add_vnc_route(struct rfapi_descriptor *rfd, /* cookie, VPN UN addr, peer */
/* Process change. */
bgp_aggregate_increment(bgp, p, bpi, afi, safi);
- bgp_process(bgp, bn, afi, safi);
+ bgp_process(bgp, bn, bpi, afi, safi);
bgp_dest_unlock_node(bn);
vnc_zlog_debug_any(
@@ -1020,7 +1021,10 @@ void add_vnc_route(struct rfapi_descriptor *rfd, /* cookie, VPN UN addr, peer */
new->extra->vnc = XCALLOC(MTYPE_BGP_ROUTE_EXTRA_VNC,
sizeof(struct bgp_path_info_extra_vnc));
new->extra->vnc->vnc.export.rfapi_handle = (void *)rfd;
- encode_label(label_val, &new->extra->label[0]);
+
+ encode_label(label_val, &bgp_labels.label[0]);
+ bgp_labels.num_labels = 1;
+ new->extra->labels = bgp_labels_intern(&bgp_labels);
/* debug */
@@ -1046,7 +1050,7 @@ void add_vnc_route(struct rfapi_descriptor *rfd, /* cookie, VPN UN addr, peer */
}
bgp_dest_unlock_node(bn);
- bgp_process(bgp, bn, afi, safi);
+ bgp_process(bgp, bn, new, afi, safi);
vnc_zlog_debug_any(
"%s: Added route (safi=%s) at prefix %s (bn=%p, prd=%pRDP)",
diff --git a/bgpd/rfapi/rfapi_import.c b/bgpd/rfapi/rfapi_import.c
index 168b8e4..2afcb2f 100644
--- a/bgpd/rfapi/rfapi_import.c
+++ b/bgpd/rfapi/rfapi_import.c
@@ -442,6 +442,7 @@ static struct bgp_path_info *rfapiBgpInfoCreate(struct attr *attr,
uint32_t *label)
{
struct bgp_path_info *new;
+ struct bgp_labels bgp_labels = {};
new = info_make(type, sub_type, 0, peer, attr, NULL);
@@ -454,8 +455,11 @@ static struct bgp_path_info *rfapiBgpInfoCreate(struct attr *attr,
new->extra->vnc->vnc.import.rd = *prd;
new->extra->vnc->vnc.import.create_time = monotime(NULL);
}
- if (label)
- encode_label(*label, &new->extra->label[0]);
+ if (label && *label != MPLS_INVALID_LABEL) {
+ encode_label(*label, &bgp_labels.label[0]);
+ bgp_labels.num_labels = 1;
+ new->extra->labels = bgp_labels_intern(&bgp_labels);
+ }
peer_lock(peer);
@@ -1267,7 +1271,10 @@ rfapiRouteInfo2NextHopEntry(struct rfapi_ip_prefix *rprefix,
bpi->extra->vnc->vnc.import.rd.val[1];
/* label comes from MP_REACH_NLRI label */
- vo->v.l2addr.label = decode_label(&bpi->extra->label[0]);
+ vo->v.l2addr.label =
+ bgp_path_info_num_labels(bpi)
+ ? decode_label(&bpi->extra->labels->label[0])
+ : MPLS_INVALID_LABEL;
new->vn_options = vo;
@@ -4154,15 +4161,16 @@ static void rfapiBgpTableFilteredImport(struct bgp *bgp,
for (bpi = bgp_dest_get_bgp_path_info(dest2);
bpi; bpi = bpi->next) {
- uint32_t label = 0;
+ uint32_t label = MPLS_INVALID_LABEL;
if (CHECK_FLAG(bpi->flags,
BGP_PATH_REMOVED))
continue;
- if (bpi->extra)
+ if (bgp_path_info_num_labels(bpi))
label = decode_label(
- &bpi->extra->label[0]);
+ &bpi->extra->labels
+ ->label[0]);
(*rfapiBgpInfoFilteredImportFunction(
safi))(
it, /* which import table */
diff --git a/bgpd/rfapi/rfapi_rib.c b/bgpd/rfapi/rfapi_rib.c
index 316904e..a0bdf49 100644
--- a/bgpd/rfapi/rfapi_rib.c
+++ b/bgpd/rfapi/rfapi_rib.c
@@ -691,7 +691,10 @@ static void rfapiRibBi2Ri(struct bgp_path_info *bpi, struct rfapi_info *ri,
bpi->extra->vnc->vnc.import.rd.val[1];
/* label comes from MP_REACH_NLRI label */
- vo->v.l2addr.label = decode_label(&bpi->extra->label[0]);
+ vo->v.l2addr.label =
+ bgp_path_info_num_labels(bpi)
+ ? decode_label(&bpi->extra->labels->label[0])
+ : MPLS_INVALID_LABEL;
rfapi_vn_options_free(
ri->vn_options); /* maybe free old version */
diff --git a/bgpd/rfapi/rfapi_vty.c b/bgpd/rfapi/rfapi_vty.c
index 5da99db..9bfb6c4 100644
--- a/bgpd/rfapi/rfapi_vty.c
+++ b/bgpd/rfapi/rfapi_vty.c
@@ -413,12 +413,12 @@ void rfapi_vty_out_vncinfo(struct vty *vty, const struct prefix *p,
XFREE(MTYPE_ECOMMUNITY_STR, s);
}
- if (bpi->extra != NULL) {
- if (bpi->extra->label[0] == BGP_PREVENT_VRF_2_VRF_LEAK)
+ if (bgp_path_info_num_labels(bpi)) {
+ if (bpi->extra->labels->label[0] == BGP_PREVENT_VRF_2_VRF_LEAK)
vty_out(vty, " label=VRF2VRF");
else
vty_out(vty, " label=%u",
- decode_label(&bpi->extra->label[0]));
+ decode_label(&bpi->extra->labels->label[0]));
}
if (bpi->attr->srv6_l3vpn || bpi->attr->srv6_vpn) {
@@ -1052,8 +1052,8 @@ static int rfapiPrintRemoteRegBi(struct bgp *bgp, void *stream,
snprintf(buf_un, sizeof(buf_un), "%s",
inet_ntop(pfx_vn.family, &pfx_vn.u.prefix, buf_ntop,
sizeof(buf_ntop)));
- if (bpi->extra) {
- uint32_t l = decode_label(&bpi->extra->label[0]);
+ if (bgp_path_info_num_labels(bpi)) {
+ uint32_t l = decode_label(&bpi->extra->labels->label[0]);
snprintf(buf_vn, sizeof(buf_vn), "Label: %d", l);
} else /* should never happen */
{
@@ -1161,8 +1161,8 @@ static int rfapiPrintRemoteRegBi(struct bgp *bgp, void *stream,
}
}
}
- if (tun_type != BGP_ENCAP_TYPE_MPLS && bpi->extra) {
- uint32_t l = decode_label(&bpi->extra->label[0]);
+ if (tun_type != BGP_ENCAP_TYPE_MPLS && bgp_path_info_num_labels(bpi)) {
+ uint32_t l = decode_label(&bpi->extra->labels->label[0]);
if (!MPLS_LABEL_IS_NULL(l)) {
fp(out, " Label: %d", l);
diff --git a/bgpd/rfapi/vnc_import_bgp.c b/bgpd/rfapi/vnc_import_bgp.c
index c067b7a..2bb7c1b 100644
--- a/bgpd/rfapi/vnc_import_bgp.c
+++ b/bgpd/rfapi/vnc_import_bgp.c
@@ -414,7 +414,7 @@ static void vnc_import_bgp_add_route_mode_resolve_nve_one_bi(
uint32_t lifetime;
uint32_t *plifetime;
struct bgp_attr_encap_subtlv *encaptlvs;
- uint32_t label = 0;
+ uint32_t label;
struct rfapi_un_option optary[3];
struct rfapi_un_option *opt = NULL;
@@ -470,16 +470,19 @@ static void vnc_import_bgp_add_route_mode_resolve_nve_one_bi(
if (bgp_attr_get_ecommunity(bpi->attr))
ecommunity_merge(new_ecom, bgp_attr_get_ecommunity(bpi->attr));
- if (bpi->extra)
- label = decode_label(&bpi->extra->label[0]);
+ if (bgp_path_info_num_labels(bpi))
+ label = decode_label(&bpi->extra->labels->label[0]);
+ else
+ label = MPLS_INVALID_LABEL;
add_vnc_route(&vncHDResolveNve, bgp, SAFI_MPLS_VPN,
- prefix, /* unicast route prefix */
+ prefix, /* unicast route prefix */
prd, &nexthop_h, /* new nexthop */
local_pref, plifetime,
(struct bgp_tea_options *)encaptlvs, /* RFP options */
opt, NULL, new_ecom, med, /* NULL => don't set med */
- (label ? &label : NULL), /* NULL= default */
+ ((label != MPLS_INVALID_LABEL) ? &label
+ : NULL), /* NULL= default */
ZEBRA_ROUTE_BGP_DIRECT, BGP_ROUTE_REDISTRIBUTE,
RFAPI_AHR_RFPOPT_IS_VNCTLV); /* flags */
@@ -1678,7 +1681,7 @@ static void vnc_import_bgp_exterior_add_route_it(
bpi_interior = bpi_interior->next) {
struct prefix_rd *prd;
struct attr new_attr;
- uint32_t label = 0;
+ uint32_t label;
if (!is_usable_interior_route(bpi_interior))
continue;
@@ -1695,14 +1698,19 @@ static void vnc_import_bgp_exterior_add_route_it(
*/
have_usable_route = 1;
- if (bpi_interior->extra) {
+ if (bpi_interior->extra)
prd = &bpi_interior->extra->vnc->vnc
.import.rd;
- label = decode_label(
- &bpi_interior->extra->label[0]);
- } else
+ else
prd = NULL;
+ if (bgp_path_info_num_labels(bpi_interior))
+ label = decode_label(
+ &bpi_interior->extra->labels
+ ->label[0]);
+ else
+ label = MPLS_INVALID_LABEL;
+
/* use local_pref from unicast route */
memset(&new_attr, 0, sizeof(new_attr));
new_attr = *bpi_interior->attr;
@@ -1851,7 +1859,7 @@ void vnc_import_bgp_exterior_del_route(
for (bpi_interior = rn->info; bpi_interior;
bpi_interior = bpi_interior->next) {
struct prefix_rd *prd;
- uint32_t label = 0;
+ uint32_t label;
if (!is_usable_interior_route(bpi_interior))
continue;
@@ -1864,14 +1872,19 @@ void vnc_import_bgp_exterior_del_route(
*/
have_usable_route = 1;
- if (bpi_interior->extra) {
+ if (bpi_interior->extra)
prd = &bpi_interior->extra->vnc->vnc
.import.rd;
- label = decode_label(
- &bpi_interior->extra->label[0]);
- } else
+ else
prd = NULL;
+ if (bgp_path_info_num_labels(bpi_interior))
+ label = decode_label(
+ &bpi_interior->extra->labels
+ ->label[0]);
+ else
+ label = MPLS_INVALID_LABEL;
+
rfapiBgpInfoFilteredImportVPN(
it, FIF_ACTION_KILL, bpi_interior->peer,
NULL, /* rfd */
@@ -2007,18 +2020,22 @@ void vnc_import_bgp_exterior_add_route_interior(
struct prefix_rd *prd;
struct attr new_attr;
- uint32_t label = 0;
+ uint32_t label;
assert(bpi_exterior);
assert(pfx_exterior);
- if (bpi_interior->extra) {
+ if (bpi_interior->extra)
prd = &bpi_interior->extra->vnc->vnc.import.rd;
- label = decode_label(
- &bpi_interior->extra->label[0]);
- } else
+ else
prd = NULL;
+ if (bgp_path_info_num_labels(bpi_interior))
+ label = decode_label(
+ &bpi_interior->extra->labels->label[0]);
+ else
+ label = MPLS_INVALID_LABEL;
+
/* use local_pref from unicast route */
memset(&new_attr, 0, sizeof(struct attr));
new_attr = *bpi_interior->attr;
@@ -2097,7 +2114,7 @@ void vnc_import_bgp_exterior_add_route_interior(
struct bgp_path_info *bpi;
struct prefix_rd *prd;
struct attr new_attr;
- uint32_t label = 0;
+ uint32_t label;
/* do pull-down */
@@ -2124,15 +2141,19 @@ void vnc_import_bgp_exterior_add_route_interior(
* parent routes.
*/
for (bpi = par->info; bpi; bpi = bpi->next) {
-
- if (bpi->extra) {
+ if (bpi->extra)
prd = &bpi->extra->vnc->vnc
.import.rd;
- label = decode_label(
- &bpi->extra->label[0]);
- } else
+ else
prd = NULL;
+ if (bgp_path_info_num_labels(bpi))
+ label = decode_label(
+ &bpi->extra->labels
+ ->label[0]);
+ else
+ label = MPLS_INVALID_LABEL;
+
rfapiBgpInfoFilteredImportVPN(
it, FIF_ACTION_KILL, bpi->peer,
NULL, /* rfd */
@@ -2147,14 +2168,19 @@ void vnc_import_bgp_exterior_add_route_interior(
* Add constructed exterior routes based on
* the new interior route at longer prefix.
*/
- if (bpi_interior->extra) {
+ if (bpi_interior->extra)
prd = &bpi_interior->extra->vnc->vnc
.import.rd;
- label = decode_label(
- &bpi_interior->extra->label[0]);
- } else
+ else
prd = NULL;
+ if (bgp_path_info_num_labels(bpi_interior))
+ label = decode_label(
+ &bpi_interior->extra->labels
+ ->label[0]);
+ else
+ label = MPLS_INVALID_LABEL;
+
/* use local_pref from unicast route */
memset(&new_attr, 0, sizeof(struct attr));
new_attr = *bpi_interior->attr;
@@ -2237,7 +2263,7 @@ void vnc_import_bgp_exterior_add_route_interior(
struct prefix_rd *prd;
struct attr new_attr;
- uint32_t label = 0;
+ uint32_t label;
/* do pull-down */
@@ -2266,13 +2292,17 @@ void vnc_import_bgp_exterior_add_route_interior(
* Add constructed exterior routes based on the
* new interior route at the longer prefix.
*/
- if (bpi_interior->extra) {
+ if (bpi_interior->extra)
prd = &bpi_interior->extra->vnc->vnc.import.rd;
- label = decode_label(
- &bpi_interior->extra->label[0]);
- } else
+ else
prd = NULL;
+ if (bgp_path_info_num_labels(bpi_interior))
+ label = decode_label(
+ &bpi_interior->extra->labels->label[0]);
+ else
+ label = MPLS_INVALID_LABEL;
+
/* use local_pref from unicast route */
memset(&new_attr, 0, sizeof(struct attr));
new_attr = *bpi_interior->attr;
@@ -2372,14 +2402,19 @@ void vnc_import_bgp_exterior_del_route_interior(
&cursor)) {
struct prefix_rd *prd;
- uint32_t label = 0;
+ uint32_t label;
- if (bpi_interior->extra) {
+ if (bpi_interior->extra)
prd = &bpi_interior->extra->vnc->vnc.import.rd;
- label = decode_label(&bpi_interior->extra->label[0]);
- } else
+ else
prd = NULL;
+ if (bgp_path_info_num_labels(bpi_interior))
+ label = decode_label(
+ &bpi_interior->extra->labels->label[0]);
+ else
+ label = MPLS_INVALID_LABEL;
+
rfapiBgpInfoFilteredImportVPN(
it, FIF_ACTION_KILL, bpi_interior->peer, NULL, /* rfd */
pfx_exterior, NULL, afi, prd, bpi_interior->attr,
@@ -2446,18 +2481,22 @@ void vnc_import_bgp_exterior_del_route_interior(
struct prefix_rd *prd;
struct attr new_attr;
- uint32_t label = 0;
+ uint32_t label;
if (bpi->type == ZEBRA_ROUTE_BGP_DIRECT_EXT)
continue;
- if (bpi->extra) {
+ if (bpi->extra)
prd = &bpi->extra->vnc->vnc.import.rd;
- label = decode_label(
- &bpi->extra->label[0]);
- } else
+ else
prd = NULL;
+ if (bgp_path_info_num_labels(bpi))
+ label = decode_label(
+ &bpi->extra->labels->label[0]);
+ else
+ label = MPLS_INVALID_LABEL;
+
/* use local_pref from unicast route */
memset(&new_attr, 0, sizeof(new_attr));
new_attr = *bpi->attr;