ospf6d: improve ordered shutdown
Improve the _disable/_enable infrastructure so it gets into
a more usable shape and make 'no router ospf6' actually work.
Signed-off-by: Christian Franke <chris@opensourcerouting.org>
Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
diff --git a/ospf6d/ospf6_area.c b/ospf6d/ospf6_area.c
index b09d961..9a4e30e 100644
--- a/ospf6d/ospf6_area.c
+++ b/ospf6d/ospf6_area.c
@@ -193,18 +193,21 @@
void
ospf6_area_delete (struct ospf6_area *oa)
{
- struct listnode *n, *nnode;
+ struct listnode *n;
struct ospf6_interface *oi;
ospf6_route_table_delete (oa->range_table);
ospf6_route_table_delete (oa->summary_prefix);
ospf6_route_table_delete (oa->summary_router);
- /* ospf6 interface list */
- for (ALL_LIST_ELEMENTS (oa->if_list, n, nnode, oi))
- {
- ospf6_interface_delete (oi);
- }
+ /* The ospf6_interface structs store configuration
+ * information which should not be lost/reset when
+ * deleting an area.
+ * So just detach the interface from the area and
+ * keep it around. */
+ for (ALL_LIST_ELEMENTS_RO (oa->if_list, n, oi))
+ oi->area = NULL;
+
list_delete (oa->if_list);
ospf6_lsdb_delete (oa->lsdb);
@@ -257,6 +260,7 @@
for (ALL_LIST_ELEMENTS (oa->if_list, node, nnode, oi))
ospf6_interface_enable (oi);
+ ospf6_abr_enable_area (oa);
}
void
@@ -269,6 +273,19 @@
for (ALL_LIST_ELEMENTS (oa->if_list, node, nnode, oi))
ospf6_interface_disable (oi);
+
+ ospf6_abr_disable_area (oa);
+ ospf6_lsdb_remove_all (oa->lsdb);
+ ospf6_lsdb_remove_all (oa->lsdb_self);
+
+ ospf6_spf_table_finish(oa->spf_table);
+ ospf6_route_remove_all(oa->route_table);
+
+ THREAD_OFF (oa->thread_spf_calculation);
+ THREAD_OFF (oa->thread_route_calculation);
+
+ THREAD_OFF (oa->thread_router_lsa);
+ THREAD_OFF (oa->thread_intra_prefix_lsa);
}
diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c
index 60df6e6..3605e3f 100644
--- a/ospf6d/ospf6_asbr.c
+++ b/ospf6d/ospf6_asbr.c
@@ -409,6 +409,8 @@
ospf6_asbr_redistribute_remove (info->type, route->nexthop[0].ifindex,
&route->prefix);
}
+
+ ospf6_asbr_routemap_unset (type);
}
void
@@ -636,7 +638,6 @@
return CMD_WARNING;
ospf6_asbr_redistribute_unset (type);
- ospf6_asbr_routemap_unset (type);
ospf6_asbr_redistribute_set (type);
return CMD_SUCCESS;
}
@@ -677,7 +678,6 @@
return CMD_WARNING;
ospf6_asbr_redistribute_unset (type);
- ospf6_asbr_routemap_unset (type);
return CMD_SUCCESS;
}
@@ -1313,6 +1313,20 @@
}
void
+ospf6_asbr_redistribute_reset (void)
+{
+ int type;
+
+ for (type = 0; type < ZEBRA_ROUTE_MAX; type++)
+ {
+ if (type == ZEBRA_ROUTE_OSPF6)
+ continue;
+ if (ospf6_zebra_is_redistribute (type))
+ ospf6_asbr_redistribute_unset(type);
+ }
+}
+
+void
ospf6_asbr_terminate (void)
{
route_map_finish ();
diff --git a/ospf6d/ospf6_asbr.h b/ospf6d/ospf6_asbr.h
index 72e4914..73770cc 100644
--- a/ospf6d/ospf6_asbr.h
+++ b/ospf6d/ospf6_asbr.h
@@ -89,6 +89,7 @@
extern int ospf6_redistribute_config_write (struct vty *vty);
extern void ospf6_asbr_init (void);
+extern void ospf6_asbr_redistribute_reset (void);
extern void ospf6_asbr_terminate (void);
extern int config_write_ospf6_debug_asbr (struct vty *vty);
diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c
index 86c0bf6..d9d2d03 100644
--- a/ospf6d/ospf6_interface.c
+++ b/ospf6d/ospf6_interface.c
@@ -219,31 +219,28 @@
ospf6_interface_enable (struct ospf6_interface *oi)
{
UNSET_FLAG (oi->flag, OSPF6_INTERFACE_DISABLE);
-
- oi->thread_send_hello =
- thread_add_event (master, ospf6_hello_send, oi, 0);
+ ospf6_interface_state_update (oi->interface);
}
void
ospf6_interface_disable (struct ospf6_interface *oi)
{
- struct listnode *node, *nnode;
- struct ospf6_neighbor *on;
-
SET_FLAG (oi->flag, OSPF6_INTERFACE_DISABLE);
- for (ALL_LIST_ELEMENTS (oi->neighbor_list, node, nnode, on))
- ospf6_neighbor_delete (on);
-
- list_delete_all_node (oi->neighbor_list);
+ thread_execute (master, interface_down, oi, 0);
ospf6_lsdb_remove_all (oi->lsdb);
+ ospf6_lsdb_remove_all (oi->lsdb_self);
ospf6_lsdb_remove_all (oi->lsupdate_list);
ospf6_lsdb_remove_all (oi->lsack_list);
THREAD_OFF (oi->thread_send_hello);
THREAD_OFF (oi->thread_send_lsupdate);
THREAD_OFF (oi->thread_send_lsack);
+
+ THREAD_OFF (oi->thread_network_lsa);
+ THREAD_OFF (oi->thread_link_lsa);
+ THREAD_OFF (oi->thread_intra_prefix_lsa);
}
static struct in6_addr *
@@ -327,6 +324,8 @@
return;
if (oi->area == NULL)
return;
+ if (CHECK_FLAG (oi->flag, OSPF6_INTERFACE_DISABLE))
+ return;
if (if_is_operative (ifp))
thread_add_event (master, interface_up, oi, 0);
@@ -355,6 +354,9 @@
if (oi->area == NULL)
return;
+ if (CHECK_FLAG (oi->flag, OSPF6_INTERFACE_DISABLE))
+ return;
+
/* update "route to advertise" interface route table */
ospf6_route_remove_all (oi->route_connected);
diff --git a/ospf6d/ospf6_intra.h b/ospf6d/ospf6_intra.h
index a25efa1..e909da2 100644
--- a/ospf6d/ospf6_intra.h
+++ b/ospf6d/ospf6_intra.h
@@ -156,32 +156,37 @@
#define OSPF6_ROUTER_LSA_SCHEDULE(oa) \
do { \
- if (! (oa)->thread_router_lsa) \
+ if (! (oa)->thread_router_lsa \
+ && CHECK_FLAG((oa)->flag, OSPF6_AREA_ENABLE)) \
(oa)->thread_router_lsa = \
thread_add_event (master, ospf6_router_lsa_originate, oa, 0); \
} while (0)
#define OSPF6_NETWORK_LSA_SCHEDULE(oi) \
do { \
- if (! (oi)->thread_network_lsa) \
+ if (! (oi)->thread_network_lsa \
+ && ! CHECK_FLAG((oi)->flag, OSPF6_INTERFACE_DISABLE)) \
(oi)->thread_network_lsa = \
thread_add_event (master, ospf6_network_lsa_originate, oi, 0); \
} while (0)
#define OSPF6_LINK_LSA_SCHEDULE(oi) \
do { \
- if (! (oi)->thread_link_lsa) \
+ if (! (oi)->thread_link_lsa \
+ && ! CHECK_FLAG((oi)->flag, OSPF6_INTERFACE_DISABLE)) \
(oi)->thread_link_lsa = \
thread_add_event (master, ospf6_link_lsa_originate, oi, 0); \
} while (0)
#define OSPF6_INTRA_PREFIX_LSA_SCHEDULE_STUB(oa) \
do { \
- if (! (oa)->thread_intra_prefix_lsa) \
+ if (! (oa)->thread_intra_prefix_lsa \
+ && CHECK_FLAG((oa)->flag, OSPF6_AREA_ENABLE)) \
(oa)->thread_intra_prefix_lsa = \
thread_add_event (master, ospf6_intra_prefix_lsa_originate_stub, \
oa, 0); \
} while (0)
#define OSPF6_INTRA_PREFIX_LSA_SCHEDULE_TRANSIT(oi) \
do { \
- if (! (oi)->thread_intra_prefix_lsa) \
+ if (! (oi)->thread_intra_prefix_lsa \
+ && ! CHECK_FLAG((oi)->flag, OSPF6_INTERFACE_DISABLE)) \
(oi)->thread_intra_prefix_lsa = \
thread_add_event (master, ospf6_intra_prefix_lsa_originate_transit, \
oi, 0); \
diff --git a/ospf6d/ospf6_main.c b/ospf6d/ospf6_main.c
index 17d7654..e991971 100644
--- a/ospf6d/ospf6_main.c
+++ b/ospf6d/ospf6_main.c
@@ -41,6 +41,8 @@
#include "ospf6_message.h"
#include "ospf6_asbr.h"
#include "ospf6_lsa.h"
+#include "ospf6_interface.h"
+#include "ospf6_zebra.h"
/* Default configuration file name for ospf6d. */
#define OSPF6_DEFAULT_CONFIG "ospf6d.conf"
@@ -134,12 +136,16 @@
static void __attribute__ ((noreturn))
ospf6_exit (int status)
{
- extern struct ospf6 *ospf6;
- extern struct zclient *zclient;
+ struct listnode *node;
+ struct interface *ifp;
if (ospf6)
ospf6_delete (ospf6);
+ for (ALL_LIST_ELEMENTS_RO(iflist, node, ifp))
+ if (ifp->info != NULL)
+ ospf6_interface_delete(ifp->info);
+
ospf6_message_terminate ();
ospf6_asbr_terminate ();
ospf6_lsa_terminate ();
diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c
index caebf5d..5fb5a21 100644
--- a/ospf6d/ospf6_message.c
+++ b/ospf6d/ospf6_message.c
@@ -1543,7 +1543,7 @@
}
oi = ospf6_interface_lookup_by_ifindex (ifindex);
- if (oi == NULL || oi->area == NULL)
+ if (oi == NULL || oi->area == NULL || CHECK_FLAG(oi->flag, OSPF6_INTERFACE_DISABLE))
{
zlog_debug ("Message received on disabled interface");
return 0;
diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c
index f83e6ab..7c0922a 100644
--- a/ospf6d/ospf6_top.c
+++ b/ospf6d/ospf6_top.c
@@ -161,6 +161,8 @@
for (ALL_LIST_ELEMENTS (o->area_list, node, nnode, oa))
ospf6_area_delete (oa);
+
+
list_delete (o->area_list);
ospf6_lsdb_delete (o->lsdb);
@@ -202,9 +204,16 @@
for (ALL_LIST_ELEMENTS (o->area_list, node, nnode, oa))
ospf6_area_disable (oa);
+ /* XXX: This also changes persistent settings */
+ ospf6_asbr_redistribute_reset();
+
ospf6_lsdb_remove_all (o->lsdb);
ospf6_route_remove_all (o->route_table);
ospf6_route_remove_all (o->brouter_table);
+
+ THREAD_OFF(o->maxage_remover);
+ THREAD_OFF(o->t_spf_calc);
+ THREAD_OFF(o->t_ase_calc);
}
}
@@ -282,8 +291,6 @@
{
if (ospf6 == NULL)
ospf6 = ospf6_create ();
- if (CHECK_FLAG (ospf6->flag, OSPF6_DISABLED))
- ospf6_enable (ospf6);
/* set current ospf point. */
vty->node = OSPF6_NODE;
@@ -299,10 +306,13 @@
NO_STR
OSPF6_ROUTER_STR)
{
- if (ospf6 == NULL || CHECK_FLAG (ospf6->flag, OSPF6_DISABLED))
- vty_out (vty, "OSPFv3 is not running%s", VNL);
+ if (ospf6 == NULL)
+ vty_out (vty, "OSPFv3 is not configured%s", VNL);
else
- ospf6_disable (ospf6);
+ {
+ ospf6_delete (ospf6);
+ ospf6 = NULL;
+ }
/* return to config node . */
vty->node = CONFIG_NODE;
@@ -435,8 +445,12 @@
SET_FLAG (oa->flag, OSPF6_AREA_ENABLE);
+ /* ospf6 process is currently disabled, not much more to do */
+ if (CHECK_FLAG (o->flag, OSPF6_DISABLED))
+ return CMD_SUCCESS;
+
/* start up */
- thread_add_event (master, interface_up, oi, 0);
+ ospf6_interface_enable (oi);
/* If the router is ABR, originate summary routes */
if (ospf6_is_router_abr (o))
@@ -861,8 +875,6 @@
/* OSPFv6 configuration. */
if (ospf6 == NULL)
return CMD_SUCCESS;
- if (CHECK_FLAG (ospf6->flag, OSPF6_DISABLED))
- return CMD_SUCCESS;
inet_ntop (AF_INET, &ospf6->router_id_static, router_id, sizeof (router_id));
vty_out (vty, "router ospf6%s", VNL);
diff --git a/ospf6d/ospf6_zebra.c b/ospf6d/ospf6_zebra.c
index f09e9d2..50ecc17 100644
--- a/ospf6d/ospf6_zebra.c
+++ b/ospf6d/ospf6_zebra.c
@@ -117,7 +117,9 @@
ifp->name, ifp->ifindex, ifp->mtu6);
#if 0
- /* Why is this commented out? */
+ /* XXX: ospf6_interface_if_del is not the right way to handle this,
+ * because among other thinkable issues, it will also clear all
+ * settings as they are contained in the struct ospf6_interface. */
ospf6_interface_if_del (ifp);
#endif /*0*/