ospfd: api: fix recovery of LSA after restart of api client

Prior to this fix, restarting the client just failed b/c the code tried to
"refresh" the existing LSA being added, except that code checked for meta-data
to exist, which was deleted when the client disconnected previously (or had
never connected and the LSA state was picked up from the network).

Signed-off-by: Christian Hopps <chopps@labn.net>
This commit is contained in:
Christian Hopps 2022-01-08 16:57:10 -05:00
parent d86760acad
commit 5349121b4c
4 changed files with 73 additions and 52 deletions

View File

@ -1627,9 +1627,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
@ -1696,17 +1696,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;
}

View File

@ -174,7 +174,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);

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 */