Merge pull request #11289 from LabNConsulting/chopps/ospfapi-update

ospfapi improvements and fixes
This commit is contained in:
Donald Sharp 2022-06-07 11:00:56 -04:00 committed by GitHub
commit a775175bfd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
33 changed files with 2493 additions and 152 deletions

View File

@ -1,3 +1,4 @@
usr/lib/frr/frr-reload.py
usr/lib/frr/generate_support_bundle.py
usr/lib/frr/frr_babeltrace.py
usr/lib/frr/ospfclient.py

View File

@ -212,7 +212,8 @@ options from the list below.
.. option:: --disable-ospfclient
Disable building of the example OSPF-API client.
Disable installation of the python ospfclient and building of the example
OSPF-API client.
.. option:: --disable-isisd

View File

@ -867,6 +867,12 @@ Opaque LSA
Show Opaque LSA from the database.
.. clicmd:: show ip ospf (1-65535) reachable-routers
.. clicmd:: show ip ospf [vrf <NAME|all>] reachable-routers
Show routing table of reachable routers.
.. _ospf-traffic-engineering:
Traffic Engineering
@ -1064,6 +1070,10 @@ Debugging OSPF
library messages and OSPF BFD integration messages that are mostly state
transitions and validation problems.
.. clicmd:: debug ospf client-api
Show debug information for the OSPF opaque data client API.
.. clicmd:: debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv) [detail]

1133
ospfclient/ospfclient.py Executable file

File diff suppressed because it is too large Load Diff

View File

@ -6,6 +6,10 @@ if OSPFCLIENT
lib_LTLIBRARIES += ospfclient/libfrrospfapiclient.la
noinst_PROGRAMS += ospfclient/ospfclient
#man8 += $(MANBUILD)/frr-ospfclient.8
sbin_SCRIPTS += \
ospfclient/ospfclient.py \
# end
endif
ospfclient_libfrrospfapiclient_la_LDFLAGS = $(LIB_LDFLAGS) -version-info 0:0:0
@ -41,3 +45,7 @@ endif
ospfclient_ospfclient_SOURCES = \
ospfclient/ospfclient.c \
# end
EXTRA_DIST += \
ospfclient/ospfclient.py \
# end

View File

@ -177,6 +177,10 @@ const char *ospf_api_typename(int msgtype)
{
MSG_NSM_CHANGE, "NSM change",
},
{
MSG_REACHABLE_CHANGE,
"Reachable change",
},
};
int i, n = array_size(NameTab);
@ -651,4 +655,31 @@ struct msg *new_msg_lsa_change_notify(uint8_t msgtype, uint32_t seqnum,
return msg_new(msgtype, nmsg, seqnum, len);
}
struct msg *new_msg_reachable_change(uint32_t seqnum, uint16_t nadd,
struct in_addr *add, uint16_t nremove,
struct in_addr *remove)
{
uint8_t buf[OSPF_API_MAX_MSG_SIZE];
struct msg_reachable_change *nmsg = (void *)buf;
const uint insz = sizeof(*nmsg->router_ids);
const uint nmax = (sizeof(buf) - sizeof(*nmsg)) / insz;
uint len;
if (nadd > nmax)
nadd = nmax;
if (nremove > (nmax - nadd))
nremove = (nmax - nadd);
if (nadd)
memcpy(nmsg->router_ids, add, nadd * insz);
if (nremove)
memcpy(&nmsg->router_ids[nadd], remove, nremove * insz);
nmsg->nadd = htons(nadd);
nmsg->nremove = htons(nremove);
len = sizeof(*nmsg) + insz * (nadd + nremove);
return msg_new(MSG_REACHABLE_CHANGE, nmsg, seqnum, len);
}
#endif /* SUPPORT_OSPF_API */

View File

@ -26,6 +26,9 @@
#ifndef _OSPF_API_H
#define _OSPF_API_H
#include <zebra.h>
#include "ospf_lsa.h"
#define OSPF_API_VERSION 1
/* MTYPE definition is not reflected to "memory.h". */
@ -112,6 +115,9 @@ extern void msg_fifo_free(struct msg_fifo *fifo);
#define MSG_SYNC_LSDB 4
#define MSG_ORIGINATE_REQUEST 5
#define MSG_DELETE_REQUEST 6
#define MSG_SYNC_REACHABLE 7
#define MSG_SYNC_ISM 8
#define MSG_SYNC_NSM 9
/* Messages from OSPF daemon. */
#define MSG_REPLY 10
@ -122,6 +128,7 @@ extern void msg_fifo_free(struct msg_fifo *fifo);
#define MSG_DEL_IF 15
#define MSG_ISM_CHANGE 16
#define MSG_NSM_CHANGE 17
#define MSG_REACHABLE_CHANGE 18
struct msg_register_opaque_type {
uint8_t lsatype;
@ -247,6 +254,12 @@ struct msg_nsm_change {
uint8_t pad[3];
};
struct msg_reachable_change {
uint16_t nadd;
uint16_t nremove;
struct in_addr router_ids[]; /* add followed by remove */
};
/* We make use of a union to define a structure that covers all
possible API messages. This allows us to find out how much memory
needs to be reserved for the largest API message. */
@ -265,6 +278,7 @@ struct apimsg {
struct msg_ism_change ism_change;
struct msg_nsm_change nsm_change;
struct msg_lsa_change_notify lsa_change_notify;
struct msg_reachable_change reachable_change;
} u;
};
@ -320,6 +334,10 @@ extern struct msg *new_msg_lsa_change_notify(uint8_t msgtype, uint32_t seqnum,
uint8_t is_self_originated,
struct lsa_header *data);
extern struct msg *new_msg_reachable_change(uint32_t seqnum, uint16_t nadd,
struct in_addr *add,
uint16_t nremove,
struct in_addr *remove);
/* string printing functions */
extern const char *ospf_api_errname(int errcode);
extern const char *ospf_api_typename(int msgtype);

View File

@ -726,6 +726,7 @@ static int ospf_apiserver_send_msg(struct ospf_apiserver *apiserv,
case MSG_DEL_IF:
case MSG_ISM_CHANGE:
case MSG_NSM_CHANGE:
case MSG_REACHABLE_CHANGE:
fifo = apiserv->out_async_fifo;
fd = apiserv->fd_async;
event = OSPF_APISERVER_ASYNC_WRITE;
@ -799,6 +800,15 @@ int ospf_apiserver_handle_msg(struct ospf_apiserver *apiserv, struct msg *msg)
case MSG_DELETE_REQUEST:
rc = ospf_apiserver_handle_delete_request(apiserv, msg);
break;
case MSG_SYNC_REACHABLE:
rc = ospf_apiserver_handle_sync_reachable(apiserv, msg);
break;
case MSG_SYNC_ISM:
rc = ospf_apiserver_handle_sync_ism(apiserv, msg);
break;
case MSG_SYNC_NSM:
rc = ospf_apiserver_handle_sync_nsm(apiserv, msg);
break;
default:
zlog_warn("ospf_apiserver_handle_msg: Unknown message type: %d",
msg->hdr.msgtype);
@ -1343,6 +1353,131 @@ int ospf_apiserver_handle_sync_lsdb(struct ospf_apiserver *apiserv,
return rc;
}
/*
* -----------------------------------------------------------
* Followings are functions for synchronization.
* -----------------------------------------------------------
*/
int ospf_apiserver_handle_sync_reachable(struct ospf_apiserver *apiserv,
struct msg *msg)
{
struct ospf *ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT);
struct route_table *rt = ospf->all_rtrs;
uint32_t seqnum = msg_get_seq(msg);
struct in_addr *a, *abuf;
struct msg_reachable_change *areach;
struct msg *amsg;
uint mcount, count;
int _rc, rc = 0;
if (!rt)
goto out;
/* send all adds based on current reachable routers */
a = abuf = XCALLOC(MTYPE_OSPF_APISERVER,
sizeof(struct in_addr) * rt->count);
for (struct route_node *rn = route_top(rt); rn; rn = route_next(rn))
if (listhead((struct list *)rn->info))
*a++ = rn->p.u.prefix4;
assert((a - abuf) <= (long)rt->count);
count = (a - abuf);
a = abuf;
while (count && !rc) {
amsg = new_msg_reachable_change(seqnum, count, a, 0, NULL);
areach = (struct msg_reachable_change *)STREAM_DATA(amsg->s);
mcount = ntohs(areach->nadd) + ntohs(areach->nremove);
assert(mcount <= count);
a = a + mcount;
count -= mcount;
rc = ospf_apiserver_send_msg(apiserv, amsg);
msg_free(amsg);
}
XFREE(MTYPE_OSPF_APISERVER, abuf);
out:
/* Send a reply back to client with return code */
_rc = ospf_apiserver_send_reply(apiserv, seqnum, rc);
rc = rc ? rc : _rc;
apiserv->reachable_sync = !rc;
return rc;
}
int ospf_apiserver_handle_sync_ism(struct ospf_apiserver *apiserv,
struct msg *msg)
{
struct ospf *ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT);
struct listnode *anode, *inode;
struct ospf_area *area;
struct ospf_interface *oi;
struct msg *m;
uint32_t seqnum = msg_get_seq(msg);
int _rc, rc = 0;
/* walk all areas */
for (ALL_LIST_ELEMENTS_RO(ospf->areas, anode, area)) {
/* walk all interfaces */
for (ALL_LIST_ELEMENTS_RO(area->oiflist, inode, oi)) {
m = new_msg_ism_change(seqnum, oi->address->u.prefix4,
area->area_id, oi->state);
rc = ospf_apiserver_send_msg(apiserv, m);
msg_free(m);
if (rc)
break;
}
if (rc)
break;
}
/* Send a reply back to client with return code */
_rc = ospf_apiserver_send_reply(apiserv, seqnum, rc);
return rc ? rc : _rc;
}
int ospf_apiserver_handle_sync_nsm(struct ospf_apiserver *apiserv,
struct msg *msg)
{
struct ospf *ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT);
struct listnode *anode, *inode;
struct ospf_area *area;
struct ospf_interface *oi;
struct ospf_neighbor *nbr;
struct route_node *rn;
struct msg *m;
uint32_t seqnum = msg_get_seq(msg);
int _rc, rc = 0;
/* walk all areas */
for (ALL_LIST_ELEMENTS_RO(ospf->areas, anode, area)) {
/* walk all interfaces */
for (ALL_LIST_ELEMENTS_RO(area->oiflist, inode, oi)) {
/* walk all neighbors */
for (rn = route_top(oi->nbrs); rn;
rn = route_next(rn)) {
nbr = rn->info;
if (!nbr)
continue;
m = new_msg_nsm_change(
seqnum, oi->address->u.prefix4,
nbr->src, nbr->router_id, nbr->state);
rc = ospf_apiserver_send_msg(apiserv, m);
msg_free(m);
if (rc)
break;
}
if (rc)
break;
}
if (rc)
break;
}
/* Send a reply back to client with return code */
_rc = ospf_apiserver_send_reply(apiserv, seqnum, rc);
return rc ? rc : _rc;
}
/* -----------------------------------------------------------
* Following are functions to originate or update LSA
@ -1427,45 +1562,20 @@ struct ospf_lsa *ospf_apiserver_opaque_lsa_new(struct ospf_area *area,
int ospf_apiserver_is_ready_type9(struct ospf_interface *oi)
{
/* Type 9 opaque LSA can be originated if there is at least one
active opaque-capable neighbor attached to the outgoing
interface. */
return (ospf_nbr_count_opaque_capable(oi) > 0);
/* We can always handle getting opaque's even if we can't flood them */
return 1;
}
int ospf_apiserver_is_ready_type10(struct ospf_area *area)
{
/* Type 10 opaque LSA can be originated if there is at least one
interface belonging to the area that has an active opaque-capable
neighbor. */
struct listnode *node, *nnode;
struct ospf_interface *oi;
for (ALL_LIST_ELEMENTS(area->oiflist, node, nnode, oi))
/* Is there an active neighbor attached to this interface? */
if (ospf_apiserver_is_ready_type9(oi))
return 1;
/* No active neighbor in area */
return 0;
/* We can always handle getting opaque's even if we can't flood them */
return 1;
}
int ospf_apiserver_is_ready_type11(struct ospf *ospf)
{
/* Type 11 opaque LSA can be originated if there is at least one
interface
that has an active opaque-capable neighbor. */
struct listnode *node, *nnode;
struct ospf_interface *oi;
for (ALL_LIST_ELEMENTS(ospf->oiflist, node, nnode, oi))
/* Is there an active neighbor attached to this interface? */
if (ospf_apiserver_is_ready_type9(oi))
return 1;
/* No active neighbor at all */
return 0;
/* We can always handle getting opaque's even if we can't flood them */
return 1;
}
@ -1570,9 +1680,9 @@ int ospf_apiserver_handle_originate_request(struct ospf_apiserver *apiserv,
/* Determine if LSA is new or an update for an existing one. */
old = ospf_lsdb_lookup(lsdb, new);
if (!old) {
if (!old || !ospf_opaque_is_owned(old)) {
/* New LSA install in LSDB. */
rc = ospf_apiserver_originate1(new);
rc = ospf_apiserver_originate1(new, old);
} else {
/*
* Keep the new LSA instance in the "waiting place" until the
@ -1639,17 +1749,33 @@ void ospf_apiserver_flood_opaque_lsa(struct ospf_lsa *lsa)
}
}
int ospf_apiserver_originate1(struct ospf_lsa *lsa)
int ospf_apiserver_originate1(struct ospf_lsa *lsa, struct ospf_lsa *old)
{
struct ospf *ospf;
ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT);
assert(ospf);
if (old) {
/*
* An old LSA exists that we didn't originate it in this
* session. Dump it, but increment past it's seqnum.
*/
assert(!ospf_opaque_is_owned(old));
if (IS_LSA_MAX_SEQ(old)) {
flog_warn(
EC_OSPF_LSA_INSTALL_FAILURE,
"ospf_apiserver_originate1: old LSA at maxseq");
return -1;
}
lsa->data->ls_seqnum = lsa_seqnum_increment(old);
ospf_discard_from_db(ospf, old->lsdb, old);
}
/* Install this LSA into LSDB. */
if (ospf_lsa_install(ospf, lsa->oi, lsa) == NULL) {
flog_warn(EC_OSPF_LSA_INSTALL_FAILURE,
"ospf_apiserver_originate1: ospf_lsa_install failed");
"%s: ospf_lsa_install failed", __func__);
return -1;
}
@ -2015,6 +2141,7 @@ int ospf_apiserver_del_if(struct interface *ifp)
if (!oi) {
/* This interface is known to Zebra but not to OSPF daemon
anymore. No need to tell clients about it */
zlog_warn("ifp name=%s not known to OSPFd", ifp->name);
return 0;
}
@ -2061,9 +2188,6 @@ void ospf_apiserver_show_info(struct vty *vty, struct json_object *json,
struct opaque_lsa *olsa;
int opaquelen;
if (json)
return;
olsa = (struct opaque_lsa *)lsa->data;
if (VALID_OPAQUE_INFO_LEN(lsa->data))
@ -2072,7 +2196,10 @@ void ospf_apiserver_show_info(struct vty *vty, struct json_object *json,
opaquelen = 0;
/* Output information about opaque LSAs */
if (vty != NULL) {
if (json)
json_object_string_addf(json, "opaqueData", "%*pHXn",
(int)opaquelen, olsa->data);
else if (vty != NULL) {
int i;
vty_out(vty,
" Added using OSPF API: %u octets of opaque data %s\n",
@ -2333,8 +2460,8 @@ void ospf_apiserver_clients_notify_nsm_change(struct ospf_neighbor *nbr)
msg_free(msg);
}
static void apiserver_clients_lsa_change_notify(uint8_t msgtype,
struct ospf_lsa *lsa)
static int apiserver_clients_lsa_change_notify(uint8_t msgtype,
struct ospf_lsa *lsa)
{
struct msg *msg;
struct listnode *node, *nnode;
@ -2362,7 +2489,7 @@ static void apiserver_clients_lsa_change_notify(uint8_t msgtype,
if (!msg) {
zlog_warn(
"apiserver_clients_lsa_change_notify: msg_new failed");
return;
return -1;
}
/* Now send message to all clients with a matching filter */
@ -2413,6 +2540,8 @@ static void apiserver_clients_lsa_change_notify(uint8_t msgtype,
}
/* Free message since it is not used anymore */
msg_free(msg);
return 0;
}
@ -2422,53 +2551,132 @@ static void apiserver_clients_lsa_change_notify(uint8_t msgtype,
*/
static int apiserver_notify_clients_lsa(uint8_t msgtype, struct ospf_lsa *lsa)
int ospf_apiserver_lsa_update(struct ospf_lsa *lsa)
{
struct msg *msg;
/* default area for AS-External and Opaque11 LSAs */
struct in_addr area_id = {.s_addr = 0L};
/* default interface for non Opaque9 LSAs */
struct in_addr ifaddr = {.s_addr = 0L};
/* Only notify this update if the LSA's age is smaller than
MAXAGE. Otherwise clients would see LSA updates with max age just
before they are deleted from the LSDB. LSA delete messages have
MAXAGE too but should not be filtered. */
if (IS_LSA_MAXAGE(lsa) && (msgtype == MSG_LSA_UPDATE_NOTIFY)) {
if (IS_LSA_MAXAGE(lsa))
return 0;
}
if (lsa->area) {
area_id = lsa->area->area_id;
}
if (lsa->data->type == OSPF_OPAQUE_LINK_LSA) {
ifaddr = lsa->oi->address->u.prefix4;
}
msg = new_msg_lsa_change_notify(msgtype, 0L, /* no sequence number */
ifaddr, area_id,
lsa->flags & OSPF_LSA_SELF, lsa->data);
if (!msg) {
zlog_warn("notify_clients_lsa: msg_new failed");
return -1;
}
/* Notify all clients that new LSA is added/updated */
apiserver_clients_lsa_change_notify(msgtype, lsa);
/* Clients made their own copies of msg so we can free msg here */
msg_free(msg);
return 0;
}
int ospf_apiserver_lsa_update(struct ospf_lsa *lsa)
{
return apiserver_notify_clients_lsa(MSG_LSA_UPDATE_NOTIFY, lsa);
return apiserver_clients_lsa_change_notify(MSG_LSA_UPDATE_NOTIFY, lsa);
}
int ospf_apiserver_lsa_delete(struct ospf_lsa *lsa)
{
return apiserver_notify_clients_lsa(MSG_LSA_DELETE_NOTIFY, lsa);
return apiserver_clients_lsa_change_notify(MSG_LSA_DELETE_NOTIFY, lsa);
}
/* -------------------------------------------------------------
* Reachable functions
* -------------------------------------------------------------
*/
static inline int cmp_route_nodes(struct route_node *orn,
struct route_node *nrn)
{
if (!orn)
return 1;
else if (!nrn)
return -1;
else if (orn->p.u.prefix4.s_addr < nrn->p.u.prefix4.s_addr)
return -1;
else if (orn->p.u.prefix4.s_addr > nrn->p.u.prefix4.s_addr)
return 1;
else
return 0;
}
void ospf_apiserver_notify_reachable(struct route_table *ort,
struct route_table *nrt)
{
struct msg *msg;
struct msg_reachable_change *areach;
struct route_node *orn, *nrn;
const uint insz = sizeof(struct in_addr);
struct in_addr *abuf = NULL, *dbuf = NULL;
struct in_addr *a = NULL, *d = NULL;
uint nadd, nremove;
int cmp;
if (!ort && !nrt) {
if (IS_DEBUG_OSPF_CLIENT_API)
zlog_debug("%s: no routing tables", __func__);
return;
}
if (nrt && nrt->count)
a = abuf = XCALLOC(MTYPE_OSPF_APISERVER, insz * nrt->count);
if (ort && ort->count)
d = dbuf = XCALLOC(MTYPE_OSPF_APISERVER, insz * ort->count);
/* walk both tables */
orn = ort ? route_top(ort) : NULL;
nrn = nrt ? route_top(nrt) : NULL;
while (orn || nrn) {
if (orn && !listhead((struct list *)orn->info)) {
orn = route_next(orn);
continue;
}
if (nrn && !listhead((struct list *)nrn->info)) {
nrn = route_next(nrn);
continue;
}
cmp = cmp_route_nodes(orn, nrn);
if (!cmp) {
/* if old == new advance old and new */
if (IS_DEBUG_OSPF_CLIENT_API)
zlog_debug("keeping router id: %pI4",
&orn->p.u.prefix4);
orn = route_next(orn);
nrn = route_next(nrn);
} else if (cmp < 0) {
assert(d != NULL); /* Silence SA warning */
/* if old < new, delete old, advance old */
*d++ = orn->p.u.prefix4;
if (IS_DEBUG_OSPF_CLIENT_API)
zlog_debug("removing router id: %pI4",
&orn->p.u.prefix4);
orn = route_next(orn);
} else {
assert(a != NULL); /* Silence SA warning */
/* if new < old, add new, advance new */
*a++ = nrn->p.u.prefix4;
if (IS_DEBUG_OSPF_CLIENT_API)
zlog_debug("adding router id: %pI4",
&nrn->p.u.prefix4);
nrn = route_next(nrn);
}
}
nadd = abuf ? (a - abuf) : 0;
nremove = dbuf ? (d - dbuf) : 0;
a = abuf;
d = dbuf;
while (nadd + nremove) {
msg = new_msg_reachable_change(0, nadd, a, nremove, d);
areach = (struct msg_reachable_change *)STREAM_DATA(msg->s);
a += ntohs(areach->nadd);
nadd = nadd - ntohs(areach->nadd);
d += ntohs(areach->nremove);
nremove = nremove - ntohs(areach->nremove);
if (IS_DEBUG_OSPF_CLIENT_API)
zlog_debug("%s: adding %d removing %d", __func__,
ntohs(areach->nadd), ntohs(areach->nremove));
ospf_apiserver_clients_notify_all(msg);
msg_free(msg);
}
if (abuf)
XFREE(MTYPE_OSPF_APISERVER, abuf);
if (dbuf)
XFREE(MTYPE_OSPF_APISERVER, dbuf);
}
#endif /* SUPPORT_OSPF_API */

View File

@ -22,6 +22,10 @@
#ifndef _OSPF_APISERVER_H
#define _OSPF_APISERVER_H
#include <zebra.h>
#include "ospf_api.h"
#include "ospf_lsdb.h"
/* MTYPE definition is not reflected to "memory.h". */
#define MTYPE_OSPF_APISERVER MTYPE_TMP
#define MTYPE_OSPF_APISERVER_MSGFILTER MTYPE_TMP
@ -52,6 +56,9 @@ struct ospf_apiserver {
/* Temporary storage for LSA instances to be refreshed. */
struct ospf_lsdb reserve;
/* Sync reachable routers */
bool reachable_sync;
/* filter for LSA update/delete notifies */
struct lsa_filter_type *filter;
@ -144,7 +151,15 @@ extern int ospf_apiserver_handle_delete_request(struct ospf_apiserver *apiserv,
struct msg *msg);
extern int ospf_apiserver_handle_sync_lsdb(struct ospf_apiserver *apiserv,
struct msg *msg);
extern int ospf_apiserver_handle_sync_reachable(struct ospf_apiserver *apiserv,
struct msg *msg);
extern int ospf_apiserver_handle_sync_ism(struct ospf_apiserver *apiserv,
struct msg *msg);
extern int ospf_apiserver_handle_sync_nsm(struct ospf_apiserver *apiserv,
struct msg *msg);
extern void ospf_apiserver_notify_reachable(struct route_table *ort,
struct route_table *nrt);
/* -----------------------------------------------------------
* Following are functions for LSA origination/deletion
@ -164,7 +179,8 @@ extern struct ospf_interface *
ospf_apiserver_if_lookup_by_addr(struct in_addr address);
extern struct ospf_interface *
ospf_apiserver_if_lookup_by_ifp(struct interface *ifp);
extern int ospf_apiserver_originate1(struct ospf_lsa *lsa);
extern int ospf_apiserver_originate1(struct ospf_lsa *lsa,
struct ospf_lsa *old);
extern void ospf_apiserver_flood_opaque_lsa(struct ospf_lsa *lsa);
@ -201,7 +217,4 @@ extern void ospf_apiserver_flush_opaque_lsa(struct ospf_apiserver *apiserv,
extern int ospf_apiserver_lsa_update(struct ospf_lsa *lsa);
extern int ospf_apiserver_lsa_delete(struct ospf_lsa *lsa);
extern void ospf_apiserver_clients_lsa_change_notify(uint8_t msgtype,
struct ospf_lsa *lsa);
#endif /* _OSPF_APISERVER_H */

View File

@ -62,6 +62,7 @@ unsigned long conf_debug_ospf_defaultinfo = 0;
unsigned long conf_debug_ospf_ldp_sync = 0;
unsigned long conf_debug_ospf_gr = 0;
unsigned long conf_debug_ospf_bfd;
unsigned long conf_debug_ospf_client_api;
/* Enable debug option variables -- valid only session. */
unsigned long term_debug_ospf_packet[5] = {0, 0, 0, 0, 0};
@ -79,6 +80,7 @@ unsigned long term_debug_ospf_defaultinfo;
unsigned long term_debug_ospf_ldp_sync;
unsigned long term_debug_ospf_gr = 0;
unsigned long term_debug_ospf_bfd;
unsigned long term_debug_ospf_client_api;
const char *ospf_redist_string(unsigned int route_type)
{
@ -1620,6 +1622,33 @@ DEFPY(debug_ospf_bfd, debug_ospf_bfd_cmd,
return CMD_SUCCESS;
}
DEFUN(debug_ospf_client_api,
debug_ospf_client_api_cmd,
"debug ospf client-api",
DEBUG_STR OSPF_STR
"OSPF client API information\n")
{
if (vty->node == CONFIG_NODE)
CONF_DEBUG_ON(client_api, CLIENT_API);
TERM_DEBUG_ON(client_api, CLIENT_API);
return CMD_SUCCESS;
}
DEFUN(no_debug_ospf_client_api,
no_debug_ospf_client_api_cmd,
"no debug ospf client-api",
NO_STR
DEBUG_STR
OSPF_STR
"OSPF client API information\n")
{
if (vty->node == CONFIG_NODE)
CONF_DEBUG_OFF(client_api, CLIENT_API);
TERM_DEBUG_OFF(client_api, CLIENT_API);
return CMD_SUCCESS;
}
DEFUN (no_debug_ospf,
no_debug_ospf_cmd,
"no debug ospf",
@ -1654,6 +1683,7 @@ DEFUN (no_debug_ospf,
DEBUG_OFF(te, TE);
DEBUG_OFF(sr, SR);
DEBUG_OFF(ti_lfa, TI_LFA);
DEBUG_OFF(client_api, CLIENT_API);
/* BFD debugging is two parts: OSPF and library. */
DEBUG_OFF(bfd, BFD_LIB);
@ -1690,6 +1720,7 @@ DEFUN (no_debug_ospf,
TERM_DEBUG_OFF(sr, SR);
TERM_DEBUG_OFF(ti_lfa, TI_LFA);
TERM_DEBUG_OFF(bfd, BFD_LIB);
TERM_DEBUG_OFF(client_api, CLIENT_API);
return CMD_SUCCESS;
}
@ -1815,6 +1846,10 @@ static int show_debugging_ospf_common(struct vty *vty)
vty_out(vty,
" OSPF BFD integration library debugging is on\n");
/* Show debug status for LDP-SYNC. */
if (IS_DEBUG_OSPF(client_api, CLIENT_API) == OSPF_DEBUG_CLIENT_API)
vty_out(vty, " OSPF client-api debugging is on\n");
vty_out(vty, "\n");
return CMD_SUCCESS;
@ -2007,6 +2042,13 @@ static int config_write_debug(struct vty *vty)
write = 1;
}
/* debug ospf client-api */
if (IS_CONF_DEBUG_OSPF(client_api, CLIENT_API) ==
OSPF_DEBUG_CLIENT_API) {
vty_out(vty, "debug ospf%s client-api\n", str);
write = 1;
}
return write;
}
@ -2027,6 +2069,7 @@ void ospf_debug_init(void)
install_element(ENABLE_NODE, &debug_ospf_ti_lfa_cmd);
install_element(ENABLE_NODE, &debug_ospf_default_info_cmd);
install_element(ENABLE_NODE, &debug_ospf_ldp_sync_cmd);
install_element(ENABLE_NODE, &debug_ospf_client_api_cmd);
install_element(ENABLE_NODE, &no_debug_ospf_ism_cmd);
install_element(ENABLE_NODE, &no_debug_ospf_nsm_cmd);
install_element(ENABLE_NODE, &no_debug_ospf_lsa_cmd);
@ -2038,6 +2081,7 @@ void ospf_debug_init(void)
install_element(ENABLE_NODE, &no_debug_ospf_ti_lfa_cmd);
install_element(ENABLE_NODE, &no_debug_ospf_default_info_cmd);
install_element(ENABLE_NODE, &no_debug_ospf_ldp_sync_cmd);
install_element(ENABLE_NODE, &no_debug_ospf_client_api_cmd);
install_element(ENABLE_NODE, &debug_ospf_gr_cmd);
install_element(ENABLE_NODE, &debug_ospf_bfd_cmd);
@ -2072,6 +2116,7 @@ void ospf_debug_init(void)
install_element(CONFIG_NODE, &debug_ospf_ti_lfa_cmd);
install_element(CONFIG_NODE, &debug_ospf_default_info_cmd);
install_element(CONFIG_NODE, &debug_ospf_ldp_sync_cmd);
install_element(CONFIG_NODE, &debug_ospf_client_api_cmd);
install_element(CONFIG_NODE, &no_debug_ospf_nsm_cmd);
install_element(CONFIG_NODE, &no_debug_ospf_lsa_cmd);
install_element(CONFIG_NODE, &no_debug_ospf_zebra_cmd);
@ -2082,6 +2127,7 @@ void ospf_debug_init(void)
install_element(CONFIG_NODE, &no_debug_ospf_ti_lfa_cmd);
install_element(CONFIG_NODE, &no_debug_ospf_default_info_cmd);
install_element(CONFIG_NODE, &no_debug_ospf_ldp_sync_cmd);
install_element(CONFIG_NODE, &no_debug_ospf_client_api_cmd);
install_element(CONFIG_NODE, &debug_ospf_gr_cmd);
install_element(CONFIG_NODE, &debug_ospf_bfd_cmd);

View File

@ -68,6 +68,8 @@
#define OSPF_DEBUG_BFD_LIB 0x01
#define OSPF_DEBUG_CLIENT_API 0x01
/* Macro for setting debug option. */
#define CONF_DEBUG_PACKET_ON(a, b) conf_debug_ospf_packet[a] |= (b)
#define CONF_DEBUG_PACKET_OFF(a, b) conf_debug_ospf_packet[a] &= ~(b)
@ -118,6 +120,7 @@
#define IS_DEBUG_OSPF_LDP_SYNC IS_DEBUG_OSPF(ldp_sync, LDP_SYNC)
#define IS_DEBUG_OSPF_GR IS_DEBUG_OSPF(gr, GR)
#define IS_DEBUG_OSPF_CLIENT_API IS_DEBUG_OSPF(client_api, CLIENT_API)
#define IS_CONF_DEBUG_OSPF_PACKET(a, b) \
(conf_debug_ospf_packet[a] & OSPF_DEBUG_##b)
@ -142,6 +145,7 @@ extern unsigned long term_debug_ospf_defaultinfo;
extern unsigned long term_debug_ospf_ldp_sync;
extern unsigned long term_debug_ospf_gr;
extern unsigned long term_debug_ospf_bfd;
extern unsigned long term_debug_ospf_client_api;
/* Message Strings. */
extern char *ospf_lsa_type_str[];

View File

@ -74,9 +74,8 @@ int ospf_apiserver_enable;
static void ospf_opaque_register_vty(void);
static void ospf_opaque_funclist_init(void);
static void ospf_opaque_funclist_term(void);
static void free_opaque_info_per_type(void *val);
static void free_opaque_info_per_type_del(void *val);
static void free_opaque_info_per_id(void *val);
static void free_opaque_info_owner(void *val);
static int ospf_opaque_lsa_install_hook(struct ospf_lsa *lsa);
static int ospf_opaque_lsa_delete_hook(struct ospf_lsa *lsa);
@ -141,7 +140,7 @@ int ospf_opaque_type9_lsa_init(struct ospf_interface *oi)
list_delete(&oi->opaque_lsa_self);
oi->opaque_lsa_self = list_new();
oi->opaque_lsa_self->del = free_opaque_info_per_type;
oi->opaque_lsa_self->del = free_opaque_info_per_type_del;
oi->t_opaque_lsa_self = NULL;
return 0;
}
@ -161,7 +160,7 @@ int ospf_opaque_type10_lsa_init(struct ospf_area *area)
list_delete(&area->opaque_lsa_self);
area->opaque_lsa_self = list_new();
area->opaque_lsa_self->del = free_opaque_info_per_type;
area->opaque_lsa_self->del = free_opaque_info_per_type_del;
area->t_opaque_lsa_self = NULL;
#ifdef MONITOR_LSDB_CHANGE
@ -189,7 +188,7 @@ int ospf_opaque_type11_lsa_init(struct ospf *top)
list_delete(&top->opaque_lsa_self);
top->opaque_lsa_self = list_new();
top->opaque_lsa_self->del = free_opaque_info_per_type;
top->opaque_lsa_self->del = free_opaque_info_per_type_del;
top->t_opaque_lsa_self = NULL;
#ifdef MONITOR_LSDB_CHANGE
@ -263,6 +262,9 @@ static const char *ospf_opaque_type_name(uint8_t opaque_type)
struct opaque_info_per_type; /* Forward declaration. */
static void free_opaque_info_per_type(struct opaque_info_per_type *oipt,
bool cleanup_owner);
struct ospf_opaque_functab {
uint8_t opaque_type;
struct opaque_info_per_type *oipt;
@ -433,12 +435,9 @@ void ospf_delete_opaque_functab(uint8_t lsa_type, uint8_t opaque_type)
if (functab->opaque_type == opaque_type) {
/* Cleanup internal control information, if it
* still remains. */
if (functab->oipt != NULL) {
free_opaque_info_owner(functab->oipt);
free_opaque_info_per_type(
functab->oipt);
}
if (functab->oipt != NULL)
free_opaque_info_per_type(functab->oipt,
true);
/* Dequeue listnode entry from the list. */
listnode_delete(funclist, functab);
@ -558,8 +557,7 @@ register_opaque_info_per_type(struct ospf_opaque_functab *functab,
case OSPF_OPAQUE_AS_LSA:
top = ospf_lookup_by_vrf_id(new->vrf_id);
if (new->area != NULL && (top = new->area->ospf) == NULL) {
free_opaque_info_owner(oipt);
free_opaque_info_per_type(oipt);
free_opaque_info_per_type(oipt, true);
oipt = NULL;
goto out; /* This case may not exist. */
}
@ -571,8 +569,7 @@ register_opaque_info_per_type(struct ospf_opaque_functab *functab,
EC_OSPF_LSA_UNEXPECTED,
"register_opaque_info_per_type: Unexpected LSA-type(%u)",
new->data->type);
free_opaque_info_owner(oipt);
free_opaque_info_per_type(oipt);
free_opaque_info_per_type(oipt, true);
oipt = NULL;
goto out; /* This case may not exist. */
}
@ -589,42 +586,13 @@ out:
return oipt;
}
/* Remove "oipt" from its owner's self-originated LSA list. */
static void free_opaque_info_owner(void *val)
static void free_opaque_info_per_type(struct opaque_info_per_type *oipt,
bool cleanup_owner)
{
struct opaque_info_per_type *oipt = (struct opaque_info_per_type *)val;
switch (oipt->lsa_type) {
case OSPF_OPAQUE_LINK_LSA: {
struct ospf_interface *oi =
(struct ospf_interface *)(oipt->owner);
listnode_delete(oi->opaque_lsa_self, oipt);
break;
}
case OSPF_OPAQUE_AREA_LSA: {
struct ospf_area *area = (struct ospf_area *)(oipt->owner);
listnode_delete(area->opaque_lsa_self, oipt);
break;
}
case OSPF_OPAQUE_AS_LSA: {
struct ospf *top = (struct ospf *)(oipt->owner);
listnode_delete(top->opaque_lsa_self, oipt);
break;
}
default:
flog_warn(EC_OSPF_LSA_UNEXPECTED,
"free_opaque_info_owner: Unexpected LSA-type(%u)",
oipt->lsa_type);
break; /* This case may not exist. */
}
}
static void free_opaque_info_per_type(void *val)
{
struct opaque_info_per_type *oipt = (struct opaque_info_per_type *)val;
struct opaque_info_per_id *oipi;
struct ospf_lsa *lsa;
struct listnode *node, *nnode;
struct list *l;
/* Control information per opaque-id may still exist. */
for (ALL_LIST_ELEMENTS(oipt->id_list, node, nnode, oipi)) {
@ -637,10 +605,37 @@ static void free_opaque_info_per_type(void *val)
OSPF_TIMER_OFF(oipt->t_opaque_lsa_self);
list_delete(&oipt->id_list);
if (cleanup_owner) {
/* Remove from its owner's self-originated LSA list. */
switch (oipt->lsa_type) {
case OSPF_OPAQUE_LINK_LSA:
l = ((struct ospf_interface *)oipt->owner)
->opaque_lsa_self;
break;
case OSPF_OPAQUE_AREA_LSA:
l = ((struct ospf_area *)oipt->owner)->opaque_lsa_self;
break;
case OSPF_OPAQUE_AS_LSA:
l = ((struct ospf *)oipt->owner)->opaque_lsa_self;
break;
default:
flog_warn(
EC_OSPF_LSA_UNEXPECTED,
"free_opaque_info_owner: Unexpected LSA-type(%u)",
oipt->lsa_type);
return;
}
listnode_delete(l, oipt);
}
XFREE(MTYPE_OPAQUE_INFO_PER_TYPE, oipt);
return;
}
static void free_opaque_info_per_type_del(void *val)
{
free_opaque_info_per_type((struct opaque_info_per_type *)val, false);
}
static struct opaque_info_per_type *
lookup_opaque_info_by_type(struct ospf_lsa *lsa)
{
@ -758,6 +753,13 @@ out:
return oipi;
}
int ospf_opaque_is_owned(struct ospf_lsa *lsa)
{
struct opaque_info_per_type *oipt = lookup_opaque_info_by_type(lsa);
return (oipt != NULL && lookup_opaque_info_by_id(oipt, lsa) != NULL);
}
/*------------------------------------------------------------------------*
* Following are (vty) configuration functions for Opaque-LSAs handling.
*------------------------------------------------------------------------*/

View File

@ -173,4 +173,6 @@ extern void ospf_opaque_self_originated_lsa_received(struct ospf_neighbor *nbr,
struct ospf_lsa *lsa);
extern struct ospf *oi_to_top(struct ospf_interface *oi);
extern int ospf_opaque_is_owned(struct ospf_lsa *lsa);
#endif /* _ZEBRA_OSPF_OPAQUE_H */

View File

@ -363,7 +363,7 @@ void ospf_route_install(struct ospf *ospf, struct route_table *rt)
/* RFC2328 16.1. (4). For "router". */
void ospf_intra_add_router(struct route_table *rt, struct vertex *v,
struct ospf_area *area)
struct ospf_area *area, bool add_all)
{
struct route_node *rn;
struct ospf_route * or ;
@ -388,7 +388,8 @@ void ospf_intra_add_router(struct route_table *rt, struct vertex *v,
/* If the newly added vertex is an area border router or AS boundary
router, a routing table entry is added whose destination type is
"router". */
if (!IS_ROUTER_LSA_BORDER(lsa) && !IS_ROUTER_LSA_EXTERNAL(lsa)) {
if (!add_all && !IS_ROUTER_LSA_BORDER(lsa) &&
!IS_ROUTER_LSA_EXTERNAL(lsa)) {
if (IS_DEBUG_OSPF_EVENT)
zlog_debug(
"ospf_intra_add_router: this router is neither ASBR nor ABR, skipping it");
@ -733,6 +734,24 @@ void ospf_route_table_dump(struct route_table *rt)
zlog_debug("========================================");
}
void ospf_router_route_table_dump(struct route_table *rt)
{
struct route_node *rn;
struct ospf_route *or;
struct listnode *node;
zlog_debug("========== OSPF routing table ==========");
for (rn = route_top(rt); rn; rn = route_next(rn)) {
for (ALL_LIST_ELEMENTS_RO((struct list *)rn->info, node, or)) {
assert(or->type == OSPF_DESTINATION_ROUTER);
zlog_debug("R %-18pI4 %-15pI4 %s %d", &rn->p.u.prefix4,
&or->u.std.area_id,
ospf_path_type_str[or->path_type], or->cost);
}
}
zlog_debug("========================================");
}
/* This is 16.4.1 implementation.
o Intra-area paths using non-backbone areas are always the most preferred.
o The other paths, intra-area backbone paths and inter-area paths,

View File

@ -139,9 +139,10 @@ extern void ospf_route_table_free(struct route_table *);
extern void ospf_route_install(struct ospf *, struct route_table *);
extern void ospf_route_table_dump(struct route_table *);
extern void ospf_router_route_table_dump(struct route_table *rt);
extern void ospf_intra_add_router(struct route_table *, struct vertex *,
struct ospf_area *);
extern void ospf_intra_add_router(struct route_table *rt, struct vertex *v,
struct ospf_area *area, bool add_all);
extern void ospf_intra_add_transit(struct route_table *, struct vertex *,
struct ospf_area *);

View File

@ -48,6 +48,7 @@
#include "ospfd/ospf_sr.h"
#include "ospfd/ospf_ti_lfa.h"
#include "ospfd/ospf_errors.h"
#include "ospfd/ospf_apiserver.h"
/* Variables to ensure a SPF scheduled log message is printed only once */
@ -1669,6 +1670,7 @@ void ospf_spf_cleanup(struct vertex *spf, struct list *vertex_list)
/* Calculating the shortest-path tree for an area, see RFC2328 16.1. */
void ospf_spf_calculate(struct ospf_area *area, struct ospf_lsa *root_lsa,
struct route_table *new_table,
struct route_table *all_rtrs,
struct route_table *new_rtrs, bool is_dry_run,
bool is_root_node)
{
@ -1737,10 +1739,13 @@ void ospf_spf_calculate(struct ospf_area *area, struct ospf_lsa *root_lsa,
ospf_vertex_add_parent(v);
/* RFC2328 16.1. (4). */
if (v->type == OSPF_VERTEX_ROUTER)
ospf_intra_add_router(new_rtrs, v, area);
else
if (v->type != OSPF_VERTEX_ROUTER)
ospf_intra_add_transit(new_table, v, area);
else {
ospf_intra_add_router(new_rtrs, v, area, false);
if (all_rtrs)
ospf_intra_add_router(all_rtrs, v, area, true);
}
/* Iterate back to (2), see RFC2328 16.1. (5). */
}
@ -1748,6 +1753,8 @@ void ospf_spf_calculate(struct ospf_area *area, struct ospf_lsa *root_lsa,
if (IS_DEBUG_OSPF_EVENT) {
ospf_spf_dump(area->spf, 0);
ospf_route_table_dump(new_table);
if (all_rtrs)
ospf_router_route_table_dump(all_rtrs);
}
/*
@ -1771,10 +1778,11 @@ void ospf_spf_calculate(struct ospf_area *area, struct ospf_lsa *root_lsa,
void ospf_spf_calculate_area(struct ospf *ospf, struct ospf_area *area,
struct route_table *new_table,
struct route_table *all_rtrs,
struct route_table *new_rtrs)
{
ospf_spf_calculate(area, area->router_lsa_self, new_table, new_rtrs,
false, true);
ospf_spf_calculate(area, area->router_lsa_self, new_table, all_rtrs,
new_rtrs, false, true);
if (ospf->ti_lfa_enabled)
ospf_ti_lfa_compute(area, new_table,
@ -1787,6 +1795,7 @@ void ospf_spf_calculate_area(struct ospf *ospf, struct ospf_area *area,
}
void ospf_spf_calculate_areas(struct ospf *ospf, struct route_table *new_table,
struct route_table *all_rtrs,
struct route_table *new_rtrs)
{
struct ospf_area *area;
@ -1799,13 +1808,14 @@ void ospf_spf_calculate_areas(struct ospf *ospf, struct route_table *new_table,
if (ospf->backbone && ospf->backbone == area)
continue;
ospf_spf_calculate_area(ospf, area, new_table, new_rtrs);
ospf_spf_calculate_area(ospf, area, new_table, all_rtrs,
new_rtrs);
}
/* SPF for backbone, if required */
if (ospf->backbone)
ospf_spf_calculate_area(ospf, ospf->backbone, new_table,
new_rtrs);
all_rtrs, new_rtrs);
}
/* Worker for SPF calculation scheduler. */
@ -1813,6 +1823,7 @@ static void ospf_spf_calculate_schedule_worker(struct thread *thread)
{
struct ospf *ospf = THREAD_ARG(thread);
struct route_table *new_table, *new_rtrs;
struct route_table *all_rtrs = NULL;
struct timeval start_time, spf_start_time;
unsigned long ia_time, prune_time, rt_time;
unsigned long abr_time, total_spf_time, spf_time;
@ -1829,7 +1840,12 @@ static void ospf_spf_calculate_schedule_worker(struct thread *thread)
monotime(&spf_start_time);
new_table = route_table_init(); /* routing table */
new_rtrs = route_table_init(); /* ABR/ASBR routing table */
ospf_spf_calculate_areas(ospf, new_table, new_rtrs);
/* If we have opaque enabled then track all router reachability */
if (CHECK_FLAG(ospf->opaque, OPAQUE_OPERATION_READY_BIT))
all_rtrs = route_table_init();
ospf_spf_calculate_areas(ospf, new_table, all_rtrs, new_rtrs);
spf_time = monotime_since(&spf_start_time, NULL);
ospf_vl_shut_unapproved(ospf);
@ -1842,6 +1858,8 @@ static void ospf_spf_calculate_schedule_worker(struct thread *thread)
/* Get rid of transit networks and routers we cannot reach anyway. */
monotime(&start_time);
ospf_prune_unreachable_networks(new_table);
if (all_rtrs)
ospf_prune_unreachable_routers(all_rtrs);
ospf_prune_unreachable_routers(new_rtrs);
prune_time = monotime_since(&start_time, NULL);
@ -1866,6 +1884,16 @@ static void ospf_spf_calculate_schedule_worker(struct thread *thread)
ospf_route_install(ospf, new_table);
rt_time = monotime_since(&start_time, NULL);
/* Free old all routers routing table */
if (ospf->oall_rtrs)
/* ospf_route_delete (ospf->old_rtrs); */
ospf_rtrs_free(ospf->oall_rtrs);
/* Update all routers routing table */
ospf->oall_rtrs = ospf->all_rtrs;
ospf->all_rtrs = all_rtrs;
ospf_apiserver_notify_reachable(ospf->oall_rtrs, ospf->all_rtrs);
/* Free old ABR/ASBR routing table */
if (ospf->old_rtrs)
/* ospf_route_delete (ospf->old_rtrs); */

View File

@ -76,13 +76,16 @@ extern void ospf_spf_calculate_schedule(struct ospf *, ospf_spf_reason_t);
extern void ospf_spf_calculate(struct ospf_area *area,
struct ospf_lsa *root_lsa,
struct route_table *new_table,
struct route_table *all_rtrs,
struct route_table *new_rtrs, bool is_dry_run,
bool is_root_node);
extern void ospf_spf_calculate_area(struct ospf *ospf, struct ospf_area *area,
struct route_table *new_table,
struct route_table *all_rtrs,
struct route_table *new_rtrs);
extern void ospf_spf_calculate_areas(struct ospf *ospf,
struct route_table *new_table,
struct route_table *all_rtrs,
struct route_table *new_rtrs);
extern void ospf_rtrs_free(struct route_table *);
extern void ospf_spf_cleanup(struct vertex *spf, struct list *vertex_list);

View File

@ -326,8 +326,8 @@ static void ospf_ti_lfa_generate_inner_label_stack(
XCALLOC(MTYPE_OSPF_P_SPACE, sizeof(struct p_spaces_head));
/* dry run true, root node false */
ospf_spf_calculate(area, start_vertex->lsa_p, new_table, new_rtrs, true,
false);
ospf_spf_calculate(area, start_vertex->lsa_p, new_table, NULL, new_rtrs,
true, false);
q_node = ospf_spf_vertex_find(end_vertex->id, area->spf_vertex_list);
@ -676,6 +676,7 @@ static void ospf_ti_lfa_generate_q_spaces(struct ospf_area *area,
sizeof(struct ospf_ti_lfa_node_info));
new_table = route_table_init();
/* XXX do these get freed?? */
new_rtrs = route_table_init();
/*
@ -683,7 +684,8 @@ static void ospf_ti_lfa_generate_q_spaces(struct ospf_area *area,
* dry run true, root node false
*/
area->spf_reversed = true;
ospf_spf_calculate(area, dest->lsa_p, new_table, new_rtrs, true, false);
ospf_spf_calculate(area, dest->lsa_p, new_table, NULL, new_rtrs, true,
false);
/* Reset the flag for reverse SPF */
area->spf_reversed = false;
@ -750,6 +752,7 @@ static void ospf_ti_lfa_generate_post_convergence_spf(struct ospf_area *area,
struct route_table *new_table, *new_rtrs;
new_table = route_table_init();
/* XXX do these get freed?? */
new_rtrs = route_table_init();
area->spf_protected_resource = p_space->protected_resource;
@ -769,8 +772,8 @@ static void ospf_ti_lfa_generate_post_convergence_spf(struct ospf_area *area,
* endeavour (because LSAs are stored as a 'raw' stream), so we go with
* this rather hacky way for now.
*/
ospf_spf_calculate(area, area->router_lsa_self, new_table, new_rtrs,
true, false);
ospf_spf_calculate(area, area->router_lsa_self, new_table, NULL,
new_rtrs, true, false);
p_space->pc_spf = area->spf;
p_space->pc_vertex_list = area->spf_vertex_list;

View File

@ -10741,8 +10741,9 @@ static void show_ip_ospf_route_router(struct vty *vty, struct ospf *ospf,
*json_nexthop = NULL;
if (!json)
vty_out(vty,
"============ OSPF router routing table =============\n");
vty_out(vty, "============ OSPF %s table =============\n",
ospf->all_rtrs == rtrs ? "reachable routers"
: "router routing");
for (rn = route_top(rtrs); rn; rn = route_next(rn)) {
if (rn->info == NULL)
@ -11004,6 +11005,114 @@ static void show_ip_ospf_route_external(struct vty *vty, struct ospf *ospf,
vty_out(vty, "\n");
}
static int show_ip_ospf_reachable_routers_common(struct vty *vty,
struct ospf *ospf,
uint8_t use_vrf)
{
if (ospf->instance)
vty_out(vty, "\nOSPF Instance: %d\n\n", ospf->instance);
ospf_show_vrf_name(ospf, vty, NULL, use_vrf);
if (ospf->all_rtrs == NULL) {
vty_out(vty, "No OSPF reachable router information exist\n");
return CMD_SUCCESS;
}
/* Show Router routes. */
show_ip_ospf_route_router(vty, ospf, ospf->all_rtrs, NULL);
vty_out(vty, "\n");
return CMD_SUCCESS;
}
DEFUN (show_ip_ospf_reachable_routers,
show_ip_ospf_reachable_routers_cmd,
"show ip ospf [vrf <NAME|all>] reachable-routers",
SHOW_STR
IP_STR
"OSPF information\n"
VRF_CMD_HELP_STR
"All VRFs\n"
"Show all the reachable OSPF routers\n")
{
struct ospf *ospf = NULL;
struct listnode *node = NULL;
char *vrf_name = NULL;
bool all_vrf = false;
int ret = CMD_SUCCESS;
int inst = 0;
int idx_vrf = 0;
uint8_t use_vrf = 0;
OSPF_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
if (vrf_name) {
bool ospf_output = false;
use_vrf = 1;
if (all_vrf) {
for (ALL_LIST_ELEMENTS_RO(om->ospf, node, ospf)) {
if (!ospf->oi_running)
continue;
ospf_output = true;
ret = show_ip_ospf_reachable_routers_common(
vty, ospf, use_vrf);
}
if (!ospf_output)
vty_out(vty, "%% OSPF instance not found\n");
} else {
ospf = ospf_lookup_by_inst_name(inst, vrf_name);
if (ospf == NULL || !ospf->oi_running) {
vty_out(vty, "%% OSPF instance not found\n");
return CMD_SUCCESS;
}
ret = show_ip_ospf_reachable_routers_common(vty, ospf,
use_vrf);
}
} else {
/* Display default ospf (instance 0) info */
ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT);
if (ospf == NULL || !ospf->oi_running) {
vty_out(vty, "%% OSPF instance not found\n");
return CMD_SUCCESS;
}
ret = show_ip_ospf_reachable_routers_common(vty, ospf, use_vrf);
}
return ret;
}
DEFUN (show_ip_ospf_instance_reachable_routers,
show_ip_ospf_instance_reachable_routers_cmd,
"show ip ospf (1-65535) reachable-routers",
SHOW_STR
IP_STR
"OSPF information\n"
"Instance ID\n"
"Show all the reachable OSPF routers\n")
{
int idx_number = 3;
struct ospf *ospf;
unsigned short instance = 0;
instance = strtoul(argv[idx_number]->arg, NULL, 10);
if (instance != ospf_instance)
return CMD_NOT_MY_INSTANCE;
ospf = ospf_lookup_instance(instance);
if (!ospf || !ospf->oi_running)
return CMD_SUCCESS;
return show_ip_ospf_reachable_routers_common(vty, ospf, 0);
}
static int show_ip_ospf_border_routers_common(struct vty *vty,
struct ospf *ospf,
uint8_t use_vrf)
@ -11146,6 +11255,10 @@ static int show_ip_ospf_route_common(struct vty *vty, struct ospf *ospf,
/* Show Router routes. */
show_ip_ospf_route_router(vty, ospf, ospf->new_rtrs, json_vrf);
/* Show Router routes. */
if (ospf->all_rtrs)
show_ip_ospf_route_router(vty, ospf, ospf->all_rtrs, json_vrf);
/* Show AS External routes. */
show_ip_ospf_route_external(vty, ospf, ospf->old_external_route,
json_vrf);
@ -12603,9 +12716,12 @@ void ospf_vty_show_init(void)
/* "show ip ospf route" commands. */
install_element(VIEW_NODE, &show_ip_ospf_route_cmd);
install_element(VIEW_NODE, &show_ip_ospf_border_routers_cmd);
install_element(VIEW_NODE, &show_ip_ospf_reachable_routers_cmd);
install_element(VIEW_NODE, &show_ip_ospf_instance_route_cmd);
install_element(VIEW_NODE, &show_ip_ospf_instance_border_routers_cmd);
install_element(VIEW_NODE,
&show_ip_ospf_instance_reachable_routers_cmd);
/* "show ip ospf vrfs" commands. */
install_element(VIEW_NODE, &show_ip_ospf_vrfs_cmd);

View File

@ -234,6 +234,9 @@ struct ospf {
struct route_table *old_table; /* Old routing table. */
struct route_table *new_table; /* Current routing table. */
struct route_table *oall_rtrs; /* Old router RT. */
struct route_table *all_rtrs; /* New routers RT. */
struct route_table *old_rtrs; /* Old ABR/ASBR RT. */
struct route_table *new_rtrs; /* New ABR/ASBR RT. */

View File

@ -466,6 +466,9 @@ install -d -m750 %{buildroot}%{rundir}
# avoid `ERROR: ambiguous python shebang in` errors
pathfix.py -pni "%{__python3} %{py3_shbang_opts}" %{buildroot}/usr/lib/frr/*.py
%py_byte_compile %{__python3} %{buildroot}/usr/lib/frr/*.py
%else
# remove ospfclient.py (if present) as it requires > python36
rm -f %{buildroot}%{_sbindir}/ospfclient.py
%endif
%pre
@ -719,11 +722,13 @@ fi
%files contrib
%doc tools
%files pythontools
%{_sbindir}/generate_support_bundle.py
%{_sbindir}/frr-reload.py
%{_sbindir}/frr_babeltrace.py
%if %{with_ospfclient} && (0%{?rhel} > 7 || 0%{?fedora} > 29)
%{_sbindir}/ospfclient.py
%endif
%if 0%{?rhel} > 7 || 0%{?fedora} > 29
%{_sbindir}/__pycache__/*
%else
@ -774,6 +779,10 @@ sed -i 's/ -M rpki//' %{_sysconfdir}/frr/daemons
%changelog
* Sun May 29 2022 Christian Hopps <chopps@labn.net> - %{version}
- ospfclient:
- Add OSPF API python client ospfclient.py
* Tue Mar 1 2022 Martin Winter <mwinter@opensourcerouting.org> - %{version}
* Tue Mar 1 2022 Jafar Al-Gharaibeh <jafar@atcorp.com> - 8.2

View File

@ -52,6 +52,7 @@ static void test_run_spf(struct vty *vty, struct ospf *ospf,
enum protection_type protection_type, bool verbose)
{
struct route_table *new_table, *new_rtrs;
struct route_table *all_rtrs = NULL;
struct ospf_area *area;
struct p_space *p_space;
struct q_space *q_space;
@ -63,10 +64,11 @@ static void test_run_spf(struct vty *vty, struct ospf *ospf,
new_table = route_table_init();
new_rtrs = route_table_init();
all_rtrs = route_table_init();
/* dryrun true, root_node false */
ospf_spf_calculate(area, area->router_lsa_self, new_table, new_rtrs,
true, false);
ospf_spf_calculate(area, area->router_lsa_self, new_table, all_rtrs,
new_rtrs, true, false);
if (verbose) {
vty_out(vty, "SPF Tree without TI-LFA backup paths:\n\n");

View File

@ -0,0 +1,137 @@
#!/usr/bin/env python3
# -*- coding: utf-8 eval: (blacken-mode 1) -*-
#
# January 17 2022, Christian Hopps <chopps@labn.net>
#
# Copyright 2022, LabN Consulting, L.L.C.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
import argparse
import asyncio
import logging
import os
import sys
CWD = os.path.dirname(os.path.realpath(__file__))
CLIENTDIR = os.path.abspath(os.path.join(CWD, "../../../ospfclient"))
if not os.path.exists(CLIENTDIR):
CLIENTDIR = os.path.join(CWD, "/usr/lib/frr")
assert os.path.exists(
os.path.join(CLIENTDIR, "ospfclient.py")
), "can't locate ospfclient.py"
sys.path[0:0] = [CLIENTDIR]
import ospfclient as api # pylint: disable=E0401 # noqa: E402
async def do_wait(c, args):
cv = asyncio.Condition()
async def cb(added, removed):
logging.debug("callback: added: %s removed: %s", added, removed)
sys.stdout.flush()
async with cv:
cv.notify_all()
logging.debug("API using callback")
await c.monitor_reachable(callback=cb)
for w in args.wait:
check = ",".join(sorted(list(w.split(","))))
logging.info("Waiting for %s", check)
while True:
async with cv:
got = ",".join(sorted([str(x) for x in c.reachable_routers]))
if check == got:
break
logging.debug("expected '%s' != '%s'\nwaiting on notify", check, got)
await cv.wait()
logging.info("SUCCESS: %s", check)
print("SUCCESS: {}".format(check))
sys.stdout.flush()
async def async_main(args):
c = api.OspfOpaqueClient(args.server)
await c.connect()
if sys.version_info[1] > 6:
asyncio.create_task(c._handle_msg_loop()) # pylint: disable=W0212
else:
asyncio.get_event_loop().create_task(
c._handle_msg_loop() # pylint: disable=W0212
)
if args.wait:
await do_wait(c, args)
return 0
def main(*args):
ap = argparse.ArgumentParser(args)
ap.add_argument("--server", default="localhost", help="OSPF API server")
ap.add_argument(
"--wait", action="append", help="wait for comma-sep set of reachable routers"
)
ap.add_argument("-v", "--verbose", action="store_true", help="be verbose")
args = ap.parse_args()
level = logging.DEBUG if args.verbose else logging.INFO
logging.basicConfig(
level=level, format="%(asctime)s %(levelname)s: TESTER: %(name)s: %(message)s"
)
# We need to flush this output to stdout right away
h = logging.StreamHandler(sys.stdout)
h.flush = sys.stdout.flush
f = logging.Formatter("%(asctime)s %(name)s: %(levelname)s: %(message)s")
h.setFormatter(f)
logger = logging.getLogger("ospfclient")
logger.addHandler(h)
logger.propagate = False
logging.info("ctester: starting")
sys.stdout.flush()
status = 3
try:
if sys.version_info[1] > 6:
status = asyncio.run(async_main(args))
else:
loop = asyncio.get_event_loop()
try:
status = loop.run_until_complete(async_main(args))
finally:
loop.close()
except KeyboardInterrupt:
logging.info("Exiting, received KeyboardInterrupt in main")
except Exception as error:
logging.info("Exiting, unexpected exception %s", error, exc_info=True)
else:
logging.info("api: clean exit")
return status
if __name__ == "__main__":
exit_status = main()
sys.exit(exit_status)

1
tests/topotests/ospfapi/lib Symbolic link
View File

@ -0,0 +1 @@
../lib

View File

@ -0,0 +1,10 @@
!
interface r1-eth0
ip ospf hello-interval 2
ip ospf dead-interval 10
ip ospf area 1.2.3.4
!
router ospf
ospf router-id 192.168.0.1
capability opaque
!

View File

@ -0,0 +1,4 @@
!
interface r1-eth0
ip address 10.0.1.1/24
!

View File

@ -0,0 +1,15 @@
!
interface r2-eth0
ip ospf hello-interval 2
ip ospf dead-interval 10
ip ospf area 1.2.3.4
!
interface r2-eth1
ip ospf hello-interval 2
ip ospf dead-interval 10
ip ospf area 1.2.3.4
!
router ospf
ospf router-id 192.168.0.2
capability opaque
!

View File

@ -0,0 +1,7 @@
!
interface r2-eth0
ip address 10.0.1.2/24
!
interface r2-eth1
ip address 10.0.2.2/24
!

View File

@ -0,0 +1,15 @@
!
interface r3-eth0
ip ospf hello-interval 2
ip ospf dead-interval 10
ip ospf area 1.2.3.4
!
interface r3-eth1
ip ospf hello-interval 2
ip ospf dead-interval 10
ip ospf area 1.2.3.4
!
router ospf
ospf router-id 192.168.0.3
capability opaque
!

View File

@ -0,0 +1,7 @@
!
interface r3-eth0
ip address 10.0.2.3/24
!
interface r3-eth1
ip address 10.0.3.3/24
!

View File

@ -0,0 +1,10 @@
!
interface r4-eth0
ip ospf hello-interval 2
ip ospf dead-interval 10
ip ospf area 1.2.3.4
!
router ospf
ospf router-id 192.168.0.4
capability opaque
!

View File

@ -0,0 +1,4 @@
!
interface r4-eth0
ip address 10.0.3.4/24
!

View File

@ -0,0 +1,470 @@
#!/usr/bin/env python
# -*- coding: utf-8 eval: (blacken-mode 1) -*-
#
# Copyright (c) 2021, LabN Consulting, L.L.C.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; see the file COPYING; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
"""
test_ospf_clientapi.py: Test the OSPF client API.
"""
import logging
import os
import re
import signal
import subprocess
import sys
import time
from datetime import datetime, timedelta
import pytest
from lib.common_config import retry, run_frr_cmd, step
from lib.micronet import comm_error
from lib.topogen import Topogen, TopoRouter
from lib.topotest import interface_set_status, json_cmp
pytestmark = [pytest.mark.ospfd]
CWD = os.path.dirname(os.path.realpath(__file__))
TESTDIR = os.path.abspath(CWD)
CLIENTDIR = os.path.abspath(os.path.join(CWD, "../../../ospfclient"))
if not os.path.exists(CLIENTDIR):
CLIENTDIR = os.path.join(CWD, "/usr/lib/frr")
assert os.path.exists(
os.path.join(CLIENTDIR, "ospfclient.py")
), "can't locate ospfclient.py"
# ----------
# Test Setup
# ----------
@pytest.fixture(scope="function", name="tgen")
def _tgen(request):
"Setup/Teardown the environment and provide tgen argument to tests"
nrouters = request.param
topodef = {f"sw{i}": (f"r{i}", f"r{i+1}") for i in range(1, nrouters)}
tgen = Topogen(topodef, request.module.__name__)
tgen.start_topology()
router_list = tgen.routers()
for _, router in router_list.items():
router.load_config(TopoRouter.RD_ZEBRA, "zebra.conf")
router.load_config(TopoRouter.RD_OSPF, "ospfd.conf")
router.net.daemons_options["ospfd"] = "--apiserver"
tgen.start_router()
yield tgen
tgen.stop_topology()
# Fixture that executes before each test
@pytest.fixture(autouse=True)
def skip_on_failure(tgen):
if tgen.routers_have_failure():
pytest.skip("skipped because of previous test failure")
# ------------
# Test Utility
# ------------
@retry(retry_timeout=45)
def verify_ospf_database(tgen, dut, input_dict, cmd="show ip ospf database json"):
del tgen
show_ospf_json = run_frr_cmd(dut, cmd, isjson=True)
if not bool(show_ospf_json):
return "ospf is not running"
result = json_cmp(show_ospf_json, input_dict)
return str(result) if result else None
def myreadline(f):
buf = b""
while True:
# logging.info("READING 1 CHAR")
c = f.read(1)
if not c:
return buf if buf else None
buf += c
# logging.info("READ CHAR: '%s'", c)
if c == b"\n":
return buf
def _wait_output(p, regex, timeout=120):
retry_until = datetime.now() + timedelta(seconds=timeout)
while datetime.now() < retry_until:
# line = p.stdout.readline()
line = myreadline(p.stdout)
if not line:
assert None, "Timeout waiting for '{}'".format(regex)
line = line.decode("utf-8")
line = line.rstrip()
if line:
logging.debug("GOT LINE: '%s'", line)
m = re.search(regex, line)
if m:
return m
assert None, "Failed to get output withint {}s".format(timeout)
# -----
# Tests
# -----
def _test_reachability(tgen, testbin):
waitlist = [
"192.168.0.1,192.168.0.2,192.168.0.4",
"192.168.0.2,192.168.0.4",
"192.168.0.1,192.168.0.2,192.168.0.4",
]
r2 = tgen.gears["r2"]
r3 = tgen.gears["r3"]
wait_args = [f"--wait={x}" for x in waitlist]
p = None
try:
step("reachable: check for initial reachability")
p = r3.popen(
["/usr/bin/timeout", "120", testbin, "-v", *wait_args],
encoding=None, # don't buffer
stdin=subprocess.DEVNULL,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
)
_wait_output(p, "SUCCESS: {}".format(waitlist[0]))
step("reachable: check for modified reachability")
interface_set_status(r2, "r2-eth0", False)
_wait_output(p, "SUCCESS: {}".format(waitlist[1]))
step("reachable: check for restored reachability")
interface_set_status(r2, "r2-eth0", True)
_wait_output(p, "SUCCESS: {}".format(waitlist[2]))
except Exception as error:
logging.error("ERROR: %s", error)
raise
finally:
if p:
p.terminate()
p.wait()
@pytest.mark.parametrize("tgen", [4], indirect=True)
def test_ospf_reachability(tgen):
testbin = os.path.join(TESTDIR, "ctester.py")
rc, o, e = tgen.gears["r2"].net.cmd_status([testbin, "--help"])
logging.info("%s --help: rc: %s stdout: '%s' stderr: '%s'", testbin, rc, o, e)
_test_reachability(tgen, testbin)
def _test_add_data(tgen, apibin):
"Test adding opaque data to domain"
r1 = tgen.gears["r1"]
step("add opaque: add opaque link local")
p = None
try:
p = r1.popen([apibin, "-v", "add,9,10.0.1.1,230,2,00000202"])
input_dict = {
"routerId": "192.168.0.1",
"areas": {
"1.2.3.4": {
"linkLocalOpaqueLsa": [
{
"lsId": "230.0.0.2",
"advertisedRouter": "192.168.0.1",
"sequenceNumber": "80000001",
}
],
}
},
}
# Wait for it to show up
assert verify_ospf_database(tgen, r1, input_dict) is None
input_dict = {
"linkLocalOpaqueLsa": {
"areas": {
"1.2.3.4": [
{
"linkStateId": "230.0.0.2",
"advertisingRouter": "192.168.0.1",
"lsaSeqNumber": "80000001",
"opaqueData": "00000202",
},
],
}
},
}
# verify content
json_cmd = "show ip ospf da opaque-link json"
assert verify_ospf_database(tgen, r1, input_dict, json_cmd) is None
step("reset client, add opaque area, verify link local flushing")
p.send_signal(signal.SIGINT)
time.sleep(2)
p.wait()
p = None
p = r1.popen([apibin, "-v", "add,10,1.2.3.4,231,1,00010101"])
input_dict = {
"routerId": "192.168.0.1",
"areas": {
"1.2.3.4": {
"linkLocalOpaqueLsa": [
{
"lsId": "230.0.0.2",
"advertisedRouter": "192.168.0.1",
"sequenceNumber": "80000001",
"lsaAge": 3600,
}
],
"areaLocalOpaqueLsa": [
{
"lsId": "231.0.0.1",
"advertisedRouter": "192.168.0.1",
"sequenceNumber": "80000001",
},
],
}
},
}
# Wait for it to show up
assert verify_ospf_database(tgen, r1, input_dict) is None
input_dict = {
"areaLocalOpaqueLsa": {
"areas": {
"1.2.3.4": [
{
"linkStateId": "231.0.0.1",
"advertisingRouter": "192.168.0.1",
"lsaSeqNumber": "80000001",
"opaqueData": "00010101",
},
],
}
},
}
# verify content
json_cmd = "show ip ospf da opaque-area json"
assert verify_ospf_database(tgen, r1, input_dict, json_cmd) is None
step("reset client, add opaque AS, verify area flushing")
p.send_signal(signal.SIGINT)
time.sleep(2)
p.wait()
p = None
p = r1.popen([apibin, "-v", "add,11,232,3,deadbeaf01234567"])
input_dict = {
"routerId": "192.168.0.1",
"areas": {
"1.2.3.4": {
"areaLocalOpaqueLsa": [
{
"lsId": "231.0.0.1",
"advertisedRouter": "192.168.0.1",
"sequenceNumber": "80000001",
"lsaAge": 3600,
},
],
}
},
"asExternalOpaqueLsa": [
{
"lsId": "232.0.0.3",
"advertisedRouter": "192.168.0.1",
"sequenceNumber": "80000001",
},
],
}
# Wait for it to show up
assert verify_ospf_database(tgen, r1, input_dict) is None
input_dict = {
"asExternalOpaqueLsa": [
{
"linkStateId": "232.0.0.3",
"advertisingRouter": "192.168.0.1",
"lsaSeqNumber": "80000001",
"opaqueData": "deadbeaf01234567",
},
]
}
# verify content
json_cmd = "show ip ospf da opaque-as json"
assert verify_ospf_database(tgen, r1, input_dict, json_cmd) is None
step("stop client, verify AS flushing")
p.send_signal(signal.SIGINT)
time.sleep(2)
p.wait()
p = None
input_dict = {
"routerId": "192.168.0.1",
"asExternalOpaqueLsa": [
{
"lsId": "232.0.0.3",
"advertisedRouter": "192.168.0.1",
"sequenceNumber": "80000001",
"lsaAge": 3600,
},
],
}
# Wait for it to be flushed
assert verify_ospf_database(tgen, r1, input_dict) is None
step("start client adding opaque domain, verify new sequence number and data")
# Originate it again
p = r1.popen([apibin, "-v", "add,11,232,3,ebadf00d"])
input_dict = {
"routerId": "192.168.0.1",
"asExternalOpaqueLsa": [
{
"lsId": "232.0.0.3",
"advertisedRouter": "192.168.0.1",
"sequenceNumber": "80000002",
},
],
}
assert verify_ospf_database(tgen, r1, input_dict) is None
input_dict = {
"asExternalOpaqueLsa": [
{
"linkStateId": "232.0.0.3",
"advertisingRouter": "192.168.0.1",
"lsaSeqNumber": "80000002",
"opaqueData": "ebadf00d",
},
]
}
# verify content
json_cmd = "show ip ospf da opaque-as json"
assert verify_ospf_database(tgen, r1, input_dict, json_cmd) is None
p.send_signal(signal.SIGINT)
time.sleep(2)
p.wait()
p = None
except Exception:
if p:
p.terminate()
if p.wait():
comm_error(p)
p = None
raise
finally:
if p:
p.terminate()
p.wait()
@pytest.mark.parametrize("tgen", [2], indirect=True)
def test_ospf_opaque_add_data3(tgen):
apibin = os.path.join(CLIENTDIR, "ospfclient.py")
rc, o, e = tgen.gears["r2"].net.cmd_status([apibin, "--help"])
logging.info("%s --help: rc: %s stdout: '%s' stderr: '%s'", apibin, rc, o, e)
_test_add_data(tgen, apibin)
def _test_opaque_add_del(tgen, apibin):
"Test adding opaque data to domain"
r1 = tgen.gears["r1"]
r2 = tgen.gears["r2"]
p = None
pread = None
try:
step("reachable: check for add notification")
pread = r2.popen(
["/usr/bin/timeout", "120", apibin, "-v"],
encoding=None, # don't buffer
stdin=subprocess.DEVNULL,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
)
p = r1.popen([apibin, "-v", "add,11,232,3,ebadf00d"])
# Wait for add notification
# RECV: LSA update msg for LSA 232.0.0.3 in area 0.0.0.0 seq 0x80000001 len 24 age 9
ls_id = "232.0.0.3"
waitfor = "RECV:.*update msg.*LSA {}.*age ([0-9]+)".format(ls_id)
_ = _wait_output(pread, waitfor)
p.terminate()
if p.wait():
comm_error(p)
# step("reachable: check for flush/age out")
# # Wait for max age notification
# waitfor = "RECV:.*update msg.*LSA {}.*age 3600".format(ls_id)
# _wait_output(pread, waitfor)
step("reachable: check for delete")
# Wait for delete notification
waitfor = "RECV:.*delete msg.*LSA {}.*".format(ls_id)
_wait_output(pread, waitfor)
except Exception:
if p:
p.terminate()
if p.wait():
comm_error(p)
p = None
raise
finally:
if pread:
pread.terminate()
pread.wait()
if p:
p.terminate()
p.wait()
@pytest.mark.parametrize("tgen", [2], indirect=True)
def test_ospf_opaque_delete_data3(tgen):
apibin = os.path.join(CLIENTDIR, "ospfclient.py")
rc, o, e = tgen.gears["r2"].net.cmd_status([apibin, "--help"])
logging.info("%s --help: rc: %s stdout: '%s' stderr: '%s'", apibin, rc, o, e)
_test_opaque_add_del(tgen, apibin)
if __name__ == "__main__":
args = ["-s"] + sys.argv[1:]
sys.exit(pytest.main(args))