summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--alpine/APKBUILD.in2
-rw-r--r--bgpd/bgp_aspath.c47
-rw-r--r--bgpd/bgp_aspath.h7
-rw-r--r--bgpd/bgp_filter.c41
-rw-r--r--bgpd/bgp_filter.h13
-rw-r--r--bgpd/bgp_packet.c6
-rw-r--r--bgpd/bgp_routemap.c59
-rw-r--r--bgpd/bgp_vty.c5
-rw-r--r--bgpd/bgpd.c14
-rw-r--r--doc/developer/ospf-ls-retrans.rst69
-rw-r--r--doc/developer/ospf.rst1
-rw-r--r--doc/user/ospfd.rst12
-rw-r--r--docker/alpine/Dockerfile6
-rwxr-xr-xdocker/alpine/libyang/APKBUILD2
-rw-r--r--isisd/isis_tlvs.c374
-rw-r--r--lib/libospf.h1
-rw-r--r--ospfd/ospf_flood.c146
-rw-r--r--ospfd/ospf_flood.h22
-rw-r--r--ospfd/ospf_interface.c5
-rw-r--r--ospfd/ospf_interface.h3
-rw-r--r--ospfd/ospf_lsdb.c53
-rw-r--r--ospfd/ospf_lsdb.h23
-rw-r--r--ospfd/ospf_memory.c2
-rw-r--r--ospfd/ospf_memory.h2
-rw-r--r--ospfd/ospf_neighbor.c8
-rw-r--r--ospfd/ospf_neighbor.h7
-rw-r--r--ospfd/ospf_nsm.c6
-rw-r--r--ospfd/ospf_packet.c91
-rw-r--r--ospfd/ospf_packet.h2
-rw-r--r--ospfd/ospf_vty.c140
-rw-r--r--pimd/pim6_main.c2
-rw-r--r--pimd/pim_addr.h4
-rw-r--r--pimd/pim_bsm.c5
-rw-r--r--pimd/pim_main.c2
-rw-r--r--pimd/pim_nht.c47
-rw-r--r--pimd/pim_nht.h7
-rw-r--r--pimd/pim_pim.c24
-rw-r--r--pimd/pim_rp.c6
-rw-r--r--tests/topotests/all_protocol_startup/r1/show_ip_ospf_interface.ref2
-rw-r--r--tests/topotests/bgp_set_aspath_exclude/r1/bgpd.conf9
-rw-r--r--tests/topotests/bgp_set_aspath_exclude/r3/zebra.conf1
-rw-r--r--tests/topotests/bgp_set_aspath_exclude/test_bgp_set_aspath_exclude.py70
-rw-r--r--tests/topotests/ospf_p2mp/r1/frr-p2mp.conf6
-rw-r--r--tests/topotests/ospf_p2mp/r2/frr-p2mp.conf6
-rw-r--r--tests/topotests/ospf_p2mp/r3/frr-p2mp.conf6
-rw-r--r--tests/topotests/ospf_p2mp/r4/frr-p2mp.conf6
-rw-r--r--tests/topotests/ospf_p2mp/test_ospf_p2mp_broadcast.py112
-rwxr-xr-xtools/checkpatch.pl1
-rw-r--r--zebra/zebra_nb_rpcs.c13
49 files changed, 1103 insertions, 395 deletions
diff --git a/alpine/APKBUILD.in b/alpine/APKBUILD.in
index 2cb3feec15..855b585903 100644
--- a/alpine/APKBUILD.in
+++ b/alpine/APKBUILD.in
@@ -33,6 +33,8 @@ _libdir=/usr/lib
_user=frr
build() {
+ export ABUILD_APK_INDEX_OPTS="--allow-untrusted"
+
cd "$builddir"
./configure \
diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c
index 9dcd0ad1d6..4c1615a5c6 100644
--- a/bgpd/bgp_aspath.c
+++ b/bgpd/bgp_aspath.c
@@ -77,6 +77,9 @@ static struct hash *ashash;
/* Stream for SNMP. See aspath_snmp_pathseg */
static struct stream *snmp_stream;
+/* as-path orphan exclude list */
+static struct as_list_list_head as_exclude_list_orphan;
+
/* Callers are required to initialize the memory */
static as_t *assegment_data_new(int num)
{
@@ -1558,6 +1561,38 @@ struct aspath *aspath_prepend(struct aspath *as1, struct aspath *as2)
/* Not reached */
}
+/* insert aspath exclude in head of orphan exclude list*/
+void as_exclude_set_orphan(struct aspath_exclude *ase)
+{
+ ase->exclude_aspath_acl = NULL;
+ as_list_list_add_head(&as_exclude_list_orphan, ase);
+}
+
+void as_exclude_remove_orphan(struct aspath_exclude *ase)
+{
+ if (as_list_list_count(&as_exclude_list_orphan))
+ as_list_list_del(&as_exclude_list_orphan, ase);
+}
+
+/* currently provide only one exclude, not a list */
+struct aspath_exclude *as_exclude_lookup_orphan(const char *acl_name)
+{
+ struct aspath_exclude *ase = NULL;
+ char *name = NULL;
+
+ frr_each (as_list_list, &as_exclude_list_orphan, ase) {
+ if (ase->exclude_aspath_acl_name) {
+ name = ase->exclude_aspath_acl_name;
+ if (!strcmp(name, acl_name))
+ break;
+ }
+ }
+ if (ase)
+ as_exclude_remove_orphan(ase);
+
+ return ase;
+}
+
/* Iterate over AS_PATH segments and wipe all occurrences of the
* listed AS numbers. Hence some segments may lose some or even
* all data on the way, the operation is implemented as a smarter
@@ -2236,14 +2271,26 @@ void aspath_init(void)
{
ashash = hash_create_size(32768, aspath_key_make, aspath_cmp,
"BGP AS Path");
+
+ as_list_list_init(&as_exclude_list_orphan);
}
void aspath_finish(void)
{
+ struct aspath_exclude *ase;
+
hash_clean_and_free(&ashash, (void (*)(void *))aspath_free);
if (snmp_stream)
stream_free(snmp_stream);
+
+ while ((ase = as_list_list_pop(&as_exclude_list_orphan))) {
+ aspath_free(ase->aspath);
+ if (ase->exclude_aspath_acl_name)
+ XFREE(MTYPE_TMP, ase->exclude_aspath_acl_name);
+ XFREE(MTYPE_ROUTE_MAP_COMPILED, ase);
+ }
+ as_list_list_fini(&as_exclude_list_orphan);
}
/* return and as path value */
diff --git a/bgpd/bgp_aspath.h b/bgpd/bgp_aspath.h
index 2a831c3a55..f7e57fd66d 100644
--- a/bgpd/bgp_aspath.h
+++ b/bgpd/bgp_aspath.h
@@ -9,6 +9,7 @@
#include "lib/json.h"
#include "bgpd/bgp_route.h"
#include "bgpd/bgp_filter.h"
+#include <typesafe.h>
/* AS path segment type. */
#define AS_SET 1
@@ -67,11 +68,14 @@ struct aspath {
/* `set as-path exclude ASn' */
struct aspath_exclude {
+ struct as_list_list_item exclude_list;
struct aspath *aspath;
bool exclude_all;
char *exclude_aspath_acl_name;
struct as_list *exclude_aspath_acl;
};
+DECLARE_DLIST(as_list_list, struct aspath_exclude, exclude_list);
+
/* Prototypes. */
extern void aspath_init(void);
@@ -83,6 +87,9 @@ extern struct aspath *aspath_parse(struct stream *s, size_t length,
extern struct aspath *aspath_dup(struct aspath *aspath);
extern struct aspath *aspath_aggregate(struct aspath *as1, struct aspath *as2);
extern struct aspath *aspath_prepend(struct aspath *as1, struct aspath *as2);
+extern void as_exclude_set_orphan(struct aspath_exclude *ase);
+extern void as_exclude_remove_orphan(struct aspath_exclude *ase);
+extern struct aspath_exclude *as_exclude_lookup_orphan(const char *acl_name);
extern struct aspath *aspath_filter_exclude(struct aspath *source,
struct aspath *exclude_list);
extern struct aspath *aspath_filter_exclude_all(struct aspath *source);
diff --git a/bgpd/bgp_filter.c b/bgpd/bgp_filter.c
index a85117965a..002f054f5e 100644
--- a/bgpd/bgp_filter.c
+++ b/bgpd/bgp_filter.c
@@ -16,7 +16,7 @@
#include "bgpd/bgp_aspath.h"
#include "bgpd/bgp_regex.h"
-/* List of AS filter list. */
+/* List of AS list. */
struct as_list_list {
struct as_list *head;
struct as_list *tail;
@@ -205,14 +205,6 @@ static struct as_list *as_list_new(void)
static void as_list_free(struct as_list *aslist)
{
- struct aspath_exclude_list *cur_bp = aslist->exclude_list;
- struct aspath_exclude_list *next_bp = NULL;
-
- while (cur_bp) {
- next_bp = cur_bp->next;
- XFREE(MTYPE_ROUTE_MAP_COMPILED, cur_bp);
- cur_bp = next_bp;
- }
XFREE (MTYPE_AS_STR, aslist->name);
XFREE (MTYPE_AS_LIST, aslist);
@@ -299,7 +291,6 @@ static void as_list_delete(struct as_list *aslist)
{
struct as_list_list *list;
struct as_filter *filter, *next;
- struct aspath_exclude_list *cur_bp;
for (filter = aslist->head; filter; filter = next) {
next = filter->next;
@@ -318,12 +309,6 @@ static void as_list_delete(struct as_list *aslist)
else
list->head = aslist->next;
- cur_bp = aslist->exclude_list;
- while (cur_bp) {
- cur_bp->bp_as_excl->exclude_aspath_acl = NULL;
- cur_bp = cur_bp->next;
- }
-
as_list_free(aslist);
}
@@ -431,6 +416,7 @@ DEFUN(as_path, bgp_as_path_cmd,
enum as_filter_type type;
struct as_filter *asfilter;
struct as_list *aslist;
+ struct aspath_exclude *ase;
regex_t *regex;
char *regstr;
int64_t seqnum = ASPATH_SEQ_NUMBER_AUTO;
@@ -482,6 +468,22 @@ DEFUN(as_path, bgp_as_path_cmd,
else
as_list_filter_add(aslist, asfilter);
+ /* init the exclude rule list*/
+ as_list_list_init(&aslist->exclude_rule);
+
+ /* get aspath orphan exclude that are using this acl */
+ ase = as_exclude_lookup_orphan(alname);
+ if (ase) {
+ as_list_list_add_head(&aslist->exclude_rule, ase);
+ /* set reverse pointer */
+ ase->exclude_aspath_acl = aslist;
+ /* set list of aspath excludes using that acl */
+ while ((ase = as_exclude_lookup_orphan(alname))) {
+ as_list_list_add_head(&aslist->exclude_rule, ase);
+ ase->exclude_aspath_acl = aslist;
+ }
+ }
+
return CMD_SUCCESS;
}
@@ -502,6 +504,7 @@ DEFUN(no_as_path, no_bgp_as_path_cmd,
enum as_filter_type type;
struct as_filter *asfilter;
struct as_list *aslist;
+ struct aspath_exclude *ase;
char *regstr;
regex_t *regex;
@@ -556,6 +559,12 @@ DEFUN(no_as_path, no_bgp_as_path_cmd,
XFREE(MTYPE_TMP, regstr);
+ /* put aspath exclude list into orphan */
+ if (as_list_list_count(&aslist->exclude_rule))
+ while ((ase = as_list_list_pop(&aslist->exclude_rule)))
+ as_exclude_set_orphan(ase);
+
+ as_list_list_fini(&aslist->exclude_rule);
as_list_filter_delete(aslist, asfilter);
return CMD_SUCCESS;
diff --git a/bgpd/bgp_filter.h b/bgpd/bgp_filter.h
index 2d9f07ce84..77a3f3c2f7 100644
--- a/bgpd/bgp_filter.h
+++ b/bgpd/bgp_filter.h
@@ -6,11 +6,12 @@
#ifndef _QUAGGA_BGP_FILTER_H
#define _QUAGGA_BGP_FILTER_H
+#include <typesafe.h>
+
#define ASPATH_SEQ_NUMBER_AUTO -1
enum as_filter_type { AS_FILTER_DENY, AS_FILTER_PERMIT };
-
/* Element of AS path filter. */
struct as_filter {
struct as_filter *next;
@@ -25,11 +26,7 @@ struct as_filter {
int64_t seq;
};
-struct aspath_exclude_list {
- struct aspath_exclude_list *next;
- struct aspath_exclude *bp_as_excl;
-};
-
+PREDECL_DLIST(as_list_list);
/* AS path filter list. */
struct as_list {
char *name;
@@ -39,7 +36,9 @@ struct as_list {
struct as_filter *head;
struct as_filter *tail;
- struct aspath_exclude_list *exclude_list;
+
+ /* Changes in AS path */
+ struct as_list_list_head exclude_rule;
};
diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c
index 8a4453f124..8825136e17 100644
--- a/bgpd/bgp_packet.c
+++ b/bgpd/bgp_packet.c
@@ -3438,7 +3438,7 @@ static void bgp_dynamic_capability_fqdn(uint8_t *pnt, int action,
}
len = *data;
- if (data + len > end) {
+ if (data + len + 1 > end) {
zlog_err("%pBP: Received invalid FQDN capability length (host name) %d",
peer, hdr->length);
return;
@@ -3469,7 +3469,7 @@ static void bgp_dynamic_capability_fqdn(uint8_t *pnt, int action,
/* domainname */
len = *data;
- if (data + len > end) {
+ if (data + len + 1 > end) {
zlog_err("%pBP: Received invalid FQDN capability length (domain name) %d",
peer, len);
return;
@@ -3695,7 +3695,7 @@ static void bgp_dynamic_capability_software_version(uint8_t *pnt, int action,
char soft_version[BGP_MAX_SOFT_VERSION + 1] = {};
if (action == CAPABILITY_ACTION_SET) {
- if (data + len > end) {
+ if (data + len + 1 > end) {
zlog_err("%pBP: Received invalid Software Version capability length %d",
peer, len);
return;
diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c
index 9b0ca72e4c..97ae92c899 100644
--- a/bgpd/bgp_routemap.c
+++ b/bgpd/bgp_routemap.c
@@ -2322,7 +2322,7 @@ static const struct route_map_rule_cmd route_set_aspath_prepend_cmd = {
static void *route_aspath_exclude_compile(const char *arg)
{
struct aspath_exclude *ase;
- struct aspath_exclude_list *ael;
+ struct as_list *aux_aslist;
const char *str = arg;
static const char asp_acl[] = "as-path-access-list";
@@ -2334,44 +2334,37 @@ static void *route_aspath_exclude_compile(const char *arg)
while (*str == ' ')
str++;
ase->exclude_aspath_acl_name = XSTRDUP(MTYPE_TMP, str);
- ase->exclude_aspath_acl = as_list_lookup(str);
+ aux_aslist = as_list_lookup(str);
+ if (!aux_aslist)
+ /* new orphan filter */
+ as_exclude_set_orphan(ase);
+ else
+ as_list_list_add_head(&aux_aslist->exclude_rule, ase);
+
+ ase->exclude_aspath_acl = aux_aslist;
} else
ase->aspath = aspath_str2aspath(str, bgp_get_asnotation(NULL));
- if (ase->exclude_aspath_acl) {
- ael = XCALLOC(MTYPE_ROUTE_MAP_COMPILED,
- sizeof(struct aspath_exclude_list));
- ael->bp_as_excl = ase;
- ael->next = ase->exclude_aspath_acl->exclude_list;
- ase->exclude_aspath_acl->exclude_list = ael;
- }
-
return ase;
}
static void route_aspath_exclude_free(void *rule)
{
struct aspath_exclude *ase = rule;
- struct aspath_exclude_list *cur_ael = NULL;
- struct aspath_exclude_list *prev_ael = NULL;
+ struct as_list *acl;
+
+ /* manage references to that rule*/
+ if (ase->exclude_aspath_acl) {
+ acl = ase->exclude_aspath_acl;
+ as_list_list_del(&acl->exclude_rule, ase);
+ } else {
+ /* no ref to acl, this aspath exclude is orphan */
+ as_exclude_remove_orphan(ase);
+ }
aspath_free(ase->aspath);
if (ase->exclude_aspath_acl_name)
XFREE(MTYPE_TMP, ase->exclude_aspath_acl_name);
- if (ase->exclude_aspath_acl)
- cur_ael = ase->exclude_aspath_acl->exclude_list;
- while (cur_ael) {
- if (cur_ael->bp_as_excl == ase) {
- if (prev_ael)
- prev_ael->next = cur_ael->next;
- else
- ase->exclude_aspath_acl->exclude_list = NULL;
- XFREE(MTYPE_ROUTE_MAP_COMPILED, cur_ael);
- break;
- }
- prev_ael = cur_ael;
- cur_ael = cur_ael->next;
- }
XFREE(MTYPE_ROUTE_MAP_COMPILED, ase);
}
@@ -2406,16 +2399,10 @@ route_set_aspath_exclude(void *rule, const struct prefix *dummy, void *object)
else if (ase->exclude_all)
path->attr->aspath = aspath_filter_exclude_all(new_path);
- else if (ase->exclude_aspath_acl_name) {
- if (!ase->exclude_aspath_acl)
- ase->exclude_aspath_acl =
- as_list_lookup(ase->exclude_aspath_acl_name);
- if (ase->exclude_aspath_acl)
- path->attr->aspath =
- aspath_filter_exclude_acl(new_path,
- ase->exclude_aspath_acl);
- }
-
+ else if (ase->exclude_aspath_acl)
+ path->attr->aspath =
+ aspath_filter_exclude_acl(new_path,
+ ase->exclude_aspath_acl);
return RMAP_OKAY;
}
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index fbe1db9d2a..230fedf4ec 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -11661,10 +11661,9 @@ static void bgp_show_peer_reset(struct vty * vty, struct peer *peer,
BGP_NOTIFY_CEASE_HARD_RESET)
: "");
} else {
- vty_out(vty, " %s (%s)\n",
+ vty_out(vty, " %s (%s)\n",
peer_down_str[(int)peer->last_reset],
- peer->soft_version ? peer->soft_version
- : "n/a");
+ peer->soft_version ? peer->soft_version : "n/a");
}
}
}
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index 2ec6a66bef..e42b7f5ca5 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -4832,6 +4832,8 @@ void bgp_shutdown_enable(struct bgp *bgp, const char *msg)
/* iterate through peers of BGP instance */
for (ALL_LIST_ELEMENTS_RO(bgp->peer, node, peer)) {
+ peer->last_reset = PEER_DOWN_USER_SHUTDOWN;
+
/* continue, if peer is already in administrative shutdown. */
if (CHECK_FLAG(peer->flags, PEER_FLAG_SHUTDOWN))
continue;
@@ -4886,8 +4888,10 @@ void bgp_shutdown_disable(struct bgp *bgp)
/* clear the BGP instances shutdown flag */
UNSET_FLAG(bgp->flags, BGP_FLAG_SHUTDOWN);
- for (ALL_LIST_ELEMENTS_RO(bgp->peer, node, peer))
+ for (ALL_LIST_ELEMENTS_RO(bgp->peer, node, peer)) {
bgp_timer_set(peer->connection);
+ peer->last_reset = PEER_DOWN_WAITING_OPEN;
+ }
}
/* Change specified peer flag. */
@@ -4959,6 +4963,10 @@ static int peer_flag_modify(struct peer *peer, uint64_t flag, int set)
bgp_zebra_terminate_radv(peer->bgp, peer);
}
+ if (flag == PEER_FLAG_SHUTDOWN)
+ peer->last_reset = set ? PEER_DOWN_USER_SHUTDOWN
+ : PEER_DOWN_WAITING_OPEN;
+
/* Execute flag action on peer. */
if (action.type == peer_change_reset)
peer_flag_modify_action(peer, flag);
@@ -4994,6 +5002,10 @@ static int peer_flag_modify(struct peer *peer, uint64_t flag, int set)
set ? bgp_zebra_initiate_radv(member->bgp, member)
: bgp_zebra_terminate_radv(member->bgp, member);
+ if (flag == PEER_FLAG_SHUTDOWN)
+ member->last_reset = set ? PEER_DOWN_USER_SHUTDOWN
+ : PEER_DOWN_WAITING_OPEN;
+
/* Execute flag action on peer-group member. */
if (action.type == peer_change_reset)
peer_flag_modify_action(member, flag);
diff --git a/doc/developer/ospf-ls-retrans.rst b/doc/developer/ospf-ls-retrans.rst
new file mode 100644
index 0000000000..230d7a1c5d
--- /dev/null
+++ b/doc/developer/ospf-ls-retrans.rst
@@ -0,0 +1,69 @@
+OSPF Neighor Retransmission List
+================================
+
+Overview
+--------
+
+OSPF neighbor link-state retransmission lists are implemented using
+both a sparse Link State Database (LSDB) and a doubly-linked list.
+Rather than previous per-neighbor periodic timer, a per-neighbor
+timer is set to the expiration time of the next scheduled LSA
+retransmission.
+
+Sparse Link State Database (LSDB)
+---------------------------------
+
+When an explicit or implied acknowledgment is recieved from a
+neighbor in 2-way state or higher, the acknowledge LSA must be
+removed from the neighbor's link state retransmission list. In order
+to do this efficiently, a sparse LSDB is utilized. LSDB entries also
+include a pointer to the corresponding list entry so that it may be
+efficiently removed from the doubly-linked list.
+
+The sparse LSDB is implemented using the OSPF functions is
+ospf_lsdb.[c,h]. OSPF LSDBs are implemented as an array of route
+tables (lib/table.[c,h]). What is unique of the LS Retransmission
+list LSDB is that each entry also has a pointer into the doubly-linked
+list to facilitate fast deletions.
+
+Doubly-Linked List
+------------------
+
+In addition to the sparse LSDB, LSAs on a neighbor LS retransmission
+list are also maintained in a linked-list order chronologically
+with the LSA scheduled for the next retransmission at the head of
+the list.
+
+The doubly-link list is implemented using the dlist macros in
+lib/typesafe.h.
+
+LSA LS Retransmission List Addition
+------------------------------------
+
+When an LSA is added to a neighbor retransmission list, it is
+added to both the sparse LSDB and the doubly-linked list with a pointer
+in the LSDB route-table node to the list entry. The LSA is added to
+the tail of the list with the expiration time set to the current time
+with the retransmission interval added. If the neighbor retransmission
+timer is not set, it is set to expire at the time of the newly added
+LSA.
+
+LSA LS Retransmission List Deletion
+-----------------------------------
+
+When an LSA is deleted from a neighbor retransmission list, it is
+deleted from eboth the sparse LSDB and the doubly-linked list with the
+pointer the LSDB route-table node used to efficiently delete the entry
+from the list. If the LSA at the head of the list was removed, then
+the neighbor retransmission timer is reset to the expiration of the
+LSA at the head of the list or canceled if the list is empty.
+
+Neighbor LS Retransmission List Expiration
+------------------------------------------
+
+When the neighbor retransmission timer expires, the LSA at the top of
+list and any in a configured window (e.g., 50 milliseconds) are
+retransmitted. The LSAs that have been retransmitted are removed from
+the list and readded to the tail of the list with a new expiration time
+which is retransmit-interval seconds in the future.
+
diff --git a/doc/developer/ospf.rst b/doc/developer/ospf.rst
index 837a0bd185..da4802533c 100644
--- a/doc/developer/ospf.rst
+++ b/doc/developer/ospf.rst
@@ -8,6 +8,7 @@ OSPFD
:maxdepth: 2
ospf-api
+ ospf-ls-retrans
ospf-sr
cspf
diff --git a/doc/user/ospfd.rst b/doc/user/ospfd.rst
index 70c15e73de..b80adba7f0 100644
--- a/doc/user/ospfd.rst
+++ b/doc/user/ospfd.rst
@@ -738,7 +738,17 @@ Interfaces
retransmitting Database Description and Link State Request packets. The
default value is 5 seconds.
-.. clicmd:: ip ospf transmit-delay (1-65535) [A.B.C.D]
+.. clicmd:: ip ospf retransmit-window (20-1000)
+
+
+ Set number of milliseconds in the window for neighbor LSA retransmission.
+ When a neighbor Link State (LS) retransmission timer expires, LSAs scheduled
+ to be retransmitted within the number of milliseconds configured are
+ retransmitted to the neighbor. Any expiring after the window will be
+ retransmitted the next time the neighbor LS retransmission timer expires.
+ The default is 50 milliseconds.
+
+ .. clicmd:: ip ospf transmit-delay (1-65535) [A.B.C.D]
Set number of seconds for InfTransDelay value. LSAs' age should be
diff --git a/docker/alpine/Dockerfile b/docker/alpine/Dockerfile
index 1cff06feee..3f811455b3 100644
--- a/docker/alpine/Dockerfile
+++ b/docker/alpine/Dockerfile
@@ -1,7 +1,7 @@
# syntax=docker/dockerfile:1
# Create a basic stage set up to build APKs
-FROM alpine:3.19 as alpine-builder
+FROM alpine:3.20 as alpine-builder
RUN apk add \
--update-cache \
abuild \
@@ -24,7 +24,7 @@ RUN cd /src/libyang \
&& abuild -r -P /pkgs/apk
# This stage builds a dist tarball from the source
-FROM alpine:3.19 as source-builder
+FROM alpine:3.20 as source-builder
RUN mkdir -p /src/alpine /pkgs/apk
COPY alpine/APKBUILD.in /src/alpine
COPY --from=alpine-apk-builder-libyang /pkgs/apk/src /pkgs/apk
@@ -57,7 +57,7 @@ RUN cd /dist \
&& abuild -r -P /pkgs/apk
# This stage installs frr from the apk
-FROM alpine:3.19
+FROM alpine:3.20
RUN mkdir -p /pkgs/apk
COPY --from=alpine-apk-builder /pkgs/apk/ /pkgs/apk/
RUN apk add \
diff --git a/docker/alpine/libyang/APKBUILD b/docker/alpine/libyang/APKBUILD
index 6973fd62d8..d8cd4d918a 100755
--- a/docker/alpine/libyang/APKBUILD
+++ b/docker/alpine/libyang/APKBUILD
@@ -11,6 +11,7 @@ makedepends="bison cmake cmocka-dev flex pcre2-dev"
checkdepends="expect grep shunit2"
subpackages="$pkgname-dev $pkgname-doc"
source="$pkgname-$pkgver.tar.gz::https://github.com/CESNET/libyang/archive/v$pkgver.tar.gz"
+options="!check"
# secfixes:
# 1.0.215-r1:
@@ -21,6 +22,7 @@ source="$pkgname-$pkgver.tar.gz::https://github.com/CESNET/libyang/archive/v$pkg
# - CVE-2021-28906
build() {
+ export ABUILD_APK_INDEX_OPTS="--allow-untrusted"
if [ "$CBUILD" != "$CHOST" ]; then
CMAKE_CROSSOPTS="-DCMAKE_SYSTEM_NAME=Linux -DCMAKE_HOST_SYSTEM_NAME=Linux"
fi
diff --git a/isisd/isis_tlvs.c b/isisd/isis_tlvs.c
index 3bb8a48246..c7f45b2469 100644
--- a/isisd/isis_tlvs.c
+++ b/isisd/isis_tlvs.c
@@ -1010,7 +1010,7 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts,
struct isis_adj_sid *adj;
if (json) {
- struct json_object *arr_adj_json, *flags_json;
+ struct json_object *arr_adj_json, *adj_sid_json;
#if CONFDATE > 20240916
CPP_NOTICE("remove deprecated key format with -")
@@ -1022,42 +1022,37 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts,
adj; adj = adj->next) {
snprintfrr(cnt_buf, sizeof(cnt_buf), "%d",
adj->sid);
- flags_json = json_object_new_object();
- json_object_int_add(flags_json, "sid",
+ adj_sid_json = json_object_new_object();
+ json_object_int_add(adj_sid_json, "sid",
adj->sid);
- json_object_int_add(flags_json, "weight",
+ json_object_int_add(adj_sid_json, "weight",
adj->weight);
- json_object_string_add(
- flags_json, "flag-f",
- adj->flags & EXT_SUBTLV_LINK_ADJ_SID_FFLG
- ? "1"
- : "0");
- json_object_string_add(
- flags_json, "flag-b",
- adj->flags & EXT_SUBTLV_LINK_ADJ_SID_BFLG
- ? "1"
- : "0");
- json_object_string_add(
- flags_json, "flag-v",
- adj->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG
- ? "1"
- : "0");
- json_object_string_add(
- flags_json, "flag-l",
- adj->flags & EXT_SUBTLV_LINK_ADJ_SID_LFLG
- ? "1"
- : "0");
- json_object_string_add(
- flags_json, "flag-s",
- adj->flags & EXT_SUBTLV_LINK_ADJ_SID_SFLG
- ? "1"
- : "0");
- json_object_string_add(
- flags_json, "flag-p",
- adj->flags & EXT_SUBTLV_LINK_ADJ_SID_PFLG
- ? "1"
- : "0");
- json_object_array_add(arr_adj_json, flags_json);
+ json_object_string_add(adj_sid_json, "flag-f",
+ adj->flags & EXT_SUBTLV_LINK_ADJ_SID_FFLG
+ ? "1"
+ : "0");
+ json_object_string_add(adj_sid_json, "flag-b",
+ adj->flags & EXT_SUBTLV_LINK_ADJ_SID_BFLG
+ ? "1"
+ : "0");
+ json_object_string_add(adj_sid_json, "flag-v",
+ adj->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG
+ ? "1"
+ : "0");
+ json_object_string_add(adj_sid_json, "flag-l",
+ adj->flags & EXT_SUBTLV_LINK_ADJ_SID_LFLG
+ ? "1"
+ : "0");
+ json_object_string_add(adj_sid_json, "flag-s",
+ adj->flags & EXT_SUBTLV_LINK_ADJ_SID_SFLG
+ ? "1"
+ : "0");
+ json_object_string_add(adj_sid_json, "flag-p",
+ adj->flags & EXT_SUBTLV_LINK_ADJ_SID_PFLG
+ ? "1"
+ : "0");
+ json_object_array_add(arr_adj_json,
+ adj_sid_json);
}
/* end old deprecated key format */
@@ -1067,35 +1062,37 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts,
adj; adj = adj->next) {
snprintfrr(cnt_buf, sizeof(cnt_buf), "%d",
adj->sid);
- flags_json = json_object_new_object();
- json_object_int_add(flags_json, "sid", adj->sid);
- json_object_int_add(flags_json, "weight",
+ adj_sid_json = json_object_new_object();
+ json_object_int_add(adj_sid_json, "sid",
+ adj->sid);
+ json_object_int_add(adj_sid_json, "weight",
adj->weight);
- json_object_boolean_add(flags_json, "flagF",
+ json_object_boolean_add(adj_sid_json, "flagF",
adj->flags & EXT_SUBTLV_LINK_ADJ_SID_FFLG
? true
: false);
- json_object_boolean_add(flags_json, "flagB",
+ json_object_boolean_add(adj_sid_json, "flagB",
adj->flags & EXT_SUBTLV_LINK_ADJ_SID_BFLG
? true
: false);
- json_object_boolean_add(flags_json, "flagV",
+ json_object_boolean_add(adj_sid_json, "flagV",
adj->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG
? true
: false);
- json_object_boolean_add(flags_json, "flagL",
+ json_object_boolean_add(adj_sid_json, "flagL",
adj->flags & EXT_SUBTLV_LINK_ADJ_SID_LFLG
? true
: false);
- json_object_boolean_add(flags_json, "flagS",
+ json_object_boolean_add(adj_sid_json, "flagS",
adj->flags & EXT_SUBTLV_LINK_ADJ_SID_SFLG
? true
: false);
- json_object_boolean_add(flags_json, "flagP",
+ json_object_boolean_add(adj_sid_json, "flagP",
adj->flags & EXT_SUBTLV_LINK_ADJ_SID_PFLG
? true
: false);
- json_object_array_add(arr_adj_json, flags_json);
+ json_object_array_add(arr_adj_json,
+ adj_sid_json);
}
} else
for (adj = (struct isis_adj_sid *)exts->adj_sid.head;
@@ -1128,7 +1125,7 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts,
if (IS_SUBTLV(exts, EXT_LAN_ADJ_SID)) {
struct isis_lan_adj_sid *lan;
if (json) {
- struct json_object *arr_adj_json, *flags_json;
+ struct json_object *arr_adj_json, *lan_adj_json;
#if CONFDATE > 20240916
CPP_NOTICE("remove deprecated key format with -")
@@ -1147,42 +1144,37 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts,
continue;
snprintfrr(cnt_buf, sizeof(cnt_buf), "%d",
lan->sid);
- flags_json = json_object_new_object();
- json_object_int_add(flags_json, "sid",
+ lan_adj_json = json_object_new_object();
+ json_object_int_add(lan_adj_json, "sid",
lan->sid);
- json_object_int_add(flags_json, "weight",
+ json_object_int_add(lan_adj_json, "weight",
lan->weight);
- json_object_string_add(
- flags_json, "flag-f",
- lan->flags & EXT_SUBTLV_LINK_ADJ_SID_FFLG
- ? "1"
- : "0");
- json_object_string_add(
- flags_json, "flag-b",
- lan->flags & EXT_SUBTLV_LINK_ADJ_SID_BFLG
- ? "1"
- : "0");
- json_object_string_add(
- flags_json, "flag-v",
- lan->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG
- ? "1"
- : "0");
- json_object_string_add(
- flags_json, "flag-l",
- lan->flags & EXT_SUBTLV_LINK_ADJ_SID_LFLG
- ? "1"
- : "0");
- json_object_string_add(
- flags_json, "flag-s",
- lan->flags & EXT_SUBTLV_LINK_ADJ_SID_SFLG
- ? "1"
- : "0");
- json_object_string_add(
- flags_json, "flag-p",
- lan->flags & EXT_SUBTLV_LINK_ADJ_SID_PFLG
- ? "1"
- : "0");
- json_object_array_add(arr_adj_json, flags_json);
+ json_object_string_add(lan_adj_json, "flag-f",
+ lan->flags & EXT_SUBTLV_LINK_ADJ_SID_FFLG
+ ? "1"
+ : "0");
+ json_object_string_add(lan_adj_json, "flag-b",
+ lan->flags & EXT_SUBTLV_LINK_ADJ_SID_BFLG
+ ? "1"
+ : "0");
+ json_object_string_add(lan_adj_json, "flag-v",
+ lan->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG
+ ? "1"
+ : "0");
+ json_object_string_add(lan_adj_json, "flag-l",
+ lan->flags & EXT_SUBTLV_LINK_ADJ_SID_LFLG
+ ? "1"
+ : "0");
+ json_object_string_add(lan_adj_json, "flag-s",
+ lan->flags & EXT_SUBTLV_LINK_ADJ_SID_SFLG
+ ? "1"
+ : "0");
+ json_object_string_add(lan_adj_json, "flag-p",
+ lan->flags & EXT_SUBTLV_LINK_ADJ_SID_PFLG
+ ? "1"
+ : "0");
+ json_object_array_add(arr_adj_json,
+ lan_adj_json);
}
/* end old deprecated key format */
@@ -1197,35 +1189,37 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts,
continue;
snprintfrr(cnt_buf, sizeof(cnt_buf), "%d",
lan->sid);
- flags_json = json_object_new_object();
- json_object_int_add(flags_json, "sid", lan->sid);
- json_object_int_add(flags_json, "weight",
+ lan_adj_json = json_object_new_object();
+ json_object_int_add(lan_adj_json, "sid",
+ lan->sid);
+ json_object_int_add(lan_adj_json, "weight",
lan->weight);
- json_object_boolean_add(flags_json, "flagF",
+ json_object_boolean_add(lan_adj_json, "flagF",
lan->flags & EXT_SUBTLV_LINK_ADJ_SID_FFLG
? true
: false);
- json_object_boolean_add(flags_json, "flagB",
+ json_object_boolean_add(lan_adj_json, "flagB",
lan->flags & EXT_SUBTLV_LINK_ADJ_SID_BFLG
? true
: false);
- json_object_boolean_add(flags_json, "flagV",
+ json_object_boolean_add(lan_adj_json, "flagV",
lan->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG
? true
: false);
- json_object_boolean_add(flags_json, "flagL",
+ json_object_boolean_add(lan_adj_json, "flagL",
lan->flags & EXT_SUBTLV_LINK_ADJ_SID_LFLG
? true
: false);
- json_object_boolean_add(flags_json, "flagS",
+ json_object_boolean_add(lan_adj_json, "flagS",
lan->flags & EXT_SUBTLV_LINK_ADJ_SID_SFLG
? true
: false);
- json_object_boolean_add(flags_json, "flagP",
+ json_object_boolean_add(lan_adj_json, "flagP",
lan->flags & EXT_SUBTLV_LINK_ADJ_SID_PFLG
? true
: false);
- json_object_array_add(arr_adj_json, flags_json);
+ json_object_array_add(arr_adj_json,
+ lan_adj_json);
}
} else
@@ -1268,7 +1262,7 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts,
struct isis_srv6_endx_sid_subtlv *adj;
if (json) {
- struct json_object *arr_adj_json, *flags_json;
+ struct json_object *arr_adj_json, *srv6_endx_sid_json;
#if CONFDATE > 20240916
CPP_NOTICE("remove deprecated key format with -")
@@ -1282,76 +1276,85 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts,
adj; adj = adj->next) {
snprintfrr(cnt_buf, sizeof(cnt_buf), "%pI6",
&adj->sid);
- flags_json = json_object_new_object();
- json_object_string_addf(flags_json, "sid",
- "%pI6", &adj->sid);
- json_object_string_add(
- flags_json, "algorithm",
- sr_algorithm_string(adj->algorithm));
- json_object_int_add(flags_json, "weight",
- adj->weight);
- json_object_string_add(
- flags_json, "behavior",
- seg6local_action2str(adj->behavior));
- json_object_string_add(
- flags_json, "flag-b",
- adj->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_BFLG
- ? "1"
- : "0");
- json_object_string_add(
- flags_json, "flag-s",
- adj->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_SFLG
- ? "1"
- : "0");
- json_object_string_add(
- flags_json, "flag-p",
- adj->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_PFLG
- ? "1"
- : "0");
- json_object_array_add(arr_adj_json, flags_json);
+ srv6_endx_sid_json = json_object_new_object();
+ json_object_string_addf(srv6_endx_sid_json,
+ "sid", "%pI6",
+ &adj->sid);
+ json_object_string_add(srv6_endx_sid_json,
+ "algorithm",
+ sr_algorithm_string(
+ adj->algorithm));
+ json_object_int_add(srv6_endx_sid_json,
+ "weight", adj->weight);
+ json_object_string_add(srv6_endx_sid_json,
+ "behavior",
+ seg6local_action2str(
+ adj->behavior));
+ json_object_string_add(srv6_endx_sid_json,
+ "flag-b",
+ adj->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_BFLG
+ ? "1"
+ : "0");
+ json_object_string_add(srv6_endx_sid_json,
+ "flag-s",
+ adj->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_SFLG
+ ? "1"
+ : "0");
+ json_object_string_add(srv6_endx_sid_json,
+ "flag-p",
+ adj->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_PFLG
+ ? "1"
+ : "0");
+ json_object_array_add(arr_adj_json,
+ srv6_endx_sid_json);
if (adj->subsubtlvs)
isis_format_subsubtlvs(adj->subsubtlvs,
NULL,
- arr_adj_json,
+ srv6_endx_sid_json,
indent + 4);
}
/* end old deprecated key format */
arr_adj_json = json_object_new_array();
- json_object_object_add(json, "srv6EndSID", arr_adj_json);
+ json_object_object_add(json, "srv6EndXSID",
+ arr_adj_json);
for (adj = (struct isis_srv6_endx_sid_subtlv *)
exts->srv6_endx_sid.head;
adj; adj = adj->next) {
snprintfrr(cnt_buf, sizeof(cnt_buf), "%pI6",
&adj->sid);
- flags_json = json_object_new_object();
- json_object_string_addf(flags_json, "sid",
- "%pI6", &adj->sid);
- json_object_string_add(flags_json, "algorithm",
+ srv6_endx_sid_json = json_object_new_object();
+ json_object_string_addf(srv6_endx_sid_json,
+ "sid", "%pI6",
+ &adj->sid);
+ json_object_string_add(srv6_endx_sid_json,
+ "algorithm",
sr_algorithm_string(
adj->algorithm));
- json_object_int_add(flags_json, "weight",
- adj->weight);
- json_object_string_add(flags_json, "behavior",
+ json_object_int_add(srv6_endx_sid_json,
+ "weight", adj->weight);
+ json_object_string_add(srv6_endx_sid_json,
+ "behavior",
seg6local_action2str(
adj->behavior));
json_object_boolean_add(
- flags_json, "flagB",
+ srv6_endx_sid_json, "flagB",
!!(adj->flags &
EXT_SUBTLV_LINK_SRV6_ENDX_SID_BFLG));
json_object_boolean_add(
- flags_json, "flagS",
+ srv6_endx_sid_json, "flagS",
!!(adj->flags &
EXT_SUBTLV_LINK_SRV6_ENDX_SID_SFLG));
json_object_boolean_add(
- flags_json, "flagP",
+ srv6_endx_sid_json, "flagP",
!!(adj->flags &
EXT_SUBTLV_LINK_SRV6_ENDX_SID_PFLG));
- json_object_array_add(arr_adj_json, flags_json);
+ json_object_array_add(arr_adj_json,
+ srv6_endx_sid_json);
if (adj->subsubtlvs)
isis_format_subsubtlvs(adj->subsubtlvs,
NULL,
- arr_adj_json,
+ srv6_endx_sid_json,
indent + 4);
}
} else
@@ -1384,7 +1387,8 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts,
if (IS_SUBTLV(exts, EXT_SRV6_LAN_ENDX_SID)) {
struct isis_srv6_lan_endx_sid_subtlv *lan;
if (json) {
- struct json_object *arr_adj_json, *flags_json;
+ struct json_object *arr_adj_json,
+ *srv6_lan_endx_sid_json;
#if CONFDATE > 20240916
CPP_NOTICE("remove deprecated key format with -")
@@ -1398,42 +1402,47 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts,
lan; lan = lan->next) {
snprintfrr(cnt_buf, sizeof(cnt_buf), "%pI6",
&lan->sid);
- flags_json = json_object_new_object();
- json_object_string_addf(flags_json, "sid",
- "%pI6", &lan->sid);
- json_object_int_add(flags_json, "weight",
- lan->weight);
- json_object_string_add(
- flags_json, "algorithm",
- sr_algorithm_string(lan->algorithm));
- json_object_int_add(flags_json, "weight",
- lan->weight);
- json_object_string_add(
- flags_json, "behavior",
- seg6local_action2str(lan->behavior));
- json_object_string_add(
- flags_json, "flag-b",
- lan->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_BFLG
- ? "1"
- : "0");
- json_object_string_add(
- flags_json, "flag-s",
- lan->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_SFLG
- ? "1"
- : "0");
- json_object_string_add(
- flags_json, "flag-p",
- lan->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_PFLG
- ? "1"
- : "0");
- json_object_string_addf(flags_json,
+ srv6_lan_endx_sid_json =
+ json_object_new_object();
+ json_object_string_addf(srv6_lan_endx_sid_json,
+ "sid", "%pI6",
+ &lan->sid);
+ json_object_int_add(srv6_lan_endx_sid_json,
+ "weight", lan->weight);
+ json_object_string_add(srv6_lan_endx_sid_json,
+ "algorithm",
+ sr_algorithm_string(
+ lan->algorithm));
+ json_object_int_add(srv6_lan_endx_sid_json,
+ "weight", lan->weight);
+ json_object_string_add(srv6_lan_endx_sid_json,
+ "behavior",
+ seg6local_action2str(
+ lan->behavior));
+ json_object_string_add(srv6_lan_endx_sid_json,
+ "flag-b",
+ lan->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_BFLG
+ ? "1"
+ : "0");
+ json_object_string_add(srv6_lan_endx_sid_json,
+ "flag-s",
+ lan->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_SFLG
+ ? "1"
+ : "0");
+ json_object_string_add(srv6_lan_endx_sid_json,
+ "flag-p",
+ lan->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_PFLG
+ ? "1"
+ : "0");
+ json_object_string_addf(srv6_lan_endx_sid_json,
"neighbor-id", "%pSY",
lan->neighbor_id);
- json_object_array_add(arr_adj_json, flags_json);
+ json_object_array_add(arr_adj_json,
+ srv6_lan_endx_sid_json);
if (lan->subsubtlvs)
isis_format_subsubtlvs(lan->subsubtlvs,
NULL,
- arr_adj_json,
+ srv6_lan_endx_sid_json,
indent + 4);
}
/* end old deprecated key format */
@@ -1446,39 +1455,44 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts,
lan; lan = lan->next) {
snprintfrr(cnt_buf, sizeof(cnt_buf), "%pI6",
&lan->sid);
- flags_json = json_object_new_object();
- json_object_string_addf(flags_json, "sid",
- "%pI6", &lan->sid);
- json_object_int_add(flags_json, "weight",
- lan->weight);
- json_object_string_add(flags_json, "algorithm",
+ srv6_lan_endx_sid_json =
+ json_object_new_object();
+ json_object_string_addf(srv6_lan_endx_sid_json,
+ "sid", "%pI6",
+ &lan->sid);
+ json_object_int_add(srv6_lan_endx_sid_json,
+ "weight", lan->weight);
+ json_object_string_add(srv6_lan_endx_sid_json,
+ "algorithm",
sr_algorithm_string(
lan->algorithm));
- json_object_int_add(flags_json, "weight",
- lan->weight);
- json_object_string_add(flags_json, "behavior",
+ json_object_int_add(srv6_lan_endx_sid_json,
+ "weight", lan->weight);
+ json_object_string_add(srv6_lan_endx_sid_json,
+ "behavior",
seg6local_action2str(
lan->behavior));
json_object_boolean_add(
- flags_json, "flagB",
+ srv6_lan_endx_sid_json, "flagB",
!!(lan->flags &
EXT_SUBTLV_LINK_SRV6_ENDX_SID_BFLG));
json_object_boolean_add(
- flags_json, "flagS",
+ srv6_lan_endx_sid_json, "flagS",
!!(lan->flags &
EXT_SUBTLV_LINK_SRV6_ENDX_SID_SFLG));
json_object_boolean_add(
- flags_json, "flagP",
+ srv6_lan_endx_sid_json, "flagP",
!!(lan->flags &
EXT_SUBTLV_LINK_SRV6_ENDX_SID_PFLG));
- json_object_string_addf(flags_json,
- "neighbor-id", "%pSY",
+ json_object_string_addf(srv6_lan_endx_sid_json,
+ "neighborID", "%pSY",
lan->neighbor_id);
- json_object_array_add(arr_adj_json, flags_json);
+ json_object_array_add(arr_adj_json,
+ srv6_lan_endx_sid_json);
if (lan->subsubtlvs)
isis_format_subsubtlvs(lan->subsubtlvs,
NULL,
- arr_adj_json,
+ srv6_lan_endx_sid_json,
indent + 4);
}
} else
diff --git a/lib/libospf.h b/lib/libospf.h
index 0ac490a00e..f2dc5d61d9 100644
--- a/lib/libospf.h
+++ b/lib/libospf.h
@@ -58,6 +58,7 @@ extern "C" {
#define OSPF_HELLO_DELAY_DEFAULT 10
#define OSPF_ROUTER_PRIORITY_DEFAULT 1
#define OSPF_RETRANSMIT_INTERVAL_DEFAULT 5
+#define OSPF_RETRANSMIT_WINDOW_DEFAULT 50 /* milliseconds */
#define OSPF_TRANSMIT_DELAY_DEFAULT 1
#define OSPF_DEFAULT_BANDWIDTH 10000 /* Mbps */
diff --git a/ospfd/ospf_flood.c b/ospfd/ospf_flood.c
index e15871ac81..e9797ce935 100644
--- a/ospfd/ospf_flood.c
+++ b/ospfd/ospf_flood.c
@@ -1015,7 +1015,7 @@ void ospf_ls_request_delete(struct ospf_neighbor *nbr, struct ospf_lsa *lsa)
ospf_lsdb_delete(&nbr->ls_req, lsa);
}
-/* Remove all LSA from neighbor's ls-requenst list. */
+/* Remove all LSAs from neighbor's ls-request list. */
void ospf_ls_request_delete_all(struct ospf_neighbor *nbr)
{
ospf_lsa_unlock(&nbr->ls_req_last);
@@ -1061,58 +1061,114 @@ int ospf_ls_retransmit_isempty(struct ospf_neighbor *nbr)
/* Add LSA to be retransmitted to neighbor's ls-retransmit list. */
void ospf_ls_retransmit_add(struct ospf_neighbor *nbr, struct ospf_lsa *lsa)
{
- struct ospf_lsa *old;
+ struct ospf_lsdb_linked_node *ls_rxmt_node;
+ struct ospf_lsa_list_entry *ls_rxmt_list_entry;
+ struct ospf_lsa *old = NULL;
+ bool rxmt_head_replaced = false;
- old = ospf_ls_retransmit_lookup(nbr, lsa);
+ ls_rxmt_node = ospf_lsdb_linked_lookup(&nbr->ls_rxmt, lsa);
+ if (ls_rxmt_node)
+ old = ls_rxmt_node->info;
if (ospf_lsa_more_recent(old, lsa) < 0) {
if (old) {
old->retransmit_counter--;
+ if (ls_rxmt_node->lsa_list_entry ==
+ ospf_lsa_list_first(&nbr->ls_rxmt_list))
+ rxmt_head_replaced = true;
+ ospf_lsa_list_del(&nbr->ls_rxmt_list,
+ ls_rxmt_node->lsa_list_entry);
+ XFREE(MTYPE_OSPF_LSA_LIST, ls_rxmt_node->lsa_list_entry);
+ ospf_lsdb_delete(&nbr->ls_rxmt, old);
if (IS_DEBUG_OSPF(lsa, LSA_FLOODING))
- zlog_debug("RXmtL(%lu)--, NBR(%pI4(%s)), LSA[%s]",
+ zlog_debug("RXmtL(%lu) NBR(%pI4(%s)) Old Delete LSA[%s] on Add",
ospf_ls_retransmit_count(nbr),
&nbr->router_id,
ospf_get_name(nbr->oi->ospf),
- dump_lsa_key(old));
- ospf_lsdb_delete(&nbr->ls_rxmt, old);
+ dump_lsa_key(lsa));
+ ospf_lsa_unlock(&old);
}
lsa->retransmit_counter++;
+ ls_rxmt_list_entry = XCALLOC(MTYPE_OSPF_LSA_LIST,
+ sizeof(struct ospf_lsa_list_entry));
+ /*
+ * Set the LSA retransmission time for the neighbor;
+ */
+ monotime(&ls_rxmt_list_entry->list_entry_time);
+ ls_rxmt_list_entry->list_entry_time.tv_sec += nbr->v_ls_rxmt;
+
+ /*
+ * Add the LSA to the neighbor retransmission list.
+ */
+ ls_rxmt_list_entry->lsa = ospf_lsa_lock(lsa);
+ ospf_lsa_list_add_tail(&nbr->ls_rxmt_list, ls_rxmt_list_entry);
+ ospf_lsdb_add(&nbr->ls_rxmt, lsa);
+
/*
- * We cannot make use of the newly introduced callback function
- * "lsdb->new_lsa_hook" to replace debug output below, just
- * because
- * it seems no simple and smart way to pass neighbor information
- * to
- * the common function "ospf_lsdb_add()" -- endo.
+ * Look up the newly added node and set the list pointer.
*/
+ ls_rxmt_node = ospf_lsdb_linked_lookup(&nbr->ls_rxmt, lsa);
+ ls_rxmt_node->lsa_list_entry = ls_rxmt_list_entry;
+
if (IS_DEBUG_OSPF(lsa, LSA_FLOODING))
- zlog_debug("RXmtL(%lu)++, NBR(%pI4(%s)), LSA[%s]",
+ zlog_debug("RXmtL(%lu) NBR(%pI4(%s)) Add LSA[%s] retrans at (%ld/%ld)",
ospf_ls_retransmit_count(nbr),
- &nbr->router_id,
- ospf_get_name(nbr->oi->ospf),
- dump_lsa_key(lsa));
- ospf_lsdb_add(&nbr->ls_rxmt, lsa);
+ &nbr->router_id, ospf_get_name(nbr->oi->ospf),
+ dump_lsa_key(lsa),
+ (long)ls_rxmt_list_entry->list_entry_time
+ .tv_sec,
+ (long)ls_rxmt_list_entry->list_entry_time
+ .tv_usec);
+ /*
+ * Reset the neighbor LSA retransmission timer if isn't currently
+ * running or the LSA at the head of the list was updated.
+ */
+ if (!nbr->t_ls_rxmt || rxmt_head_replaced)
+ ospf_ls_retransmit_set_timer(nbr);
}
}
/* Remove LSA from neibghbor's ls-retransmit list. */
void ospf_ls_retransmit_delete(struct ospf_neighbor *nbr, struct ospf_lsa *lsa)
{
- if (ospf_ls_retransmit_lookup(nbr, lsa)) {
+ struct ospf_lsdb_linked_node *ls_rxmt_node;
+
+ ls_rxmt_node = ospf_lsdb_linked_lookup(&nbr->ls_rxmt, lsa);
+
+ if (ls_rxmt_node) {
+ bool rxmt_timer_reset;
+
+ if (ls_rxmt_node->lsa_list_entry ==
+ ospf_lsa_list_first(&nbr->ls_rxmt_list))
+ rxmt_timer_reset = true;
+ else
+ rxmt_timer_reset = false;
+
lsa->retransmit_counter--;
- if (IS_DEBUG_OSPF(lsa, LSA_FLOODING)) /* -- endo. */
- zlog_debug("RXmtL(%lu)--, NBR(%pI4(%s)), LSA[%s]",
+ ospf_lsa_list_del(&nbr->ls_rxmt_list,
+ ls_rxmt_node->lsa_list_entry);
+ XFREE(MTYPE_OSPF_LSA_LIST, ls_rxmt_node->lsa_list_entry);
+ ospf_lsdb_delete(&nbr->ls_rxmt, lsa);
+ if (IS_DEBUG_OSPF(lsa, LSA_FLOODING))
+ zlog_debug("RXmtL(%lu) NBR(%pI4(%s)) Delete LSA[%s]",
ospf_ls_retransmit_count(nbr),
- &nbr->router_id,
- ospf_get_name(nbr->oi->ospf),
+ &nbr->router_id, ospf_get_name(nbr->oi->ospf),
dump_lsa_key(lsa));
- ospf_lsdb_delete(&nbr->ls_rxmt, lsa);
+ ospf_lsa_unlock(&lsa);
+
+ /*
+ * If the LS retransmission entry at the head of the list was
+ * deleted, reset the timer.
+ */
+ if (rxmt_timer_reset)
+ ospf_ls_retransmit_set_timer(nbr);
}
}
/* Clear neighbor's ls-retransmit list. */
void ospf_ls_retransmit_clear(struct ospf_neighbor *nbr)
{
+ struct ospf_lsa_list_entry *ls_rxmt_list_entry;
struct ospf_lsdb *lsdb;
int i;
@@ -1128,10 +1184,54 @@ void ospf_ls_retransmit_clear(struct ospf_neighbor *nbr)
ospf_ls_retransmit_delete(nbr, lsa);
}
+ frr_each_safe (ospf_lsa_list, &nbr->ls_rxmt_list, ls_rxmt_list_entry) {
+ ospf_lsa_list_del(&nbr->ls_rxmt_list, ls_rxmt_list_entry);
+ ospf_lsa_unlock(&ls_rxmt_list_entry->lsa);
+ XFREE(MTYPE_OSPF_LSA_LIST, ls_rxmt_list_entry);
+ }
+
ospf_lsa_unlock(&nbr->ls_req_last);
nbr->ls_req_last = NULL;
}
+/*
+ * Set the neighbor's ls-retransmit timer based on the next
+ * LSA retransmit time.
+ */
+void ospf_ls_retransmit_set_timer(struct ospf_neighbor *nbr)
+{
+ struct ospf_lsa_list_entry *ls_rxmt_list_entry;
+
+ if (nbr->t_ls_rxmt)
+ EVENT_OFF(nbr->t_ls_rxmt);
+
+ ls_rxmt_list_entry = ospf_lsa_list_first(&nbr->ls_rxmt_list);
+ if (ls_rxmt_list_entry) {
+ struct timeval current_time, delay;
+ unsigned long delay_milliseconds;
+
+ monotime(&current_time);
+ if (timercmp(&current_time,
+ &ls_rxmt_list_entry->list_entry_time, >=))
+ delay_milliseconds = 10;
+ else {
+ timersub(&ls_rxmt_list_entry->list_entry_time,
+ &current_time, &delay);
+ delay_milliseconds = (delay.tv_sec * 1000) +
+ (delay.tv_usec / 1000);
+ }
+
+ event_add_timer_msec(master, ospf_ls_rxmt_timer, nbr,
+ delay_milliseconds, &nbr->t_ls_rxmt);
+ if (IS_DEBUG_OSPF(lsa, LSA_FLOODING))
+ zlog_debug("RXmtL(%lu) NBR(%pI4(%s)) retrans timer set in %ld msecs - Head LSA(%s)",
+ ospf_ls_retransmit_count(nbr),
+ &nbr->router_id, ospf_get_name(nbr->oi->ospf),
+ delay_milliseconds,
+ dump_lsa_key(ls_rxmt_list_entry->lsa));
+ }
+}
+
/* Lookup LSA from neighbor's ls-retransmit list. */
struct ospf_lsa *ospf_ls_retransmit_lookup(struct ospf_neighbor *nbr,
struct ospf_lsa *lsa)
diff --git a/ospfd/ospf_flood.h b/ospfd/ospf_flood.h
index 3757400d0c..d9d9537351 100644
--- a/ospfd/ospf_flood.h
+++ b/ospfd/ospf_flood.h
@@ -7,6 +7,26 @@
#ifndef _ZEBRA_OSPF_FLOOD_H
#define _ZEBRA_OSPF_FLOOD_H
+/*
+ * OSPF Temporal LSA List
+ */
+PREDECL_DLIST(ospf_lsa_list);
+
+struct ospf_lsa_list_entry {
+ /* Linkage for LSA List */
+ struct ospf_lsa_list_item list_linkage;
+
+ /*
+ * Time associated with the list entry. For example, for a neigbhor
+ * link retransmission list, this is the retransmission time.
+ */
+ struct timeval list_entry_time;
+
+ struct ospf_lsa *lsa;
+};
+
+DECLARE_DLIST(ospf_lsa_list, struct ospf_lsa_list_entry, list_linkage);
+
extern int ospf_flood(struct ospf *, struct ospf_neighbor *, struct ospf_lsa *,
struct ospf_lsa *);
extern int ospf_flood_through(struct ospf *, struct ospf_neighbor *,
@@ -36,6 +56,8 @@ extern void ospf_ls_retransmit_add(struct ospf_neighbor *, struct ospf_lsa *);
extern void ospf_ls_retransmit_delete(struct ospf_neighbor *,
struct ospf_lsa *);
extern void ospf_ls_retransmit_clear(struct ospf_neighbor *);
+extern void ospf_ls_retransmit_set_timer(struct ospf_neighbor *nbr);
+
extern struct ospf_lsa *ospf_ls_retransmit_lookup(struct ospf_neighbor *,
struct ospf_lsa *);
extern void ospf_ls_retransmit_delete_nbr_area(struct ospf_area *,
diff --git a/ospfd/ospf_interface.c b/ospfd/ospf_interface.c
index 11ac7af7c9..803c36861d 100644
--- a/ospfd/ospf_interface.c
+++ b/ospfd/ospf_interface.c
@@ -542,6 +542,7 @@ static struct ospf_if_params *ospf_new_if_params(void)
UNSET_IF_PARAM(oip, output_cost_cmd);
UNSET_IF_PARAM(oip, transmit_delay);
UNSET_IF_PARAM(oip, retransmit_interval);
+ UNSET_IF_PARAM(oip, retransmit_window);
UNSET_IF_PARAM(oip, passive_interface);
UNSET_IF_PARAM(oip, v_hello);
UNSET_IF_PARAM(oip, fast_hello);
@@ -599,6 +600,7 @@ void ospf_free_if_params(struct interface *ifp, struct in_addr addr)
if (!OSPF_IF_PARAM_CONFIGURED(oip, output_cost_cmd) &&
!OSPF_IF_PARAM_CONFIGURED(oip, transmit_delay) &&
!OSPF_IF_PARAM_CONFIGURED(oip, retransmit_interval) &&
+ !OSPF_IF_PARAM_CONFIGURED(oip, retransmit_window) &&
!OSPF_IF_PARAM_CONFIGURED(oip, passive_interface) &&
!OSPF_IF_PARAM_CONFIGURED(oip, v_hello) &&
!OSPF_IF_PARAM_CONFIGURED(oip, fast_hello) &&
@@ -695,6 +697,9 @@ int ospf_if_new_hook(struct interface *ifp)
IF_DEF_PARAMS(ifp)->retransmit_interval =
OSPF_RETRANSMIT_INTERVAL_DEFAULT;
+ SET_IF_PARAM(IF_DEF_PARAMS(ifp), retransmit_window);
+ IF_DEF_PARAMS(ifp)->retransmit_window = OSPF_RETRANSMIT_WINDOW_DEFAULT;
+
SET_IF_PARAM(IF_DEF_PARAMS(ifp), priority);
IF_DEF_PARAMS(ifp)->priority = OSPF_ROUTER_PRIORITY_DEFAULT;
diff --git a/ospfd/ospf_interface.h b/ospfd/ospf_interface.h
index 45d0b7943a..a944847b5d 100644
--- a/ospfd/ospf_interface.h
+++ b/ospfd/ospf_interface.h
@@ -47,6 +47,8 @@ struct ospf_if_params {
output_cost_cmd); /* Command Interface Output Cost */
DECLARE_IF_PARAM(uint32_t,
retransmit_interval); /* Retransmission Interval */
+ DECLARE_IF_PARAM(uint32_t,
+ retransmit_window); /* Retransmission Window */
DECLARE_IF_PARAM(uint8_t, passive_interface); /* OSPF Interface is
passive: no sending or
receiving (no need to
@@ -296,6 +298,7 @@ struct ospf_interface {
uint32_t ls_ack_out; /* LS Ack message output count. */
uint32_t discarded; /* discarded input count by error. */
uint32_t state_change; /* Number of status change. */
+ uint32_t ls_rxmt_lsa; /* Number of LSAs retransmitted. */
uint32_t full_nbrs;
diff --git a/ospfd/ospf_lsdb.c b/ospfd/ospf_lsdb.c
index 0111c4924e..d1b3eb0d35 100644
--- a/ospfd/ospf_lsdb.c
+++ b/ospfd/ospf_lsdb.c
@@ -34,6 +34,59 @@ void ospf_lsdb_init(struct ospf_lsdb *lsdb)
lsdb->type[i].db = route_table_init();
}
+static struct route_node *
+ospf_lsdb_linked_node_create(route_table_delegate_t *delegate,
+ struct route_table *table)
+{
+ struct ospf_lsdb_linked_node *node;
+
+ node = XCALLOC(MTYPE_OSPF_LSDB_NODE,
+ sizeof(struct ospf_lsdb_linked_node));
+
+ return (struct route_node *)node;
+}
+
+static void ospf_lsdb_linked_node_destroy(route_table_delegate_t *delegate,
+ struct route_table *table,
+ struct route_node *node)
+{
+ struct ospf_lsdb_linked_node *lsdb_linked_node =
+ (struct ospf_lsdb_linked_node *)node;
+
+ XFREE(MTYPE_OSPF_LSDB_NODE, lsdb_linked_node);
+}
+
+static route_table_delegate_t ospf_lsdb_linked_table_delegate = {
+ .create_node = ospf_lsdb_linked_node_create,
+ .destroy_node = ospf_lsdb_linked_node_destroy,
+};
+
+void ospf_lsdb_linked_init(struct ospf_lsdb *lsdb)
+{
+ int i;
+
+ for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++)
+ lsdb->type[i].db = route_table_init_with_delegate(
+ &ospf_lsdb_linked_table_delegate);
+}
+
+struct ospf_lsdb_linked_node *ospf_lsdb_linked_lookup(struct ospf_lsdb *lsdb,
+ struct ospf_lsa *lsa)
+{
+ struct ospf_lsdb_linked_node *lsdb_linked_node;
+ struct route_table *table;
+ struct prefix_ls lp;
+
+ table = lsdb->type[lsa->data->type].db;
+ ls_prefix_set(&lp, lsa);
+ lsdb_linked_node = (struct ospf_lsdb_linked_node *)
+ route_node_lookup(table, (struct prefix *)&lp);
+ if (lsdb_linked_node)
+ route_unlock_node((struct route_node *)lsdb_linked_node);
+
+ return lsdb_linked_node;
+}
+
void ospf_lsdb_free(struct ospf_lsdb *lsdb)
{
ospf_lsdb_cleanup(lsdb);
diff --git a/ospfd/ospf_lsdb.h b/ospfd/ospf_lsdb.h
index bf295ca830..e5e3be8baa 100644
--- a/ospfd/ospf_lsdb.h
+++ b/ospfd/ospf_lsdb.h
@@ -7,6 +7,9 @@
#ifndef _ZEBRA_OSPF_LSDB_H
#define _ZEBRA_OSPF_LSDB_H
+#include "prefix.h"
+#include "table.h"
+
/* OSPF LSDB structure. */
struct ospf_lsdb {
struct {
@@ -43,9 +46,29 @@ struct ospf_lsdb {
#define AREA_LSDB(A,T) ((A)->lsdb->type[(T)].db)
#define AS_LSDB(O,T) ((O)->lsdb->type[(T)].db)
+/*
+ * Alternate route node structure for LSDB nodes linked to
+ * list elements.
+ */
+struct ospf_lsdb_linked_node {
+ /*
+ * Caution these must be the very first fields
+ */
+ ROUTE_NODE_FIELDS
+
+ /*
+ * List entry on an LSA list, e.g., a neighbor
+ * retransmission list.
+ */
+ struct ospf_lsa_list_entry *lsa_list_entry;
+};
+
/* OSPF LSDB related functions. */
extern struct ospf_lsdb *ospf_lsdb_new(void);
extern void ospf_lsdb_init(struct ospf_lsdb *);
+extern void ospf_lsdb_linked_init(struct ospf_lsdb *lsdb);
+extern struct ospf_lsdb_linked_node *
+ospf_lsdb_linked_lookup(struct ospf_lsdb *lsdb, struct ospf_lsa *lsa);
extern void ospf_lsdb_free(struct ospf_lsdb *);
extern void ospf_lsdb_cleanup(struct ospf_lsdb *);
extern void ls_prefix_set(struct prefix_ls *lp, struct ospf_lsa *lsa);
diff --git a/ospfd/ospf_memory.c b/ospfd/ospf_memory.c
index 9854c8cae8..478af323d3 100644
--- a/ospfd/ospf_memory.c
+++ b/ospfd/ospf_memory.c
@@ -45,3 +45,5 @@ DEFINE_MTYPE(OSPFD, OSPF_GR_HELPER, "OSPF Graceful Restart Helper");
DEFINE_MTYPE(OSPFD, OSPF_EXTERNAL_RT_AGGR, "OSPF External Route Summarisation");
DEFINE_MTYPE(OSPFD, OSPF_P_SPACE, "OSPF TI-LFA P-Space");
DEFINE_MTYPE(OSPFD, OSPF_Q_SPACE, "OSPF TI-LFA Q-Space");
+DEFINE_MTYPE(OSPFD, OSPF_LSA_LIST, "OSPF LSA List");
+DEFINE_MTYPE(OSPFD, OSPF_LSDB_NODE, "OSPF LSDB Linked Node");
diff --git a/ospfd/ospf_memory.h b/ospfd/ospf_memory.h
index d11b69abb0..e2139b517b 100644
--- a/ospfd/ospf_memory.h
+++ b/ospfd/ospf_memory.h
@@ -44,5 +44,7 @@ DECLARE_MTYPE(OSPF_GR_HELPER);
DECLARE_MTYPE(OSPF_EXTERNAL_RT_AGGR);
DECLARE_MTYPE(OSPF_P_SPACE);
DECLARE_MTYPE(OSPF_Q_SPACE);
+DECLARE_MTYPE(OSPF_LSA_LIST);
+DECLARE_MTYPE(OSPF_LSDB_NODE);
#endif /* _QUAGGA_OSPF_MEMORY_H */
diff --git a/ospfd/ospf_neighbor.c b/ospfd/ospf_neighbor.c
index d47d581605..2514fc0ab3 100644
--- a/ospfd/ospf_neighbor.c
+++ b/ospfd/ospf_neighbor.c
@@ -68,7 +68,7 @@ struct ospf_neighbor *ospf_nbr_new(struct ospf_interface *oi)
nbr->v_inactivity = OSPF_IF_PARAM(oi, v_wait);
nbr->v_db_desc = OSPF_IF_PARAM(oi, retransmit_interval);
nbr->v_ls_req = OSPF_IF_PARAM(oi, retransmit_interval);
- nbr->v_ls_upd = OSPF_IF_PARAM(oi, retransmit_interval);
+ nbr->v_ls_rxmt = OSPF_IF_PARAM(oi, retransmit_interval);
nbr->priority = -1;
/* DD flags. */
@@ -80,8 +80,10 @@ struct ospf_neighbor *ospf_nbr_new(struct ospf_interface *oi)
nbr->nbr_nbma = NULL;
ospf_lsdb_init(&nbr->db_sum);
- ospf_lsdb_init(&nbr->ls_rxmt);
+
+ ospf_lsdb_linked_init(&nbr->ls_rxmt);
ospf_lsdb_init(&nbr->ls_req);
+ ospf_lsa_list_init(&nbr->ls_rxmt_list);
nbr->crypt_seqnum = 0;
@@ -128,7 +130,7 @@ void ospf_nbr_free(struct ospf_neighbor *nbr)
EVENT_OFF(nbr->t_inactivity);
EVENT_OFF(nbr->t_db_desc);
EVENT_OFF(nbr->t_ls_req);
- EVENT_OFF(nbr->t_ls_upd);
+ EVENT_OFF(nbr->t_ls_rxmt);
/* Cancel all events. */ /* Thread lookup cost would be negligible. */
event_cancel_event(master, nbr);
diff --git a/ospfd/ospf_neighbor.h b/ospfd/ospf_neighbor.h
index 07d095f03d..0e041f9e6d 100644
--- a/ospfd/ospf_neighbor.h
+++ b/ospfd/ospf_neighbor.h
@@ -9,6 +9,7 @@
#include <ospfd/ospf_gr.h>
#include <ospfd/ospf_packet.h>
+#include <ospfd/ospf_flood.h>
/* Neighbor Data Structure */
struct ospf_neighbor {
@@ -44,6 +45,7 @@ struct ospf_neighbor {
/* LSA data. */
struct ospf_lsdb ls_rxmt;
+ struct ospf_lsa_list_head ls_rxmt_list;
struct ospf_lsdb db_sum;
struct ospf_lsdb ls_req;
struct ospf_lsa *ls_req_last;
@@ -54,13 +56,13 @@ struct ospf_neighbor {
uint32_t v_inactivity;
uint32_t v_db_desc;
uint32_t v_ls_req;
- uint32_t v_ls_upd;
+ uint32_t v_ls_rxmt;
/* Threads. */
struct event *t_inactivity;
struct event *t_db_desc;
struct event *t_ls_req;
- struct event *t_ls_upd;
+ struct event *t_ls_rxmt;
struct event *t_hello_reply;
/* NBMA configured neighbour */
@@ -71,6 +73,7 @@ struct ospf_neighbor {
struct timeval ts_last_regress; /* last regressive NSM change */
const char *last_regress_str; /* Event which last regressed NSM */
uint32_t state_change; /* NSM state change counter */
+ uint32_t ls_rxmt_lsa; /* Number of LSAs retransmited. */
/* BFD information */
struct bfd_session_params *bfd_session;
diff --git a/ospfd/ospf_nsm.c b/ospfd/ospf_nsm.c
index c466ddcc6f..079a1fa55e 100644
--- a/ospfd/ospf_nsm.c
+++ b/ospfd/ospf_nsm.c
@@ -112,18 +112,16 @@ static void nsm_timer_set(struct ospf_neighbor *nbr)
case NSM_Init:
case NSM_TwoWay:
EVENT_OFF(nbr->t_db_desc);
- EVENT_OFF(nbr->t_ls_upd);
+ EVENT_OFF(nbr->t_ls_rxmt);
EVENT_OFF(nbr->t_ls_req);
break;
case NSM_ExStart:
OSPF_NSM_TIMER_ON(nbr->t_db_desc, ospf_db_desc_timer,
nbr->v_db_desc);
- EVENT_OFF(nbr->t_ls_upd);
+ EVENT_OFF(nbr->t_ls_rxmt);
EVENT_OFF(nbr->t_ls_req);
break;
case NSM_Exchange:
- OSPF_NSM_TIMER_ON(nbr->t_ls_upd, ospf_ls_upd_timer,
- nbr->v_ls_upd);
if (!IS_SET_DD_MS(nbr->dd_flags))
EVENT_OFF(nbr->t_db_desc);
break;
diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c
index 87aaccad92..86f877b621 100644
--- a/ospfd/ospf_packet.c
+++ b/ospfd/ospf_packet.c
@@ -292,54 +292,66 @@ void ospf_ls_req_event(struct ospf_neighbor *nbr)
event_add_event(master, ospf_ls_req_timer, nbr, 0, &nbr->t_ls_req);
}
-/* Cyclic timer function. Fist registered in ospf_nbr_new () in
- ospf_neighbor.c */
-void ospf_ls_upd_timer(struct event *thread)
+/*
+ * OSPF neighbor link state retransmission timer handler. Unicast
+ * unacknowledged LSAs to the neigbhors.
+ */
+void ospf_ls_rxmt_timer(struct event *thread)
{
struct ospf_neighbor *nbr;
+ int retransmit_interval, retransmit_window, rxmt_lsa_count = 0;
nbr = EVENT_ARG(thread);
- nbr->t_ls_upd = NULL;
+ nbr->t_ls_rxmt = NULL;
+ retransmit_interval = nbr->v_ls_rxmt;
+ retransmit_window = OSPF_IF_PARAM(nbr->oi, retransmit_window);
/* Send Link State Update. */
if (ospf_ls_retransmit_count(nbr) > 0) {
+ struct ospf_lsa_list_entry *ls_rxmt_list_entry;
+ struct timeval current_time, latest_rxmt_time, next_rxmt_time;
+ struct timeval rxmt_interval = { retransmit_interval, 0 };
+ struct timeval rxmt_window;
struct list *update;
- struct ospf_lsdb *lsdb;
- int i;
- int retransmit_interval;
- retransmit_interval =
- OSPF_IF_PARAM(nbr->oi, retransmit_interval);
+ /*
+ * Set the retransmission window based on the configured value
+ * in milliseconds.
+ */
+ rxmt_window.tv_sec = retransmit_window / 1000;
+ rxmt_window.tv_usec = (retransmit_window % 1000) * 1000;
+
+ /*
+ * Calculate the latest retransmit time for LSAs transmited in
+ * this timer pass by adding the retransmission window to the
+ * current time. Calculate the next retransmission time by adding
+ * the retransmit interval to the current time.
+ */
+ monotime(&current_time);
+ timeradd(&current_time, &rxmt_window, &latest_rxmt_time);
+ timeradd(&current_time, &rxmt_interval, &next_rxmt_time);
- lsdb = &nbr->ls_rxmt;
update = list_new();
+ while ((ls_rxmt_list_entry =
+ ospf_lsa_list_first(&nbr->ls_rxmt_list))) {
+ if (timercmp(&ls_rxmt_list_entry->list_entry_time,
+ &latest_rxmt_time, >))
+ break;
- for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++) {
- struct route_table *table = lsdb->type[i].db;
- struct route_node *rn;
-
- for (rn = route_top(table); rn; rn = route_next(rn)) {
- struct ospf_lsa *lsa;
-
- if ((lsa = rn->info) != NULL) {
- /* Don't retransmit an LSA if we
- received it within
- the last RxmtInterval seconds - this
- is to allow the
- neighbour a chance to acknowledge the
- LSA as it may
- have ben just received before the
- retransmit timer
- fired. This is a small tweak to what
- is in the RFC,
- but it will cut out out a lot of
- retransmit traffic
- - MAG */
- if (monotime_since(&lsa->tv_recv, NULL)
- >= retransmit_interval * 1000000LL)
- listnode_add(update, rn->info);
- }
- }
+ listnode_add(update, ls_rxmt_list_entry->lsa);
+ rxmt_lsa_count++;
+
+ /*
+ * Set the next retransmit time for the LSA and move it
+ * to the end of the neighbor's retransmission list.
+ */
+ ls_rxmt_list_entry->list_entry_time = next_rxmt_time;
+ ospf_lsa_list_del(&nbr->ls_rxmt_list,
+ ls_rxmt_list_entry);
+ ospf_lsa_list_add_tail(&nbr->ls_rxmt_list,
+ ls_rxmt_list_entry);
+ nbr->ls_rxmt_lsa++;
+ nbr->oi->ls_rxmt_lsa++;
}
if (listcount(update) > 0)
@@ -348,8 +360,13 @@ void ospf_ls_upd_timer(struct event *thread)
list_delete(&update);
}
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_debug("RXmtL(%lu) NBR(%pI4(%s)) timer event - sent %u LSAs",
+ ospf_ls_retransmit_count(nbr), &nbr->router_id,
+ ospf_get_name(nbr->oi->ospf), rxmt_lsa_count);
+
/* Set LS Update retransmission timer. */
- OSPF_NSM_TIMER_ON(nbr->t_ls_upd, ospf_ls_upd_timer, nbr->v_ls_upd);
+ ospf_ls_retransmit_set_timer(nbr);
}
void ospf_ls_ack_timer(struct event *thread)
diff --git a/ospfd/ospf_packet.h b/ospfd/ospf_packet.h
index 234738979e..2c9dba6c88 100644
--- a/ospfd/ospf_packet.h
+++ b/ospfd/ospf_packet.h
@@ -140,7 +140,7 @@ extern void ospf_ls_ack_send_delayed(struct ospf_interface *);
extern void ospf_ls_retransmit(struct ospf_interface *, struct ospf_lsa *);
extern void ospf_ls_req_event(struct ospf_neighbor *);
-extern void ospf_ls_upd_timer(struct event *thread);
+extern void ospf_ls_rxmt_timer(struct event *thread);
extern void ospf_ls_ack_timer(struct event *thread);
extern void ospf_poll_timer(struct event *thread);
extern void ospf_hello_reply_timer(struct event *thread);
diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c
index 3a11b21232..7a7a684dd6 100644
--- a/ospfd/ospf_vty.c
+++ b/ospfd/ospf_vty.c
@@ -815,6 +815,7 @@ struct ospf_vl_config_data {
int del_keychain;
int hello_interval; /* Obvious what these are... */
int retransmit_interval;
+ int retransmit_window;
int transmit_delay;
int dead_interval;
};
@@ -957,6 +958,12 @@ static int ospf_vl_set_timers(struct ospf_vl_data *vl_data,
vl_config->retransmit_interval;
}
+ if (vl_config->retransmit_window) {
+ SET_IF_PARAM(IF_DEF_PARAMS(ifp), retransmit_window);
+ IF_DEF_PARAMS(ifp)->retransmit_window =
+ vl_config->retransmit_window;
+ }
+
if (vl_config->transmit_delay) {
SET_IF_PARAM(IF_DEF_PARAMS(ifp), transmit_delay);
IF_DEF_PARAMS(ifp)->transmit_delay = vl_config->transmit_delay;
@@ -1012,14 +1019,16 @@ static int ospf_vl_set(struct ospf *ospf, struct ospf_vl_config_data *vl_config)
"Use null authentication\n" \
"Use message-digest authentication\n"
-#define VLINK_HELPSTR_TIME_PARAM \
- "Time between HELLO packets\n" \
- "Seconds\n" \
- "Time between retransmitting lost link state advertisements\n" \
- "Seconds\n" \
- "Link state transmit delay\n" \
- "Seconds\n" \
- "Interval time after which a neighbor is declared down\n" \
+#define VLINK_HELPSTR_TIME_PARAM \
+ "Time between HELLO packets\n" \
+ "Seconds\n" \
+ "Time between retransmitting lost link state advertisements\n" \
+ "Seconds\n" \
+ "Window for LSA retransmit - Retransmit LSAs expiring in this window\n" \
+ "Milliseconds\n" \
+ "Link state transmit delay\n" \
+ "Seconds\n" \
+ "Interval time after which a neighbor is declared down\n" \
"Seconds\n"
#define VLINK_HELPSTR_AUTH_SIMPLE \
@@ -1204,7 +1213,7 @@ DEFUN (no_ospf_area_vlink,
DEFUN (ospf_area_vlink_intervals,
ospf_area_vlink_intervals_cmd,
- "area <A.B.C.D|(0-4294967295)> virtual-link A.B.C.D {hello-interval (1-65535)|retransmit-interval (1-65535)|transmit-delay (1-65535)|dead-interval (1-65535)}",
+ "area <A.B.C.D|(0-4294967295)> virtual-link A.B.C.D {hello-interval (1-65535)|retransmit-interval (1-65535)|retransmit-window (20-10000)|transmit-delay (1-65535)|dead-interval (1-65535)}",
VLINK_HELPSTR_IPADDR
VLINK_HELPSTR_TIME_PARAM)
{
@@ -1236,6 +1245,9 @@ DEFUN (ospf_area_vlink_intervals,
else if (strmatch(argv[idx]->text, "retransmit-interval"))
vl_config.retransmit_interval =
strtol(argv[++idx]->arg, NULL, 10);
+ else if (strmatch(argv[idx]->text, "retransmit-window"))
+ vl_config.retransmit_window = strtol(argv[++idx]->arg,
+ NULL, 10);
else if (strmatch(argv[idx]->text, "transmit-delay"))
vl_config.transmit_delay =
strtol(argv[++idx]->arg, NULL, 10);
@@ -1250,7 +1262,7 @@ DEFUN (ospf_area_vlink_intervals,
DEFUN (no_ospf_area_vlink_intervals,
no_ospf_area_vlink_intervals_cmd,
- "no area <A.B.C.D|(0-4294967295)> virtual-link A.B.C.D {hello-interval (1-65535)|retransmit-interval (1-65535)|transmit-delay (1-65535)|dead-interval (1-65535)}",
+ "no area <A.B.C.D|(0-4294967295)> virtual-link A.B.C.D {hello-interval (1-65535)|retransmit-interval (1-65535)|retransmit-window (20-1000)|transmit-delay (1-65535)|dead-interval (1-65535)}",
NO_STR
VLINK_HELPSTR_IPADDR
VLINK_HELPSTR_TIME_PARAM)
@@ -1282,6 +1294,9 @@ DEFUN (no_ospf_area_vlink_intervals,
else if (strmatch(argv[idx]->text, "retransmit-interval"))
vl_config.retransmit_interval =
OSPF_RETRANSMIT_INTERVAL_DEFAULT;
+ else if (strmatch(argv[idx]->text, "retransmit-window"))
+ vl_config.retransmit_window =
+ OSPF_RETRANSMIT_WINDOW_DEFAULT;
else if (strmatch(argv[idx]->text, "transmit-delay"))
vl_config.transmit_delay = OSPF_TRANSMIT_DELAY_DEFAULT;
else if (strmatch(argv[idx]->text, "dead-interval"))
@@ -3846,6 +3861,10 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf,
json_object_int_add(
json_interface_sub, "timerRetransmitSecs",
OSPF_IF_PARAM(oi, retransmit_interval));
+ json_object_int_add(json_interface_sub,
+ "timerRetransmitWindowMsecs",
+ OSPF_IF_PARAM(oi,
+ retransmit_window));
} else {
vty_out(vty, " Timer intervals configured,");
vty_out(vty, " Hello ");
@@ -3964,6 +3983,16 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf,
"nbrFilterPrefixList",
"N/A");
}
+
+ /* Non-Traffic interface counters
+ */
+ if (use_json)
+ json_object_int_add(json_interface_sub,
+ "lsaRetransmissions",
+ oi->ls_rxmt_lsa);
+ else
+ vty_out(vty, " LSA retransmissions: %u\n",
+ oi->ls_rxmt_lsa);
}
}
@@ -5177,12 +5206,20 @@ static void show_ip_ospf_neighbor_detail_sub(struct vty *vty,
lookup_msg(ospf_ism_state_msg, ospf_nbr_ism_state(nbr),
NULL));
}
+
/* Show state changes. */
if (use_json)
json_object_int_add(json_neigh, "stateChangeCounter",
nbr->state_change);
else
- vty_out(vty, " %d state changes\n", nbr->state_change);
+ vty_out(vty, " %d state changes\n", nbr->state_change);
+
+ /* Show LSA retransmissions. */
+ if (use_json)
+ json_object_int_add(json_neigh, "lsaRetransmissions",
+ nbr->ls_rxmt_lsa);
+ else
+ vty_out(vty, " %u LSA retransmissions\n", nbr->ls_rxmt_lsa);
if (nbr->ts_last_progress.tv_sec || nbr->ts_last_progress.tv_usec) {
struct timeval res;
@@ -5231,7 +5268,7 @@ static void show_ip_ospf_neighbor_detail_sub(struct vty *vty,
if (DR(oi).s_addr == INADDR_ANY) {
if (!use_json)
vty_out(vty,
- " No designated router on this network\n");
+ " No designated router on this network\n");
} else {
nbr_dr = ospf_nbr_lookup_by_addr(oi->nbrs, &DR(oi));
if (nbr_dr) {
@@ -5250,14 +5287,14 @@ static void show_ip_ospf_neighbor_detail_sub(struct vty *vty,
if (nbr_bdr == NULL) {
if (!use_json)
vty_out(vty,
- " No backup designated router on this network\n");
+ " No backup designated router on this network\n");
} else {
if (use_json)
json_object_string_addf(json_neigh,
"routerDesignatedBackupId",
"%pI4", &nbr_bdr->router_id);
else
- vty_out(vty, " BDR is %pI4\n", &nbr_bdr->router_id);
+ vty_out(vty, " BDR is %pI4\n", &nbr_bdr->router_id);
}
/* Show options. */
@@ -5347,7 +5384,7 @@ static void show_ip_ospf_neighbor_detail_sub(struct vty *vty,
/* Show Link State Update Retransmission thread. */
if (use_json) {
- if (nbr->t_ls_upd != NULL)
+ if (nbr->t_ls_rxmt != NULL)
json_object_string_add(
json_neigh,
"threadLinkStateUpdateRetransmission",
@@ -5355,7 +5392,7 @@ static void show_ip_ospf_neighbor_detail_sub(struct vty *vty,
} else
vty_out(vty,
" Thread Link State Update Retransmission %s\n\n",
- nbr->t_ls_upd != NULL ? "on" : "off");
+ nbr->t_ls_rxmt != NULL ? "on" : "off");
if (!use_json) {
vty_out(vty, " Graceful restart Helper info:\n");
@@ -7993,7 +8030,7 @@ static void ospf_nbr_timer_update(struct ospf_interface *oi)
nbr->v_inactivity = OSPF_IF_PARAM(oi, v_wait);
nbr->v_db_desc = OSPF_IF_PARAM(oi, retransmit_interval);
nbr->v_ls_req = OSPF_IF_PARAM(oi, retransmit_interval);
- nbr->v_ls_upd = OSPF_IF_PARAM(oi, retransmit_interval);
+ nbr->v_ls_rxmt = OSPF_IF_PARAM(oi, retransmit_interval);
}
}
@@ -8728,6 +8765,40 @@ DEFUN_HIDDEN (no_ospf_retransmit_interval,
return no_ip_ospf_retransmit_interval(self, vty, argc, argv);
}
+DEFPY(ip_ospf_retransmit_window, ip_ospf_retransmit_window_addr_cmd,
+ "[no] ip ospf retransmit-window ![(20-1000)]$retransmit-window [A.B.C.D]$ip_addr", NO_STR
+ "IP Information\n"
+ "OSPF interface commands\n"
+ "Window for LSA retransmit - Retransmit LSAs expiring in this window\n"
+ "Milliseconds\n"
+ "Address of interface\n")
+{
+ VTY_DECLVAR_CONTEXT(interface, ifp);
+ struct ospf_if_params *params;
+
+ params = IF_DEF_PARAMS(ifp);
+
+ if (ip_addr.s_addr != INADDR_ANY) {
+ params = ospf_get_if_params(ifp, ip_addr);
+ ospf_if_update_params(ifp, ip_addr);
+ }
+
+ if (no) {
+ UNSET_IF_PARAM(params, retransmit_window);
+ params->retransmit_window = OSPF_RETRANSMIT_WINDOW_DEFAULT;
+ } else {
+ SET_IF_PARAM(params, retransmit_window);
+ params->retransmit_window = retransmit_window;
+ }
+
+ /*
+ * There is nothing to do when the retransmit-window changes, any
+ * change will take effect the next time the interface LSA retransmision
+ * timer expires.
+ */
+ return CMD_SUCCESS;
+}
+
DEFPY (ip_ospf_gr_hdelay,
ip_ospf_gr_hdelay_cmd,
"ip ospf graceful-restart hello-delay (1-1800)",
@@ -12210,6 +12281,17 @@ static int config_write_interface_one(struct vty *vty, struct vrf *vrf)
vty_out(vty, "\n");
}
+ /* Retransmit Window print. */
+ if (OSPF_IF_PARAM_CONFIGURED(params, retransmit_window) &&
+ params->retransmit_window !=
+ OSPF_RETRANSMIT_WINDOW_DEFAULT) {
+ vty_out(vty, " ip ospf retransmit-window %u",
+ params->retransmit_window);
+ if (params != IF_DEF_PARAMS(ifp) && rn)
+ vty_out(vty, " %pI4", &rn->p.u.prefix4);
+ vty_out(vty, "\n");
+ }
+
/* Transmit Delay print. */
if (OSPF_IF_PARAM_CONFIGURED(params, transmit_delay)
&& params->transmit_delay
@@ -12567,19 +12649,22 @@ static int config_write_virtual_link(struct vty *vty, struct ospf *ospf)
oi = vl_data->vl_oi;
/* timers */
- if (OSPF_IF_PARAM(oi, v_hello)
- != OSPF_HELLO_INTERVAL_DEFAULT
- || OSPF_IF_PARAM(oi, v_wait)
- != OSPF_ROUTER_DEAD_INTERVAL_DEFAULT
- || OSPF_IF_PARAM(oi, retransmit_interval)
- != OSPF_RETRANSMIT_INTERVAL_DEFAULT
- || OSPF_IF_PARAM(oi, transmit_delay)
- != OSPF_TRANSMIT_DELAY_DEFAULT)
+ if (OSPF_IF_PARAM(oi, v_hello) !=
+ OSPF_HELLO_INTERVAL_DEFAULT ||
+ OSPF_IF_PARAM(oi, v_wait) !=
+ OSPF_ROUTER_DEAD_INTERVAL_DEFAULT ||
+ OSPF_IF_PARAM(oi, retransmit_interval) !=
+ OSPF_RETRANSMIT_INTERVAL_DEFAULT ||
+ OSPF_IF_PARAM(oi, retransmit_window) !=
+ OSPF_RETRANSMIT_WINDOW_DEFAULT ||
+ OSPF_IF_PARAM(oi, transmit_delay) !=
+ OSPF_TRANSMIT_DELAY_DEFAULT)
vty_out(vty,
- " area %s virtual-link %pI4 hello-interval %d retransmit-interval %d transmit-delay %d dead-interval %d\n",
+ " area %s virtual-link %pI4 hello-interval %d retransmit-interval %d retransmit-window %d transmit-delay %d dead-interval %d\n",
buf, &vl_data->vl_peer,
OSPF_IF_PARAM(oi, v_hello),
OSPF_IF_PARAM(oi, retransmit_interval),
+ OSPF_IF_PARAM(oi, retransmit_window),
OSPF_IF_PARAM(oi, transmit_delay),
OSPF_IF_PARAM(oi, v_wait));
else
@@ -13112,6 +13197,9 @@ static void ospf_vty_if_init(void)
install_element(INTERFACE_NODE,
&no_ip_ospf_retransmit_interval_addr_cmd);
+ /* "ip ospf retransmit-window" commands. */
+ install_element(INTERFACE_NODE, &ip_ospf_retransmit_window_addr_cmd);
+
/* "ip ospf transmit-delay" commands. */
install_element(INTERFACE_NODE, &ip_ospf_transmit_delay_addr_cmd);
install_element(INTERFACE_NODE, &no_ip_ospf_transmit_delay_addr_cmd);
diff --git a/pimd/pim6_main.c b/pimd/pim6_main.c
index 5ce6985c45..24443404eb 100644
--- a/pimd/pim6_main.c
+++ b/pimd/pim6_main.c
@@ -94,6 +94,7 @@ struct frr_signal_t pim6d_signals[] = {
},
};
+/* clang-format off */
static const struct frr_yang_module_info *const pim6d_yang_modules[] = {
&frr_filter_info,
&frr_interface_info,
@@ -105,7 +106,6 @@ static const struct frr_yang_module_info *const pim6d_yang_modules[] = {
&frr_gmp_info,
};
-/* clang-format off */
FRR_DAEMON_INFO(pim6d, PIM6,
.vty_port = PIM6D_VTY_PORT,
.proghelp = "Protocol Independent Multicast (RFC7761) for IPv6",
diff --git a/pimd/pim_addr.h b/pimd/pim_addr.h
index ecba739a5a..7b0c3f0350 100644
--- a/pimd/pim_addr.h
+++ b/pimd/pim_addr.h
@@ -14,11 +14,13 @@
#if PIM_IPV == 4
typedef struct in_addr pim_addr;
+typedef struct prefix_ipv4 prefix_pim;
#define PIM_ADDRSTRLEN INET_ADDRSTRLEN
#define PIM_AF AF_INET
#define PIM_AFI AFI_IP
#define PIM_PROTO_REG IPPROTO_RAW
+#define PIM_IANA_AFI IANA_AFI_IPV4
#define PIM_IPADDR IPADDR_V4
#define ipaddr_pim ipaddr_v4
#define PIM_MAX_BITLEN IPV4_MAX_BITLEN
@@ -44,11 +46,13 @@ union pimprefixconstptr {
#else
typedef struct in6_addr pim_addr;
+typedef struct prefix_ipv6 prefix_pim;
#define PIM_ADDRSTRLEN INET6_ADDRSTRLEN
#define PIM_AF AF_INET6
#define PIM_AFI AFI_IP6
#define PIM_PROTO_REG IPPROTO_PIM
+#define PIM_IANA_AFI IANA_AFI_IPV6
#define PIM_IPADDR IPADDR_V6
#define ipaddr_pim ipaddr_v6
#define PIM_MAX_BITLEN IPV6_MAX_BITLEN
diff --git a/pimd/pim_bsm.c b/pimd/pim_bsm.c
index df9161943d..2d451718a9 100644
--- a/pimd/pim_bsm.c
+++ b/pimd/pim_bsm.c
@@ -1451,3 +1451,8 @@ int pim_bsm_process(struct interface *ifp, pim_sgaddr *sg, uint8_t *buf,
return 0;
}
+
+void pim_crp_nht_update(struct pim_instance *pim, struct pim_nexthop_cache *pnc)
+{
+ /* stub for Candidate-RP */
+}
diff --git a/pimd/pim_main.c b/pimd/pim_main.c
index 400db396c2..8f2ce0bed3 100644
--- a/pimd/pim_main.c
+++ b/pimd/pim_main.c
@@ -59,6 +59,7 @@ struct zebra_privs_t pimd_privs = {
.cap_num_p = array_size(_caps_p),
.cap_num_i = 0};
+/* clang-format off */
static const struct frr_yang_module_info *const pimd_yang_modules[] = {
&frr_filter_info,
&frr_interface_info,
@@ -70,7 +71,6 @@ static const struct frr_yang_module_info *const pimd_yang_modules[] = {
&frr_gmp_info,
};
-/* clang-format off */
FRR_DAEMON_INFO(pimd, PIM,
.vty_port = PIMD_VTY_PORT,
.proghelp = "Implementation of the PIM routing protocol.",
diff --git a/pimd/pim_nht.c b/pimd/pim_nht.c
index 32cdf4bf82..57dcff3b47 100644
--- a/pimd/pim_nht.c
+++ b/pimd/pim_nht.c
@@ -161,18 +161,27 @@ void pim_nht_bsr_add(struct pim_instance *pim, pim_addr addr)
pnc->bsr_count++;
}
+bool pim_nht_candrp_add(struct pim_instance *pim, pim_addr addr)
+{
+ struct pim_nexthop_cache *pnc;
+
+ pnc = pim_nht_get(pim, addr);
+
+ pnc->candrp_count++;
+ return CHECK_FLAG(pnc->flags, PIM_NEXTHOP_VALID);
+}
+
static void pim_nht_drop_maybe(struct pim_instance *pim,
struct pim_nexthop_cache *pnc)
{
if (PIM_DEBUG_PIM_NHT)
- zlog_debug(
- "%s: NHT %pPA(%s) rp_list count:%d upstream count:%ld BSR count:%u",
- __func__, &pnc->rpf.rpf_addr, pim->vrf->name,
- pnc->rp_list->count, pnc->upstream_hash->count,
- pnc->bsr_count);
+ zlog_debug("%s: NHT %pPA(%s) rp_list count:%d upstream count:%ld BSR count:%u Cand-RP count:%u",
+ __func__, &pnc->rpf.rpf_addr, pim->vrf->name,
+ pnc->rp_list->count, pnc->upstream_hash->count,
+ pnc->bsr_count, pnc->candrp_count);
- if (pnc->rp_list->count == 0 && pnc->upstream_hash->count == 0
- && pnc->bsr_count == 0) {
+ if (pnc->rp_list->count == 0 && pnc->upstream_hash->count == 0 &&
+ pnc->bsr_count == 0 && pnc->candrp_count == 0) {
struct zclient *zclient = pim_zebra_zclient_get();
pim_sendmsg_zebra_rnh(pim, zclient, pnc,
@@ -258,6 +267,27 @@ void pim_nht_bsr_del(struct pim_instance *pim, pim_addr addr)
pim_nht_drop_maybe(pim, pnc);
}
+void pim_nht_candrp_del(struct pim_instance *pim, pim_addr addr)
+{
+ struct pim_nexthop_cache *pnc = NULL;
+ struct pim_nexthop_cache lookup;
+
+ lookup.rpf.rpf_addr = addr;
+
+ pnc = hash_lookup(pim->rpf_hash, &lookup);
+
+ if (!pnc) {
+ zlog_warn("attempting to delete nonexistent NHT C-RP entry %pPA",
+ &addr);
+ return;
+ }
+
+ assertf(pnc->candrp_count > 0, "addr=%pPA", &addr);
+ pnc->candrp_count--;
+
+ pim_nht_drop_maybe(pim, pnc);
+}
+
bool pim_nht_bsr_rpf_check(struct pim_instance *pim, pim_addr bsr_addr,
struct interface *src_ifp, pim_addr src_ip)
{
@@ -900,6 +930,9 @@ void pim_nexthop_update(struct vrf *vrf, struct prefix *match,
pim_update_rp_nh(pim, pnc);
if (pnc->upstream_hash->count)
pim_update_upstream_nh(pim, pnc);
+
+ if (pnc->candrp_count)
+ pim_crp_nht_update(pim, pnc);
}
int pim_ecmp_nexthop_lookup(struct pim_instance *pim,
diff --git a/pimd/pim_nht.h b/pimd/pim_nht.h
index a1feb76e3b..e74b375dc6 100644
--- a/pimd/pim_nht.h
+++ b/pimd/pim_nht.h
@@ -38,6 +38,7 @@ struct pim_nexthop_cache {
* same BSR
*/
uint32_t bsr_count;
+ uint32_t candrp_count;
};
struct pnc_hash_walk_data {
@@ -71,4 +72,10 @@ void pim_nht_bsr_del(struct pim_instance *pim, pim_addr bsr_addr);
bool pim_nht_bsr_rpf_check(struct pim_instance *pim, pim_addr bsr_addr,
struct interface *src_ifp, pim_addr src_ip);
void pim_upstream_nh_if_update(struct pim_instance *pim, struct interface *ifp);
+
+/* wrappers for usage with Candidate RPs in BSMs */
+bool pim_nht_candrp_add(struct pim_instance *pim, pim_addr addr);
+void pim_nht_candrp_del(struct pim_instance *pim, pim_addr addr);
+void pim_crp_nht_update(struct pim_instance *pim, struct pim_nexthop_cache *pnc);
+
#endif
diff --git a/pimd/pim_pim.c b/pimd/pim_pim.c
index 1bc265b138..6a7e8924f2 100644
--- a/pimd/pim_pim.c
+++ b/pimd/pim_pim.c
@@ -636,17 +636,15 @@ static int pim_msg_send_frame(pim_addr src, pim_addr dst, ifindex_t ifindex,
int pim_msg_send(int fd, pim_addr src, pim_addr dst, uint8_t *pim_msg,
int pim_msg_size, struct interface *ifp)
{
- struct pim_interface *pim_ifp;
-
+ if (ifp) {
+ struct pim_interface *pim_ifp = ifp->info;
- pim_ifp = ifp->info;
-
- if (pim_ifp->pim_passive_enable) {
- if (PIM_DEBUG_PIM_PACKETS)
- zlog_debug(
- "skip sending PIM message on passive interface %s",
- ifp->name);
- return 0;
+ if (pim_ifp->pim_passive_enable) {
+ if (PIM_DEBUG_PIM_PACKETS)
+ zlog_debug("skip sending PIM message on passive interface %s",
+ ifp->name);
+ return 0;
+ }
}
#if PIM_IPV == 4
@@ -710,7 +708,7 @@ int pim_msg_send(int fd, pim_addr src, pim_addr dst, uint8_t *pim_msg,
if (PIM_DEBUG_PIM_PACKETS)
zlog_debug("%s: to %pPA on %s: msg_size=%d checksum=%x",
- __func__, &dst, ifp->name, pim_msg_size,
+ __func__, &dst, ifp ? ifp->name : "*", pim_msg_size,
header->checksum);
if (PIM_DEBUG_PIM_PACKETDUMP_SEND) {
@@ -718,7 +716,7 @@ int pim_msg_send(int fd, pim_addr src, pim_addr dst, uint8_t *pim_msg,
}
pim_msg_send_frame(fd, (char *)buffer, sendlen, (struct sockaddr *)&to,
- tolen, ifp->name);
+ tolen, ifp ? ifp->name : "*");
return 0;
#else
@@ -727,7 +725,7 @@ int pim_msg_send(int fd, pim_addr src, pim_addr dst, uint8_t *pim_msg,
iovector[0].iov_base = pim_msg;
iovector[0].iov_len = pim_msg_size;
- pim_msg_send_frame(src, dst, ifp->ifindex, &iovector[0], fd);
+ pim_msg_send_frame(src, dst, ifp ? ifp->ifindex : 0, &iovector[0], fd);
return 0;
#endif
diff --git a/pimd/pim_rp.c b/pimd/pim_rp.c
index d8d25712a3..b0fb8a509a 100644
--- a/pimd/pim_rp.c
+++ b/pimd/pim_rp.c
@@ -543,6 +543,9 @@ int pim_rp_new(struct pim_instance *pim, pim_addr rp_addr, struct prefix group,
pim_zebra_update_all_interfaces(pim);
pim_rp_check_interfaces(pim, rp_all);
+ if (rp_all->i_am_rp && PIM_DEBUG_PIM_NHT_RP)
+ zlog_debug("new RP %pPA for %pFX is ourselves",
+ &rp_all->rp.rpf_addr, &rp_all->group);
pim_rp_refresh_group_to_rp_mapping(pim);
pim_find_or_track_nexthop(pim, nht_p, NULL, rp_all,
NULL);
@@ -634,6 +637,9 @@ int pim_rp_new(struct pim_instance *pim, pim_addr rp_addr, struct prefix group,
pim_zebra_update_all_interfaces(pim);
pim_rp_check_interfaces(pim, rp_info);
+ if (rp_info->i_am_rp && PIM_DEBUG_PIM_NHT_RP)
+ zlog_debug("new RP %pPA for %pFX is ourselves",
+ &rp_info->rp.rpf_addr, &rp_info->group);
pim_rp_refresh_group_to_rp_mapping(pim);
/* Register addr with Zebra NHT */
diff --git a/tests/topotests/all_protocol_startup/r1/show_ip_ospf_interface.ref b/tests/topotests/all_protocol_startup/r1/show_ip_ospf_interface.ref
index f52b51d9d8..e4e3290111 100644
--- a/tests/topotests/all_protocol_startup/r1/show_ip_ospf_interface.ref
+++ b/tests/topotests/all_protocol_startup/r1/show_ip_ospf_interface.ref
@@ -11,6 +11,7 @@ r1-eth0 is up
Hello due in XX.XXXs
Neighbor Count is 0, Adjacent neighbor count is 0
Graceful Restart hello delay: 10s
+ LSA retransmissions: 0
r1-eth3 is up
ifindex X, MTU 1500 bytes, BW XX Mbit <UP,LOWER_UP,BROADCAST,RUNNING,MULTICAST>
Internet Address 192.168.3.1/26, Broadcast 192.168.3.63, Area 0.0.0.0
@@ -24,3 +25,4 @@ r1-eth3 is up
Hello due in XX.XXXs
Neighbor Count is 0, Adjacent neighbor count is 0
Graceful Restart hello delay: 10s
+ LSA retransmissions: 0
diff --git a/tests/topotests/bgp_set_aspath_exclude/r1/bgpd.conf b/tests/topotests/bgp_set_aspath_exclude/r1/bgpd.conf
index 9bef24f931..c70b4934a0 100644
--- a/tests/topotests/bgp_set_aspath_exclude/r1/bgpd.conf
+++ b/tests/topotests/bgp_set_aspath_exclude/r1/bgpd.conf
@@ -8,10 +8,19 @@ router bgp 65001
exit-address-family
!
ip prefix-list p1 seq 5 permit 172.16.255.31/32
+ip prefix-list p2 seq 5 permit 172.16.255.32/32
+ip prefix-list p3 seq 5 permit 172.16.255.30/32
!
+bgp as-path access-list FIRST permit ^65
+bgp as-path access-list SECOND permit 2$
+
+route-map r2 permit 6
+ match ip address prefix-list p2
+ set as-path exclude as-path-access-list SECOND
route-map r2 permit 10
match ip address prefix-list p1
set as-path exclude 65003
route-map r2 permit 20
+ match ip address prefix-list p3
set as-path exclude all
!
diff --git a/tests/topotests/bgp_set_aspath_exclude/r3/zebra.conf b/tests/topotests/bgp_set_aspath_exclude/r3/zebra.conf
index 3fa6c64484..56893158a4 100644
--- a/tests/topotests/bgp_set_aspath_exclude/r3/zebra.conf
+++ b/tests/topotests/bgp_set_aspath_exclude/r3/zebra.conf
@@ -1,5 +1,6 @@
!
int lo
+ ip address 172.16.255.30/32
ip address 172.16.255.31/32
ip address 172.16.255.32/32
!
diff --git a/tests/topotests/bgp_set_aspath_exclude/test_bgp_set_aspath_exclude.py b/tests/topotests/bgp_set_aspath_exclude/test_bgp_set_aspath_exclude.py
index 64cc48e54f..63f1719e1d 100644
--- a/tests/topotests/bgp_set_aspath_exclude/test_bgp_set_aspath_exclude.py
+++ b/tests/topotests/bgp_set_aspath_exclude/test_bgp_set_aspath_exclude.py
@@ -64,29 +64,33 @@ def teardown_module(mod):
expected_1 = {
"routes": {
+ "172.16.255.30/32": [{"path": ""}],
"172.16.255.31/32": [{"path": "65002"}],
- "172.16.255.32/32": [{"path": ""}],
+ "172.16.255.32/32": [{"path": "65003"}],
}
}
expected_2 = {
"routes": {
- "172.16.255.31/32": [{"path": ""}],
+ "172.16.255.30/32": [{"path": ""}],
+ "172.16.255.31/32": [{"path": "65002"}],
"172.16.255.32/32": [{"path": ""}],
}
}
expected_3 = {
"routes": {
- "172.16.255.31/32": [{"path": "65003"}],
- "172.16.255.32/32": [{"path": "65003"}],
+ "172.16.255.30/32": [{"path": ""}],
+ "172.16.255.31/32": [{"path": "65002"}],
+ "172.16.255.32/32": [{"path": "65002 65003"}],
}
}
expected_4 = {
"routes": {
- "172.16.255.31/32": [{"path": "65002 65003"}],
- "172.16.255.32/32": [{"path": "65002 65003"}],
+ "172.16.255.30/32": [{"path": ""}],
+ "172.16.255.31/32": [{"path": "65002"}],
+ "172.16.255.32/32": [{"path": "65002"}],
}
}
@@ -117,34 +121,42 @@ def test_bgp_set_aspath_exclude_access_list():
rname = "r1"
r1 = tgen.gears[rname]
+ # tgen.mininet_cli()
r1.vtysh_cmd(
"""
conf
bgp as-path access-list FIRST permit ^65
route-map r2 permit 6
+ no set as-path exclude as-path-access-list SECOND
set as-path exclude as-path-access-list FIRST
"""
)
+ # tgen.mininet_cli()
+ r1.vtysh_cmd(
+ """
+clear bgp *
+ """
+ )
test_func = functools.partial(bgp_converge, tgen.gears["r1"], expected_2)
_, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5)
- assert result is None, "Failed overriding incoming AS-PATH with regex 1 route-map"
+ assert result is None, "Failed change of exclude rule in route map"
r1.vtysh_cmd(
"""
conf
- bgp as-path access-list SECOND permit 2
route-map r2 permit 6
+ no set as-path exclude as-path-access-list FIRST
set as-path exclude as-path-access-list SECOND
"""
)
# tgen.mininet_cli()
- test_func = functools.partial(bgp_converge, tgen.gears["r1"], expected_3)
+ test_func = functools.partial(bgp_converge, tgen.gears["r1"], expected_1)
_, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5)
- assert result is None, "Failed overriding incoming AS-PATH with regex 2 route-map"
+ assert result is None, "Failed reverting exclude rule in route map"
def test_no_bgp_set_aspath_exclude_access_list():
@@ -159,15 +171,28 @@ def test_no_bgp_set_aspath_exclude_access_list():
r1.vtysh_cmd(
"""
conf
- no bgp as-path access-list SECOND permit 2
+ no bgp as-path access-list SECOND permit 2$
+ """
+ )
+
+ r1.vtysh_cmd(
+ """
+clear bgp *
"""
)
test_func = functools.partial(bgp_converge, tgen.gears["r1"], expected_3)
_, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5)
- assert result is None, "Failed removing bgp as-path access-list"
+ assert result is None, "Failed to removing current accesslist"
+ # tgen.mininet_cli()
+ r1.vtysh_cmd(
+ """
+conf
+ bgp as-path access-list SECOND permit 3$
+ """
+ )
r1.vtysh_cmd(
"""
clear bgp *
@@ -177,7 +202,26 @@ clear bgp *
test_func = functools.partial(bgp_converge, tgen.gears["r1"], expected_4)
_, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5)
- assert result is None, "Failed to renegotiate with peers"
+ assert result is None, "Failed to renegotiate with peers 2"
+
+ r1.vtysh_cmd(
+ """
+conf
+ route-map r2 permit 6
+ no set as-path exclude as-path-access-list SECOND
+ """
+ )
+
+ r1.vtysh_cmd(
+ """
+clear bgp *
+ """
+ )
+
+ test_func = functools.partial(bgp_converge, tgen.gears["r1"], expected_3)
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5)
+
+ assert result is None, "Failed to renegotiate with peers 2"
if __name__ == "__main__":
diff --git a/tests/topotests/ospf_p2mp/r1/frr-p2mp.conf b/tests/topotests/ospf_p2mp/r1/frr-p2mp.conf
index cb4538c0e3..89f255bb44 100644
--- a/tests/topotests/ospf_p2mp/r1/frr-p2mp.conf
+++ b/tests/topotests/ospf_p2mp/r1/frr-p2mp.conf
@@ -1,4 +1,10 @@
!
+!log file ospfd.log debug
+! debug ospf event
+! debug ospf client
+! debug ospf lsa
+! debug ospf packet all
+
hostname r1
password zebra
log file /tmp/r1-frr.log
diff --git a/tests/topotests/ospf_p2mp/r2/frr-p2mp.conf b/tests/topotests/ospf_p2mp/r2/frr-p2mp.conf
index 0ca8aec3bf..429330987e 100644
--- a/tests/topotests/ospf_p2mp/r2/frr-p2mp.conf
+++ b/tests/topotests/ospf_p2mp/r2/frr-p2mp.conf
@@ -1,4 +1,10 @@
!
+!log file ospfd.log debug
+! debug ospf event
+! debug ospf client
+! debug ospf lsa
+! debug ospf packet all
+!
hostname r2
password zebra
log file /tmp/r1-frr.log
diff --git a/tests/topotests/ospf_p2mp/r3/frr-p2mp.conf b/tests/topotests/ospf_p2mp/r3/frr-p2mp.conf
index 41ea70d443..eada78450e 100644
--- a/tests/topotests/ospf_p2mp/r3/frr-p2mp.conf
+++ b/tests/topotests/ospf_p2mp/r3/frr-p2mp.conf
@@ -1,4 +1,10 @@
!
+!log file ospfd.log debug
+! debug ospf event
+! debug ospf client
+! debug ospf lsa
+! debug ospf packet all
+!
hostname r3
password zebra
log file /tmp/r1-frr.log
diff --git a/tests/topotests/ospf_p2mp/r4/frr-p2mp.conf b/tests/topotests/ospf_p2mp/r4/frr-p2mp.conf
index 21fa9c72f9..3146ea0957 100644
--- a/tests/topotests/ospf_p2mp/r4/frr-p2mp.conf
+++ b/tests/topotests/ospf_p2mp/r4/frr-p2mp.conf
@@ -1,4 +1,10 @@
!
+!log file ospfd.log debug
+! debug ospf event
+! debug ospf client
+! debug ospf lsa
+! debug ospf packet all
+!
hostname r4
password zebra
log file /tmp/r1-frr.log
diff --git a/tests/topotests/ospf_p2mp/test_ospf_p2mp_broadcast.py b/tests/topotests/ospf_p2mp/test_ospf_p2mp_broadcast.py
index d52c8147fe..455c737f0d 100644
--- a/tests/topotests/ospf_p2mp/test_ospf_p2mp_broadcast.py
+++ b/tests/topotests/ospf_p2mp/test_ospf_p2mp_broadcast.py
@@ -9,6 +9,7 @@
import os
import sys
+from time import sleep
from functools import partial
import pytest
@@ -113,7 +114,9 @@ def teardown_module():
tgen.stop_topology()
-def verify_p2mp_interface(tgen, router, nbr_cnt, nbr_adj_cnt, nbr_filter):
+def verify_p2mp_interface(
+ tgen, router, nbr_cnt, nbr_adj_cnt, delay_reflood, nbr_filter
+):
"Verify the P2MP Configuration and interface settings"
topo_router = tgen.gears[router]
@@ -147,7 +150,7 @@ def verify_p2mp_interface(tgen, router, nbr_cnt, nbr_adj_cnt, nbr_filter):
"nbrCount": nbr_cnt,
"nbrAdjacentCount": nbr_adj_cnt,
"prefixSuppression": False,
- "p2mpDelayReflood": False,
+ "p2mpDelayReflood": delay_reflood,
"nbrFilterPrefixList": nbr_filter,
}
}
@@ -280,7 +283,7 @@ def test_p2mp_broadcast_interface():
pytest.skip("Skipped because of router(s) failure")
step("Verify router r1 interface r1-eth0 p2mp configuration")
- verify_p2mp_interface(tgen, "r1", 3, 3, "N/A")
+ verify_p2mp_interface(tgen, "r1", 3, 3, False, "N/A")
step("Verify router r1 p2mp interface r1-eth0 neighbors")
verify_p2mp_neighbor(
@@ -305,7 +308,7 @@ def test_p2mp_broadcast_interface():
step("Verify router r1 interface r1-eth0 p2mp configuration application")
r1.vtysh_cmd("conf t\ninterface r1-eth0\nip ospf network point-to-multipoint")
- verify_p2mp_interface(tgen, "r1", 3, 3, "N/A")
+ verify_p2mp_interface(tgen, "r1", 3, 3, False, "N/A")
step("Verify restablishment of r1-eth0 p2mp neighbors")
verify_p2mp_neighbor(
@@ -324,14 +327,14 @@ def test_p2mp_broadcast_interface():
verify_p2mp_route(tgen, "r1", "10.1.4.0/24", 24, "10.1.0.4", "r1-eth0")
-def test_p2mp_broadcast_neighbor_filter():
+def p2mp_broadcast_neighbor_filter_common(delay_reflood):
tgen = get_topogen()
if tgen.routers_have_failure():
pytest.skip("Skipped because of router(s) failure")
step("Verify router r1 interface r1-eth0 p2mp configuration")
- verify_p2mp_interface(tgen, "r1", 3, 3, "N/A")
+ verify_p2mp_interface(tgen, "r1", 3, 3, delay_reflood, "N/A")
step("Verify router r1 p2mp interface r1-eth0 neighbors")
verify_p2mp_neighbor(
@@ -362,7 +365,7 @@ def test_p2mp_broadcast_neighbor_filter():
assert neighbor_filter_cfg == " ip ospf neighbor-filter nbr-filter", assertmsg
step("Verify non-existent neighbor-filter is not applied to r1 interfaces")
- verify_p2mp_interface(tgen, "r1", 3, 3, "N/A")
+ verify_p2mp_interface(tgen, "r1", 3, 3, delay_reflood, "N/A")
step("Add nbr-filter prefix-list configuration to r1")
r1.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 200 permit any")
@@ -370,7 +373,7 @@ def test_p2mp_broadcast_neighbor_filter():
step(
"Verify neighbor-filter is now applied to r1 interface and neighbors still adjacent"
)
- verify_p2mp_interface(tgen, "r1", 3, 3, "nbr-filter")
+ verify_p2mp_interface(tgen, "r1", 3, 3, delay_reflood, "nbr-filter")
step("Add nbr-filter prefix-list configuration to block r4")
r1.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 10 deny 10.1.0.4/32")
@@ -378,7 +381,7 @@ def test_p2mp_broadcast_neighbor_filter():
step(
"Verify neighbor-filter is now applied to r1 interface and r4 is no longer adjacent"
)
- verify_p2mp_interface(tgen, "r1", 2, 2, "nbr-filter")
+ verify_p2mp_interface(tgen, "r1", 2, 2, delay_reflood, "nbr-filter")
verify_p2mp_neighbor_missing(tgen, "r1", "4.4.4.4")
step("Verify route to r4 subnet is now through r2")
@@ -390,7 +393,7 @@ def test_p2mp_broadcast_neighbor_filter():
step(
"Verify neighbor-filter is now applied to r1 interface and r2 is no longer adjacent"
)
- verify_p2mp_interface(tgen, "r1", 1, 1, "nbr-filter")
+ verify_p2mp_interface(tgen, "r1", 1, 1, delay_reflood, "nbr-filter")
verify_p2mp_neighbor_missing(tgen, "r1", "2.2.2.2")
step("Verify route to r4 and r2 subnet are now through r3")
@@ -406,24 +409,105 @@ def test_p2mp_broadcast_neighbor_filter():
assert rc, assertmsg
step("Verify interface neighbor-filter is removed and neighbors present")
- verify_p2mp_interface(tgen, "r1", 3, 3, "N/A")
+ verify_p2mp_interface(tgen, "r1", 3, 3, delay_reflood, "N/A")
step("Add neighbor filter configuration and verify neighbors are filtered")
r1.vtysh_cmd("conf t\ninterface r1-eth0\nip ospf neighbor-filter nbr-filter")
- verify_p2mp_interface(tgen, "r1", 1, 1, "nbr-filter")
+ verify_p2mp_interface(tgen, "r1", 1, 1, delay_reflood, "nbr-filter")
verify_p2mp_neighbor_missing(tgen, "r1", "2.2.2.2")
verify_p2mp_neighbor_missing(tgen, "r1", "4.4.4.4")
step("Remove nbr-filter prefix-list configuration to block r2 and verify neighbor")
r1.vtysh_cmd("conf t\nno ip prefix-list nbr-filter seq 20")
- verify_p2mp_interface(tgen, "r1", 2, 2, "nbr-filter")
+ verify_p2mp_interface(tgen, "r1", 2, 2, delay_reflood, "nbr-filter")
verify_p2mp_neighbor(
tgen, "r1", "2.2.2.2", "Full/DROther", "10.1.0.2", "r1-eth0:10.1.0.1"
)
step("Delete nbr-filter prefix-list and verify neighbors are present")
r1.vtysh_cmd("conf t\nno ip prefix-list nbr-filter")
- verify_p2mp_interface(tgen, "r1", 3, 3, "N/A")
+ verify_p2mp_interface(tgen, "r1", 3, 3, delay_reflood, "N/A")
+
+
+def test_p2mp_broadcast_neighbor_filter():
+ p2mp_broadcast_neighbor_filter_common(False)
+
+
+def test_p2mp_broadcast_neighbor_filter_delay_reflood():
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip("Skipped because of router(s) failure")
+
+ step("Modify router r1 interface r1-eth0 p2mp delay-reflood configuration")
+ r1 = tgen.gears["r1"]
+ r1.vtysh_cmd(
+ "conf t\ninterface r1-eth0\nip ospf network point-to-multipoint delay-reflood"
+ )
+ verify_p2mp_interface(tgen, "r1", 3, 3, True, "N/A")
+
+ step("Modify router r2 interface r2-eth0 p2mp delay-reflood configuration")
+ r2 = tgen.gears["r2"]
+ r2.vtysh_cmd(
+ "conf t\ninterface r2-eth0\nip ospf network point-to-multipoint delay-reflood"
+ )
+
+ step("Modify router r3 interface r3-eth0 p2mp delay-reflood configuration")
+ r3 = tgen.gears["r3"]
+ r3.vtysh_cmd(
+ "conf t\ninterface r3-eth0\nip ospf network point-to-multipoint delay-reflood"
+ )
+
+ step("Modify router r4 interface r4-eth0 p2mp delay-reflood configuration")
+ r4 = tgen.gears["r4"]
+ r4.vtysh_cmd(
+ "conf t\ninterface r4-eth0\nip ospf network point-to-multipoint delay-reflood"
+ )
+
+ p2mp_broadcast_neighbor_filter_common(True)
+
+ step("Recreate a partial P2MP mesh with neighbor filters")
+ step("Add nbr-filter prefix-list configuration to block r4")
+ r1.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 30 permit any")
+ r1.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 10 deny 10.1.0.3/32")
+ r1.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 20 deny 10.1.0.4/32")
+ r1.vtysh_cmd("conf t\ninterface r1-eth0\nip ospf neighbor-filter nbr-filter")
+
+ r2.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 30 permit any")
+ r2.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 10 deny 10.1.0.4/32")
+ r2.vtysh_cmd("conf t\ninterface r2-eth0\nip ospf neighbor-filter nbr-filter")
+
+ r3.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 30 permit any")
+ r3.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 10 deny 10.1.0.1/32")
+ r3.vtysh_cmd("conf t\ninterface r3-eth0\nip ospf neighbor-filter nbr-filter")
+
+ r4.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 30 permit any")
+ r4.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 10 deny 10.1.0.1/32")
+ r4.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 20 deny 10.1.0.2/32")
+ r4.vtysh_cmd("conf t\ninterface r4-eth0\nip ospf neighbor-filter nbr-filter")
+
+ step(
+ "Add redistribution and spaced static routes to r1 to test delay flood retransmission"
+ )
+ r1.vtysh_cmd("conf t\nrouter ospf\nredistribute static")
+ r1.vtysh_cmd("conf t\nip route 20.1.1.1/32 null0")
+ sleep(1)
+ r1.vtysh_cmd("conf t\nip route 20.1.1.2/32 null0")
+ sleep(1)
+ r1.vtysh_cmd("conf t\nip route 20.1.1.3/32 null0")
+ sleep(1)
+ r1.vtysh_cmd("conf t\nip route 20.1.1.4/32 null0")
+ sleep(1)
+ r1.vtysh_cmd("conf t\nip route 20.1.1.5/32 null0")
+ sleep(1)
+
+ step(
+ "Verify the routes are installed on r1 with delay-reflood in P2MP partial mesh"
+ )
+ verify_p2mp_route(tgen, "r4", "20.1.1.1/32", 32, "10.1.0.3", "r4-eth0")
+ verify_p2mp_route(tgen, "r4", "20.1.1.2/32", 32, "10.1.0.3", "r4-eth0")
+ verify_p2mp_route(tgen, "r4", "20.1.1.3/32", 32, "10.1.0.3", "r4-eth0")
+ verify_p2mp_route(tgen, "r4", "20.1.1.4/32", 32, "10.1.0.3", "r4-eth0")
def test_memory_leak():
diff --git a/tools/checkpatch.pl b/tools/checkpatch.pl
index f52f1a1616..3e7abeda39 100755
--- a/tools/checkpatch.pl
+++ b/tools/checkpatch.pl
@@ -4668,6 +4668,7 @@ sub process {
# check for new typedefs, only function parameters and sparse annotations
# make sense.
if ($line =~ /\btypedef\s/ &&
+ $line !~ /\btypedef.*\s(pim_[^\s]+|[^\s]+_pim)\s*;/ &&
$line !~ /\btypedef\s+$Type\s*\(\s*\*?$Ident\s*\)\s*\(/ &&
$line !~ /\btypedef\s+$Type\s+$Ident\s*\(/ &&
$line !~ /\b$typeTypedefs\b/ &&
diff --git a/zebra/zebra_nb_rpcs.c b/zebra/zebra_nb_rpcs.c
index 938193df2f..744ba620f2 100644
--- a/zebra/zebra_nb_rpcs.c
+++ b/zebra/zebra_nb_rpcs.c
@@ -12,6 +12,8 @@
#include "zebra/zebra_router.h"
#include "zebra/zebra_vrf.h"
#include "zebra/zebra_vxlan.h"
+#include "zebra/zebra_vxlan_if.h"
+#include "zebra/zebra_evpn.h"
/*
* XPath: /frr-zebra:clear-evpn-dup-addr
@@ -21,6 +23,11 @@ int clear_evpn_dup_addr_rpc(struct nb_cb_rpc_args *args)
struct zebra_vrf *zvrf;
int ret = NB_OK;
+ if (!is_evpn_enabled()) {
+ snprintf(args->errmsg, args->errmsg_len,
+ "%% EVPN not enabled\n");
+ return NB_ERR_VALIDATION;
+ }
zvrf = zebra_vrf_get_evpn();
if (yang_dnode_exists(args->input, "all-vnis")) {
@@ -30,6 +37,12 @@ int clear_evpn_dup_addr_rpc(struct nb_cb_rpc_args *args)
struct ipaddr host_ip = {.ipa_type = IPADDR_NONE};
struct ethaddr mac;
+ if (!zebra_evpn_lookup(vni)) {
+ snprintf(args->errmsg, args->errmsg_len,
+ "%% VNI %u does not exist\n", vni);
+ return NB_ERR_VALIDATION;
+ }
+
if (yang_dnode_exists(args->input, "mac-addr")) {
yang_dnode_get_mac(&mac, args->input, "mac-addr");
ret = zebra_vxlan_clear_dup_detect_vni_mac(zvrf, vni,