summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bfdd/bfd.c4
-rw-r--r--bfdd/bfd_packet.c36
-rw-r--r--bgpd/bgp_evpn.c4
-rw-r--r--bgpd/bgp_fsm.c5
-rw-r--r--bgpd/bgp_labelpool.c647
-rw-r--r--bgpd/bgp_labelpool.h1
-rw-r--r--bgpd/bgp_route.c58
-rw-r--r--bgpd/bgp_routemap.c4
-rw-r--r--bgpd/bgp_rpki.c10
-rw-r--r--bgpd/bgp_table.h75
-rw-r--r--bgpd/bgp_updgrp.c2
-rw-r--r--bgpd/bgpd.c5
-rw-r--r--bgpd/subdir.am1
-rw-r--r--eigrpd/eigrp_network.c4
-rw-r--r--eigrpd/eigrp_packet.c8
-rw-r--r--eigrpd/eigrpd.c3
-rw-r--r--lib/bitfield.h69
-rw-r--r--lib/routemap.c6
-rw-r--r--tests/topotests/bgp_aggregate_address_matching_med/__init__.py0
-rw-r--r--tests/topotests/bgp_aggregate_address_matching_med/r1/bgpd.conf21
-rw-r--r--tests/topotests/bgp_aggregate_address_matching_med/r1/zebra.conf11
-rw-r--r--tests/topotests/bgp_aggregate_address_matching_med/r2/bgpd.conf11
-rw-r--r--tests/topotests/bgp_aggregate_address_matching_med/r2/zebra.conf9
-rw-r--r--tests/topotests/bgp_aggregate_address_matching_med/r3/bgpd.conf6
-rw-r--r--tests/topotests/bgp_aggregate_address_matching_med/r3/zebra.conf6
-rw-r--r--tests/topotests/bgp_aggregate_address_matching_med/test_bgp_aggregate_address_matching_med.py148
-rw-r--r--tests/topotests/bgp_lu_topo1/R1/labelpool.summ.json2
-rw-r--r--tests/topotests/bgp_lu_topo2/R1/labelpool.summ.json2
-rw-r--r--tests/topotests/bgp_remove_private_as/test_bgp_remove_private_as.py19
-rw-r--r--zebra/kernel_netlink.c18
30 files changed, 996 insertions, 199 deletions
diff --git a/bfdd/bfd.c b/bfdd/bfd.c
index a1fb67d357..4367f253e1 100644
--- a/bfdd/bfd.c
+++ b/bfdd/bfd.c
@@ -348,7 +348,7 @@ int bfd_session_enable(struct bfd_session *bs)
/* Sanity check: don't leak open sockets. */
if (bs->sock != -1) {
if (bglobal.debug_peer_event)
- zlog_debug("session-enable: previous socket open");
+ zlog_debug("%s: previous socket open", __func__);
close(bs->sock);
bs->sock = -1;
@@ -952,7 +952,7 @@ int ptm_bfd_sess_del(struct bfd_peer_cfg *bpc)
}
if (bglobal.debug_peer_event)
- zlog_debug("session-delete: %s", bs_to_string(bs));
+ zlog_debug("%s: %s", __func__, bs_to_string(bs));
control_notify_config(BCM_NOTIFY_CONFIG_DELETE, bs);
diff --git a/bfdd/bfd_packet.c b/bfdd/bfd_packet.c
index 98411a8732..382f78a0f6 100644
--- a/bfdd/bfd_packet.c
+++ b/bfdd/bfd_packet.c
@@ -578,8 +578,8 @@ ssize_t bfd_recv_ipv4(int sd, uint8_t *msgbuf, size_t msgbuflen, uint8_t *ttl,
memcpy(&ttlval, CMSG_DATA(cm), sizeof(ttlval));
if (ttlval > 255) {
if (bglobal.debug_network)
- zlog_debug("ipv4-recv: invalid TTL: %u",
- ttlval);
+ zlog_debug("%s: invalid TTL: %u",
+ __func__, ttlval);
return -1;
}
*ttl = ttlval;
@@ -686,8 +686,8 @@ ssize_t bfd_recv_ipv6(int sd, uint8_t *msgbuf, size_t msgbuflen, uint8_t *ttl,
memcpy(&ttlval, CMSG_DATA(cm), sizeof(ttlval));
if (ttlval > 255) {
if (bglobal.debug_network)
- zlog_debug("ipv6-recv: invalid TTL: %u",
- ttlval);
+ zlog_debug("%s: invalid TTL: %u",
+ __func__, ttlval);
return -1;
}
@@ -1127,13 +1127,13 @@ int bp_udp_send_fp(int sd, uint8_t *data, size_t datalen,
if (wlen <= 0) {
if (bglobal.debug_network)
- zlog_debug("udp-send: loopback failure: (%d) %s", errno,
- strerror(errno));
+ zlog_debug("%s: loopback failure: (%d) %s", __func__,
+ errno, strerror(errno));
return -1;
} else if (wlen < (ssize_t)datalen) {
if (bglobal.debug_network)
- zlog_debug("udp-send: partial send: %zd expected %zu",
- wlen, datalen);
+ zlog_debug("%s: partial send: %zd expected %zu",
+ __func__, wlen, datalen);
return -1;
}
@@ -1194,13 +1194,13 @@ int bp_udp_send(int sd, uint8_t ttl, uint8_t *data, size_t datalen,
wlen = sendmsg(sd, &msg, 0);
if (wlen <= 0) {
if (bglobal.debug_network)
- zlog_debug("udp-send: loopback failure: (%d) %s", errno,
- strerror(errno));
+ zlog_debug("%s: loopback failure: (%d) %s", __func__,
+ errno, strerror(errno));
return -1;
} else if (wlen < (ssize_t)datalen) {
if (bglobal.debug_network)
- zlog_debug("udp-send: partial send: %zd expected %zu",
- wlen, datalen);
+ zlog_debug("%s: partial send: %zd expected %zu",
+ __func__, wlen, datalen);
return -1;
}
@@ -1221,7 +1221,7 @@ int bp_set_ttl(int sd, uint8_t value)
int ttl = value;
if (setsockopt(sd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl)) == -1) {
- zlog_warn("set-ttl: setsockopt(IP_TTL, %d): %s", value,
+ zlog_warn("%s: setsockopt(IP_TTL, %d): %s", __func__, value,
strerror(errno));
return -1;
}
@@ -1234,7 +1234,7 @@ int bp_set_tos(int sd, uint8_t value)
int tos = value;
if (setsockopt(sd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) == -1) {
- zlog_warn("set-tos: setsockopt(IP_TOS, %d): %s", value,
+ zlog_warn("%s: setsockopt(IP_TOS, %d): %s", __func__, value,
strerror(errno));
return -1;
}
@@ -1247,8 +1247,8 @@ static bool bp_set_reuse_addr(int sd)
int one = 1;
if (setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) == -1) {
- zlog_warn("set-reuse-addr: setsockopt(SO_REUSEADDR, %d): %s",
- one, strerror(errno));
+ zlog_warn("%s: setsockopt(SO_REUSEADDR, %d): %s", __func__, one,
+ strerror(errno));
return false;
}
return true;
@@ -1259,8 +1259,8 @@ static bool bp_set_reuse_port(int sd)
int one = 1;
if (setsockopt(sd, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)) == -1) {
- zlog_warn("set-reuse-port: setsockopt(SO_REUSEPORT, %d): %s",
- one, strerror(errno));
+ zlog_warn("%s: setsockopt(SO_REUSEPORT, %d): %s", __func__, one,
+ strerror(errno));
return false;
}
return true;
diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c
index dc15d9c695..58f5e9a226 100644
--- a/bgpd/bgp_evpn.c
+++ b/bgpd/bgp_evpn.c
@@ -3631,8 +3631,10 @@ static int update_advertise_vni_routes(struct bgp *bgp, struct bgpevpn *vpn)
pi->type == ZEBRA_ROUTE_BGP
&& pi->sub_type == BGP_ROUTE_STATIC)
break;
- if (!pi) /* unexpected */
+ if (!pi) {
+ bgp_dest_unlock_node(dest);
return 0;
+ }
attr = pi->attr;
global_dest = bgp_global_evpn_node_get(bgp->rib[afi][safi],
diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c
index 1164546df7..a8accc25f5 100644
--- a/bgpd/bgp_fsm.c
+++ b/bgpd/bgp_fsm.c
@@ -300,11 +300,6 @@ 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];
- if (from_peer->soo[afi][safi]) {
- ecommunity_free(&peer->soo[afi][safi]);
- peer->soo[afi][safi] =
- ecommunity_dup(from_peer->soo[afi][safi]);
- }
}
if (bgp_getsockname(peer) < 0) {
diff --git a/bgpd/bgp_labelpool.c b/bgpd/bgp_labelpool.c
index fa1dcf33e0..c227a5e41c 100644
--- a/bgpd/bgp_labelpool.c
+++ b/bgpd/bgp_labelpool.c
@@ -37,18 +37,41 @@
#include "bgpd/bgp_errors.h"
#include "bgpd/bgp_route.h"
+#define BGP_LABELPOOL_ENABLE_TESTS 0
+
+#ifndef VTYSH_EXTRACT_PL
+#include "bgpd/bgp_labelpool_clippy.c"
+#endif
+
+
/*
* Definitions and external declarations.
*/
extern struct zclient *zclient;
+#if BGP_LABELPOOL_ENABLE_TESTS
+static void lptest_init(void);
+static void lptest_finish(void);
+#endif
+
/*
* Remember where pool data are kept
*/
static struct labelpool *lp;
-/* request this many labels at a time from zebra */
-#define LP_CHUNK_SIZE 50
+/*
+ * Number of labels requested at a time from the zebra label manager.
+ * We start small but double the request size each time up to a
+ * maximum size.
+ *
+ * The label space is 20 bits which is shared with other FRR processes
+ * on this host, so to avoid greedily requesting a mostly wasted chunk,
+ * we limit the chunk size to 1/16 of the label space (that's the -4 bits
+ * in the definition below). This limit slightly increases our cost of
+ * finding free labels in our allocated chunks.
+ */
+#define LP_CHUNK_SIZE_MIN 128
+#define LP_CHUNK_SIZE_MAX (1 << (20 - 4))
DEFINE_MTYPE_STATIC(BGPD, BGP_LABEL_CHUNK, "BGP Label Chunk");
DEFINE_MTYPE_STATIC(BGPD, BGP_LABEL_FIFO, "BGP Label FIFO item");
@@ -58,6 +81,9 @@ DEFINE_MTYPE_STATIC(BGPD, BGP_LABEL_CBQ, "BGP Dynamic Label Callback");
struct lp_chunk {
uint32_t first;
uint32_t last;
+ uint32_t nfree; /* un-allocated count */
+ uint32_t idx_last_allocated; /* start looking here */
+ bitfield_t allocated_map;
};
/*
@@ -160,6 +186,9 @@ static void lp_lcb_free(void *goner)
static void lp_chunk_free(void *goner)
{
+ struct lp_chunk *chunk = (struct lp_chunk *)goner;
+
+ bf_free(chunk->allocated_map);
XFREE(MTYPE_BGP_LABEL_CHUNK, goner);
}
@@ -180,6 +209,12 @@ void bgp_lp_init(struct thread_master *master, struct labelpool *pool)
lp->callback_q->spec.workfunc = lp_cbq_docallback;
lp->callback_q->spec.del_item_data = lp_cbq_item_free;
lp->callback_q->spec.max_retries = 0;
+
+ lp->next_chunksize = LP_CHUNK_SIZE_MIN;
+
+#if BGP_LABELPOOL_ENABLE_TESTS
+ lptest_init();
+#endif
}
/* check if a label callback was for a BGP LU node, and if so, unlock it */
@@ -201,6 +236,9 @@ void bgp_lp_finish(void)
struct lp_fifo *lf;
struct work_queue_item *item, *titem;
+#if BGP_LABELPOOL_ENABLE_TESTS
+ lptest_finish();
+#endif
if (!lp)
return;
@@ -240,25 +278,53 @@ static mpls_label_t get_label_from_pool(void *labelid)
/*
* Find a free label
- * Linear search is not efficient but should be executed infrequently.
*/
for (ALL_LIST_ELEMENTS_RO(lp->chunks, node, chunk)) {
uintptr_t lbl;
+ unsigned int index;
if (debug)
zlog_debug("%s: chunk first=%u last=%u",
__func__, chunk->first, chunk->last);
- for (lbl = chunk->first; lbl <= chunk->last; ++lbl) {
- /* labelid is key to all-request "ledger" list */
- if (!skiplist_insert(lp->inuse, (void *)lbl, labelid)) {
- /*
- * Success
- */
- return lbl;
- }
+ /*
+ * don't look in chunks with no available labels
+ */
+ if (!chunk->nfree)
+ continue;
+
+ /*
+ * roll through bitfield starting where we stopped
+ * last time
+ */
+ index = bf_find_next_clear_bit_wrap(
+ &chunk->allocated_map, chunk->idx_last_allocated + 1,
+ 0);
+
+ /*
+ * since chunk->nfree is non-zero, we should always get
+ * a valid index
+ */
+ assert(index != WORD_MAX);
+
+ lbl = chunk->first + index;
+ if (skiplist_insert(lp->inuse, (void *)lbl, labelid)) {
+ /* something is very wrong */
+ zlog_err("%s: unable to insert inuse label %u (id %p)",
+ __func__, (uint32_t)lbl, labelid);
+ return MPLS_LABEL_NONE;
}
+
+ /*
+ * Success
+ */
+ bf_set_bit(chunk->allocated_map, index);
+ chunk->idx_last_allocated = index;
+ chunk->nfree -= 1;
+
+ return lbl;
}
+
return MPLS_LABEL_NONE;
}
@@ -299,10 +365,14 @@ static struct lp_lcb *lcb_alloc(
* When connection to zebra is reestablished, previous label assignments
* will be invalidated (via callbacks having the "allocated" parameter unset)
* and new labels will be automatically reassigned by this labelpool module
- * (that is, a requestor does not need to call lp_get() again if it is
+ * (that is, a requestor does not need to call bgp_lp_get() again if it is
* notified via callback that its label has been lost: it will eventually
* get another callback with a new label assignment).
*
+ * The callback function should return 0 to accept the allocation
+ * and non-zero to refuse it. The callback function return value is
+ * ignored for invalidations (i.e., when the "allocated" parameter is false)
+ *
* Prior requests for a given labelid are detected so that requests and
* assignments are not duplicated.
*/
@@ -392,10 +462,13 @@ void bgp_lp_get(
if (lp_fifo_count(&lp->requests) > lp->pending_count) {
if (!zclient || zclient->sock < 0)
return;
- if (zclient_send_get_label_chunk(zclient, 0, LP_CHUNK_SIZE,
- MPLS_LABEL_BASE_ANY)
- != ZCLIENT_SEND_FAILURE)
- lp->pending_count += LP_CHUNK_SIZE;
+ if (zclient_send_get_label_chunk(zclient, 0, lp->next_chunksize,
+ MPLS_LABEL_BASE_ANY) !=
+ ZCLIENT_SEND_FAILURE) {
+ lp->pending_count += lp->next_chunksize;
+ if ((lp->next_chunksize << 1) <= LP_CHUNK_SIZE_MAX)
+ lp->next_chunksize <<= 1;
+ }
}
}
@@ -408,13 +481,36 @@ void bgp_lp_release(
if (!skiplist_search(lp->ledger, labelid, (void **)&lcb)) {
if (label == lcb->label && type == lcb->type) {
+ struct listnode *node;
+ struct lp_chunk *chunk;
uintptr_t lbl = label;
+ bool deallocated = false;
/* no longer in use */
skiplist_delete(lp->inuse, (void *)lbl, NULL);
/* no longer requested */
skiplist_delete(lp->ledger, labelid, NULL);
+
+ /*
+ * Find the chunk this label belongs to and
+ * deallocate the label
+ */
+ for (ALL_LIST_ELEMENTS_RO(lp->chunks, node, chunk)) {
+ uint32_t index;
+
+ if ((label < chunk->first) ||
+ (label > chunk->last))
+ continue;
+
+ index = label - chunk->first;
+ assert(bf_test_index(chunk->allocated_map,
+ index));
+ bf_release_index(chunk->allocated_map, index);
+ chunk->nfree += 1;
+ deallocated = true;
+ }
+ assert(deallocated);
}
}
}
@@ -427,6 +523,7 @@ void bgp_lp_event_chunk(uint8_t keep, uint32_t first, uint32_t last)
struct lp_chunk *chunk;
int debug = BGP_DEBUG(labelpool, LABELPOOL);
struct lp_fifo *lf;
+ uint32_t labelcount;
if (last < first) {
flog_err(EC_BGP_LABEL,
@@ -437,19 +534,27 @@ void bgp_lp_event_chunk(uint8_t keep, uint32_t first, uint32_t last)
chunk = XCALLOC(MTYPE_BGP_LABEL_CHUNK, sizeof(struct lp_chunk));
+ labelcount = last - first + 1;
+
chunk->first = first;
chunk->last = last;
+ chunk->nfree = labelcount;
+ bf_init(chunk->allocated_map, labelcount);
- listnode_add(lp->chunks, chunk);
+ /*
+ * Optimize for allocation by adding the new (presumably larger)
+ * chunk at the head of the list so it is examined first.
+ */
+ listnode_add_head(lp->chunks, chunk);
- lp->pending_count -= (last - first + 1);
+ lp->pending_count -= labelcount;
if (debug) {
zlog_debug("%s: %zu pending requests", __func__,
lp_fifo_count(&lp->requests));
}
- while ((lf = lp_fifo_first(&lp->requests))) {
+ while (labelcount && (lf = lp_fifo_first(&lp->requests))) {
struct lp_lcb *lcb;
void *labelid = lf->lcb.labelid;
@@ -495,6 +600,8 @@ void bgp_lp_event_chunk(uint8_t keep, uint32_t first, uint32_t last)
break;
}
+ labelcount -= 1;
+
/*
* we filled the request from local pool.
* Enqueue response work item with new label.
@@ -535,8 +642,8 @@ void bgp_lp_event_zebra_down(void)
*/
void bgp_lp_event_zebra_up(void)
{
- int labels_needed;
- int chunks_needed;
+ unsigned int labels_needed;
+ unsigned int chunks_needed;
void *labelid;
struct lp_lcb *lcb;
int lm_init_ok;
@@ -548,9 +655,16 @@ void bgp_lp_event_zebra_up(void)
labels_needed = lp_fifo_count(&lp->requests) +
skiplist_count(lp->inuse);
+ if (labels_needed > lp->next_chunksize) {
+ while ((lp->next_chunksize < labels_needed) &&
+ (lp->next_chunksize << 1 <= LP_CHUNK_SIZE_MAX))
+
+ lp->next_chunksize <<= 1;
+ }
+
/* round up */
- chunks_needed = (labels_needed / LP_CHUNK_SIZE) + 1;
- labels_needed = chunks_needed * LP_CHUNK_SIZE;
+ chunks_needed = (labels_needed / lp->next_chunksize) + 1;
+ labels_needed = chunks_needed * lp->next_chunksize;
lm_init_ok = lm_label_manager_connect(zclient, 1) == 0;
@@ -937,25 +1051,496 @@ DEFUN(show_bgp_labelpool_chunks, show_bgp_labelpool_chunks_cmd,
}
json = json_object_new_array();
} else {
- vty_out(vty, "First Last\n");
- vty_out(vty, "--------------\n");
+ vty_out(vty, "%10s %10s %10s %10s\n", "First", "Last", "Size",
+ "nfree");
+ vty_out(vty, "-------------------------------------------\n");
}
for (ALL_LIST_ELEMENTS_RO(lp->chunks, node, chunk)) {
+ uint32_t size;
+
+ size = chunk->last - chunk->first + 1;
+
if (uj) {
json_elem = json_object_new_object();
json_object_array_add(json, json_elem);
json_object_int_add(json_elem, "first", chunk->first);
json_object_int_add(json_elem, "last", chunk->last);
+ json_object_int_add(json_elem, "size", size);
+ json_object_int_add(json_elem, "numberFree",
+ chunk->nfree);
} else
- vty_out(vty, "%-10u %-10u\n", chunk->first,
- chunk->last);
+ vty_out(vty, "%10u %10u %10u %10u\n", chunk->first,
+ chunk->last, size, chunk->nfree);
}
if (uj)
vty_json(vty, json);
return CMD_SUCCESS;
}
+#if BGP_LABELPOOL_ENABLE_TESTS
+/*------------------------------------------------------------------------
+ * Testing code start
+ *------------------------------------------------------------------------*/
+
+DEFINE_MTYPE_STATIC(BGPD, LABELPOOL_TEST, "Label pool test");
+
+#define LPT_STAT_INSERT_FAIL 0
+#define LPT_STAT_DELETE_FAIL 1
+#define LPT_STAT_ALLOCATED 2
+#define LPT_STAT_DEALLOCATED 3
+#define LPT_STAT_MAX 4
+
+const char *lpt_counter_names[] = {
+ "sl insert failures",
+ "sl delete failures",
+ "labels allocated",
+ "labels deallocated",
+};
+
+static uint8_t lpt_generation;
+static bool lpt_inprogress;
+static struct skiplist *lp_tests;
+static unsigned int lpt_test_cb_tcb_lookup_fails;
+static unsigned int lpt_release_tcb_lookup_fails;
+static unsigned int lpt_test_event_tcb_lookup_fails;
+static unsigned int lpt_stop_tcb_lookup_fails;
+
+struct lp_test {
+ uint8_t generation;
+ unsigned int request_maximum;
+ unsigned int request_blocksize;
+ uintptr_t request_count; /* match type of labelid */
+ int label_type;
+ struct skiplist *labels;
+ struct timeval starttime;
+ struct skiplist *timestamps_alloc;
+ struct skiplist *timestamps_dealloc;
+ struct thread *event_thread;
+ unsigned int counter[LPT_STAT_MAX];
+};
+
+/* test parameters */
+#define LPT_MAX_COUNT 500000 /* get this many labels in all */
+#define LPT_BLKSIZE 10000 /* this many at a time, then yield */
+#define LPT_TS_INTERVAL 10000 /* timestamp every this many labels */
+
+
+static int test_cb(mpls_label_t label, void *labelid, bool allocated)
+{
+ uintptr_t generation;
+ struct lp_test *tcb;
+
+ generation = ((uintptr_t)labelid >> 24) & 0xff;
+
+ if (skiplist_search(lp_tests, (void *)generation, (void **)&tcb)) {
+
+ /* couldn't find current test in progress */
+ ++lpt_test_cb_tcb_lookup_fails;
+ return -1; /* reject allocation */
+ }
+
+ if (allocated) {
+ ++tcb->counter[LPT_STAT_ALLOCATED];
+ if (!(tcb->counter[LPT_STAT_ALLOCATED] % LPT_TS_INTERVAL)) {
+ uintptr_t time_ms;
+
+ time_ms = monotime_since(&tcb->starttime, NULL) / 1000;
+ skiplist_insert(tcb->timestamps_alloc,
+ (void *)(uintptr_t)tcb
+ ->counter[LPT_STAT_ALLOCATED],
+ (void *)time_ms);
+ }
+ if (skiplist_insert(tcb->labels, labelid,
+ (void *)(uintptr_t)label)) {
+ ++tcb->counter[LPT_STAT_INSERT_FAIL];
+ return -1;
+ }
+ } else {
+ ++tcb->counter[LPT_STAT_DEALLOCATED];
+ if (!(tcb->counter[LPT_STAT_DEALLOCATED] % LPT_TS_INTERVAL)) {
+ uintptr_t time_ms;
+
+ time_ms = monotime_since(&tcb->starttime, NULL) / 1000;
+ skiplist_insert(tcb->timestamps_dealloc,
+ (void *)(uintptr_t)tcb
+ ->counter[LPT_STAT_ALLOCATED],
+ (void *)time_ms);
+ }
+ if (skiplist_delete(tcb->labels, labelid, 0)) {
+ ++tcb->counter[LPT_STAT_DELETE_FAIL];
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static void labelpool_test_event_handler(struct thread *thread)
+{
+ struct lp_test *tcb;
+
+ if (skiplist_search(lp_tests, (void *)(uintptr_t)(lpt_generation),
+ (void **)&tcb)) {
+
+ /* couldn't find current test in progress */
+ ++lpt_test_event_tcb_lookup_fails;
+ return;
+ }
+
+ /*
+ * request a bunch of labels
+ */
+ for (unsigned int i = 0; (i < tcb->request_blocksize) &&
+ (tcb->request_count < tcb->request_maximum);
+ ++i) {
+
+ uintptr_t id;
+
+ ++tcb->request_count;
+
+ /*
+ * construct 32-bit id from request_count and generation
+ */
+ id = ((uintptr_t)tcb->generation << 24) |
+ (tcb->request_count & 0x00ffffff);
+ bgp_lp_get(LP_TYPE_VRF, (void *)id, test_cb);
+ }
+
+ if (tcb->request_count < tcb->request_maximum)
+ thread_add_event(bm->master, labelpool_test_event_handler, NULL,
+ 0, &tcb->event_thread);
+}
+
+static void lptest_stop(void)
+{
+ struct lp_test *tcb;
+
+ if (!lpt_inprogress)
+ return;
+
+ if (skiplist_search(lp_tests, (void *)(uintptr_t)(lpt_generation),
+ (void **)&tcb)) {
+
+ /* couldn't find current test in progress */
+ ++lpt_stop_tcb_lookup_fails;
+ return;
+ }
+
+ if (tcb->event_thread)
+ thread_cancel(&tcb->event_thread);
+
+ lpt_inprogress = false;
+}
+
+static int lptest_start(struct vty *vty)
+{
+ struct lp_test *tcb;
+
+ if (lpt_inprogress) {
+ vty_out(vty, "test already in progress\n");
+ return -1;
+ }
+
+ if (skiplist_count(lp_tests) >=
+ (1 << (8 * sizeof(lpt_generation))) - 1) {
+ /*
+ * Too many test runs
+ */
+ vty_out(vty, "too many tests: clear first\n");
+ return -1;
+ }
+
+ /*
+ * We pack the generation and request number into the labelid;
+ * make sure they fit.
+ */
+ unsigned int n1 = LPT_MAX_COUNT;
+ unsigned int sh = 0;
+ unsigned int label_bits;
+
+ label_bits = 8 * (sizeof(tcb->request_count) - sizeof(lpt_generation));
+
+ /* n1 should be same type as tcb->request_maximum */
+ assert(sizeof(n1) == sizeof(tcb->request_maximum));
+
+ while (n1 >>= 1)
+ ++sh;
+ sh += 1; /* number of bits needed to hold LPT_MAX_COUNT */
+
+ if (sh > label_bits) {
+ vty_out(vty,
+ "Sorry, test iteration count too big on this platform (LPT_MAX_COUNT %u, need %u bits, but label_bits is only %u)\n",
+ LPT_MAX_COUNT, sh, label_bits);
+ return -1;
+ }
+
+ lpt_inprogress = true;
+ ++lpt_generation;
+
+ tcb = XCALLOC(MTYPE_LABELPOOL_TEST, sizeof(*tcb));
+
+ tcb->generation = lpt_generation;
+ tcb->label_type = LP_TYPE_VRF;
+ tcb->request_maximum = LPT_MAX_COUNT;
+ tcb->request_blocksize = LPT_BLKSIZE;
+ tcb->labels = skiplist_new(0, NULL, NULL);
+ tcb->timestamps_alloc = skiplist_new(0, NULL, NULL);
+ tcb->timestamps_dealloc = skiplist_new(0, NULL, NULL);
+ thread_add_event(bm->master, labelpool_test_event_handler, NULL, 0,
+ &tcb->event_thread);
+ monotime(&tcb->starttime);
+
+ skiplist_insert(lp_tests, (void *)(uintptr_t)tcb->generation, tcb);
+ return 0;
+}
+
+DEFPY(start_labelpool_perf_test, start_labelpool_perf_test_cmd,
+ "debug bgp lptest start",
+ DEBUG_STR BGP_STR
+ "label pool test\n"
+ "start\n")
+{
+ lptest_start(vty);
+ return CMD_SUCCESS;
+}
+
+static void lptest_print_stats(struct vty *vty, struct lp_test *tcb)
+{
+ unsigned int i;
+
+ vty_out(vty, "Global Lookup Failures in test_cb: %5u\n",
+ lpt_test_cb_tcb_lookup_fails);
+ vty_out(vty, "Global Lookup Failures in release: %5u\n",
+ lpt_release_tcb_lookup_fails);
+ vty_out(vty, "Global Lookup Failures in event: %5u\n",
+ lpt_test_event_tcb_lookup_fails);
+ vty_out(vty, "Global Lookup Failures in stop: %5u\n",
+ lpt_stop_tcb_lookup_fails);
+ vty_out(vty, "\n");
+
+ if (!tcb) {
+ if (skiplist_search(lp_tests, (void *)(uintptr_t)lpt_generation,
+ (void **)&tcb)) {
+ vty_out(vty, "Error: can't find test %u\n",
+ lpt_generation);
+ return;
+ }
+ }
+
+ vty_out(vty, "Test Generation %u:\n", tcb->generation);
+
+ vty_out(vty, "Counter Value\n");
+ for (i = 0; i < LPT_STAT_MAX; ++i) {
+ vty_out(vty, "%20s: %10u\n", lpt_counter_names[i],
+ tcb->counter[i]);
+ }
+ vty_out(vty, "\n");
+
+ if (tcb->timestamps_alloc) {
+ void *Key;
+ void *Value;
+ void *cursor;
+
+ float elapsed;
+
+ vty_out(vty, "%10s %10s\n", "Count", "Seconds");
+
+ cursor = NULL;
+ while (!skiplist_next(tcb->timestamps_alloc, &Key, &Value,
+ &cursor)) {
+
+ elapsed = ((float)(uintptr_t)Value) / 1000;
+
+ vty_out(vty, "%10llu %10.3f\n",
+ (unsigned long long)(uintptr_t)Key, elapsed);
+ }
+ vty_out(vty, "\n");
+ }
+}
+
+DEFPY(show_labelpool_perf_test, show_labelpool_perf_test_cmd,
+ "debug bgp lptest show",
+ DEBUG_STR BGP_STR
+ "label pool test\n"
+ "show\n")
+{
+
+ if (lp_tests) {
+ void *Key;
+ void *Value;
+ void *cursor;
+
+ cursor = NULL;
+ while (!skiplist_next(lp_tests, &Key, &Value, &cursor)) {
+ lptest_print_stats(vty, (struct lp_test *)Value);
+ }
+ } else {
+ vty_out(vty, "no test results\n");
+ }
+ return CMD_SUCCESS;
+}
+
+DEFPY(stop_labelpool_perf_test, stop_labelpool_perf_test_cmd,
+ "debug bgp lptest stop",
+ DEBUG_STR BGP_STR
+ "label pool test\n"
+ "stop\n")
+{
+
+ if (lpt_inprogress) {
+ lptest_stop();
+ lptest_print_stats(vty, NULL);
+ } else {
+ vty_out(vty, "no test in progress\n");
+ }
+ return CMD_SUCCESS;
+}
+
+DEFPY(clear_labelpool_perf_test, clear_labelpool_perf_test_cmd,
+ "debug bgp lptest clear",
+ DEBUG_STR BGP_STR
+ "label pool test\n"
+ "clear\n")
+{
+
+ if (lpt_inprogress) {
+ lptest_stop();
+ }
+ if (lp_tests) {
+ while (!skiplist_first(lp_tests, NULL, NULL))
+ /* del function of skiplist cleans up tcbs */
+ skiplist_delete_first(lp_tests);
+ }
+ return CMD_SUCCESS;
+}
+
+/*
+ * With the "release" command, we can release labels at intervals through
+ * the ID space. Thus we can to exercise the bitfield-wrapping behavior
+ * of the allocator in a subsequent test.
+ */
+/* clang-format off */
+DEFPY(release_labelpool_perf_test, release_labelpool_perf_test_cmd,
+ "debug bgp lptest release test GENERATION$generation every (1-5)$every_nth",
+ DEBUG_STR
+ BGP_STR
+ "label pool test\n"
+ "release labels\n"
+ "\"test\"\n"
+ "test number\n"
+ "\"every\"\n"
+ "label fraction denominator\n")
+{
+ /* clang-format on */
+
+ unsigned long testnum;
+ char *end;
+ struct lp_test *tcb;
+
+ testnum = strtoul(generation, &end, 0);
+ if (*end) {
+ vty_out(vty, "Invalid test number: \"%s\"\n", generation);
+ return CMD_SUCCESS;
+ }
+ if (lpt_inprogress && (testnum == lpt_generation)) {
+ vty_out(vty,
+ "Error: Test %lu is still in progress (stop first)\n",
+ testnum);
+ return CMD_SUCCESS;
+ }
+
+ if (skiplist_search(lp_tests, (void *)(uintptr_t)testnum,
+ (void **)&tcb)) {
+
+ /* couldn't find current test in progress */
+ vty_out(vty, "Error: Can't look up test number: \"%lu\"\n",
+ testnum);
+ ++lpt_release_tcb_lookup_fails;
+ return CMD_SUCCESS;
+ }
+
+ void *Key, *cKey;
+ void *Value, *cValue;
+ void *cursor;
+ unsigned int iteration;
+ int rc;
+
+ cursor = NULL;
+ iteration = 0;
+ rc = skiplist_next(tcb->labels, &Key, &Value, &cursor);
+
+ while (!rc) {
+ cKey = Key;
+ cValue = Value;
+
+ /* find next item before we delete this one */
+ rc = skiplist_next(tcb->labels, &Key, &Value, &cursor);
+
+ if (!(iteration % every_nth)) {
+ bgp_lp_release(tcb->label_type, cKey,
+ (mpls_label_t)(uintptr_t)cValue);
+ skiplist_delete(tcb->labels, cKey, NULL);
+ ++tcb->counter[LPT_STAT_DEALLOCATED];
+ }
+ ++iteration;
+ }
+
+ return CMD_SUCCESS;
+}
+
+static void lptest_delete(void *val)
+{
+ struct lp_test *tcb = (struct lp_test *)val;
+ void *Key;
+ void *Value;
+ void *cursor;
+
+ if (tcb->labels) {
+ cursor = NULL;
+ while (!skiplist_next(tcb->labels, &Key, &Value, &cursor))
+ bgp_lp_release(tcb->label_type, Key,
+ (mpls_label_t)(uintptr_t)Value);
+ skiplist_free(tcb->labels);
+ tcb->labels = NULL;
+ }
+ if (tcb->timestamps_alloc) {
+ cursor = NULL;
+ skiplist_free(tcb->timestamps_alloc);
+ tcb->timestamps_alloc = NULL;
+ }
+
+ if (tcb->timestamps_dealloc) {
+ cursor = NULL;
+ skiplist_free(tcb->timestamps_dealloc);
+ tcb->timestamps_dealloc = NULL;
+ }
+
+ if (tcb->event_thread)
+ thread_cancel(&tcb->event_thread);
+
+ memset(tcb, 0, sizeof(*tcb));
+
+ XFREE(MTYPE_LABELPOOL_TEST, tcb);
+}
+
+static void lptest_init(void)
+{
+ lp_tests = skiplist_new(0, NULL, lptest_delete);
+}
+
+static void lptest_finish(void)
+{
+ if (lp_tests) {
+ skiplist_free(lp_tests);
+ lp_tests = NULL;
+ }
+}
+
+/*------------------------------------------------------------------------
+ * Testing code end
+ *------------------------------------------------------------------------*/
+#endif /* BGP_LABELPOOL_ENABLE_TESTS */
+
void bgp_lp_vty_init(void)
{
install_element(VIEW_NODE, &show_bgp_labelpool_summary_cmd);
@@ -963,4 +1548,12 @@ void bgp_lp_vty_init(void)
install_element(VIEW_NODE, &show_bgp_labelpool_inuse_cmd);
install_element(VIEW_NODE, &show_bgp_labelpool_requests_cmd);
install_element(VIEW_NODE, &show_bgp_labelpool_chunks_cmd);
+
+#if BGP_LABELPOOL_ENABLE_TESTS
+ install_element(ENABLE_NODE, &start_labelpool_perf_test_cmd);
+ install_element(ENABLE_NODE, &show_labelpool_perf_test_cmd);
+ install_element(ENABLE_NODE, &stop_labelpool_perf_test_cmd);
+ install_element(ENABLE_NODE, &release_labelpool_perf_test_cmd);
+ install_element(ENABLE_NODE, &clear_labelpool_perf_test_cmd);
+#endif /* BGP_LABELPOOL_ENABLE_TESTS */
}
diff --git a/bgpd/bgp_labelpool.h b/bgpd/bgp_labelpool.h
index d6a8eec84d..2f3ffe437f 100644
--- a/bgpd/bgp_labelpool.h
+++ b/bgpd/bgp_labelpool.h
@@ -41,6 +41,7 @@ struct labelpool {
struct work_queue *callback_q;
uint32_t pending_count; /* requested from zebra */
uint32_t reconnect_count; /* zebra reconnections */
+ uint32_t next_chunksize; /* request this many labels */
};
extern void bgp_lp_init(struct thread_master *master, struct labelpool *pool);
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index e7fac8153c..9eb7407af6 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -1776,10 +1776,20 @@ static void bgp_peer_remove_private_as(struct bgp *bgp, afi_t afi, safi_t safi,
static void bgp_peer_as_override(struct bgp *bgp, afi_t afi, safi_t safi,
struct peer *peer, struct attr *attr)
{
+ struct aspath *aspath;
+
if (peer->sort == BGP_PEER_EBGP &&
- peer_af_flag_check(peer, afi, safi, PEER_FLAG_AS_OVERRIDE))
- attr->aspath = aspath_replace_specific_asn(attr->aspath,
- peer->as, bgp->as);
+ peer_af_flag_check(peer, afi, safi, PEER_FLAG_AS_OVERRIDE)) {
+ if (attr->aspath->refcnt)
+ aspath = aspath_dup(attr->aspath);
+ else
+ aspath = attr->aspath;
+
+ attr->aspath = aspath_intern(
+ aspath_replace_specific_asn(aspath, peer->as, bgp->as));
+
+ aspath_free(aspath);
+ }
}
void bgp_attr_add_llgr_community(struct attr *attr)
@@ -6482,6 +6492,7 @@ static int bgp_static_set(struct vty *vty, const char *negate,
/* Label index cannot be changed. */
if (bgp_static->label_index != label_index) {
vty_out(vty, "%% cannot change label-index\n");
+ bgp_dest_unlock_node(dest);
return CMD_WARNING_CONFIG_FAILED;
}
@@ -7266,6 +7277,7 @@ static void bgp_aggregate_install(
aggregate, atomic_aggregate, p);
if (!attr) {
+ bgp_dest_unlock_node(dest);
bgp_aggregate_delete(bgp, p, afi, safi, aggregate);
if (BGP_DEBUG(update_groups, UPDATE_GROUPS))
zlog_debug("%s: %pFX null attribute", __func__,
@@ -7426,31 +7438,21 @@ void bgp_aggregate_toggle_suppressed(struct bgp_aggregate *aggregate,
static void bgp_aggregate_med_update(struct bgp_aggregate *aggregate,
struct bgp *bgp, const struct prefix *p,
afi_t afi, safi_t safi,
- struct bgp_path_info *pi, bool is_adding)
+ struct bgp_path_info *pi)
{
/* MED matching disabled. */
if (!aggregate->match_med)
return;
- /* Aggregation with different MED, nothing to do. */
- if (aggregate->med_mismatched)
- return;
-
- /*
- * Test the current entry:
- *
- * is_adding == true: if the new entry doesn't match then we must
- * install all suppressed routes.
- *
- * is_adding == false: if the entry being removed was the last
- * unmatching entry then we can suppress all routes.
+ /* Aggregation with different MED, recheck if we have got equal MEDs
+ * now.
*/
- if (!is_adding) {
- if (bgp_aggregate_test_all_med(aggregate, bgp, p, afi, safi)
- && aggregate->summary_only)
- bgp_aggregate_toggle_suppressed(aggregate, bgp, p, afi,
- safi, true);
- } else
+ if (aggregate->med_mismatched &&
+ bgp_aggregate_test_all_med(aggregate, bgp, p, afi, safi) &&
+ aggregate->summary_only)
+ bgp_aggregate_toggle_suppressed(aggregate, bgp, p, afi, safi,
+ true);
+ else
bgp_aggregate_med_match(aggregate, bgp, pi);
/* No mismatches, just quit. */
@@ -7816,7 +7818,7 @@ static void bgp_add_route_to_aggregate(struct bgp *bgp,
*/
if (aggregate->match_med)
bgp_aggregate_med_update(aggregate, bgp, aggr_p, afi, safi,
- pinew, true);
+ pinew);
if (aggregate->summary_only && AGGREGATE_MED_VALID(aggregate))
aggr_suppress_path(aggregate, pinew);
@@ -7939,8 +7941,7 @@ static void bgp_remove_route_from_aggregate(struct bgp *bgp, afi_t afi,
* "unsuppressing" twice.
*/
if (aggregate->match_med)
- bgp_aggregate_med_update(aggregate, bgp, aggr_p, afi, safi, pi,
- true);
+ bgp_aggregate_med_update(aggregate, bgp, aggr_p, afi, safi, pi);
if (aggregate->count > 0)
aggregate->count--;
@@ -11159,13 +11160,14 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi,
if (type == bgp_show_type_route_map) {
struct route_map *rmap = output_arg;
struct bgp_path_info path;
- struct attr dummy_attr;
+ struct bgp_path_info_extra extra;
+ struct attr dummy_attr = {};
route_map_result_t ret;
dummy_attr = *pi->attr;
- path.peer = pi->peer;
- path.attr = &dummy_attr;
+ prep_for_rmap_apply(&path, &extra, dest, pi,
+ pi->peer, &dummy_attr);
ret = route_map_apply(rmap, dest_p, &path);
bgp_attr_flush(&dummy_attr);
diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c
index 40bbdccff4..64c867f988 100644
--- a/bgpd/bgp_routemap.c
+++ b/bgpd/bgp_routemap.c
@@ -2270,6 +2270,8 @@ route_set_aspath_replace(void *rule, const struct prefix *dummy, void *object)
aspath_new, replace_asn, own_asn);
}
+ aspath_free(aspath_new);
+
return RMAP_OKAY;
}
@@ -4143,8 +4145,6 @@ static void bgp_route_map_process_update_cb(char *rmap_name)
void bgp_route_map_update_timer(struct thread *thread)
{
- bm->t_rmap_update = NULL;
-
route_map_walk_update_list(bgp_route_map_process_update_cb);
}
diff --git a/bgpd/bgp_rpki.c b/bgpd/bgp_rpki.c
index de1c559641..b90c09c68b 100644
--- a/bgpd/bgp_rpki.c
+++ b/bgpd/bgp_rpki.c
@@ -428,14 +428,15 @@ static void bgpd_sync_callback(struct thread *thread)
safi_t safi;
for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) {
- if (!bgp->rib[afi][safi])
+ struct bgp_table *table = bgp->rib[afi][safi];
+
+ if (!table)
continue;
struct bgp_dest *match;
struct bgp_dest *node;
- match = bgp_table_subtree_lookup(bgp->rib[afi][safi],
- prefix);
+ match = bgp_table_subtree_lookup(table, prefix);
node = match;
while (node) {
@@ -445,6 +446,9 @@ static void bgpd_sync_callback(struct thread *thread)
node = bgp_route_next_until(node, match);
}
+
+ if (match)
+ bgp_dest_unlock_node(match);
}
}
diff --git a/bgpd/bgp_table.h b/bgpd/bgp_table.h
index d832383ab4..86cd4f3da1 100644
--- a/bgpd/bgp_table.h
+++ b/bgpd/bgp_table.h
@@ -256,28 +256,6 @@ static inline struct bgp_dest *bgp_node_match(const struct bgp_table *table,
return bgp_dest_from_rnode(rn);
}
-/*
- * bgp_node_match_ipv4
- */
-static inline struct bgp_dest *
-bgp_node_match_ipv4(const struct bgp_table *table, struct in_addr *addr)
-{
- struct route_node *rn = route_node_match_ipv4(table->route_table, addr);
-
- return bgp_dest_from_rnode(rn);
-}
-
-/*
- * bgp_node_match_ipv6
- */
-static inline struct bgp_dest *
-bgp_node_match_ipv6(const struct bgp_table *table, struct in6_addr *addr)
-{
- struct route_node *rn = route_node_match_ipv6(table->route_table, addr);
-
- return bgp_dest_from_rnode(rn);
-}
-
static inline unsigned long bgp_table_count(const struct bgp_table *const table)
{
return route_table_count(table->route_table);
@@ -292,59 +270,6 @@ static inline struct bgp_dest *bgp_table_get_next(const struct bgp_table *table,
return bgp_dest_from_rnode(route_table_get_next(table->route_table, p));
}
-/*
- * bgp_table_iter_init
- */
-static inline void bgp_table_iter_init(bgp_table_iter_t *iter,
- struct bgp_table *table)
-{
- bgp_table_lock(table);
- iter->table = table;
- route_table_iter_init(&iter->rt_iter, table->route_table);
-}
-
-/*
- * bgp_table_iter_next
- */
-static inline struct bgp_dest *bgp_table_iter_next(bgp_table_iter_t *iter)
-{
- return bgp_dest_from_rnode(route_table_iter_next(&iter->rt_iter));
-}
-
-/*
- * bgp_table_iter_cleanup
- */
-static inline void bgp_table_iter_cleanup(bgp_table_iter_t *iter)
-{
- route_table_iter_cleanup(&iter->rt_iter);
- bgp_table_unlock(iter->table);
- iter->table = NULL;
-}
-
-/*
- * bgp_table_iter_pause
- */
-static inline void bgp_table_iter_pause(bgp_table_iter_t *iter)
-{
- route_table_iter_pause(&iter->rt_iter);
-}
-
-/*
- * bgp_table_iter_is_done
- */
-static inline int bgp_table_iter_is_done(bgp_table_iter_t *iter)
-{
- return route_table_iter_is_done(&iter->rt_iter);
-}
-
-/*
- * bgp_table_iter_started
- */
-static inline int bgp_table_iter_started(bgp_table_iter_t *iter)
-{
- return route_table_iter_started(&iter->rt_iter);
-}
-
/* This would benefit from a real atomic operation...
* until then. */
static inline uint64_t bgp_table_next_version(struct bgp_table *table)
diff --git a/bgpd/bgp_updgrp.c b/bgpd/bgp_updgrp.c
index d198aec983..0219535b0d 100644
--- a/bgpd/bgp_updgrp.c
+++ b/bgpd/bgp_updgrp.c
@@ -254,6 +254,8 @@ static void conf_release(struct peer *src, afi_t afi, safi_t safi)
XFREE(MTYPE_BGP_FILTER_NAME, srcfilter->advmap.cname);
XFREE(MTYPE_BGP_PEER_HOST, src->host);
+
+ ecommunity_free(&src->soo[afi][safi]);
}
static void peer2_updgrp_copy(struct update_group *updgrp, struct peer_af *paf)
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index a889a737eb..4c151b2d37 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -1473,11 +1473,6 @@ 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];
- if (peer_src->soo[afi][safi]) {
- ecommunity_free(&peer_dst->soo[afi][safi]);
- peer_dst->soo[afi][safi] =
- ecommunity_dup(peer_src->soo[afi][safi]);
- }
}
for (afidx = BGP_AF_START; afidx < BGP_AF_MAX; afidx++) {
diff --git a/bgpd/subdir.am b/bgpd/subdir.am
index 9e3a095529..b1eeb937e1 100644
--- a/bgpd/subdir.am
+++ b/bgpd/subdir.am
@@ -232,6 +232,7 @@ clippy_scan += \
bgpd/bgp_bmp.c \
bgpd/bgp_debug.c \
bgpd/bgp_evpn_vty.c \
+ bgpd/bgp_labelpool.c \
bgpd/bgp_route.c \
bgpd/bgp_routemap.c \
bgpd/bgp_rpki.c \
diff --git a/eigrpd/eigrp_network.c b/eigrpd/eigrp_network.c
index 6b3a0afc12..13db38ce91 100644
--- a/eigrpd/eigrp_network.c
+++ b/eigrpd/eigrp_network.c
@@ -69,8 +69,8 @@ int eigrp_sock_init(struct vrf *vrf)
AF_INET, SOCK_RAW, IPPROTO_EIGRPIGP, vrf->vrf_id,
vrf->vrf_id != VRF_DEFAULT ? vrf->name : NULL);
if (eigrp_sock < 0) {
- zlog_err("eigrp_read_sock_init: socket: %s",
- safe_strerror(errno));
+ zlog_err("%s: socket: %s",
+ __func__, safe_strerror(errno));
exit(1);
}
diff --git a/eigrpd/eigrp_packet.c b/eigrpd/eigrp_packet.c
index dd5ba8a164..1ea6f9813b 100644
--- a/eigrpd/eigrp_packet.c
+++ b/eigrpd/eigrp_packet.c
@@ -727,8 +727,8 @@ static struct stream *eigrp_recv_packet(struct eigrp *eigrp,
if ((unsigned int)ret < sizeof(*iph)) /* ret must be > 0 now */
{
zlog_warn(
- "eigrp_recv_packet: discarding runt packet of length %d (ip header size is %u)",
- ret, (unsigned int)sizeof(*iph));
+ "%s: discarding runt packet of length %d (ip header size is %u)",
+ __func__, ret, (unsigned int)sizeof(*iph));
return NULL;
}
@@ -772,8 +772,8 @@ static struct stream *eigrp_recv_packet(struct eigrp *eigrp,
if (ret != ip_len) {
zlog_warn(
- "eigrp_recv_packet read length mismatch: ip_len is %d, but recvmsg returned %d",
- ip_len, ret);
+ "%s read length mismatch: ip_len is %d, but recvmsg returned %d",
+ __func__, ip_len, ret);
return NULL;
}
diff --git a/eigrpd/eigrpd.c b/eigrpd/eigrpd.c
index 7bc7be9706..0ec9574813 100644
--- a/eigrpd/eigrpd.c
+++ b/eigrpd/eigrpd.c
@@ -163,7 +163,8 @@ static struct eigrp *eigrp_new(uint16_t as, vrf_id_t vrf_id)
if (eigrp->fd < 0) {
flog_err_sys(
EC_LIB_SOCKET,
- "eigrp_new: fatal error: eigrp_sock_init was unable to open a socket");
+ "%s: fatal error: eigrp_sock_init was unable to open a socket",
+ __func__);
exit(1);
}
diff --git a/lib/bitfield.h b/lib/bitfield.h
index a3f361ed9d..9af4053daf 100644
--- a/lib/bitfield.h
+++ b/lib/bitfield.h
@@ -158,6 +158,75 @@ DECLARE_MTYPE(BITFIELD);
(b) += (w * WORD_SIZE); \
} while (0)
+/*
+ * Find a clear bit in v and return it
+ * Start looking in the word containing bit position start_index.
+ * If necessary, wrap around after bit position max_index.
+ */
+static inline unsigned int
+bf_find_next_clear_bit_wrap(bitfield_t *v, word_t start_index, word_t max_index)
+{
+ int start_bit;
+ unsigned long i, offset, scanbits, wordcount_max, index_max;
+
+ if (start_index > max_index)
+ start_index = 0;
+
+ start_bit = start_index & (WORD_SIZE - 1);
+ wordcount_max = bf_index(max_index) + 1;
+
+ scanbits = WORD_SIZE;
+ for (i = bf_index(start_index); i < v->m; ++i) {
+ if (v->data[i] == WORD_MAX) {
+ /* if the whole word is full move to the next */
+ start_bit = 0;
+ continue;
+ }
+ /* scan one word for clear bits */
+ if ((i == v->m - 1) && (v->m >= wordcount_max))
+ /* max index could be only part of word */
+ scanbits = (max_index % WORD_SIZE) + 1;
+ for (offset = start_bit; offset < scanbits; ++offset) {
+ if (!((v->data[i] >> offset) & 1))
+ return ((i * WORD_SIZE) + offset);
+ }
+ /* move to the next word */
+ start_bit = 0;
+ }
+
+ if (v->m < wordcount_max) {
+ /*
+ * We can expand bitfield, so no need to wrap.
+ * Return the index of the first bit of the next word.
+ * Assumption is that caller will call bf_set_bit which
+ * will allocate additional space.
+ */
+ v->m += 1;
+ v->data = (word_t *)realloc(v->data, v->m * sizeof(word_t));
+ v->data[v->m - 1] = 0;
+ return v->m * WORD_SIZE;
+ }
+
+ /*
+ * start looking for a clear bit at the start of the bitfield and
+ * stop when we reach start_index
+ */
+ scanbits = WORD_SIZE;
+ index_max = bf_index(start_index - 1);
+ for (i = 0; i <= index_max; ++i) {
+ if (i == index_max)
+ scanbits = ((start_index - 1) % WORD_SIZE) + 1;
+ for (offset = start_bit; offset < scanbits; ++offset) {
+ if (!((v->data[i] >> offset) & 1))
+ return ((i * WORD_SIZE) + offset);
+ }
+ /* move to the next word */
+ start_bit = 0;
+ }
+
+ return WORD_MAX;
+}
+
static inline unsigned int bf_find_next_set_bit(bitfield_t v,
word_t start_index)
{
diff --git a/lib/routemap.c b/lib/routemap.c
index 9529b79419..e6310465e3 100644
--- a/lib/routemap.c
+++ b/lib/routemap.c
@@ -812,17 +812,13 @@ int route_map_mark_updated(const char *name)
return (ret);
}
-static int route_map_clear_updated(struct route_map *map)
+static void route_map_clear_updated(struct route_map *map)
{
- int ret = -1;
-
if (map) {
map->to_be_processed = false;
if (map->deleted)
route_map_free_map(map);
}
-
- return (ret);
}
/* Lookup route map. If there isn't route map create one and return
diff --git a/tests/topotests/bgp_aggregate_address_matching_med/__init__.py b/tests/topotests/bgp_aggregate_address_matching_med/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/bgp_aggregate_address_matching_med/__init__.py
diff --git a/tests/topotests/bgp_aggregate_address_matching_med/r1/bgpd.conf b/tests/topotests/bgp_aggregate_address_matching_med/r1/bgpd.conf
new file mode 100644
index 0000000000..35597602f7
--- /dev/null
+++ b/tests/topotests/bgp_aggregate_address_matching_med/r1/bgpd.conf
@@ -0,0 +1,21 @@
+!
+router bgp 65001
+ no bgp ebgp-requires-policy
+ neighbor 192.168.1.2 remote-as external
+ neighbor 192.168.1.2 timers 3 10
+ address-family ipv4 unicast
+ redistribute connected
+ neighbor 192.168.1.2 route-map r2 out
+ exit-address-family
+!
+ip prefix-list p1 seq 5 permit 172.16.255.1/32
+ip prefix-list p1 seq 10 permit 172.16.255.2/32
+ip prefix-list p2 seq 15 permit 172.16.255.3/32
+!
+route-map r2 permit 10
+ match ip address prefix-list p1
+ set metric 300
+route-map r2 permit 20
+ match ip address prefix-list p2
+ set metric 400
+!
diff --git a/tests/topotests/bgp_aggregate_address_matching_med/r1/zebra.conf b/tests/topotests/bgp_aggregate_address_matching_med/r1/zebra.conf
new file mode 100644
index 0000000000..685adb3080
--- /dev/null
+++ b/tests/topotests/bgp_aggregate_address_matching_med/r1/zebra.conf
@@ -0,0 +1,11 @@
+!
+interface lo
+ ip address 172.16.255.1/32
+ ip address 172.16.255.2/32
+ ip address 172.16.255.3/32
+!
+interface r1-eth0
+ ip address 192.168.1.1/24
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_aggregate_address_matching_med/r2/bgpd.conf b/tests/topotests/bgp_aggregate_address_matching_med/r2/bgpd.conf
new file mode 100644
index 0000000000..9bc9a3132f
--- /dev/null
+++ b/tests/topotests/bgp_aggregate_address_matching_med/r2/bgpd.conf
@@ -0,0 +1,11 @@
+!
+router bgp 65002
+ no bgp ebgp-requires-policy
+ neighbor 192.168.1.1 remote-as external
+ neighbor 192.168.1.1 timers 3 10
+ neighbor 192.168.2.1 remote-as external
+ neighbor 192.168.2.1 timers 3 10
+ address-family ipv4 unicast
+ aggregate-address 172.16.255.0/24 summary-only matching-MED-only
+ exit-address-family
+!
diff --git a/tests/topotests/bgp_aggregate_address_matching_med/r2/zebra.conf b/tests/topotests/bgp_aggregate_address_matching_med/r2/zebra.conf
new file mode 100644
index 0000000000..f229954341
--- /dev/null
+++ b/tests/topotests/bgp_aggregate_address_matching_med/r2/zebra.conf
@@ -0,0 +1,9 @@
+!
+interface r2-eth0
+ ip address 192.168.1.2/24
+!
+interface r2-eth1
+ ip address 192.168.2.2/24
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_aggregate_address_matching_med/r3/bgpd.conf b/tests/topotests/bgp_aggregate_address_matching_med/r3/bgpd.conf
new file mode 100644
index 0000000000..dfb5ac7a3c
--- /dev/null
+++ b/tests/topotests/bgp_aggregate_address_matching_med/r3/bgpd.conf
@@ -0,0 +1,6 @@
+!
+router bgp 65003
+ no bgp ebgp-requires-policy
+ neighbor 192.168.2.2 remote-as external
+ neighbor 192.168.2.2 timers 3 10
+!
diff --git a/tests/topotests/bgp_aggregate_address_matching_med/r3/zebra.conf b/tests/topotests/bgp_aggregate_address_matching_med/r3/zebra.conf
new file mode 100644
index 0000000000..11e06d47cc
--- /dev/null
+++ b/tests/topotests/bgp_aggregate_address_matching_med/r3/zebra.conf
@@ -0,0 +1,6 @@
+!
+interface r3-eth0
+ ip address 192.168.2.1/24
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_aggregate_address_matching_med/test_bgp_aggregate_address_matching_med.py b/tests/topotests/bgp_aggregate_address_matching_med/test_bgp_aggregate_address_matching_med.py
new file mode 100644
index 0000000000..edf50dc9e0
--- /dev/null
+++ b/tests/topotests/bgp_aggregate_address_matching_med/test_bgp_aggregate_address_matching_med.py
@@ -0,0 +1,148 @@
+#!/usr/bin/env python
+
+#
+# Copyright (c) 2022 by
+# Donatas Abraitis <donatas@opensourcerouting.org>
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+Test if aggregate-address command works fine when suppressing summary-only
+and using matching-MED-only together.
+"""
+
+import os
+import sys
+import json
+import pytest
+import functools
+from lib.common_config import (
+ step,
+)
+
+# pylint: disable=C0413
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+
+pytestmark = [pytest.mark.bgpd]
+
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+
+def build_topo(tgen):
+ for routern in range(1, 5):
+ tgen.add_router("r{}".format(routern))
+
+ switch = tgen.add_switch("s1")
+ switch.add_link(tgen.gears["r1"])
+ switch.add_link(tgen.gears["r2"])
+
+ switch = tgen.add_switch("s2")
+ switch.add_link(tgen.gears["r2"])
+ switch.add_link(tgen.gears["r3"])
+
+
+def setup_module(mod):
+ tgen = Topogen(build_topo, mod.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+
+ for i, (rname, router) in enumerate(router_list.items(), 1):
+ router.load_config(
+ TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname))
+ )
+
+ tgen.start_router()
+
+
+def teardown_module(mod):
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+
+def test_aggregate_address_matching_med():
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ r1 = tgen.gears["r1"]
+ r3 = tgen.gears["r3"]
+
+ def _bgp_converge():
+ output = json.loads(r3.vtysh_cmd("show bgp ipv4 unicast json"))
+ expected = {
+ "routes": {
+ "172.16.255.0/24": None,
+ "172.16.255.1/32": [{"path": "65002 65001"}],
+ "172.16.255.2/32": [{"path": "65002 65001"}],
+ "172.16.255.3/32": [{"path": "65002 65001"}],
+ }
+ }
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(_bgp_converge)
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5)
+ assert result is None, "Failed to see unsuppressed routes from R2"
+
+ step("Change MED for 172.16.255.3/32 from 400 to 300")
+ r1.vtysh_cmd(
+ """
+ configure terminal
+ route-map r2 permit 20
+ set metric 300
+ """
+ )
+
+ step("Check if 172.16.255.0/24 aggregated route was created and others suppressed")
+
+ def _bgp_aggregated_summary_only_med_match():
+ output = json.loads(r3.vtysh_cmd("show bgp ipv4 unicast json"))
+ expected = {
+ "routes": {
+ "172.16.255.0/24": [{"path": "65002"}],
+ "172.16.255.1/32": None,
+ "172.16.255.2/32": None,
+ "172.16.255.3/32": None,
+ }
+ }
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(_bgp_aggregated_summary_only_med_match)
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5)
+ assert result is None, "Failed to see unsuppressed routes from R2"
+
+ step("Change MED for 172.16.255.3/32 back to 400 from 300")
+ r1.vtysh_cmd(
+ """
+ configure terminal
+ route-map r2 permit 20
+ set metric 400
+ """
+ )
+ test_func = functools.partial(_bgp_converge)
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5)
+ assert result is None, "Failed to see unsuppressed routes from R2"
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/bgp_lu_topo1/R1/labelpool.summ.json b/tests/topotests/bgp_lu_topo1/R1/labelpool.summ.json
index 29e6c2cbf7..e2eee513e6 100644
--- a/tests/topotests/bgp_lu_topo1/R1/labelpool.summ.json
+++ b/tests/topotests/bgp_lu_topo1/R1/labelpool.summ.json
@@ -2,7 +2,7 @@
"Ledger":506,
"InUse":506,
"Requests":0,
- "LabelChunks":11,
+ "LabelChunks":3,
"Pending":0,
"Reconnects":0
}
diff --git a/tests/topotests/bgp_lu_topo2/R1/labelpool.summ.json b/tests/topotests/bgp_lu_topo2/R1/labelpool.summ.json
index 77705e8d35..0dc59b58cf 100644
--- a/tests/topotests/bgp_lu_topo2/R1/labelpool.summ.json
+++ b/tests/topotests/bgp_lu_topo2/R1/labelpool.summ.json
@@ -2,7 +2,7 @@
"Ledger":51,
"InUse":51,
"Requests":0,
- "LabelChunks":2,
+ "LabelChunks":1,
"Pending":0,
"Reconnects":0
}
diff --git a/tests/topotests/bgp_remove_private_as/test_bgp_remove_private_as.py b/tests/topotests/bgp_remove_private_as/test_bgp_remove_private_as.py
index 7d52048ebe..1108919e13 100644
--- a/tests/topotests/bgp_remove_private_as/test_bgp_remove_private_as.py
+++ b/tests/topotests/bgp_remove_private_as/test_bgp_remove_private_as.py
@@ -361,13 +361,6 @@ def test_bgp_remove_private_as():
return True
return False
- def _get_pfx_path_from_nh(router, prefix, nh):
- """Return as-path for a specific route + path."""
- output = json.loads(tgen.gears[router].vtysh_cmd(f"show ip bgp {prefix} json"))
- for path in output[prefix]:
- if path["nexthops"]["ip"] == nh:
- return path["aspath"]["string"]
-
def _routers_up(tx_rtrs, rx_rtrs):
"""Ensure all BGP sessions are up and all routes are installed."""
# all sessions go through tx_routers, so ensure all their peers are up
@@ -408,11 +401,7 @@ def test_bgp_remove_private_as():
for pfx in prefixes:
good_path = expected_paths[rtr][remove_type][peer][pfx]
real_path = adj_rib_in["receivedRoutes"][pfx]["path"]
- msg = (
- f"{rtr} received incorrect AS-Path from {peer} "
- f'({p_ip}) for {pfx}. remove_type: "{remove_type}"'
- )
- assert real_path == good_path, msg
+ return real_path == good_path
#######################
# Begin Test
@@ -424,7 +413,11 @@ def test_bgp_remove_private_as():
# test each variation of remove-private-AS
for rmv_type in remove_types:
_change_remove_type(rmv_type, "add")
- _validate_paths(rmv_type)
+
+ test_func = partial(_validate_paths, rmv_type)
+ _, result = topotest.run_and_expect(test_func, True, count=60, wait=0.5)
+ assert result == True, "Not all routes have correct AS-Path values!"
+
# each variation sets a separate peer flag in bgpd. we need to clear
# the old flag after each iteration so we only test the flags we expect.
_change_remove_type(rmv_type, "del")
diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c
index 45a372f88c..a8b56bb8f2 100644
--- a/zebra/kernel_netlink.c
+++ b/zebra/kernel_netlink.c
@@ -1033,12 +1033,18 @@ static int netlink_parse_error(const struct nlsock *nl, struct nlmsghdr *h,
return 1;
}
- /* Deal with errors that occur because of races in link handling. */
- if (is_cmd
- && ((msg_type == RTM_DELROUTE
- && (-errnum == ENODEV || -errnum == ESRCH))
- || (msg_type == RTM_NEWROUTE
- && (-errnum == ENETDOWN || -errnum == EEXIST)))) {
+ /*
+ * Deal with errors that occur because of races in link handling
+ * or types are not supported in kernel.
+ */
+ if (is_cmd &&
+ ((msg_type == RTM_DELROUTE &&
+ (-errnum == ENODEV || -errnum == ESRCH)) ||
+ (msg_type == RTM_NEWROUTE &&
+ (-errnum == ENETDOWN || -errnum == EEXIST)) ||
+ ((msg_type == RTM_NEWTUNNEL || msg_type == RTM_DELTUNNEL ||
+ msg_type == RTM_GETTUNNEL) &&
+ (-errnum == EOPNOTSUPP)))) {
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug("%s: error: %s type=%s(%u), seq=%u, pid=%u",
nl->name, safe_strerror(-errnum),