mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-03 04:01:59 +00:00
Merge pull request #16128 from LabNConsulting/aceelindem/ospf-ls-retrans-improve
ospfd: Improve OSPF neighbor retransmission list granularity and pacing
This commit is contained in:
commit
87c2f100e1
69
doc/developer/ospf-ls-retrans.rst
Normal file
69
doc/developer/ospf-ls-retrans.rst
Normal file
@ -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.
|
||||
|
@ -8,6 +8,7 @@ OSPFD
|
||||
:maxdepth: 2
|
||||
|
||||
ospf-api
|
||||
ospf-ls-retrans
|
||||
ospf-sr
|
||||
cspf
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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));
|
||||
/*
|
||||
* 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.
|
||||
* Set the LSA retransmission time for the neighbor;
|
||||
*/
|
||||
if (IS_DEBUG_OSPF(lsa, LSA_FLOODING))
|
||||
zlog_debug("RXmtL(%lu)++, NBR(%pI4(%s)), LSA[%s]",
|
||||
ospf_ls_retransmit_count(nbr),
|
||||
&nbr->router_id,
|
||||
ospf_get_name(nbr->oi->ospf),
|
||||
dump_lsa_key(lsa));
|
||||
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);
|
||||
|
||||
/*
|
||||
* 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)) 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),
|
||||
(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_ls_retransmit_count(nbr),
|
||||
&nbr->router_id,
|
||||
ospf_get_name(nbr->oi->ospf),
|
||||
dump_lsa_key(lsa));
|
||||
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),
|
||||
dump_lsa_key(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(¤t_time);
|
||||
if (timercmp(¤t_time,
|
||||
&ls_rxmt_list_entry->list_entry_time, >=))
|
||||
delay_milliseconds = 10;
|
||||
else {
|
||||
timersub(&ls_rxmt_list_entry->list_entry_time,
|
||||
¤t_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)
|
||||
|
@ -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 *,
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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");
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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(¤t_time);
|
||||
timeradd(¤t_time, &rxmt_window, &latest_rxmt_time);
|
||||
timeradd(¤t_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;
|
||||
listnode_add(update, ls_rxmt_list_entry->lsa);
|
||||
rxmt_lsa_count++;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* 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)
|
||||
|
@ -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);
|
||||
|
140
ospfd/ospf_vty.c
140
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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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():
|
||||
|
Loading…
Reference in New Issue
Block a user