summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_attr.c16
-rw-r--r--bgpd/bgp_attr.h1
-rw-r--r--bgpd/bgp_conditional_adv.c1
-rw-r--r--bgpd/bgp_open.c17
-rw-r--r--bgpd/bgp_open.h2
-rw-r--r--bgpd/bgp_packet.c327
-rw-r--r--bgpd/bgp_snmp.c85
-rw-r--r--bgpd/bgp_snmp.h3
-rw-r--r--bgpd/bgp_snmp_bgp4.c4
-rw-r--r--bgpd/bgp_snmp_bgp4.h4
-rw-r--r--bgpd/bgp_snmp_bgp4v2.c105
-rw-r--r--bgpd/bgp_snmp_bgp4v2.h10
-rw-r--r--bgpd/bgp_vty.c82
-rw-r--r--bgpd/bgpd.c35
-rw-r--r--bgpd/bgpd.h6
-rw-r--r--bgpd/subdir.am1
-rw-r--r--doc/developer/topotests.rst6
-rw-r--r--doc/user/bgp.rst27
-rw-r--r--doc/user/snmptrap.rst20
-rw-r--r--lib/northbound.c5
-rw-r--r--pimd/pim_register.c7
-rw-r--r--tests/topotests/all_protocol_startup/test_all_protocol_startup.py6
-rw-r--r--tests/topotests/bgp_conditional_advertisement_static_route/__init__.py0
-rw-r--r--tests/topotests/bgp_conditional_advertisement_static_route/r1/frr.conf10
-rw-r--r--tests/topotests/bgp_conditional_advertisement_static_route/r2/frr.conf39
-rw-r--r--tests/topotests/bgp_conditional_advertisement_static_route/r3/frr.conf19
-rw-r--r--tests/topotests/bgp_conditional_advertisement_static_route/test_bgp_conditional_advertisement_static_route.py118
-rw-r--r--tests/topotests/bgp_dynamic_capability/r1/frr.conf2
-rw-r--r--tests/topotests/bgp_dynamic_capability/r2/frr.conf1
-rw-r--r--tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_addpath.py2
-rw-r--r--tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_orf.py172
-rw-r--r--tests/topotests/bgp_snmp_bgp4v2mib/r2/snmpd.conf9
-rw-r--r--tests/topotests/bgp_snmp_bgp4v2mib/r2/snmptrapd.conf2
-rwxr-xr-xtests/topotests/bgp_snmp_bgp4v2mib/test_bgp_snmp_bgp4v2mib.py92
-rw-r--r--tests/topotests/bgp_unique_rid/test_bgp_unique_rid.py149
-rwxr-xr-xtests/topotests/conftest.py6
-rw-r--r--tests/topotests/lib/snmptest.py56
-rw-r--r--tests/topotests/lib/topogen.py6
-rw-r--r--tests/topotests/lib/topotest.py115
-rw-r--r--watchfrr/watchfrr.c3
-rw-r--r--zebra/debug_nl.c1
-rw-r--r--zebra/zebra_nhg.c82
42 files changed, 1510 insertions, 144 deletions
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
index 6925aff727..cf2dbe65b8 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -2421,7 +2421,7 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args,
mp_update->afi = afi;
mp_update->safi = safi;
- return BGP_ATTR_PARSE_EOR;
+ return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_MAL_ATTR, 0);
}
mp_update->afi = afi;
@@ -3385,13 +3385,15 @@ bgp_attr_unknown(struct bgp_attr_parser_args *args)
}
/* Well-known attribute check. */
-static int bgp_attr_check(struct peer *peer, struct attr *attr)
+static int bgp_attr_check(struct peer *peer, struct attr *attr,
+ bgp_size_t length)
{
uint8_t type = 0;
/* BGP Graceful-Restart End-of-RIB for IPv4 unicast is signaled as an
* empty UPDATE. */
- if (CHECK_FLAG(peer->cap, PEER_CAP_RESTART_RCV) && !attr->flag)
+ if (CHECK_FLAG(peer->cap, PEER_CAP_RESTART_RCV) && !attr->flag &&
+ !length)
return BGP_ATTR_PARSE_PROCEED;
/* "An UPDATE message that contains the MP_UNREACH_NLRI is not required
@@ -3443,7 +3445,7 @@ enum bgp_attr_parse_ret bgp_attr_parse(struct peer *peer, struct attr *attr,
enum bgp_attr_parse_ret ret;
uint8_t flag = 0;
uint8_t type = 0;
- bgp_size_t length;
+ bgp_size_t length = 0;
uint8_t *startp, *endp;
uint8_t *attr_endp;
uint8_t seen[BGP_ATTR_BITMAP_SIZE];
@@ -3759,10 +3761,6 @@ enum bgp_attr_parse_ret bgp_attr_parse(struct peer *peer, struct attr *attr,
goto done;
}
- if (ret == BGP_ATTR_PARSE_EOR) {
- goto done;
- }
-
if (ret == BGP_ATTR_PARSE_ERROR) {
flog_warn(EC_BGP_ATTRIBUTE_PARSE_ERROR,
"%s: Attribute %s, parse error", peer->host,
@@ -3835,7 +3833,7 @@ enum bgp_attr_parse_ret bgp_attr_parse(struct peer *peer, struct attr *attr,
}
/* Check all mandatory well-known attributes are present */
- ret = bgp_attr_check(peer, attr);
+ ret = bgp_attr_check(peer, attr, length);
if (ret < 0)
goto done;
diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h
index 961e5f1224..fc347e7a1b 100644
--- a/bgpd/bgp_attr.h
+++ b/bgpd/bgp_attr.h
@@ -364,7 +364,6 @@ enum bgp_attr_parse_ret {
/* only used internally, send notify + convert to BGP_ATTR_PARSE_ERROR
*/
BGP_ATTR_PARSE_ERROR_NOTIFYPLS = -3,
- BGP_ATTR_PARSE_EOR = -4,
};
struct bpacket_attr_vec_arr;
diff --git a/bgpd/bgp_conditional_adv.c b/bgpd/bgp_conditional_adv.c
index b30052d95a..3b5f5e986b 100644
--- a/bgpd/bgp_conditional_adv.c
+++ b/bgpd/bgp_conditional_adv.c
@@ -90,6 +90,7 @@ static void bgp_conditional_adv_routes(struct peer *peer, afi_t afi,
addpath_capable = bgp_addpath_encode_tx(peer, afi, safi);
+ SET_FLAG(subgrp->sflags, SUBGRP_STATUS_FORCE_UPDATES);
for (dest = bgp_table_top(table); dest; dest = bgp_route_next(dest)) {
dest_p = bgp_dest_get_prefix(dest);
assert(dest_p);
diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c
index 866930c732..545da7c559 100644
--- a/bgpd/bgp_open.c
+++ b/bgpd/bgp_open.c
@@ -340,15 +340,14 @@ static void bgp_capability_orf_not_support(struct peer *peer, iana_afi_t afi,
peer->host, afi, safi, type, mode);
}
-static const struct message orf_type_str[] = {
- {ORF_TYPE_RESERVED, "Reserved"},
- {ORF_TYPE_PREFIX, "Prefixlist"},
- {0}};
-
-static const struct message orf_mode_str[] = {{ORF_MODE_RECEIVE, "Receive"},
- {ORF_MODE_SEND, "Send"},
- {ORF_MODE_BOTH, "Both"},
- {0}};
+const struct message orf_type_str[] = { { ORF_TYPE_RESERVED, "Reserved" },
+ { ORF_TYPE_PREFIX, "Prefixlist" },
+ { 0 } };
+
+const struct message orf_mode_str[] = { { ORF_MODE_RECEIVE, "Receive" },
+ { ORF_MODE_SEND, "Send" },
+ { ORF_MODE_BOTH, "Both" },
+ { 0 } };
static int bgp_capability_orf_entry(struct peer *peer,
struct capability_header *hdr)
diff --git a/bgpd/bgp_open.h b/bgpd/bgp_open.h
index a92c56d1b5..34f4b7619e 100644
--- a/bgpd/bgp_open.h
+++ b/bgpd/bgp_open.h
@@ -108,5 +108,7 @@ extern void bgp_capability_vty_out(struct vty *vty, struct peer *peer,
bool use_json, json_object *json_neigh);
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[];
#endif /* _QUAGGA_BGP_OPEN_H */
diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c
index fe39488d56..a7514a26aa 100644
--- a/bgpd/bgp_packet.c
+++ b/bgpd/bgp_packet.c
@@ -1214,8 +1214,12 @@ void bgp_capability_send(struct peer *peer, afi_t afi, safi_t safi,
uint32_t gr_restart_time;
uint8_t addpath_afi_safi_count = 0;
bool adv_addpath_tx = false;
+ unsigned long number_of_orfs_p;
+ uint8_t number_of_orfs = 0;
const char *capability = lookup_msg(capcode_str, capability_code,
"Unknown");
+ const char *hostname = cmd_hostname_get();
+ const char *domainname = cmd_domainname_get();
if (!peer_established(peer->connection))
return;
@@ -1458,12 +1462,119 @@ void bgp_capability_send(struct peer *peer, afi_t afi, safi_t safi,
iana_safi2str(pkt_safi));
break;
- case CAPABILITY_CODE_REFRESH:
case CAPABILITY_CODE_ORF:
+ /* Convert AFI, SAFI to values for packet. */
+ bgp_map_afi_safi_int2iana(afi, safi, &pkt_afi, &pkt_safi);
+
+ stream_putc(s, action);
+ stream_putc(s, CAPABILITY_CODE_ORF);
+ cap_len = stream_get_endp(s);
+ stream_putc(s, 0);
+
+ stream_putw(s, pkt_afi); /* Address Family Identifier */
+ stream_putc(s, 0); /* Reserved */
+ stream_putc(s,
+ pkt_safi); /* Subsequent Address Family Identifier */
+
+ number_of_orfs_p =
+ stream_get_endp(s); /* Number of ORFs pointer */
+ stream_putc(s, 0); /* Number of ORFs */
+
+ /* Address Prefix ORF */
+ if (CHECK_FLAG(peer->af_flags[afi][safi],
+ PEER_FLAG_ORF_PREFIX_SM) ||
+ CHECK_FLAG(peer->af_flags[afi][safi],
+ PEER_FLAG_ORF_PREFIX_RM)) {
+ stream_putc(s, ORF_TYPE_PREFIX);
+
+ if (CHECK_FLAG(peer->af_flags[afi][safi],
+ PEER_FLAG_ORF_PREFIX_SM) &&
+ CHECK_FLAG(peer->af_flags[afi][safi],
+ PEER_FLAG_ORF_PREFIX_RM)) {
+ SET_FLAG(peer->af_cap[afi][safi],
+ PEER_CAP_ORF_PREFIX_SM_ADV);
+ SET_FLAG(peer->af_cap[afi][safi],
+ PEER_CAP_ORF_PREFIX_RM_ADV);
+ stream_putc(s, ORF_MODE_BOTH);
+ } else if (CHECK_FLAG(peer->af_flags[afi][safi],
+ PEER_FLAG_ORF_PREFIX_SM)) {
+ SET_FLAG(peer->af_cap[afi][safi],
+ PEER_CAP_ORF_PREFIX_SM_ADV);
+ UNSET_FLAG(peer->af_cap[afi][safi],
+ PEER_CAP_ORF_PREFIX_RM_ADV);
+ stream_putc(s, ORF_MODE_SEND);
+ } else {
+ SET_FLAG(peer->af_cap[afi][safi],
+ PEER_CAP_ORF_PREFIX_RM_ADV);
+ UNSET_FLAG(peer->af_cap[afi][safi],
+ PEER_CAP_ORF_PREFIX_SM_ADV);
+ stream_putc(s, ORF_MODE_RECEIVE);
+ }
+ number_of_orfs++;
+ } else {
+ UNSET_FLAG(peer->af_cap[afi][safi],
+ PEER_CAP_ORF_PREFIX_SM_ADV);
+ UNSET_FLAG(peer->af_cap[afi][safi],
+ PEER_CAP_ORF_PREFIX_RM_ADV);
+ }
+
+ /* Total Number of ORFs. */
+ stream_putc_at(s, number_of_orfs_p, number_of_orfs);
+
+ len = stream_get_endp(s) - cap_len - 1;
+ stream_putc_at(s, cap_len, len);
+
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug("%pBP sending CAPABILITY has %s %s for afi/safi: %s/%s",
+ peer,
+ action == CAPABILITY_ACTION_SET
+ ? "Advertising"
+ : "Removing",
+ capability, iana_afi2str(pkt_afi),
+ iana_safi2str(pkt_safi));
+ break;
+ case CAPABILITY_CODE_FQDN:
+ if (hostname) {
+ SET_FLAG(peer->cap, PEER_CAP_HOSTNAME_ADV);
+ stream_putc(s, action);
+ stream_putc(s, CAPABILITY_CODE_FQDN);
+ cap_len = stream_get_endp(s);
+ stream_putc(s, 0); /* Capability Length */
+
+ len = strlen(hostname);
+ if (len > BGP_MAX_HOSTNAME)
+ len = BGP_MAX_HOSTNAME;
+
+ stream_putc(s, len);
+ stream_put(s, hostname, len);
+
+ if (domainname) {
+ len = strlen(domainname);
+ if (len > BGP_MAX_HOSTNAME)
+ len = BGP_MAX_HOSTNAME;
+
+ stream_putc(s, len);
+ stream_put(s, domainname, len);
+ } else
+ stream_putc(s, 0);
+
+ len = stream_get_endp(s) - cap_len - 1;
+ stream_putc_at(s, cap_len, len);
+
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug("%pBP sending CAPABILITY has %s %s for afi/safi: %s/%s",
+ peer,
+ action == CAPABILITY_ACTION_SET
+ ? "Advertising"
+ : "Removing",
+ capability, iana_afi2str(pkt_afi),
+ iana_safi2str(pkt_safi));
+ }
+ break;
+ case CAPABILITY_CODE_REFRESH:
case CAPABILITY_CODE_AS4:
case CAPABILITY_CODE_DYNAMIC:
case CAPABILITY_CODE_ENHANCED_RR:
- case CAPABILITY_CODE_FQDN:
case CAPABILITY_CODE_ENHE:
case CAPABILITY_CODE_EXT_MESSAGE:
break;
@@ -2325,8 +2436,7 @@ static int bgp_update_receive(struct peer_connection *connection,
* Non-MP IPv4/Unicast EoR is a completely empty UPDATE
* and MP EoR should have only an empty MP_UNREACH
*/
- if ((!update_len && !withdraw_len && nlris[NLRI_MP_UPDATE].length == 0)
- || (attr_parse_ret == BGP_ATTR_PARSE_EOR)) {
+ if (!update_len && !withdraw_len && nlris[NLRI_MP_UPDATE].length == 0) {
afi_t afi = 0;
safi_t safi;
struct graceful_restart_info *gr_info;
@@ -2347,9 +2457,6 @@ static int bgp_update_receive(struct peer_connection *connection,
&& nlris[NLRI_MP_WITHDRAW].length == 0) {
afi = nlris[NLRI_MP_WITHDRAW].afi;
safi = nlris[NLRI_MP_WITHDRAW].safi;
- } else if (attr_parse_ret == BGP_ATTR_PARSE_EOR) {
- afi = nlris[NLRI_MP_UPDATE].afi;
- safi = nlris[NLRI_MP_UPDATE].safi;
}
if (afi && peer->afc[afi][safi]) {
@@ -3044,6 +3151,204 @@ static void bgp_dynamic_capability_addpath(uint8_t *pnt, int action,
}
}
+static void bgp_dynamic_capability_orf(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;
+
+ struct capability_mp_data mpc;
+ uint8_t num;
+ iana_afi_t pkt_afi;
+ afi_t afi;
+ iana_safi_t pkt_safi;
+ safi_t safi;
+ uint8_t type;
+ uint8_t mode;
+ uint16_t sm_cap = PEER_CAP_ORF_PREFIX_SM_RCV;
+ uint16_t rm_cap = PEER_CAP_ORF_PREFIX_RM_RCV;
+ int i;
+
+ if (data + CAPABILITY_CODE_ORF_LEN > end) {
+ flog_warn(EC_BGP_CAPABILITY_INVALID_LENGTH,
+ "ORF: Received invalid length %zu, less than %d", len,
+ CAPABILITY_CODE_ORF_LEN);
+ return;
+ }
+
+ /* ORF Entry header */
+ memcpy(&mpc, data, sizeof(mpc));
+ data += sizeof(mpc);
+ num = *data++;
+ pkt_afi = ntohs(mpc.afi);
+ pkt_safi = mpc.safi;
+
+ /* Convert AFI, SAFI to internal values, check. */
+ if (bgp_map_afi_safi_iana2int(pkt_afi, pkt_safi, &afi, &safi)) {
+ zlog_info("%pBP Addr-family %d/%d not supported. Ignoring the ORF capability",
+ peer, pkt_afi, pkt_safi);
+ return;
+ }
+
+ /* validate number field */
+ if (CAPABILITY_CODE_ORF_LEN + (num * 2) > hdr->length) {
+ zlog_info("%pBP ORF Capability entry length error, Cap length %u, num %u",
+ peer, hdr->length, num);
+ return;
+ }
+
+ if (action == CAPABILITY_ACTION_UNSET) {
+ UNSET_FLAG(peer->af_cap[afi][safi], sm_cap);
+ UNSET_FLAG(peer->af_cap[afi][safi], rm_cap);
+ return;
+ }
+
+ for (i = 0; i < num; i++) {
+ if (data + 1 > end) {
+ flog_err(EC_BGP_CAPABILITY_INVALID_LENGTH,
+ "%pBP ORF Capability entry length (type) error, Cap length %u, num %u",
+ peer, hdr->length, num);
+ return;
+ }
+ type = *data++;
+
+ if (data + 1 > end) {
+ flog_err(EC_BGP_CAPABILITY_INVALID_LENGTH,
+ "%pBP ORF Capability entry length (mode) error, Cap length %u, num %u",
+ peer, hdr->length, num);
+ return;
+ }
+ mode = *data++;
+
+ /* ORF Mode error check */
+ switch (mode) {
+ case ORF_MODE_BOTH:
+ case ORF_MODE_SEND:
+ case ORF_MODE_RECEIVE:
+ break;
+ default:
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug("%pBP Addr-family %d/%d has ORF type/mode %d/%d not supported",
+ peer, afi, safi, type, mode);
+ continue;
+ }
+
+ if (!((afi == AFI_IP && safi == SAFI_UNICAST) ||
+ (afi == AFI_IP && safi == SAFI_MULTICAST) ||
+ (afi == AFI_IP6 && safi == SAFI_UNICAST))) {
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug("%pBP Addr-family %d/%d unsupported AFI/SAFI received",
+ peer, afi, safi);
+ continue;
+ }
+
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug("%pBP OPEN has %s ORF capability as %s for afi/safi: %s/%s",
+ peer, lookup_msg(orf_type_str, type, NULL),
+ lookup_msg(orf_mode_str, mode, NULL),
+ iana_afi2str(pkt_afi),
+ iana_safi2str(pkt_safi));
+
+ switch (mode) {
+ case ORF_MODE_BOTH:
+ SET_FLAG(peer->af_cap[afi][safi], sm_cap);
+ SET_FLAG(peer->af_cap[afi][safi], rm_cap);
+ break;
+ case ORF_MODE_SEND:
+ SET_FLAG(peer->af_cap[afi][safi], sm_cap);
+ UNSET_FLAG(peer->af_cap[afi][safi], rm_cap);
+ break;
+ case ORF_MODE_RECEIVE:
+ SET_FLAG(peer->af_cap[afi][safi], rm_cap);
+ UNSET_FLAG(peer->af_cap[afi][safi], sm_cap);
+ break;
+ }
+ }
+}
+
+static void bgp_dynamic_capability_fqdn(uint8_t *pnt, int action,
+ struct capability_header *hdr,
+ struct peer *peer)
+{
+ uint8_t *data = pnt + 3;
+ uint8_t *end = data + hdr->length;
+ char str[BGP_MAX_HOSTNAME + 1] = {};
+ uint8_t len;
+
+ if (action == CAPABILITY_ACTION_SET) {
+ /* hostname */
+ if (data + 1 > end) {
+ zlog_err("%pBP: Received invalid FQDN capability (host name length)",
+ peer);
+ return;
+ }
+
+ len = *data;
+ if (data + len > end) {
+ zlog_err("%pBP: Received invalid FQDN capability length (host name) %d",
+ peer, hdr->length);
+ return;
+ }
+ data++;
+
+ if (len > BGP_MAX_HOSTNAME) {
+ memcpy(&str, data, BGP_MAX_HOSTNAME);
+ str[BGP_MAX_HOSTNAME] = '\0';
+ } else if (len) {
+ memcpy(&str, data, len);
+ str[len] = '\0';
+ }
+ data += len;
+
+ if (len) {
+ XFREE(MTYPE_BGP_PEER_HOST, peer->hostname);
+ XFREE(MTYPE_BGP_PEER_HOST, peer->domainname);
+
+ peer->hostname = XSTRDUP(MTYPE_BGP_PEER_HOST, str);
+ }
+
+ if (data + 1 > end) {
+ zlog_err("%pBP: Received invalid FQDN capability (domain name length)",
+ peer);
+ return;
+ }
+
+ /* domainname */
+ len = *data;
+ if (data + len > end) {
+ zlog_err("%pBP: Received invalid FQDN capability length (domain name) %d",
+ peer, len);
+ return;
+ }
+ data++;
+
+ if (len > BGP_MAX_HOSTNAME) {
+ memcpy(&str, data, BGP_MAX_HOSTNAME);
+ str[BGP_MAX_HOSTNAME] = '\0';
+ } else if (len) {
+ memcpy(&str, data, len);
+ str[len] = '\0';
+ }
+ data += len;
+
+ if (len) {
+ str[len] = '\0';
+
+ XFREE(MTYPE_BGP_PEER_HOST, peer->domainname);
+
+ peer->domainname = XSTRDUP(MTYPE_BGP_PEER_HOST, str);
+ }
+
+ SET_FLAG(peer->cap, PEER_CAP_HOSTNAME_RCV);
+ } else {
+ UNSET_FLAG(peer->cap, PEER_CAP_HOSTNAME_RCV);
+ XFREE(MTYPE_BGP_PEER_HOST, peer->hostname);
+ XFREE(MTYPE_BGP_PEER_HOST, peer->domainname);
+ }
+}
+
static void bgp_dynamic_capability_llgr(uint8_t *pnt, int action,
struct capability_header *hdr,
struct peer *peer)
@@ -3401,12 +3706,16 @@ 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_REFRESH:
case CAPABILITY_CODE_ORF:
+ bgp_dynamic_capability_orf(pnt, action, hdr, peer);
+ break;
+ case CAPABILITY_CODE_FQDN:
+ bgp_dynamic_capability_fqdn(pnt, action, hdr, peer);
+ break;
+ case CAPABILITY_CODE_REFRESH:
case CAPABILITY_CODE_AS4:
case CAPABILITY_CODE_DYNAMIC:
case CAPABILITY_CODE_ENHANCED_RR:
- case CAPABILITY_CODE_FQDN:
case CAPABILITY_CODE_ENHE:
case CAPABILITY_CODE_EXT_MESSAGE:
break;
diff --git a/bgpd/bgp_snmp.c b/bgpd/bgp_snmp.c
index ce9442c1e0..065ea7672c 100644
--- a/bgpd/bgp_snmp.c
+++ b/bgpd/bgp_snmp.c
@@ -29,10 +29,93 @@
#include "bgpd/bgp_snmp_bgp4.h"
#include "bgpd/bgp_snmp_bgp4v2.h"
#include "bgpd/bgp_mplsvpn_snmp.h"
+#include "bgpd/bgp_snmp_clippy.c"
+
+
+
+static int bgp_cli_snmp_traps_config_write(struct vty *vty);
+
+DEFPY(bgp_snmp_traps_rfc4273, bgp_snmp_traps_rfc4273_cmd,
+ "[no$no] bgp snmp traps rfc4273",
+ NO_STR BGP_STR
+ "Configure BGP SNMP\n"
+ "Configure SNMP traps for BGP\n"
+ "Configure use of rfc4273 SNMP traps for BGP\n")
+{
+ if (no) {
+ UNSET_FLAG(bm->options, BGP_OPT_TRAPS_RFC4273);
+ return CMD_SUCCESS;
+ }
+ SET_FLAG(bm->options, BGP_OPT_TRAPS_RFC4273);
+ return CMD_SUCCESS;
+}
+
+DEFPY(bgp_snmp_traps_bgp4_mibv2, bgp_snmp_traps_bgp4_mibv2_cmd,
+ "[no$no] bgp snmp traps bgp4-mibv2",
+ NO_STR BGP_STR
+ "Configure BGP SNMP\n"
+ "Configure SNMP traps for BGP\n"
+ "Configure use of BGP4-MIBv2 SNMP traps for BGP\n")
+{
+ if (no) {
+ UNSET_FLAG(bm->options, BGP_OPT_TRAPS_BGP4MIBV2);
+ return CMD_SUCCESS;
+ }
+ SET_FLAG(bm->options, BGP_OPT_TRAPS_BGP4MIBV2);
+ return CMD_SUCCESS;
+}
+
+static void bgp_snmp_traps_init(void)
+{
+ install_element(CONFIG_NODE, &bgp_snmp_traps_rfc4273_cmd);
+ install_element(CONFIG_NODE, &bgp_snmp_traps_bgp4_mibv2_cmd);
+
+ SET_FLAG(bm->options, BGP_OPT_TRAPS_RFC4273);
+ /* BGP4MIBv2 traps are disabled by default */
+}
+
+int bgp_cli_snmp_traps_config_write(struct vty *vty)
+{
+ int write = 0;
+
+ if (!CHECK_FLAG(bm->options, BGP_OPT_TRAPS_RFC4273)) {
+ vty_out(vty, "no bgp snmp traps rfc4273\n");
+ write++;
+ }
+ if (CHECK_FLAG(bm->options, BGP_OPT_TRAPS_BGP4MIBV2)) {
+ vty_out(vty, "bgp snmp traps bgp4-mibv2\n");
+ write++;
+ }
+
+ return write;
+}
+
+int bgpTrapEstablished(struct peer *peer)
+{
+ if (CHECK_FLAG(bm->options, BGP_OPT_TRAPS_RFC4273))
+ bgp4TrapEstablished(peer);
+
+ if (CHECK_FLAG(bm->options, BGP_OPT_TRAPS_BGP4MIBV2))
+ bgpv2TrapEstablished(peer);
+
+ return 0;
+}
+
+int bgpTrapBackwardTransition(struct peer *peer)
+{
+ if (CHECK_FLAG(bm->options, BGP_OPT_TRAPS_RFC4273))
+ bgp4TrapBackwardTransition(peer);
+
+ if (CHECK_FLAG(bm->options, BGP_OPT_TRAPS_BGP4MIBV2))
+ bgpv2TrapBackwardTransition(peer);
+
+ return 0;
+}
static int bgp_snmp_init(struct event_loop *tm)
{
smux_init(tm);
+ bgp_snmp_traps_init();
bgp_snmp_bgp4_init(tm);
bgp_snmp_bgp4v2_init(tm);
bgp_mpls_l3vpn_module_init();
@@ -44,6 +127,8 @@ static int bgp_snmp_module_init(void)
hook_register(peer_status_changed, bgpTrapEstablished);
hook_register(peer_backward_transition, bgpTrapBackwardTransition);
hook_register(frr_late_init, bgp_snmp_init);
+ hook_register(bgp_snmp_traps_config_write,
+ bgp_cli_snmp_traps_config_write);
return 0;
}
diff --git a/bgpd/bgp_snmp.h b/bgpd/bgp_snmp.h
index d324782ae3..12ec652f8d 100644
--- a/bgpd/bgp_snmp.h
+++ b/bgpd/bgp_snmp.h
@@ -15,4 +15,7 @@
#define IPADDRESS ASN_IPADDRESS
#define GAUGE32 ASN_UNSIGNED
+extern int bgpTrapEstablished(struct peer *peer);
+extern int bgpTrapBackwardTransition(struct peer *peer);
+
#endif /* _FRR_BGP_SNMP_H_ */
diff --git a/bgpd/bgp_snmp_bgp4.c b/bgpd/bgp_snmp_bgp4.c
index 692e232a83..3d04dc2ece 100644
--- a/bgpd/bgp_snmp_bgp4.c
+++ b/bgpd/bgp_snmp_bgp4.c
@@ -757,7 +757,7 @@ static struct variable bgp_variables[] = {
{6, 1, 14}},
};
-int bgpTrapEstablished(struct peer *peer)
+int bgp4TrapEstablished(struct peer *peer)
{
int ret;
struct in_addr addr;
@@ -782,7 +782,7 @@ int bgpTrapEstablished(struct peer *peer)
return 0;
}
-int bgpTrapBackwardTransition(struct peer *peer)
+int bgp4TrapBackwardTransition(struct peer *peer)
{
int ret;
struct in_addr addr;
diff --git a/bgpd/bgp_snmp_bgp4.h b/bgpd/bgp_snmp_bgp4.h
index ccf00d6b7c..67f7cc640b 100644
--- a/bgpd/bgp_snmp_bgp4.h
+++ b/bgpd/bgp_snmp_bgp4.h
@@ -69,8 +69,8 @@
#define BGP4PATHATTRBEST 13
#define BGP4PATHATTRUNKNOWN 14
-extern int bgpTrapEstablished(struct peer *peer);
-extern int bgpTrapBackwardTransition(struct peer *peer);
+extern int bgp4TrapEstablished(struct peer *peer);
+extern int bgp4TrapBackwardTransition(struct peer *peer);
extern int bgp_snmp_bgp4_init(struct event_loop *tm);
#endif /* _FRR_BGP_SNMP_BGP4_H_ */
diff --git a/bgpd/bgp_snmp_bgp4v2.c b/bgpd/bgp_snmp_bgp4v2.c
index fb6f13a6ca..b7a5f94a31 100644
--- a/bgpd/bgp_snmp_bgp4v2.c
+++ b/bgpd/bgp_snmp_bgp4v2.c
@@ -32,6 +32,7 @@
SNMP_LOCAL_VARIABLES
static oid bgpv2_oid[] = {BGP4V2MIB};
+static oid bgpv2_trap_oid[] = { BGP4V2MIB, 0 };
static struct in_addr bgp_empty_addr = {};
static struct peer *peer_lookup_all_vrf(struct ipaddr *addr)
@@ -793,6 +794,37 @@ static uint8_t *bgp4v2PathAttrTable(struct variable *v, oid name[],
return NULL;
}
+/* BGP V2 Traps. */
+static struct trap_object bgpv2TrapEstListv4[] = {
+ { 6, { 1, 2, 1, BGP4V2_PEER_STATE, 1, 1 } },
+ { 6, { 1, 2, 1, BGP4V2_PEER_LOCAL_PORT, 1, 1 } },
+ { 6, { 1, 2, 1, BGP4V2_PEER_REMOTE_PORT, 1, 1 } }
+};
+
+static struct trap_object bgpv2TrapEstListv6[] = {
+ { 6, { 1, 2, 1, BGP4V2_PEER_STATE, 1, 2 } },
+ { 6, { 1, 2, 1, BGP4V2_PEER_LOCAL_PORT, 1, 2 } },
+ { 6, { 1, 2, 1, BGP4V2_PEER_REMOTE_PORT, 1, 2 } }
+};
+
+static struct trap_object bgpv2TrapBackListv4[] = {
+ { 6, { 1, 2, 1, BGP4V2_PEER_STATE, 1, 1 } },
+ { 6, { 1, 2, 1, BGP4V2_PEER_LOCAL_PORT, 1, 1 } },
+ { 6, { 1, 2, 1, BGP4V2_PEER_REMOTE_PORT, 1, 1 } },
+ { 6, { 1, 3, 1, BGP4V2_PEER_LAST_ERROR_CODE_RECEIVED, 1, 1 } },
+ { 6, { 1, 3, 1, BGP4V2_PEER_LAST_ERROR_SUBCODE_RECEIVED, 1, 1 } },
+ { 6, { 1, 3, 1, BGP4V2_PEER_LAST_ERROR_RECEIVED_TEXT, 1, 1 } }
+};
+
+static struct trap_object bgpv2TrapBackListv6[] = {
+ { 6, { 1, 2, 1, BGP4V2_PEER_STATE, 1, 2 } },
+ { 6, { 1, 2, 1, BGP4V2_PEER_LOCAL_PORT, 1, 2 } },
+ { 6, { 1, 2, 1, BGP4V2_PEER_REMOTE_PORT, 1, 2 } },
+ { 6, { 1, 3, 1, BGP4V2_PEER_LAST_ERROR_CODE_RECEIVED, 1, 2 } },
+ { 6, { 1, 3, 1, BGP4V2_PEER_LAST_ERROR_SUBCODE_RECEIVED, 1, 2 } },
+ { 6, { 1, 3, 1, BGP4V2_PEER_LAST_ERROR_RECEIVED_TEXT, 1, 2 } }
+};
+
static struct variable bgpv2_variables[] = {
/* bgp4V2PeerEntry */
{BGP4V2_PEER_INSTANCE,
@@ -1412,6 +1444,79 @@ static struct variable bgpv2_variables[] = {
{1, 9, 1, BGP4V2_NLRI_PATH_ATTR_UNKNOWN, 1, 2}},
};
+int bgpv2TrapEstablished(struct peer *peer)
+{
+ oid index[sizeof(oid) * IN6_ADDR_SIZE];
+ size_t length;
+
+ if (!CHECK_FLAG(bm->options, BGP_OPT_TRAPS_BGP4MIBV2))
+ return 0;
+
+ /* Check if this peer just went to Established */
+ if ((peer->connection->ostatus != OpenConfirm) ||
+ !(peer_established(peer->connection)))
+ return 0;
+
+ switch (sockunion_family(&peer->connection->su)) {
+ case AF_INET:
+ oid_copy_in_addr(index, &peer->connection->su.sin.sin_addr);
+ length = IN_ADDR_SIZE;
+ smux_trap(bgpv2_variables, array_size(bgpv2_variables),
+ bgpv2_trap_oid, array_size(bgpv2_trap_oid), bgpv2_oid,
+ sizeof(bgpv2_oid) / sizeof(oid), index, length,
+ bgpv2TrapEstListv4, array_size(bgpv2TrapEstListv4),
+ BGP4V2ESTABLISHED);
+ break;
+ case AF_INET6:
+ oid_copy_in6_addr(index, &peer->connection->su.sin6.sin6_addr);
+ length = IN6_ADDR_SIZE;
+ smux_trap(bgpv2_variables, array_size(bgpv2_variables),
+ bgpv2_trap_oid, array_size(bgpv2_trap_oid), bgpv2_oid,
+ sizeof(bgpv2_oid) / sizeof(oid), index, length,
+ bgpv2TrapEstListv6, array_size(bgpv2TrapEstListv6),
+ BGP4V2ESTABLISHED);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+int bgpv2TrapBackwardTransition(struct peer *peer)
+{
+ oid index[sizeof(oid) * IN6_ADDR_SIZE];
+ size_t length;
+
+ if (!CHECK_FLAG(bm->options, BGP_OPT_TRAPS_BGP4MIBV2))
+ return 0;
+
+ switch (sockunion_family(&peer->connection->su)) {
+ case AF_INET:
+ oid_copy_in_addr(index, &peer->connection->su.sin.sin_addr);
+ length = IN_ADDR_SIZE;
+ smux_trap(bgpv2_variables, array_size(bgpv2_variables),
+ bgpv2_trap_oid, array_size(bgpv2_trap_oid), bgpv2_oid,
+ sizeof(bgpv2_oid) / sizeof(oid), index, length,
+ bgpv2TrapBackListv4, array_size(bgpv2TrapBackListv4),
+ BGP4V2BACKWARDTRANSITION);
+ break;
+ case AF_INET6:
+ oid_copy_in6_addr(index, &peer->connection->su.sin6.sin6_addr);
+ length = IN6_ADDR_SIZE;
+ smux_trap(bgpv2_variables, array_size(bgpv2_variables),
+ bgpv2_trap_oid, array_size(bgpv2_trap_oid), bgpv2_oid,
+ sizeof(bgpv2_oid) / sizeof(oid), index, length,
+ bgpv2TrapBackListv6, array_size(bgpv2TrapBackListv6),
+ BGP4V2BACKWARDTRANSITION);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
int bgp_snmp_bgp4v2_init(struct event_loop *tm)
{
REGISTER_MIB("mibII/bgpv2", bgpv2_variables, variable, bgpv2_oid);
diff --git a/bgpd/bgp_snmp_bgp4v2.h b/bgpd/bgp_snmp_bgp4v2.h
index 6587a825c5..ca355338a6 100644
--- a/bgpd/bgp_snmp_bgp4v2.h
+++ b/bgpd/bgp_snmp_bgp4v2.h
@@ -16,6 +16,14 @@
* offset 1.3.6.1.3.5.1.1.2.1.x.(1|2).(4|16) = 13
* offset 1.3.6.1.4.1.7336.3.2.1.1.2.1.x.1.(1|2) = 16
*/
+
+
+/* bgpTraps */
+#define BGP4V2ESTABLISHED 1
+#define BGP4V2BACKWARDTRANSITION 2
+
+/* bgpPeerTable */
+
#define BGP4V2_PEER_ENTRY_OFFSET 13
#define BGP4V2_PEER_INSTANCE 1
#define BGP4V2_PEER_LOCAL_ADDR_TYPE 2
@@ -84,5 +92,7 @@
#define BGP4V2_BACKWARD_TRANSITION_NOTIFICATION 2
extern int bgp_snmp_bgp4v2_init(struct event_loop *tm);
+extern int bgpv2TrapEstablished(struct peer *peer);
+extern int bgpv2TrapBackwardTransition(struct peer *peer);
#endif /* _FRR_BGP_SNMP_BGP4V2_H_ */
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index 8144d6e7b3..5d6ae589fa 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -128,6 +128,7 @@ DEFINE_HOOK(bgp_inst_config_write,
(bgp, vty));
DEFINE_HOOK(bgp_snmp_update_last_changed, (struct bgp *bgp), (bgp));
DEFINE_HOOK(bgp_snmp_init_stats, (struct bgp *bgp), (bgp));
+DEFINE_HOOK(bgp_snmp_traps_config_write, (struct vty * vty), (vty));
static struct peer_group *listen_range_exists(struct bgp *bgp,
struct prefix *range, int exact);
@@ -5831,24 +5832,37 @@ DEFUN (neighbor_capability_orf_prefix,
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, peer_str);
if (!peer)
return CMD_WARNING_CONFIG_FAILED;
- if (strmatch(argv[idx_send_recv]->text, "send"))
- return peer_af_flag_set_vty(vty, peer_str, afi, safi,
- PEER_FLAG_ORF_PREFIX_SM);
+ if (strmatch(argv[idx_send_recv]->text, "send")) {
+ ret = peer_af_flag_set_vty(vty, peer_str, afi, safi,
+ PEER_FLAG_ORF_PREFIX_SM);
+ bgp_capability_send(peer, afi, safi, CAPABILITY_CODE_ORF,
+ CAPABILITY_ACTION_SET);
+ return ret;
+ }
- if (strmatch(argv[idx_send_recv]->text, "receive"))
- return peer_af_flag_set_vty(vty, peer_str, afi, safi,
- PEER_FLAG_ORF_PREFIX_RM);
+ if (strmatch(argv[idx_send_recv]->text, "receive")) {
+ ret = peer_af_flag_set_vty(vty, peer_str, afi, safi,
+ PEER_FLAG_ORF_PREFIX_RM);
+ bgp_capability_send(peer, afi, safi, CAPABILITY_CODE_ORF,
+ CAPABILITY_ACTION_SET);
+ return ret;
+ }
- if (strmatch(argv[idx_send_recv]->text, "both"))
- return peer_af_flag_set_vty(vty, peer_str, afi, safi,
- PEER_FLAG_ORF_PREFIX_SM)
- | peer_af_flag_set_vty(vty, peer_str, afi, safi,
- PEER_FLAG_ORF_PREFIX_RM);
+ if (strmatch(argv[idx_send_recv]->text, "both")) {
+ ret = peer_af_flag_set_vty(vty, peer_str, afi, safi,
+ PEER_FLAG_ORF_PREFIX_SM) |
+ peer_af_flag_set_vty(vty, peer_str, afi, safi,
+ PEER_FLAG_ORF_PREFIX_RM);
+ bgp_capability_send(peer, afi, safi, CAPABILITY_CODE_ORF,
+ CAPABILITY_ACTION_SET);
+ return ret;
+ }
return CMD_WARNING_CONFIG_FAILED;
}
@@ -5883,24 +5897,37 @@ DEFUN (no_neighbor_capability_orf_prefix,
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, peer_str);
if (!peer)
return CMD_WARNING_CONFIG_FAILED;
- if (strmatch(argv[idx_send_recv]->text, "send"))
- return peer_af_flag_unset_vty(vty, peer_str, afi, safi,
- PEER_FLAG_ORF_PREFIX_SM);
+ if (strmatch(argv[idx_send_recv]->text, "send")) {
+ ret = peer_af_flag_unset_vty(vty, peer_str, afi, safi,
+ PEER_FLAG_ORF_PREFIX_SM);
+ bgp_capability_send(peer, afi, safi, CAPABILITY_CODE_ORF,
+ CAPABILITY_ACTION_UNSET);
+ return ret;
+ }
- if (strmatch(argv[idx_send_recv]->text, "receive"))
- return peer_af_flag_unset_vty(vty, peer_str, afi, safi,
- PEER_FLAG_ORF_PREFIX_RM);
+ if (strmatch(argv[idx_send_recv]->text, "receive")) {
+ ret = peer_af_flag_unset_vty(vty, peer_str, afi, safi,
+ PEER_FLAG_ORF_PREFIX_RM);
+ bgp_capability_send(peer, afi, safi, CAPABILITY_CODE_ORF,
+ CAPABILITY_ACTION_UNSET);
+ return ret;
+ }
- if (strmatch(argv[idx_send_recv]->text, "both"))
- return peer_af_flag_unset_vty(vty, peer_str, afi, safi,
- PEER_FLAG_ORF_PREFIX_SM)
- | peer_af_flag_unset_vty(vty, peer_str, afi, safi,
- PEER_FLAG_ORF_PREFIX_RM);
+ if (strmatch(argv[idx_send_recv]->text, "both")) {
+ ret = peer_af_flag_unset_vty(vty, peer_str, afi, safi,
+ PEER_FLAG_ORF_PREFIX_SM) |
+ peer_af_flag_unset_vty(vty, peer_str, afi, safi,
+ PEER_FLAG_ORF_PREFIX_RM);
+ bgp_capability_send(peer, afi, safi, CAPABILITY_CODE_ORF,
+ CAPABILITY_ACTION_UNSET);
+ return ret;
+ }
return CMD_WARNING_CONFIG_FAILED;
}
@@ -10546,7 +10573,7 @@ static int bgp_clear_prefix(struct vty *vty, const char *view_name,
/* one clear bgp command to rule them all */
DEFUN (clear_ip_bgp_all,
clear_ip_bgp_all_cmd,
- "clear [ip] bgp [<view|vrf> VIEWVRFNAME] [<ipv4|ipv6|l2vpn> [<unicast|multicast|vpn|labeled-unicast|flowspec|evpn>]] <*|A.B.C.D$neighbor|X:X::X:X$neighbor|WORD$neighbor|ASNUM|external|peer-group PGNAME> [<soft [<in|out>]|in [prefix-filter]|out|message-stats>]",
+ "clear [ip] bgp [<view|vrf> VIEWVRFNAME] [<ipv4|ipv6|l2vpn> [<unicast|multicast|vpn|labeled-unicast|flowspec|evpn>]] <*|A.B.C.D$neighbor|X:X::X:X$neighbor|WORD$neighbor|ASNUM|external|peer-group PGNAME> [<soft [<in|out>]|in [prefix-filter]|out|message-stats|capabilities>]",
CLEAR_STR
IP_STR
BGP_STR
@@ -10569,7 +10596,8 @@ DEFUN (clear_ip_bgp_all,
BGP_SOFT_IN_STR
"Push out prefix-list ORF and do inbound soft reconfig\n"
BGP_SOFT_OUT_STR
- "Reset message statistics\n")
+ "Reset message statistics\n"
+ "Resend capabilities\n")
{
char *vrf = NULL;
@@ -10626,7 +10654,7 @@ DEFUN (clear_ip_bgp_all,
clr_sort = clear_external;
}
- /* [<soft [<in|out>]|in [prefix-filter]|out|message-stats>] */
+ /* [<soft [<in|out>]|in [prefix-filter]|out|message-stats|capabilities>] */
if (argv_find(argv, argc, "soft", &idx)) {
if (argv_find(argv, argc, "in", &idx)
|| argv_find(argv, argc, "out", &idx))
@@ -10643,6 +10671,8 @@ DEFUN (clear_ip_bgp_all,
clr_type = BGP_CLEAR_SOFT_OUT;
} else if (argv_find(argv, argc, "message-stats", &idx)) {
clr_type = BGP_CLEAR_MESSAGE_STATS;
+ } else if (argv_find(argv, argc, "capabilities", &idx)) {
+ clr_type = BGP_CLEAR_CAPABILITIES;
} else
clr_type = BGP_CLEAR_SOFT_NONE;
@@ -18477,6 +18507,8 @@ int bgp_config_write(struct vty *vty)
safi_t safi;
uint32_t tovpn_sid_index = 0;
+ hook_call(bgp_snmp_traps_config_write, vty);
+
if (bm->rmap_update_timer != RMAP_DEFAULT_UPDATE_TIMER)
vty_out(vty, "bgp route-map delay-timer %u\n",
bm->rmap_update_timer);
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index 12e462a8ca..0a01d71968 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -4979,6 +4979,16 @@ static int peer_af_flag_modify(struct peer *peer, afi_t afi, safi_t safi,
else if (flag == PEER_FLAG_ORF_PREFIX_RM)
peer->last_reset = PEER_DOWN_CAPABILITY_CHANGE;
+ /* We should not reset the session if
+ * dynamic capability is enabled and we
+ * are changing the ORF prefix flags.
+ */
+ if ((CHECK_FLAG(peer->cap, PEER_CAP_DYNAMIC_RCV) &&
+ CHECK_FLAG(peer->cap, PEER_CAP_DYNAMIC_ADV)) &&
+ (flag == PEER_FLAG_ORF_PREFIX_RM ||
+ flag == PEER_FLAG_ORF_PREFIX_SM))
+ action.type = peer_change_none;
+
peer_change_action(peer, afi, safi, action.type);
}
}
@@ -5039,6 +5049,18 @@ static int peer_af_flag_modify(struct peer *peer, afi_t afi, safi_t safi,
member->last_reset =
PEER_DOWN_CAPABILITY_CHANGE;
+ /* We should not reset the session if
+ * dynamic capability is enabled and we
+ * are changing the ORF prefix flags.
+ */
+ if ((CHECK_FLAG(peer->cap,
+ PEER_CAP_DYNAMIC_RCV) &&
+ CHECK_FLAG(peer->cap,
+ PEER_CAP_DYNAMIC_ADV)) &&
+ (flag == PEER_FLAG_ORF_PREFIX_RM ||
+ flag == PEER_FLAG_ORF_PREFIX_SM))
+ action.type = peer_change_none;
+
peer_change_action(member, afi, safi,
action.type);
}
@@ -8024,6 +8046,16 @@ static void peer_reset_message_stats(struct peer *peer)
}
}
+/* Helper function to resend some BGP capabilities that are uncontrolled.
+ * For instance, FQDN capability, that can't be turned off, but let's say
+ * we changed the hostname, we need to resend it.
+ */
+static void peer_clear_capabilities(struct peer *peer, afi_t afi, safi_t safi)
+{
+ bgp_capability_send(peer, afi, safi, CAPABILITY_CODE_FQDN,
+ CAPABILITY_ACTION_SET);
+}
+
/*
* If peer clear is invoked in a loop for all peers on the BGP instance,
* it may end up freeing the doppelganger, and if this was the next node
@@ -8132,6 +8164,9 @@ int peer_clear_soft(struct peer *peer, afi_t afi, safi_t safi,
if (stype == BGP_CLEAR_MESSAGE_STATS)
peer_reset_message_stats(peer);
+ if (stype == BGP_CLEAR_CAPABILITIES)
+ peer_clear_capabilities(peer, afi, safi);
+
return 0;
}
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index bc2008b78b..42e4c167f6 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -121,6 +121,8 @@ struct bgp_master {
#define BGP_OPT_NO_FIB (1 << 0)
#define BGP_OPT_NO_LISTEN (1 << 1)
#define BGP_OPT_NO_ZEBRA (1 << 2)
+#define BGP_OPT_TRAPS_RFC4273 (1 << 3)
+#define BGP_OPT_TRAPS_BGP4MIBV2 (1 << 4)
uint64_t updgrp_idspace;
uint64_t subgrp_idspace;
@@ -832,6 +834,7 @@ DECLARE_HOOK(bgp_inst_delete, (struct bgp *bgp), (bgp));
DECLARE_HOOK(bgp_inst_config_write,
(struct bgp *bgp, struct vty *vty),
(bgp, vty));
+DECLARE_HOOK(bgp_snmp_traps_config_write, (struct vty *vty), (vty));
DECLARE_HOOK(bgp_config_end, (struct bgp *bgp), (bgp));
/* Thread callback information */
@@ -2073,7 +2076,8 @@ enum bgp_clear_type {
BGP_CLEAR_SOFT_IN,
BGP_CLEAR_SOFT_BOTH,
BGP_CLEAR_SOFT_IN_ORF_PREFIX,
- BGP_CLEAR_MESSAGE_STATS
+ BGP_CLEAR_MESSAGE_STATS,
+ BGP_CLEAR_CAPABILITIES,
};
/* Macros. */
diff --git a/bgpd/subdir.am b/bgpd/subdir.am
index c2dd207a49..7de6e7a9f1 100644
--- a/bgpd/subdir.am
+++ b/bgpd/subdir.am
@@ -214,6 +214,7 @@ clippy_scan += \
bgpd/bgp_rpki.c \
bgpd/bgp_vty.c \
bgpd/bgp_nexthop.c \
+ bgpd/bgp_snmp.c \
# end
nodist_bgpd_bgpd_SOURCES = \
diff --git a/doc/developer/topotests.rst b/doc/developer/topotests.rst
index 0e4f05ed00..fb860fb45f 100644
--- a/doc/developer/topotests.rst
+++ b/doc/developer/topotests.rst
@@ -583,6 +583,12 @@ Here's an example of launching ``zebra`` and ``bgpd`` inside ``gdb`` on router
--gdb-breakpoints=nb_config_diff \
all-protocol-startup
+Finally, for Emacs users, you can specify ``--gdb-use-emacs``. When specified
+the first router and daemon to be launched in gdb will be launched and run with
+Emacs gdb functionality by using `emacsclient --eval` commands. This provides an
+IDE debugging experience for Emacs users. This functionality works best when
+using password-less sudo.
+
Reporting Memleaks with FRR Memory Statistics
"""""""""""""""""""""""""""""""""""""""""""""
diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst
index d19278e4d9..43572be07e 100644
--- a/doc/user/bgp.rst
+++ b/doc/user/bgp.rst
@@ -1521,6 +1521,13 @@ Configuring Peers
value is carried encoded as uint32. To enable backward compatibility we
need to disable IEEE floating-point encoding option per-peer.
+.. clicmd:: neighbor PEER enforce-first-as
+
+ Discard updates received from the specified (eBGP) peer if the AS_PATH
+ attribute does not contain the PEER's ASN as the first AS_PATH segment.
+
+ Default: disabled.
+
.. clicmd:: neighbor PEER extended-optional-parameters
Force Extended Optional Parameters Length format to be used for OPEN messages.
@@ -3931,6 +3938,26 @@ The following are available in the top level *enable* mode:
Clear BGP message statistics for a specified peer or for all peers,
optionally filtered by activated address-family and sub-address-family.
+.. clicmd:: clear bgp [ipv4|ipv6] [unicast] PEER|\* capabilities
+
+ Clear specific BGP capabilities for a specified peer or for all peers. This
+ includes such capabilities like FQDN capability, that can't be controlled by
+ any other configuration knob.
+
+ For example, if you want to change the FQDN, you MUST reset the BGP session
+ in order to send a new FQDN capability to the peer. This command allows you
+ to resend FQDN capability without resetting the session.
+
+ .. code-block:: frr
+
+ hostname bgp-new.example.com
+ clear bgp 10.10.10.1 capabilities
+
+.. note::
+
+ Changing the hostname is possible only when connected to the specific daemon.
+ If you change the hostname via ``vtysh``, it won't be changed.
+
The following are available in the ``router bgp`` mode:
.. clicmd:: write-quanta (1-64)
diff --git a/doc/user/snmptrap.rst b/doc/user/snmptrap.rst
index 7e306b743d..df534e28bd 100644
--- a/doc/user/snmptrap.rst
+++ b/doc/user/snmptrap.rst
@@ -4,8 +4,9 @@ Handling SNMP Traps
To handle snmp traps make sure your snmp setup of frr works correctly as
described in the frr documentation in :ref:`snmp-support`.
-The BGP4 mib will send traps on peer up/down events. These should be visible in
-your snmp logs with a message similar to:
+BGP handles both :rfc:`4273` and [Draft-IETF-idr-bgp4-mibv2-11]_ MIBs.
+The BGP4 MIBs will send traps on peer up/down events. These should be
+visible in your snmp logs with a message similar to:
::
@@ -199,3 +200,18 @@ a siren, have your display flash, etc., be creative ;).
# mail the notification
echo "$MAIL" | mail -s "$SUBJECT" $EMAILADDR
+
+.. _traps-mib-selection:
+
+Traps Mib Selection in BGP
+--------------------------
+
+Both :rfc:`4273` and [Draft-IETF-idr-bgp4-mibv2-11]_ MIBs define traps for
+dealing with up/down events and state transition. The user has the
+possibility to select the MIB he wants to receive traps from:
+
+.. clicmd:: bgp snmp traps <rfc4273|bgp4-mibv2>
+
+By default, only rfc4273 traps are enabled and sent.
+
+.. [Draft-IETF-idr-bgp4-mibv2-11] <https://tools.ietf.org/id/draft-ietf-idr-bgp4-mibv2-11.txt>
diff --git a/lib/northbound.c b/lib/northbound.c
index 69b96d3656..be49d92841 100644
--- a/lib/northbound.c
+++ b/lib/northbound.c
@@ -906,11 +906,6 @@ void nb_candidate_edit_config_changes(
if (error && *error) {
char buf[BUFSIZ];
- /*
- * Failure to edit the candidate configuration should never
- * happen in practice, unless there's a bug in the code. When
- * that happens, log the error but otherwise ignore it.
- */
snprintf(err_buf, err_bufsize,
"%% Failed to edit configuration.\n\n%s",
yang_print_errors(ly_native_ctx, buf, sizeof(buf)));
diff --git a/pimd/pim_register.c b/pimd/pim_register.c
index 1f69175829..01da699dbd 100644
--- a/pimd/pim_register.c
+++ b/pimd/pim_register.c
@@ -416,11 +416,8 @@ void pim_null_register_send(struct pim_upstream *up)
memset(buffer, 0, (sizeof(ip6_hdr) + sizeof(pim_msg_header)));
memcpy(buffer, &ip6_hdr, sizeof(ip6_hdr));
- pim_msg_header.ver = 0;
- pim_msg_header.type = 0;
- pim_msg_header.reserved = 0;
-
- pim_msg_header.checksum = 0;
+ memset(&pim_msg_header, 0, sizeof(pim_msg_header));
+ memset(&ph, 0, sizeof(ph));
ph.src = up->sg.src;
ph.dst = up->sg.grp;
diff --git a/tests/topotests/all_protocol_startup/test_all_protocol_startup.py b/tests/topotests/all_protocol_startup/test_all_protocol_startup.py
index c319477c8a..ca340749fe 100644
--- a/tests/topotests/all_protocol_startup/test_all_protocol_startup.py
+++ b/tests/topotests/all_protocol_startup/test_all_protocol_startup.py
@@ -599,16 +599,16 @@ def test_nexthop_groups():
count = 0
dups = []
nhg_id = route_get_nhg_id("6.6.6.1/32")
- while (len(dups) != 3) and count < 10:
+ while (len(dups) != 4) and count < 10:
output = net["r1"].cmd('vtysh -c "show nexthop-group rib %d"' % nhg_id)
dups = re.findall(r"(via 1\.1\.1\.1)", output)
- if len(dups) != 3:
+ if len(dups) != 4:
count += 1
sleep(1)
# Should find 3, itself is inactive
- assert len(dups) == 3, (
+ assert len(dups) == 4, (
"Route 6.6.6.1/32 with Nexthop Group ID=%d has wrong number of resolved nexthops"
% nhg_id
)
diff --git a/tests/topotests/bgp_conditional_advertisement_static_route/__init__.py b/tests/topotests/bgp_conditional_advertisement_static_route/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/bgp_conditional_advertisement_static_route/__init__.py
diff --git a/tests/topotests/bgp_conditional_advertisement_static_route/r1/frr.conf b/tests/topotests/bgp_conditional_advertisement_static_route/r1/frr.conf
new file mode 100644
index 0000000000..3e51337eee
--- /dev/null
+++ b/tests/topotests/bgp_conditional_advertisement_static_route/r1/frr.conf
@@ -0,0 +1,10 @@
+!
+int r1-eth0
+ ip address 192.168.1.1/24
+!
+router bgp 65000
+ no bgp ebgp-requires-policy
+ neighbor 192.168.1.2 remote-as internal
+ neighbor 192.168.1.2 timers 1 3
+ neighbor 192.168.1.2 timers connect 1
+!
diff --git a/tests/topotests/bgp_conditional_advertisement_static_route/r2/frr.conf b/tests/topotests/bgp_conditional_advertisement_static_route/r2/frr.conf
new file mode 100644
index 0000000000..9dc4099341
--- /dev/null
+++ b/tests/topotests/bgp_conditional_advertisement_static_route/r2/frr.conf
@@ -0,0 +1,39 @@
+!
+!debug bgp conditional-advertisement
+!debug bgp updates
+!
+int r2-eth0
+ ip address 192.168.1.2/24
+!
+int r2-eth1
+ ip address 192.168.2.2/24
+!
+router bgp 65000
+ no bgp ebgp-requires-policy
+ bgp conditional-advertisement timer 5
+ neighbor 192.168.1.1 remote-as internal
+ neighbor 192.168.1.1 timers 1 3
+ neighbor 192.168.1.1 timers connect 1
+ neighbor 192.168.2.1 remote-as internal
+ neighbor 192.168.2.1 timers 1 3
+ neighbor 192.168.2.1 timers connect 1
+ address-family ipv4 unicast
+ redistribute static
+ neighbor 192.168.1.1 advertise-map advertise-map exist-map exist-map
+ neighbor 192.168.1.1 route-map deny-all out
+ exit-address-family
+!
+ip route 10.10.10.1/32 r2-eth0
+ip route 10.10.10.2/32 r2-eth0
+!
+ip prefix-list default seq 5 permit 0.0.0.0/0
+ip prefix-list advertise seq 5 permit 10.10.10.1/32
+!
+route-map deny-all deny 10
+!
+route-map exist-map permit 10
+ match ip address prefix-list default
+!
+route-map advertise-map permit 10
+ match ip address prefix-list advertise
+!
diff --git a/tests/topotests/bgp_conditional_advertisement_static_route/r3/frr.conf b/tests/topotests/bgp_conditional_advertisement_static_route/r3/frr.conf
new file mode 100644
index 0000000000..a24a2cb04e
--- /dev/null
+++ b/tests/topotests/bgp_conditional_advertisement_static_route/r3/frr.conf
@@ -0,0 +1,19 @@
+!
+int lo
+ ip address 10.10.10.1/32
+ ip address 10.10.10.2/32
+!
+int r3-eth0
+ ip address 192.168.2.1/24
+!
+router bgp 65000
+ no bgp ebgp-requires-policy
+ no bgp network import-check
+ neighbor 192.168.2.2 remote-as internal
+ neighbor 192.168.2.2 timers 1 3
+ neighbor 192.168.2.2 timers connect 1
+ !
+ address-family ipv4 unicast
+ neighbor 192.168.2.2 default-originate
+ exit-address-family
+!
diff --git a/tests/topotests/bgp_conditional_advertisement_static_route/test_bgp_conditional_advertisement_static_route.py b/tests/topotests/bgp_conditional_advertisement_static_route/test_bgp_conditional_advertisement_static_route.py
new file mode 100644
index 0000000000..9d61bbd643
--- /dev/null
+++ b/tests/topotests/bgp_conditional_advertisement_static_route/test_bgp_conditional_advertisement_static_route.py
@@ -0,0 +1,118 @@
+#!/usr/bin/env python
+# SPDX-License-Identifier: ISC
+
+# Copyright (c) 2023 by
+# Donatas Abraitis <donatas@opensourcerouting.org>
+#
+
+"""
+Test if static route with BGP conditional advertisement works correctly
+if we modify the prefix-lists.
+"""
+
+import os
+import re
+import sys
+import json
+import pytest
+import functools
+
+pytestmark = pytest.mark.bgpd
+
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# pylint: disable=C0413
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.common_config import step
+
+pytestmark = [pytest.mark.bgpd]
+
+
+def setup_module(mod):
+ topodef = {"s1": ("r1", "r2"), "s2": ("r2", "r3")}
+ tgen = Topogen(topodef, mod.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+
+ for _, (rname, router) in enumerate(router_list.items(), 1):
+ router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname)))
+
+ tgen.start_router()
+
+
+def teardown_module(mod):
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+
+def test_bgp_conditional_advertisements_static_route():
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ r2 = tgen.gears["r2"]
+
+ def _bgp_converge():
+ output = json.loads(
+ r2.vtysh_cmd(
+ "show bgp ipv4 unicast neighbor 192.168.1.1 advertised-routes json"
+ )
+ )
+ expected = {
+ "advertisedRoutes": {
+ "10.10.10.1/32": {
+ "valid": True,
+ }
+ },
+ "totalPrefixCounter": 1,
+ }
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(
+ _bgp_converge,
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+ assert result is None, "Can't converge"
+
+ step("Append prefix-list to advertise 10.10.10.2/32")
+
+ r2.vtysh_cmd(
+ """
+ configure terminal
+ ip prefix-list advertise seq 10 permit 10.10.10.2/32
+ """
+ )
+
+ def _bgp_check_advertised_after_update():
+ output = json.loads(
+ r2.vtysh_cmd(
+ "show bgp ipv4 unicast neighbor 192.168.1.1 advertised-routes json"
+ )
+ )
+ expected = {
+ "advertisedRoutes": {
+ "10.10.10.1/32": {
+ "valid": True,
+ },
+ "10.10.10.2/32": {
+ "valid": True,
+ },
+ },
+ "totalPrefixCounter": 2,
+ }
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(
+ _bgp_check_advertised_after_update,
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+ assert result is None, "10.10.10.2/32 is not advertised after prefix-list update"
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/bgp_dynamic_capability/r1/frr.conf b/tests/topotests/bgp_dynamic_capability/r1/frr.conf
index 6ff69037bd..aa5c3db9a6 100644
--- a/tests/topotests/bgp_dynamic_capability/r1/frr.conf
+++ b/tests/topotests/bgp_dynamic_capability/r1/frr.conf
@@ -17,3 +17,5 @@ router bgp 65001
neighbor 192.168.1.2 addpath-tx-all-paths
exit-address-family
!
+ip prefix-list r2 seq 5 permit 10.10.10.10/32
+!
diff --git a/tests/topotests/bgp_dynamic_capability/r2/frr.conf b/tests/topotests/bgp_dynamic_capability/r2/frr.conf
index 16b83a5c58..7f25665ed5 100644
--- a/tests/topotests/bgp_dynamic_capability/r2/frr.conf
+++ b/tests/topotests/bgp_dynamic_capability/r2/frr.conf
@@ -3,6 +3,7 @@
!
int lo
ip address 10.10.10.10/32
+ ip address 10.10.10.20/32
!
int r2-eth0
ip address 192.168.1.2/24
diff --git a/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_addpath.py b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_addpath.py
index 208251ec91..6bf0078daa 100644
--- a/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_addpath.py
+++ b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_addpath.py
@@ -47,7 +47,7 @@ def teardown_module(mod):
tgen.stop_topology()
-def test_bgp_dynamic_capability_role():
+def test_bgp_dynamic_capability_addpath():
tgen = get_topogen()
if tgen.routers_have_failure():
diff --git a/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_orf.py b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_orf.py
new file mode 100644
index 0000000000..49c7e554eb
--- /dev/null
+++ b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_orf.py
@@ -0,0 +1,172 @@
+#!/usr/bin/env python
+# SPDX-License-Identifier: ISC
+
+# Copyright (c) 2023 by
+# Donatas Abraitis <donatas@opensourcerouting.org>
+#
+
+"""
+Test if ORF capability is adjusted dynamically.
+"""
+
+import os
+import re
+import sys
+import json
+import pytest
+import functools
+
+pytestmark = pytest.mark.bgpd
+
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# pylint: disable=C0413
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.common_config import step
+
+pytestmark = [pytest.mark.bgpd]
+
+
+def setup_module(mod):
+ topodef = {"s1": ("r1", "r2")}
+ tgen = Topogen(topodef, mod.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+
+ for _, (rname, router) in enumerate(router_list.items(), 1):
+ router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname)))
+
+ tgen.start_router()
+
+
+def teardown_module(mod):
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+
+def test_bgp_dynamic_capability_orf():
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ r1 = tgen.gears["r1"]
+ r2 = tgen.gears["r2"]
+
+ def _bgp_converge():
+ output = json.loads(r1.vtysh_cmd("show bgp neighbor json"))
+ expected = {
+ "192.168.1.2": {
+ "bgpState": "Established",
+ "neighborCapabilities": {
+ "dynamic": "advertisedAndReceived",
+ },
+ }
+ }
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(
+ _bgp_converge,
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+ assert result is None, "Can't converge"
+
+ step(
+ "Apply incoming prefix-list to r1 and check if we advertise only 10.10.10.20/32 from r2"
+ )
+
+ # Clear message stats to check if we receive a notification or not after we
+ # enable ORF capability.
+ r1.vtysh_cmd("clear bgp 192.168.1.2 message-stats")
+ r1.vtysh_cmd(
+ """
+ configure terminal
+ router bgp
+ address-family ipv4 unicast
+ neighbor 192.168.1.2 prefix-list r2 in
+ neighbor 192.168.1.2 capability orf prefix-list both
+ """
+ )
+
+ r2.vtysh_cmd(
+ """
+ configure terminal
+ router bgp
+ address-family ipv4 unicast
+ neighbor 192.168.1.1 capability orf prefix-list both
+ """
+ )
+
+ def _bgp_check_if_session_not_reset():
+ output = json.loads(r1.vtysh_cmd("show bgp neighbor json"))
+ expected = {
+ "192.168.1.2": {
+ "bgpState": "Established",
+ "neighborCapabilities": {
+ "dynamic": "advertisedAndReceived",
+ },
+ "messageStats": {
+ "notificationsRecv": 0,
+ "notificationsSent": 0,
+ "capabilityRecv": 1,
+ "capabilitySent": 1,
+ },
+ "addressFamilyInfo": {
+ "ipv4Unicast": {
+ "afDependentCap": {
+ "orfPrefixList": {
+ "sendMode": "advertisedAndReceived",
+ "recvMode": "advertisedAndReceived",
+ }
+ },
+ "incomingUpdatePrefixFilterList": "r2",
+ }
+ },
+ }
+ }
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(
+ _bgp_check_if_session_not_reset,
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+ assert result is None, "Session was reset after setting up ORF capability"
+
+ r1.vtysh_cmd(
+ """
+ configure terminal
+ ip prefix-list r2 seq 5 permit 10.10.10.20/32
+ """
+ )
+
+ def _bgp_check_if_we_send_correct_prefix():
+ output = json.loads(
+ r2.vtysh_cmd(
+ "show bgp ipv4 unicast neighbors 192.168.1.1 advertised-routes json"
+ )
+ )
+ expected = {
+ "advertisedRoutes": {
+ "10.10.10.20/32": {
+ "valid": True,
+ },
+ },
+ "totalPrefixCounter": 1,
+ }
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(
+ _bgp_check_if_we_send_correct_prefix,
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+ assert (
+ result is None
+ ), "Only 10.10.10.20/32 SHOULD be advertised due to ORF filtering"
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/bgp_snmp_bgp4v2mib/r2/snmpd.conf b/tests/topotests/bgp_snmp_bgp4v2mib/r2/snmpd.conf
index 032b93b676..f0957cca7a 100644
--- a/tests/topotests/bgp_snmp_bgp4v2mib/r2/snmpd.conf
+++ b/tests/topotests/bgp_snmp_bgp4v2mib/r2/snmpd.conf
@@ -6,6 +6,15 @@ access public_group "" any noauth prefix all all none
rocommunity public default
+trapsess -v2c -c public 127.0.0.1
+
+notificationEvent linkUpTrap linkUp ifIndex ifAdminStatus ifOperStatus
+notificationEvent linkDownTrap linkDown ifIndex ifAdminStatus ifOperStatus
+
+monitor -r 2 -e linkUpTrap "Generate linkUp" ifOperStatus != 2
+monitor -r 2 -e linkDownTrap "Generate linkDown" ifOperStatus == 2
+
+
view all included .1
iquerySecName frr
diff --git a/tests/topotests/bgp_snmp_bgp4v2mib/r2/snmptrapd.conf b/tests/topotests/bgp_snmp_bgp4v2mib/r2/snmptrapd.conf
new file mode 100644
index 0000000000..f6e4abfef7
--- /dev/null
+++ b/tests/topotests/bgp_snmp_bgp4v2mib/r2/snmptrapd.conf
@@ -0,0 +1,2 @@
+authCommunity net,log public
+disableAuthorization yes
diff --git a/tests/topotests/bgp_snmp_bgp4v2mib/test_bgp_snmp_bgp4v2mib.py b/tests/topotests/bgp_snmp_bgp4v2mib/test_bgp_snmp_bgp4v2mib.py
index 6b6153db46..18a8575793 100755
--- a/tests/topotests/bgp_snmp_bgp4v2mib/test_bgp_snmp_bgp4v2mib.py
+++ b/tests/topotests/bgp_snmp_bgp4v2mib/test_bgp_snmp_bgp4v2mib.py
@@ -24,6 +24,7 @@ sys.path.append(os.path.join(CWD, "../"))
from lib.topogen import Topogen, TopoRouter, get_topogen
from lib.snmptest import SnmpTester
from lib import topotest
+from lib.topolog import logger
pytestmark = [pytest.mark.bgpd, pytest.mark.snmp]
@@ -55,11 +56,17 @@ def setup_module(mod):
os.path.join(CWD, "{}/bgpd.conf".format(rname)),
"-M snmp",
)
- router.load_config(
- TopoRouter.RD_SNMP,
- os.path.join(CWD, "{}/snmpd.conf".format(rname)),
- "-Le -Ivacm_conf,usmConf,iquery -V -DAgentX",
- )
+
+ tgen.gears["r2"].load_config(
+ TopoRouter.RD_SNMP,
+ os.path.join(CWD, "{}/snmpd.conf".format(rname)),
+ "-Le -Ivacm_conf,usmConf,iquery -V -DAgentX",
+ )
+ tgen.gears["r2"].load_config(
+ TopoRouter.RD_TRAP,
+ os.path.join(CWD, "{}/snmptrapd.conf".format(rname)),
+ " -On -OQ ",
+ )
tgen.start_router()
@@ -72,6 +79,7 @@ def teardown_module(mod):
def test_bgp_snmp_bgp4v2():
tgen = get_topogen()
+ r1 = tgen.gears["r1"]
r2 = tgen.gears["r2"]
def _bgp_converge_summary():
@@ -197,7 +205,9 @@ def test_bgp_snmp_bgp4v2():
}
# bgp4V2NlriOrigin
+ # tgen.mininet_cli()
output, _ = snmp.walk(".1.3.6.1.3.5.1.1.9.1.9")
+ logger.info(output)
return output == expected
_, result = topotest.run_and_expect(_snmpwalk_origin, True, count=10, wait=1)
@@ -220,6 +230,78 @@ def test_bgp_snmp_bgp4v2():
assertmsg = "Can't fetch SNMP for bgp4V2NlriMed"
assert result, assertmsg
+ def _snmptrap_ipv4():
+ expected = [
+ ("1.3.6.1.2.1.15.3.1.7.192.168.12.1", "192.168.12.1"),
+ ("1.3.6.1.2.1.15.3.1.14.192.168.12.1", '"06 04 "'),
+ ("1.3.6.1.2.1.15.3.1.2.192.168.12.1", "7"),
+ ("1.3.6.1.2.1.15.3.1.7.192.168.12.1", "192.168.12.1"),
+ ("1.3.6.1.2.1.15.3.1.14.192.168.12.1", '"06 04 "'),
+ ("1.3.6.1.2.1.15.3.1.2.192.168.12.1", "6"),
+ ]
+
+ # load trapd resulting file
+ # tgen.mininet_cli()
+
+ snmptrapfile = "{}/{}/snmptrapd.log".format(r2.logdir, r2.name)
+ outputfile = open(snmptrapfile).read()
+ output = snmp.trap(outputfile)
+ return output == expected
+
+ # skip tests is SNMP not installed
+ if not os.path.isfile("/usr/sbin/snmptrapd"):
+ error_msg = "SNMP not installed - skipping"
+ pytest.skip(error_msg)
+
+ snmptrapfile = "{}/{}/snmptrapd.log".format(r2.logdir, r2.name)
+ trap_file = open(snmptrapfile, "w")
+ trap_file.truncate(0)
+ trap_file.close()
+ r1.vtysh_cmd("clear bgp *")
+ _, result = topotest.run_and_expect(_snmptrap_ipv4, True, count=2, wait=10)
+ assertmsg = "Can't fetch SNMP trap for ipv4"
+ assert result, assertmsg
+
+ def _snmptrap_ipv6():
+ expected = [
+ ("1.3.6.1.3.5.1.1.2.1.13.1.1.192.168.12.1", "7"),
+ ("1.3.6.1.3.5.1.1.2.1.6.1.1.192.168.12.1", "179"),
+ ("1.3.6.1.3.5.1.1.3.1.1.1.1.192.168.12.1", "6"),
+ ("1.3.6.1.3.5.1.1.3.1.2.1.1.192.168.12.1", "4"),
+ ("1.3.6.1.3.5.1.1.3.1.4.1.1.192.168.12.1", '"00 "'),
+ ("1.3.6.1.3.5.1.1.2.1.13.1.2.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1", "7"),
+ ("1.3.6.1.3.5.1.1.2.1.6.1.2.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1", "179"),
+ ("1.3.6.1.3.5.1.1.3.1.1.1.2.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1", "6"),
+ ("1.3.6.1.3.5.1.1.3.1.2.1.2.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1", "4"),
+ (
+ "1.3.6.1.3.5.1.1.3.1.4.1.2.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1",
+ '"00 "',
+ ),
+ ("1.3.6.1.3.5.1.1.2.1.13.1.1.192.168.12.1", "6"),
+ ("1.3.6.1.3.5.1.1.2.1.6.1.1.192.168.12.1", "179"),
+ ("1.3.6.1.3.5.1.1.2.1.13.1.2.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1", "6"),
+ ("1.3.6.1.3.5.1.1.2.1.6.1.2.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1", "179"),
+ ]
+
+ # load trapd resulting file
+ # tgen.mininet_cli()
+
+ snmptrapfile = "{}/{}/snmptrapd.log".format(r2.logdir, r2.name)
+ outputfile = open(snmptrapfile).read()
+ output = snmp.trap(outputfile)
+ return output == expected
+
+ snmptrapfile = "{}/{}/snmptrapd.log".format(r2.logdir, r2.name)
+ trap_file = open(snmptrapfile, "w")
+ trap_file.truncate(0)
+ trap_file.close()
+ r2.vtysh_cmd("conf\nbgp snmp traps bgp4-mibv2")
+ r2.vtysh_cmd("conf\nno bgp snmp traps rfc4273")
+ r1.vtysh_cmd("clear bgp *")
+ _, result = topotest.run_and_expect(_snmptrap_ipv6, True, count=2, wait=10)
+ assertmsg = "Can't fetch SNMP trap for ipv6"
+ assert result, assertmsg
+
def test_memory_leak():
"Run the memory leak test and report results."
diff --git a/tests/topotests/bgp_unique_rid/test_bgp_unique_rid.py b/tests/topotests/bgp_unique_rid/test_bgp_unique_rid.py
index f89f3378fb..9fbcdc26fe 100644
--- a/tests/topotests/bgp_unique_rid/test_bgp_unique_rid.py
+++ b/tests/topotests/bgp_unique_rid/test_bgp_unique_rid.py
@@ -83,6 +83,7 @@ from lib.bgp import (
create_router_bgp,
clear_bgp_and_verify,
)
+from lib.ospf import verify_ospf_neighbor, clear_ospf
# Global variables
topo = None
@@ -886,6 +887,154 @@ def test_bgp_unique_rid_chaos4_p2():
write_test_footer(tc_name)
+def test_bgp_unique_rid_chaos2_p2():
+ """
+ TC: 8
+ 8. Chaos - Verify bgp unique rid functionality when ospf and bgp share the same router ids.
+
+ """
+ tgen = get_topogen()
+ global bgp_convergence
+
+ if bgp_convergence is not True:
+ pytest.skip("skipped because of BGP Convergence failure")
+
+ # test case name
+ tc_name = inspect.stack()[0][3]
+ write_test_header(tc_name)
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+
+ step("Configure base config as per the topology")
+ step("Redistribute routes between bgp and ospf.")
+ reset_config_on_routers(tgen)
+
+ step(
+ "Base config should be up, verify using BGP convergence on all \
+ the routers for IPv4 and IPv6 nbrs"
+ )
+
+ result = verify_bgp_convergence(tgen, topo)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ ospf_covergence = verify_ospf_neighbor(tgen, topo, dut="r3")
+ assert ospf_covergence is True, "Testcase :Failed \n Error:" " {}".format(
+ ospf_covergence
+ )
+
+ step(
+ "Configure ospf between R3 and R4 with same router ids in both ospf and bgp 10.10.10.10 on R3 BGP and OSPF, and 10.10.10.10 in R4 BGP and 11.11.11.11 in R4 OSPF."
+ )
+ input_dict = {
+ "r3": {"bgp": {"router_id": "10.10.10.10"}},
+ "r4": {"bgp": {"router_id": "10.10.10.10"}},
+ "r5": {"bgp": {"router_id": "10.10.10.10"}},
+ }
+ result = create_router_bgp(tgen, topo, input_dict)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "The session should be established between R3 & R4 between BGP process and neighborship should be full between OSPF too."
+ )
+
+ result = verify_bgp_convergence(tgen, topo)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ ospf_covergence = verify_ospf_neighbor(tgen, topo, dut="r3")
+ assert ospf_covergence is True, "Testcase :Failed \n Error:" " {}".format(
+ ospf_covergence
+ )
+
+ step("All the routes should be calculated and installed.")
+ # Verifying RIB routes
+ protocol = "bgp"
+ input_dict = topo["routers"]
+ verify_rib_rtes = {
+ "ipv4": {
+ "r3": {
+ "static_routes": [
+ {"network": NETWORK["ipv4"], "next_hop": "Null0"},
+ ]
+ }
+ },
+ "ipv6": {
+ "r3": {
+ "static_routes": [
+ {
+ "network": NETWORK["ipv6"],
+ "next_hop": "Null0",
+ }
+ ]
+ }
+ },
+ }
+ dut = "r3"
+ for addr_type in ADDR_TYPES:
+ result4 = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ verify_rib_rtes,
+ protocol=protocol,
+ )
+ assert result4 is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result4
+ )
+
+ step("Clear ospf process.")
+ clear_ospf(tgen, "r3")
+
+ step("All the routes should be calculated and installed.")
+ for addr_type in ADDR_TYPES:
+ result4 = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ verify_rib_rtes,
+ protocol=protocol,
+ )
+ assert result4 is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result4
+ )
+
+ step("Clear bgp process.")
+ clear_bgp_and_verify(tgen, topo, "r3")
+
+ step("All the routes should be calculated and installed.")
+ for addr_type in ADDR_TYPES:
+ result4 = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ verify_rib_rtes,
+ protocol=protocol,
+ )
+ assert result4 is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result4
+ )
+
+ step(
+ "Configure ospf between R3 and R5. Configure static routes in R5 and redistribute static routes in ospf on R5."
+ )
+ # Covered as base config.
+
+ step("Verify routes are installed in R3 and R4 route tables.")
+ dut = "r4"
+ for addr_type in ADDR_TYPES:
+ result4 = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ verify_rib_rtes,
+ protocol=protocol,
+ )
+ assert result4 is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result4
+ )
+
+ write_test_footer(tc_name)
+
+
if __name__ == "__main__":
args = ["-s"] + sys.argv[1:]
sys.exit(pytest.main(args))
diff --git a/tests/topotests/conftest.py b/tests/topotests/conftest.py
index 0afebde1cf..b6b2880db8 100755
--- a/tests/topotests/conftest.py
+++ b/tests/topotests/conftest.py
@@ -103,6 +103,12 @@ def pytest_addoption(parser):
)
parser.addoption(
+ "--gdb-use-emacs",
+ action="store_true",
+ help="Use emacsclient to run gdb instead of a shell",
+ )
+
+ parser.addoption(
"--logd",
action="append",
metavar="DAEMON[,ROUTER[,...]",
diff --git a/tests/topotests/lib/snmptest.py b/tests/topotests/lib/snmptest.py
index e7cd657b20..598ad05f58 100644
--- a/tests/topotests/lib/snmptest.py
+++ b/tests/topotests/lib/snmptest.py
@@ -18,6 +18,7 @@ Basic usage instructions:
"""
from lib.topolog import logger
+import re
class SnmpTester(object):
@@ -72,15 +73,38 @@ class SnmpTester(object):
# third token onwards is the value of the object
return tokens[0].split(".", 1)[1]
- @staticmethod
- def _get_snmp_oid(snmp_output):
- tokens = snmp_output.strip().split()
-
- # if len(tokens) > 5:
- # return None
-
- # third token is the value of the object
- return tokens[0].split(".", 1)[1]
+ def _parse_notification_trap(self, snmp_out):
+ # we use the "=" as separator thus we will have
+ # element of list formated "value oid"
+ # value for index i is corresponding to index i-1
+ results = snmp_out.strip().split("=")
+
+ # remove the notification part date, notification OID
+ del results[0:2]
+
+ index = 0
+ oid_list = []
+ next_oid = ""
+ oid = ""
+ while index < len(results):
+ result = results[index].strip().split()
+ if index < len(results) - 1:
+ raw_oid = result[-1]
+ # remove initial "." of oid
+ next_oid = raw_oid.split(".", 1)[1]
+ # remove oid from result to have only value
+ del result[-1]
+ if index > 0:
+ value = " ".join(result)
+ # ignore remote port oid 1.3.6.1.3.5.1.1.2.1.9 since
+ # it's value is variable
+ local_port = re.search("1.3.6.1.3.5.1.1.2.1.9", oid)
+ if not local_port:
+ oid_list.append((oid, value))
+
+ oid = next_oid
+ index += 1
+ return oid_list
def _parse_multiline(self, snmp_output):
results = snmp_output.strip().split("\n")
@@ -93,6 +117,15 @@ class SnmpTester(object):
return out_dict, out_list
+ def _parse_multiline_trap(self, results):
+ out_list = []
+ results = [elem for index, elem in enumerate(results) if index % 2 != 0]
+
+ for response in results:
+ oid_list = self._parse_notification_trap(response)
+ out_list += oid_list
+ return out_list
+
def get(self, oid):
cmd = "snmpget {0} {1}".format(self._snmp_config(), oid)
@@ -116,6 +149,11 @@ class SnmpTester(object):
result = self.router.cmd(cmd)
return self._parse_multiline(result)
+ def trap(self, outputfile):
+ whitecleanfile = re.sub("\t", " ", outputfile)
+ results = whitecleanfile.strip().split("\n")
+ return self._parse_multiline_trap(results)
+
def test_oid(self, oid, value):
print("oid: {}".format(self.get_next(oid)))
return self.get_next(oid) == value
diff --git a/tests/topotests/lib/topogen.py b/tests/topotests/lib/topogen.py
index 4d935b9538..48caf6f03a 100644
--- a/tests/topotests/lib/topogen.py
+++ b/tests/topotests/lib/topogen.py
@@ -744,6 +744,7 @@ class TopoRouter(TopoGear):
RD_SNMP = 18
RD_PIM6 = 19
RD_MGMTD = 20
+ RD_TRAP = 21
RD = {
RD_FRR: "frr",
RD_ZEBRA: "zebra",
@@ -766,6 +767,7 @@ class TopoRouter(TopoGear):
RD_PATH: "pathd",
RD_SNMP: "snmpd",
RD_MGMTD: "mgmtd",
+ RD_TRAP: "snmptrapd",
}
def __init__(self, tgen, cls, name, **params):
@@ -842,7 +844,7 @@ class TopoRouter(TopoGear):
TopoRouter.RD_RIPNG, TopoRouter.RD_OSPF, TopoRouter.RD_OSPF6,
TopoRouter.RD_ISIS, TopoRouter.RD_BGP, TopoRouter.RD_LDP,
TopoRouter.RD_PIM, TopoRouter.RD_PIM6, TopoRouter.RD_PBR,
- TopoRouter.RD_SNMP, TopoRouter.RD_MGMTD.
+ TopoRouter.RD_SNMP, TopoRouter.RD_MGMTD, TopoRouter.RD_TRAP.
Possible `source` values are `None` for an empty config file, a path name which is
used directly, or a file name with no path components which is first looked for
@@ -880,7 +882,7 @@ class TopoRouter(TopoGear):
# Enable all daemon command logging, logging files
# and set them to the start dir.
for daemon, enabled in nrouter.daemons.items():
- if enabled and daemon != "snmpd":
+ if enabled and daemon != "snmpd" and daemon != "snmptrapd":
self.vtysh_cmd(
"\n".join(
[
diff --git a/tests/topotests/lib/topotest.py b/tests/topotests/lib/topotest.py
index c220bcfed1..8491314e16 100644
--- a/tests/topotests/lib/topotest.py
+++ b/tests/topotests/lib/topotest.py
@@ -31,7 +31,8 @@ from copy import deepcopy
import lib.topolog as topolog
from lib.micronet_compat import Node
from lib.topolog import logger
-from munet.base import Timeout
+from munet.base import commander, get_exec_path_host, Timeout
+from munet.testing.util import retry
from lib import micronet
@@ -1261,8 +1262,8 @@ def rlimit_atleast(rname, min_value, raises=False):
def fix_netns_limits(ns):
# Maximum read and write socket buffer sizes
- sysctl_atleast(ns, "net.ipv4.tcp_rmem", [10 * 1024, 87380, 16 * 2 ** 20])
- sysctl_atleast(ns, "net.ipv4.tcp_wmem", [10 * 1024, 87380, 16 * 2 ** 20])
+ sysctl_atleast(ns, "net.ipv4.tcp_rmem", [10 * 1024, 87380, 16 * 2**20])
+ sysctl_atleast(ns, "net.ipv4.tcp_wmem", [10 * 1024, 87380, 16 * 2**20])
sysctl_assure(ns, "net.ipv4.conf.all.rp_filter", 0)
sysctl_assure(ns, "net.ipv4.conf.default.rp_filter", 0)
@@ -1321,8 +1322,8 @@ def fix_host_limits():
sysctl_atleast(None, "net.core.netdev_max_backlog", 4 * 1024)
# Maximum read and write socket buffer sizes
- sysctl_atleast(None, "net.core.rmem_max", 16 * 2 ** 20)
- sysctl_atleast(None, "net.core.wmem_max", 16 * 2 ** 20)
+ sysctl_atleast(None, "net.core.rmem_max", 16 * 2**20)
+ sysctl_atleast(None, "net.core.wmem_max", 16 * 2**20)
# Garbage Collection Settings for ARP and Neighbors
sysctl_atleast(None, "net.ipv4.neigh.default.gc_thresh2", 4 * 1024)
@@ -1363,6 +1364,8 @@ def setup_node_tmpdir(logdir, name):
class Router(Node):
"A Node with IPv4/IPv6 forwarding enabled"
+ gdb_emacs_router = None
+
def __init__(self, name, *posargs, **params):
# Backward compatibility:
# Load configuration defaults like topogen.
@@ -1420,6 +1423,7 @@ class Router(Node):
"pathd": 0,
"snmpd": 0,
"mgmtd": 0,
+ "snmptrapd": 0,
}
self.daemons_options = {"zebra": ""}
self.reportCores = True
@@ -1799,6 +1803,7 @@ class Router(Node):
gdb_breakpoints = g_pytest_config.get_option_list("--gdb-breakpoints")
gdb_daemons = g_pytest_config.get_option_list("--gdb-daemons")
gdb_routers = g_pytest_config.get_option_list("--gdb-routers")
+ gdb_use_emacs = bool(g_pytest_config.option.gdb_use_emacs)
valgrind_extra = bool(g_pytest_config.option.valgrind_extra)
valgrind_memleaks = bool(g_pytest_config.option.valgrind_memleaks)
strace_daemons = g_pytest_config.get_option_list("--strace-daemons")
@@ -1883,6 +1888,15 @@ class Router(Node):
daemon_opts
) + "{}.pid -x /etc/frr/agentx".format(runbase)
# check_daemon_files.append(runbase + ".pid")
+ elif daemon == "snmptrapd":
+ binary = "/usr/sbin/snmptrapd"
+ cmdenv = ""
+ cmdopt = (
+ "{} ".format(daemon_opts)
+ + "-C -c /etc/{}/snmptrapd.conf".format(self.routertype)
+ + " -p {}.pid".format(runbase)
+ + " -LF 6-7 {}/{}/snmptrapd.log".format(self.logdir, self.name)
+ )
else:
binary = os.path.join(self.daemondir, daemon)
check_daemon_files.extend([runbase + ".pid", runbase + ".vty"])
@@ -1922,16 +1936,24 @@ class Router(Node):
tail_log_files.append(
"{}/{}/{}.log".format(self.logdir, self.name, daemon)
)
+
if extra_opts:
cmdopt += " " + extra_opts
if (
- (gdb_routers or gdb_daemons)
+ (not gdb_use_emacs or Router.gdb_emacs_router)
+ and (gdb_routers or gdb_daemons)
and (
not gdb_routers or self.name in gdb_routers or "all" in gdb_routers
)
and (not gdb_daemons or daemon in gdb_daemons or "all" in gdb_daemons)
):
+ if Router.gdb_emacs_router is not None:
+ logger.warning(
+ "--gdb-use-emacs can only run a single router and daemon, using"
+ " new window"
+ )
+
if daemon == "snmpd":
cmdopt += " -f "
@@ -1942,12 +1964,87 @@ class Router(Node):
for bp in gdb_breakpoints:
gdbcmd += " -ex 'b {}'".format(bp)
gdbcmd += " -ex 'run {}'".format(cmdopt)
-
self.run_in_window(gdbcmd, daemon)
logger.info(
"%s: %s %s launched in gdb window", self, self.routertype, daemon
)
+ elif (
+ gdb_use_emacs
+ and (daemon in gdb_daemons)
+ and (not gdb_routers or self.name in gdb_routers)
+ ):
+ assert Router.gdb_emacs_router is None
+ Router.gdb_emacs_router = self
+
+ if daemon == "snmpd":
+ cmdopt += " -f "
+ cmdopt += rediropt
+
+ sudo_path = get_exec_path_host("sudo")
+ ecbin = [
+ sudo_path,
+ "-Eu",
+ os.environ["SUDO_USER"],
+ get_exec_path_host("emacsclient"),
+ ]
+ pre_cmd = self._get_pre_cmd(True, False, ns_only=True, root_level=True)
+ # why fail:? gdb -i=mi -iex='set debuginfod enabled off' {binary} "
+ gdbcmd = f"{sudo_path} {pre_cmd} gdb -i=mi {binary} "
+
+ commander.cmd_raises(
+ ecbin
+ + [
+ "--eval",
+ f'(gdb "{gdbcmd}"))',
+ ]
+ )
+
+ elcheck = (
+ '(ignore-errors (with-current-buffer "*gud-nsenter*"'
+ " (and (string-match-p"
+ ' "(gdb) "'
+ " (buffer-substring-no-properties "
+ ' (- (point-max) 10) (point-max))) "ready")))'
+ )
+
+ @retry(10)
+ def emacs_gdb_ready():
+ check = commander.cmd_nostatus(ecbin + ["--eval", elcheck])
+ return None if "ready" in check else False
+
+ emacs_gdb_ready()
+
+ # target gdb commands
+ cmd = "set breakpoint pending on"
+ self.cmd_raises(
+ ecbin
+ + [
+ "--eval",
+ f'(gud-gdb-run-command-fetch-lines "{cmd}" "*gud-gdb*")',
+ ]
+ )
+ # gdb breakpoints
+ for bp in gdb_breakpoints:
+ self.cmd_raises(
+ ecbin
+ + [
+ "--eval",
+ f'(gud-gdb-run-command-fetch-lines "br {bp}" "*gud-gdb*")',
+ ]
+ )
+ # gdb run cmd
+ self.cmd_raises(
+ ecbin
+ + [
+ "--eval",
+ f'(gud-gdb-run-command-fetch-lines "run {cmdopt}" "*gud-gdb*")',
+ ]
+ )
+
+ logger.info(
+ "%s: %s %s launched in gdb window", self, self.routertype, daemon
+ )
elif daemon in perfds and (
self.name in perfds[daemon] or "all" in perfds[daemon]
):
@@ -1970,7 +2067,7 @@ class Router(Node):
"%s: %s %s started with perf", self, self.routertype, daemon
)
else:
- if daemon != "snmpd":
+ if daemon != "snmpd" and daemon != "snmptrapd":
cmdopt += " -d "
cmdopt += rediropt
@@ -2213,6 +2310,8 @@ class Router(Node):
for daemon in self.daemons:
if daemon == "snmpd":
continue
+ if daemon == "snmptrapd":
+ continue
if (self.daemons[daemon] == 1) and not (daemon in daemonsRunning):
sys.stderr.write("%s: Daemon %s not running\n" % (self.name, daemon))
if daemon == "staticd":
diff --git a/watchfrr/watchfrr.c b/watchfrr/watchfrr.c
index 34acf683ef..73a033170c 100644
--- a/watchfrr/watchfrr.c
+++ b/watchfrr/watchfrr.c
@@ -600,6 +600,9 @@ static void daemon_restarting_operational(struct event *thread)
static void daemon_down(struct daemon *dmn, const char *why)
{
+ if (dmn->ignore_timeout)
+ return;
+
if (IS_UP(dmn) || (dmn->state == DAEMON_INIT))
flog_err(EC_WATCHFRR_CONNECTION, "%s state -> down : %s",
dmn->name, why);
diff --git a/zebra/debug_nl.c b/zebra/debug_nl.c
index df0b5aae7b..a7cccdb98f 100644
--- a/zebra/debug_nl.c
+++ b/zebra/debug_nl.c
@@ -983,6 +983,7 @@ next_rta:
zlog_debug(" rta [len=%d (payload=%zu) type=(%d) %s]", rta->rta_len,
plen, rta_type, rta_type2str(rta_type));
switch (rta_type) {
+ case IFLA_IFNAME:
case IFLA_IFALIAS:
if (plen == 0) {
zlog_debug(" invalid length");
diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c
index 6517b7830b..19e2657f1d 100644
--- a/zebra/zebra_nhg.c
+++ b/zebra/zebra_nhg.c
@@ -2248,20 +2248,6 @@ static int nexthop_active(struct nexthop *nexthop, struct nhg_hash_entry *nhe,
return 1;
}
- if (top &&
- ((top->family == AF_INET && top->prefixlen == IPV4_MAX_BITLEN &&
- nexthop->gate.ipv4.s_addr == top->u.prefix4.s_addr) ||
- (top->family == AF_INET6 && top->prefixlen == IPV6_MAX_BITLEN &&
- memcmp(&nexthop->gate.ipv6, &top->u.prefix6, IPV6_MAX_BYTELEN) ==
- 0)) &&
- nexthop->vrf_id == vrf_id) {
- if (IS_ZEBRA_DEBUG_RIB_DETAILED)
- zlog_debug(
- " :%s: Attempting to install a max prefixlength route through itself",
- __func__);
- return 0;
- }
-
/* Validation for ipv4 mapped ipv6 nexthop. */
if (IS_MAPPED_IPV6(&nexthop->gate.ipv6)) {
afi = AFI_IP;
@@ -2364,7 +2350,7 @@ static int nexthop_active(struct nexthop *nexthop, struct nhg_hash_entry *nhe,
zlog_debug(
" %s: Matched against ourself and prefix length is not max bit length",
__func__);
- return 0;
+ goto continue_up_tree;
}
/* Pick up selected route. */
@@ -2391,20 +2377,12 @@ static int nexthop_active(struct nexthop *nexthop, struct nhg_hash_entry *nhe,
/* If there is no selected route or matched route is EGP, go up
* tree.
*/
- if (!match) {
- do {
- rn = rn->parent;
- } while (rn && rn->info == NULL);
- if (rn)
- route_lock_node(rn);
- continue;
- }
/* If the candidate match's type is considered "connected",
* we consider it first.
*/
- if (RIB_CONNECTED_ROUTE(match) ||
- (RIB_SYSTEM_ROUTE(match) && RSYSTEM_ROUTE(type))) {
+ if (match && (RIB_CONNECTED_ROUTE(match) ||
+ (RIB_SYSTEM_ROUTE(match) && RSYSTEM_ROUTE(type)))) {
match = zebra_nhg_connected_ifindex(rn, match,
nexthop->ifindex);
@@ -2420,11 +2398,7 @@ static int nexthop_active(struct nexthop *nexthop, struct nhg_hash_entry *nhe,
zlog_debug(
"%s: %pNHv given ifindex does not match nexthops ifindex found: %pNHv",
__func__, nexthop, newhop);
- /*
- * NEXTHOP_TYPE_*_IFINDEX but ifindex
- * doesn't match what we found.
- */
- return 0;
+ goto continue_up_tree;
}
/* NHRP special case: need to indicate onlink */
@@ -2437,7 +2411,7 @@ static int nexthop_active(struct nexthop *nexthop, struct nhg_hash_entry *nhe,
__func__, match, match->nhe, newhop);
return 1;
- } else if (CHECK_FLAG(flags, ZEBRA_FLAG_ALLOW_RECURSION)) {
+ } else if (match && CHECK_FLAG(flags, ZEBRA_FLAG_ALLOW_RECURSION)) {
struct nexthop_group *nhg;
struct nexthop *resolver;
struct backup_nh_map_s map = {};
@@ -2473,6 +2447,10 @@ static int nexthop_active(struct nexthop *nexthop, struct nhg_hash_entry *nhe,
"%s: match %p (%pNG) not installed or being Route Replaced",
__func__, match, match->nhe);
+ if (CHECK_FLAG(match->status,
+ ROUTE_ENTRY_QUEUED))
+ goto continue_up_tree;
+
goto done_with_match;
}
@@ -2541,25 +2519,37 @@ done_with_match:
if (pmtu)
*pmtu = match->mtu;
- } else if (IS_ZEBRA_DEBUG_RIB_DETAILED)
- zlog_debug(
- " %s: Recursion failed to find",
- __func__);
-
- return resolved;
- } else {
- if (IS_ZEBRA_DEBUG_RIB_DETAILED) {
- zlog_debug(
- " %s: Route Type %s has not turned on recursion",
- __func__, zebra_route_string(type));
- if (type == ZEBRA_ROUTE_BGP
- && !CHECK_FLAG(flags, ZEBRA_FLAG_IBGP))
+ } else {
+ if (IS_ZEBRA_DEBUG_RIB_DETAILED)
zlog_debug(
- " EBGP: see \"disable-ebgp-connected-route-check\" or \"disable-connected-check\"");
+ " %s: Recursion failed to find while looking at %pRN",
+ __func__, rn);
+ goto continue_up_tree;
}
- return 0;
+
+ return 1;
+ } else if (IS_ZEBRA_DEBUG_RIB_DETAILED) {
+ zlog_debug(
+ " %s: Route Type %s has not turned on recursion %pRN failed to match",
+ __func__, zebra_route_string(type), rn);
+ if (type == ZEBRA_ROUTE_BGP
+ && !CHECK_FLAG(flags, ZEBRA_FLAG_IBGP))
+ zlog_debug(
+ " EBGP: see \"disable-ebgp-connected-route-check\" or \"disable-connected-check\"");
}
+
+ continue_up_tree:
+ /*
+ * If there is no selected route or matched route is EGP, go up
+ * tree.
+ */
+ do {
+ rn = rn->parent;
+ } while (rn && rn->info == NULL);
+ if (rn)
+ route_lock_node(rn);
}
+
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
zlog_debug(" %s: Nexthop did not lookup in table",
__func__);