]> git.puffer.fish Git - matthieu/frr.git/commitdiff
ospfd: api: fix recovery of LSA after restart of api client
authorChristian Hopps <chopps@labn.net>
Sat, 8 Jan 2022 21:57:10 +0000 (16:57 -0500)
committerChristian Hopps <chopps@labn.net>
Thu, 2 Jun 2022 20:37:16 +0000 (16:37 -0400)
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>
ospfd/ospf_apiserver.c
ospfd/ospf_apiserver.h
ospfd/ospf_opaque.c
ospfd/ospf_opaque.h

index 259ba2a3f1274f87c699717720518cd497a4c49b..4015566b10be87cacacfe09f4630e0e0e47fcd7f 100644 (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;
        }
 
index 8a756e9c3c8a12864642337f925591b7c1c0d9eb..a57f172b5d9243d301f0cc330f1124f70d0b7655 100644 (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);
 
 
index 947454c0dfaa059a33b5c29d2610ab3097d657dc..7e95cb591a7c75df087c1a73fd19ac7b6570b2fc 100644 (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)
-{
-       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)
+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;
        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.
  *------------------------------------------------------------------------*/
index 59d4288bf26f4119124a678cd0f1bcafe9fb03bc..9c768779086388a9c5248ce11ef83661ca783dd3 100644 (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 */