/* * This is an implementation of rfc2370. * Copyright (C) 2001 KDD R&D Laboratories, Inc. * http://www.kddlabs.co.jp/ * * This file is part of GNU Zebra. * * GNU Zebra 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, or (at your option) any * later version. * * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ /***** MTYPE definitions are not reflected to "memory.h" yet. *****/ #define MTYPE_OSPF_OPAQUE_FUNCTAB 0 #define MTYPE_OPAQUE_INFO_PER_TYPE 0 #define MTYPE_OPAQUE_INFO_PER_ID 0 #include #ifdef HAVE_OPAQUE_LSA #include "linklist.h" #include "prefix.h" #include "if.h" #include "table.h" #include "memory.h" #include "command.h" #include "vty.h" #include "stream.h" #include "log.h" #include "thread.h" #include "hash.h" #include "sockunion.h" /* for inet_aton() */ #include "ospfd/ospfd.h" #include "ospfd/ospf_interface.h" #include "ospfd/ospf_ism.h" #include "ospfd/ospf_asbr.h" #include "ospfd/ospf_lsa.h" #include "ospfd/ospf_lsdb.h" #include "ospfd/ospf_neighbor.h" #include "ospfd/ospf_nsm.h" #include "ospfd/ospf_flood.h" #include "ospfd/ospf_packet.h" #include "ospfd/ospf_spf.h" #include "ospfd/ospf_dump.h" #include "ospfd/ospf_route.h" #include "ospfd/ospf_ase.h" #include "ospfd/ospf_zebra.h" /*------------------------------------------------------------------------* * Followings are initialize/terminate functions for Opaque-LSAs handling. *------------------------------------------------------------------------*/ #ifdef HAVE_OSPF_TE #include "ospfd/ospf_te.h" #endif /* HAVE_OSPF_TE */ #ifdef SUPPORT_OSPF_API int ospf_apiserver_init (void); void ospf_apiserver_term (void); /* Init apiserver? It's disabled by default. */ int ospf_apiserver_enable; #endif /* SUPPORT_OSPF_API */ 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_id (void *val); static int ospf_opaque_lsa_install_hook (struct ospf_lsa *lsa); static int ospf_opaque_lsa_delete_hook (struct ospf_lsa *lsa); void ospf_opaque_init (void) { ospf_opaque_register_vty (); ospf_opaque_funclist_init (); #ifdef HAVE_OSPF_TE if (ospf_mpls_te_init () != 0) exit (1); #endif /* HAVE_OSPF_TE */ #ifdef SUPPORT_OSPF_API if ((ospf_apiserver_enable) && (ospf_apiserver_init () != 0)) exit (1); #endif /* SUPPORT_OSPF_API */ return; } void ospf_opaque_term (void) { #ifdef HAVE_OSPF_TE ospf_mpls_te_term (); #endif /* HAVE_OSPF_TE */ #ifdef SUPPORT_OSPF_API ospf_apiserver_term (); #endif /* SUPPORT_OSPF_API */ ospf_opaque_funclist_term (); return; } int ospf_opaque_type9_lsa_init (struct ospf_interface *oi) { if (oi->opaque_lsa_self != NULL) list_delete (oi->opaque_lsa_self); oi->opaque_lsa_self = list_new (); oi->opaque_lsa_self->del = free_opaque_info_per_type; oi->t_opaque_lsa_self = NULL; return 0; } void ospf_opaque_type9_lsa_term (struct ospf_interface *oi) { OSPF_TIMER_OFF (oi->t_opaque_lsa_self); if (oi->opaque_lsa_self != NULL) list_delete (oi->opaque_lsa_self); oi->opaque_lsa_self = NULL; return; } int ospf_opaque_type10_lsa_init (struct ospf_area *area) { if (area->opaque_lsa_self != NULL) list_delete (area->opaque_lsa_self); area->opaque_lsa_self = list_new (); area->opaque_lsa_self->del = free_opaque_info_per_type; area->t_opaque_lsa_self = NULL; #ifdef MONITOR_LSDB_CHANGE area->lsdb->new_lsa_hook = ospf_opaque_lsa_install_hook; area->lsdb->del_lsa_hook = ospf_opaque_lsa_delete_hook; #endif /* MONITOR_LSDB_CHANGE */ return 0; } void ospf_opaque_type10_lsa_term (struct ospf_area *area) { #ifdef MONITOR_LSDB_CHANGE area->lsdb->new_lsa_hook = area->lsdb->del_lsa_hook = NULL; #endif /* MONITOR_LSDB_CHANGE */ OSPF_TIMER_OFF (area->t_opaque_lsa_self); if (area->opaque_lsa_self != NULL) list_delete (area->opaque_lsa_self); area->opaque_lsa_self = NULL; return; } int ospf_opaque_type11_lsa_init (struct ospf *top) { if (top->opaque_lsa_self != NULL) list_delete (top->opaque_lsa_self); top->opaque_lsa_self = list_new (); top->opaque_lsa_self->del = free_opaque_info_per_type; top->t_opaque_lsa_self = NULL; #ifdef MONITOR_LSDB_CHANGE top->lsdb->new_lsa_hook = ospf_opaque_lsa_install_hook; top->lsdb->del_lsa_hook = ospf_opaque_lsa_delete_hook; #endif /* MONITOR_LSDB_CHANGE */ return 0; } void ospf_opaque_type11_lsa_term (struct ospf *top) { #ifdef MONITOR_LSDB_CHANGE top->lsdb->new_lsa_hook = top->lsdb->del_lsa_hook = NULL; #endif /* MONITOR_LSDB_CHANGE */ OSPF_TIMER_OFF (top->t_opaque_lsa_self); if (top->opaque_lsa_self != NULL) list_delete (top->opaque_lsa_self); top->opaque_lsa_self = NULL; return; } static const char * ospf_opaque_type_name (u_char opaque_type) { const char *name = "Unknown"; switch (opaque_type) { case OPAQUE_TYPE_WILDCARD: /* This is a special assignment! */ name = "Wildcard"; break; case OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA: name = "Traffic Engineering LSA"; break; case OPAQUE_TYPE_SYCAMORE_OPTICAL_TOPOLOGY_DESC: name = "Sycamore optical topology description"; break; case OPAQUE_TYPE_GRACE_LSA: name = "Grace-LSA"; break; default: if (OPAQUE_TYPE_RANGE_UNASSIGNED (opaque_type)) name = "Unassigned"; else { u_int32_t bigger_range = opaque_type; /* * Get around type-limits warning: comparison is always true due to limited range of data type */ if (OPAQUE_TYPE_RANGE_RESERVED (bigger_range)) name = "Private/Experimental"; } break; } return name; } /*------------------------------------------------------------------------* * Followings are management functions to store user specified callbacks. *------------------------------------------------------------------------*/ struct opaque_info_per_type; /* Forward declaration. */ struct ospf_opaque_functab { u_char opaque_type; struct opaque_info_per_type *oipt; int (* new_if_hook)(struct interface *ifp); int (* del_if_hook)(struct interface *ifp); void (* ism_change_hook)(struct ospf_interface *oi, int old_status); void (* nsm_change_hook)(struct ospf_neighbor *nbr, int old_status); void (* config_write_router)(struct vty *vty); void (* config_write_if )(struct vty *vty, struct interface *ifp); void (* config_write_debug )(struct vty *vty); void (* show_opaque_info )(struct vty *vty, struct ospf_lsa *lsa); int (* lsa_originator)(void *arg); struct ospf_lsa *(* lsa_refresher )(struct ospf_lsa *lsa); int (* new_lsa_hook)(struct ospf_lsa *lsa); int (* del_lsa_hook)(struct ospf_lsa *lsa); }; /* Handle LSA-9/10/11 altogether. */ static struct list *ospf_opaque_wildcard_funclist; static struct list *ospf_opaque_type9_funclist; static struct list *ospf_opaque_type10_funclist; static struct list *ospf_opaque_type11_funclist; static void ospf_opaque_del_functab (void *val) { XFREE (MTYPE_OSPF_OPAQUE_FUNCTAB, val); return; } static void ospf_opaque_funclist_init (void) { struct list *funclist; funclist = ospf_opaque_wildcard_funclist = list_new (); funclist->del = ospf_opaque_del_functab; funclist = ospf_opaque_type9_funclist = list_new (); funclist->del = ospf_opaque_del_functab; funclist = ospf_opaque_type10_funclist = list_new (); funclist->del = ospf_opaque_del_functab; funclist = ospf_opaque_type11_funclist = list_new (); funclist->del = ospf_opaque_del_functab; return; } static void ospf_opaque_funclist_term (void) { struct list *funclist; funclist = ospf_opaque_wildcard_funclist; list_delete (funclist); funclist = ospf_opaque_type9_funclist; list_delete (funclist); funclist = ospf_opaque_type10_funclist; list_delete (funclist); funclist = ospf_opaque_type11_funclist; list_delete (funclist); return; } static struct list * ospf_get_opaque_funclist (u_char lsa_type) { struct list *funclist = NULL; switch (lsa_type) { case OPAQUE_TYPE_WILDCARD: /* XXX * This is an ugly trick to handle type-9/10/11 LSA altogether. * Yes, "OPAQUE_TYPE_WILDCARD (value 0)" is not an LSA-type, nor * an officially assigned opaque-type. * Though it is possible that the value might be officially used * in the future, we use it internally as a special label, for now. */ funclist = ospf_opaque_wildcard_funclist; break; case OSPF_OPAQUE_LINK_LSA: funclist = ospf_opaque_type9_funclist; break; case OSPF_OPAQUE_AREA_LSA: funclist = ospf_opaque_type10_funclist; break; case OSPF_OPAQUE_AS_LSA: funclist = ospf_opaque_type11_funclist; break; default: zlog_warn ("ospf_get_opaque_funclist: Unexpected LSA-type(%u)", lsa_type); break; } return funclist; } /* XXX: such a huge argument list can /not/ be healthy... */ int ospf_register_opaque_functab ( u_char lsa_type, u_char opaque_type, int (* new_if_hook)(struct interface *ifp), int (* del_if_hook)(struct interface *ifp), void (* ism_change_hook)(struct ospf_interface *oi, int old_status), void (* nsm_change_hook)(struct ospf_neighbor *nbr, int old_status), void (* config_write_router)(struct vty *vty), void (* config_write_if )(struct vty *vty, struct interface *ifp), void (* config_write_debug )(struct vty *vty), void (* show_opaque_info )(struct vty *vty, struct ospf_lsa *lsa), int (* lsa_originator)(void *arg), struct ospf_lsa *(* lsa_refresher )(struct ospf_lsa *lsa), int (* new_lsa_hook)(struct ospf_lsa *lsa), int (* del_lsa_hook)(struct ospf_lsa *lsa)) { struct list *funclist; struct ospf_opaque_functab *new; int rc = -1; if ((funclist = ospf_get_opaque_funclist (lsa_type)) == NULL) { zlog_warn ("ospf_register_opaque_functab: Cannot get funclist" " for Type-%u LSAs?", lsa_type); goto out; } else { struct listnode *node, *nnode; struct ospf_opaque_functab *functab; for (ALL_LIST_ELEMENTS (funclist, node, nnode, functab)) if (functab->opaque_type == opaque_type) { zlog_warn ("ospf_register_opaque_functab: Duplicated entry?:" " lsa_type(%u), opaque_type(%u)", lsa_type, opaque_type); goto out; } } if ((new = XCALLOC (MTYPE_OSPF_OPAQUE_FUNCTAB, sizeof (struct ospf_opaque_functab))) == NULL) { zlog_warn ("ospf_register_opaque_functab: XMALLOC: %s", safe_strerror (errno)); goto out; } new->opaque_type = opaque_type; new->oipt = NULL; new->new_if_hook = new_if_hook; new->del_if_hook = del_if_hook; new->ism_change_hook = ism_change_hook; new->nsm_change_hook = nsm_change_hook; new->config_write_router = config_write_router; new->config_write_if = config_write_if; new->config_write_debug = config_write_debug; new->show_opaque_info = show_opaque_info; new->lsa_originator = lsa_originator; new->lsa_refresher = lsa_refresher; new->new_lsa_hook = new_lsa_hook; new->del_lsa_hook = del_lsa_hook; listnode_add (funclist, new); rc = 0; out: return rc; } void ospf_delete_opaque_functab (u_char lsa_type, u_char opaque_type) { struct list *funclist; struct listnode *node, *nnode; struct ospf_opaque_functab *functab; if ((funclist = ospf_get_opaque_funclist (lsa_type)) != NULL) for (ALL_LIST_ELEMENTS (funclist, node, nnode, functab)) { if (functab->opaque_type == opaque_type) { /* Cleanup internal control information, if it still remains. */ if (functab->oipt != NULL) free_opaque_info_per_type (functab->oipt); /* Dequeue listnode entry from the list. */ listnode_delete (funclist, functab); /* Avoid misjudgement in the next lookup. */ if (listcount (funclist) == 0) funclist->head = funclist->tail = NULL; XFREE (MTYPE_OSPF_OPAQUE_FUNCTAB, functab); break; } } return; } static struct ospf_opaque_functab * ospf_opaque_functab_lookup (struct ospf_lsa *lsa) { struct list *funclist; struct listnode *node; struct ospf_opaque_functab *functab; u_char key = GET_OPAQUE_TYPE (ntohl (lsa->data->id.s_addr)); if ((funclist = ospf_get_opaque_funclist (lsa->data->type)) != NULL) for (ALL_LIST_ELEMENTS_RO (funclist, node, functab)) if (functab->opaque_type == key) return functab; return NULL; } /*------------------------------------------------------------------------* * Followings are management functions for self-originated LSA entries. *------------------------------------------------------------------------*/ /* * Opaque-LSA control information per opaque-type. * Single Opaque-Type may have multiple instances; each of them will be * identified by their opaque-id. */ struct opaque_info_per_type { u_char lsa_type; u_char opaque_type; enum { PROC_NORMAL, PROC_SUSPEND } status; /* * Thread for (re-)origination scheduling for this opaque-type. * * Initial origination of Opaque-LSAs is controlled by generic * Opaque-LSA handling module so that same opaque-type entries are * called all at once when certain conditions are met. * However, there might be cases that some Opaque-LSA clients need * to (re-)originate their own Opaque-LSAs out-of-sync with others. * This thread is prepared for that specific purpose. */ struct thread *t_opaque_lsa_self; /* * Backpointer to an "owner" which is LSA-type dependent. * type-9: struct ospf_interface * type-10: struct ospf_area * type-11: struct ospf */ void *owner; /* Collection of callback functions for this opaque-type. */ struct ospf_opaque_functab *functab; /* List of Opaque-LSA control informations per opaque-id. */ struct list *id_list; }; /* Opaque-LSA control information per opaque-id. */ struct opaque_info_per_id { u_int32_t opaque_id; /* Thread for refresh/flush scheduling for this opaque-type/id. */ struct thread *t_opaque_lsa_self; /* Backpointer to Opaque-LSA control information per opaque-type. */ struct opaque_info_per_type *opqctl_type; /* Here comes an actual Opaque-LSA entry for this opaque-type/id. */ struct ospf_lsa *lsa; }; static struct opaque_info_per_type *register_opaque_info_per_type (struct ospf_opaque_functab *functab, struct ospf_lsa *new); static struct opaque_info_per_type *lookup_opaque_info_by_type (struct ospf_lsa *lsa); static struct opaque_info_per_id *register_opaque_info_per_id (struct opaque_info_per_type *oipt, struct ospf_lsa *new); static struct opaque_info_per_id *lookup_opaque_info_by_id (struct opaque_info_per_type *oipt, struct ospf_lsa *lsa); static struct opaque_info_per_id *register_opaque_lsa (struct ospf_lsa *new); static struct opaque_info_per_type * register_opaque_info_per_type (struct ospf_opaque_functab *functab, struct ospf_lsa *new) { struct ospf *top; struct opaque_info_per_type *oipt; if ((oipt = XCALLOC (MTYPE_OPAQUE_INFO_PER_TYPE, sizeof (struct opaque_info_per_type))) == NULL) { zlog_warn ("register_opaque_info_per_type: XMALLOC: %s", safe_strerror (errno)); goto out; } switch (new->data->type) { case OSPF_OPAQUE_LINK_LSA: oipt->owner = new->oi; listnode_add (new->oi->opaque_lsa_self, oipt); break; case OSPF_OPAQUE_AREA_LSA: oipt->owner = new->area; listnode_add (new->area->opaque_lsa_self, oipt); break; case OSPF_OPAQUE_AS_LSA: top = ospf_lookup (); if (new->area != NULL && (top = new->area->ospf) == NULL) { free_opaque_info_per_type ((void *) oipt); oipt = NULL; goto out; /* This case may not exist. */ } oipt->owner = top; listnode_add (top->opaque_lsa_self, oipt); break; default: zlog_warn ("register_opaque_info_per_type: Unexpected LSA-type(%u)", new->data->type); free_opaque_info_per_type ((void *) oipt); oipt = NULL; goto out; /* This case may not exist. */ } oipt->lsa_type = new->data->type; oipt->opaque_type = GET_OPAQUE_TYPE (ntohl (new->data->id.s_addr)); oipt->status = PROC_NORMAL; oipt->t_opaque_lsa_self = NULL; oipt->functab = functab; functab->oipt = oipt; oipt->id_list = list_new (); oipt->id_list->del = free_opaque_info_per_id; out: return oipt; } 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; /* Control information per opaque-id may still exist. */ for (ALL_LIST_ELEMENTS (oipt->id_list, node, nnode, oipi)) { if ((lsa = oipi->lsa) == NULL) continue; if (IS_LSA_MAXAGE (lsa)) continue; ospf_opaque_lsa_flush_schedule (lsa); } /* Remove "oipt" from its owner's self-originated LSA list. */ 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: zlog_warn ("free_opaque_info_per_type: Unexpected LSA-type(%u)", oipt->lsa_type); break; /* This case may not exist. */ } OSPF_TIMER_OFF (oipt->t_opaque_lsa_self); list_delete (oipt->id_list); XFREE (MTYPE_OPAQUE_INFO_PER_TYPE, oipt); return; } static struct opaque_info_per_type * lookup_opaque_info_by_type (struct ospf_lsa *lsa) { struct ospf *top; struct ospf_area *area; struct ospf_interface *oi; struct list *listtop = NULL; struct listnode *node, *nnode; struct opaque_info_per_type *oipt = NULL; u_char key = GET_OPAQUE_TYPE (ntohl (lsa->data->id.s_addr)); switch (lsa->data->type) { case OSPF_OPAQUE_LINK_LSA: if ((oi = lsa->oi) != NULL) listtop = oi->opaque_lsa_self; else zlog_warn ("Type-9 Opaque-LSA: Reference to OI is missing?"); break; case OSPF_OPAQUE_AREA_LSA: if ((area = lsa->area) != NULL) listtop = area->opaque_lsa_self; else zlog_warn ("Type-10 Opaque-LSA: Reference to AREA is missing?"); break; case OSPF_OPAQUE_AS_LSA: top = ospf_lookup (); if ((area = lsa->area) != NULL && (top = area->ospf) == NULL) { zlog_warn ("Type-11 Opaque-LSA: Reference to OSPF is missing?"); break; /* Unlikely to happen. */ } listtop = top->opaque_lsa_self; break; default: zlog_warn ("lookup_opaque_info_by_type: Unexpected LSA-type(%u)", lsa->data->type); break; } if (listtop != NULL) for (ALL_LIST_ELEMENTS (listtop, node, nnode, oipt)) if (oipt->opaque_type == key) return oipt; return NULL; } static struct opaque_info_per_id * register_opaque_info_per_id (struct opaque_info_per_type *oipt, struct ospf_lsa *new) { struct opaque_info_per_id *oipi; if ((oipi = XCALLOC (MTYPE_OPAQUE_INFO_PER_ID, sizeof (struct opaque_info_per_id))) == NULL) { zlog_warn ("register_opaque_info_per_id: XMALLOC: %s", safe_strerror (errno)); goto out; } oipi->opaque_id = GET_OPAQUE_ID (ntohl (new->data->id.s_addr)); oipi->t_opaque_lsa_self = NULL; oipi->opqctl_type = oipt; oipi->lsa = ospf_lsa_lock (new); listnode_add (oipt->id_list, oipi); out: return oipi; } static void free_opaque_info_per_id (void *val) { struct opaque_info_per_id *oipi = (struct opaque_info_per_id *) val; OSPF_TIMER_OFF (oipi->t_opaque_lsa_self); if (oipi->lsa != NULL) ospf_lsa_unlock (&oipi->lsa); XFREE (MTYPE_OPAQUE_INFO_PER_ID, oipi); return; } static struct opaque_info_per_id * lookup_opaque_info_by_id (struct opaque_info_per_type *oipt, struct ospf_lsa *lsa) { struct listnode *node, *nnode; struct opaque_info_per_id *oipi; u_int32_t key = GET_OPAQUE_ID (ntohl (lsa->data->id.s_addr)); for (ALL_LIST_ELEMENTS (oipt->id_list, node, nnode, oipi)) if (oipi->opaque_id == key) return oipi; return NULL; } static struct opaque_info_per_id * register_opaque_lsa (struct ospf_lsa *new) { struct ospf_opaque_functab *functab; struct opaque_info_per_type *oipt; struct opaque_info_per_id *oipi = NULL; if ((functab = ospf_opaque_functab_lookup (new)) == NULL) goto out; if ((oipt = lookup_opaque_info_by_type (new)) == NULL && (oipt = register_opaque_info_per_type (functab, new)) == NULL) goto out; if ((oipi = register_opaque_info_per_id (oipt, new)) == NULL) goto out; out: return oipi; } /*------------------------------------------------------------------------* * Followings are (vty) configuration functions for Opaque-LSAs handling. *------------------------------------------------------------------------*/ DEFUN (capability_opaque, capability_opaque_cmd, "capability opaque", "Enable specific OSPF feature\n" "Opaque LSA\n") { struct ospf *ospf = (struct ospf *) vty->index; /* Turn on the "master switch" of opaque-lsa capability. */ if (!CHECK_FLAG (ospf->config, OSPF_OPAQUE_CAPABLE)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Opaque capability: OFF -> ON"); SET_FLAG (ospf->config, OSPF_OPAQUE_CAPABLE); ospf_renegotiate_optional_capabilities (ospf); } return CMD_SUCCESS; } ALIAS (capability_opaque, ospf_opaque_capable_cmd, "ospf opaque-lsa", "OSPF specific commands\n" "Enable the Opaque-LSA capability (rfc2370)\n") DEFUN (no_capability_opaque, no_capability_opaque_cmd, "no capability opaque", NO_STR "Enable specific OSPF feature\n" "Opaque LSA\n") { struct ospf *ospf = (struct ospf *) vty->index; /* Turn off the "master switch" of opaque-lsa capability. */ if (CHECK_FLAG (ospf->config, OSPF_OPAQUE_CAPABLE)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Opaque capability: ON -> OFF"); UNSET_FLAG (ospf->config, OSPF_OPAQUE_CAPABLE); ospf_renegotiate_optional_capabilities (ospf); } return CMD_SUCCESS; } ALIAS (no_capability_opaque, no_ospf_opaque_capable_cmd, "no ospf opaque-lsa", NO_STR "OSPF specific commands\n" "Disable the Opaque-LSA capability (rfc2370)\n") static void ospf_opaque_register_vty (void) { install_element (OSPF_NODE, &capability_opaque_cmd); install_element (OSPF_NODE, &no_capability_opaque_cmd); install_element (OSPF_NODE, &ospf_opaque_capable_cmd); install_element (OSPF_NODE, &no_ospf_opaque_capable_cmd); return; } /*------------------------------------------------------------------------* * Followings are collection of user-registered function callers. *------------------------------------------------------------------------*/ static int opaque_lsa_new_if_callback (struct list *funclist, struct interface *ifp) { struct listnode *node, *nnode; struct ospf_opaque_functab *functab; int rc = -1; for (ALL_LIST_ELEMENTS (funclist, node, nnode, functab)) if (functab->new_if_hook != NULL) if ((* functab->new_if_hook)(ifp) != 0) goto out; rc = 0; out: return rc; } static int opaque_lsa_del_if_callback (struct list *funclist, struct interface *ifp) { struct listnode *node, *nnode; struct ospf_opaque_functab *functab; int rc = -1; for (ALL_LIST_ELEMENTS (funclist, node, nnode, functab)) if (functab->del_if_hook != NULL) if ((* functab->del_if_hook)(ifp) != 0) goto out; rc = 0; out: return rc; } static void opaque_lsa_ism_change_callback (struct list *funclist, struct ospf_interface *oi, int old_status) { struct listnode *node, *nnode; struct ospf_opaque_functab *functab; for (ALL_LIST_ELEMENTS (funclist, node, nnode, functab)) if (functab->ism_change_hook != NULL) (* functab->ism_change_hook)(oi, old_status); return; } static void opaque_lsa_nsm_change_callback (struct list *funclist, struct ospf_neighbor *nbr, int old_status) { struct listnode *node, *nnode; struct ospf_opaque_functab *functab; for (ALL_LIST_ELEMENTS (funclist, node, nnode, functab)) if (functab->nsm_change_hook != NULL) (* functab->nsm_change_hook)(nbr, old_status); return; } static void opaque_lsa_config_write_router_callback (struct list *funclist, struct vty *vty) { struct listnode *node, *nnode; struct ospf_opaque_functab *functab; for (ALL_LIST_ELEMENTS (funclist, node, nnode, functab)) if (functab->config_write_router != NULL) (* functab->config_write_router)(vty); return; } static void opaque_lsa_config_write_if_callback (struct list *funclist, struct vty *vty, struct interface *ifp) { struct listnode *node, *nnode; struct ospf_opaque_functab *functab; for (ALL_LIST_ELEMENTS (funclist, node, nnode, functab)) if (functab->config_write_if != NULL) (* functab->config_write_if)(vty, ifp); return; } static void opaque_lsa_config_write_debug_callback (struct list *funclist, struct vty *vty) { struct listnode *node, *nnode; struct ospf_opaque_functab *functab; for (ALL_LIST_ELEMENTS (funclist, node, nnode, functab)) if (functab->config_write_debug != NULL) (* functab->config_write_debug)(vty); return; } static int opaque_lsa_originate_callback (struct list *funclist, void *lsa_type_dependent) { struct listnode *node, *nnode; struct ospf_opaque_functab *functab; int rc = -1; for (ALL_LIST_ELEMENTS (funclist, node, nnode, functab)) if (functab->lsa_originator != NULL) if ((* functab->lsa_originator)(lsa_type_dependent) != 0) goto out; rc = 0; out: return rc; } static int new_lsa_callback (struct list *funclist, struct ospf_lsa *lsa) { struct listnode *node, *nnode; struct ospf_opaque_functab *functab; int rc = -1; /* This function handles ALL types of LSAs, not only opaque ones. */ for (ALL_LIST_ELEMENTS (funclist, node, nnode, functab)) if (functab->new_lsa_hook != NULL) if ((* functab->new_lsa_hook)(lsa) != 0) goto out; rc = 0; out: return rc; } static int del_lsa_callback (struct list *funclist, struct ospf_lsa *lsa) { struct listnode *node, *nnode; struct ospf_opaque_functab *functab; int rc = -1; /* This function handles ALL types of LSAs, not only opaque ones. */ for (ALL_LIST_ELEMENTS (funclist, node, nnode, functab)) if (functab->del_lsa_hook != NULL) if ((* functab->del_lsa_hook)(lsa) != 0) goto out; rc = 0; out: return rc; } /*------------------------------------------------------------------------* * Followings are glue functions to call Opaque-LSA specific processing. *------------------------------------------------------------------------*/ int ospf_opaque_new_if (struct interface *ifp) { struct list *funclist; int rc = -1; funclist = ospf_opaque_wildcard_funclist; if (opaque_lsa_new_if_callback (funclist, ifp) != 0) goto out; funclist = ospf_opaque_type9_funclist; if (opaque_lsa_new_if_callback (funclist, ifp) != 0) goto out; funclist = ospf_opaque_type10_funclist; if (opaque_lsa_new_if_callback (funclist, ifp) != 0) goto out; funclist = ospf_opaque_type11_funclist; if (opaque_lsa_new_if_callback (funclist, ifp) != 0) goto out; rc = 0; out: return rc; } int ospf_opaque_del_if (struct interface *ifp) { struct list *funclist; int rc = -1; funclist = ospf_opaque_wildcard_funclist; if (opaque_lsa_del_if_callback (funclist, ifp) != 0) goto out; funclist = ospf_opaque_type9_funclist; if (opaque_lsa_del_if_callback (funclist, ifp) != 0) goto out; funclist = ospf_opaque_type10_funclist; if (opaque_lsa_del_if_callback (funclist, ifp) != 0) goto out; funclist = ospf_opaque_type11_funclist; if (opaque_lsa_del_if_callback (funclist, ifp) != 0) goto out; rc = 0; out: return rc; } void ospf_opaque_ism_change (struct ospf_interface *oi, int old_status) { struct list *funclist; funclist = ospf_opaque_wildcard_funclist; opaque_lsa_ism_change_callback (funclist, oi, old_status); funclist = ospf_opaque_type9_funclist; opaque_lsa_ism_change_callback (funclist, oi, old_status); funclist = ospf_opaque_type10_funclist; opaque_lsa_ism_change_callback (funclist, oi, old_status); funclist = ospf_opaque_type11_funclist; opaque_lsa_ism_change_callback (funclist, oi, old_status); return; } void ospf_opaque_nsm_change (struct ospf_neighbor *nbr, int old_state) { struct ospf *top; struct list *funclist; if ((top = oi_to_top (nbr->oi)) == NULL) goto out; if (old_state != NSM_Full && nbr->state == NSM_Full) { if (CHECK_FLAG (nbr->options, OSPF_OPTION_O)) { if (! CHECK_FLAG (top->opaque, OPAQUE_OPERATION_READY_BIT)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Opaque-LSA: Now get operational!"); SET_FLAG (top->opaque, OPAQUE_OPERATION_READY_BIT); } ospf_opaque_lsa_originate_schedule (nbr->oi, NULL); } } else if (old_state == NSM_Full && nbr->state != NSM_Full) { #ifdef NOTYET /* * If no more opaque-capable full-state neighbor remains in the * flooding scope which corresponds to Opaque-LSA type, periodic * LS flooding should be stopped. */ #endif /* NOTYET */ ; } funclist = ospf_opaque_wildcard_funclist; opaque_lsa_nsm_change_callback (funclist, nbr, old_state); funclist = ospf_opaque_type9_funclist; opaque_lsa_nsm_change_callback (funclist, nbr, old_state); funclist = ospf_opaque_type10_funclist; opaque_lsa_nsm_change_callback (funclist, nbr, old_state); funclist = ospf_opaque_type11_funclist; opaque_lsa_nsm_change_callback (funclist, nbr, old_state); out: return; } void ospf_opaque_config_write_router (struct vty *vty, struct ospf *ospf) { struct list *funclist; if (CHECK_FLAG (ospf->config, OSPF_OPAQUE_CAPABLE)) vty_out (vty, " capability opaque%s", VTY_NEWLINE); funclist = ospf_opaque_wildcard_funclist; opaque_lsa_config_write_router_callback (funclist, vty); funclist = ospf_opaque_type9_funclist; opaque_lsa_config_write_router_callback (funclist, vty); funclist = ospf_opaque_type10_funclist; opaque_lsa_config_write_router_callback (funclist, vty); funclist = ospf_opaque_type11_funclist; opaque_lsa_config_write_router_callback (funclist, vty); return; } void ospf_opaque_config_write_if (struct vty *vty, struct interface *ifp) { struct list *funclist; funclist = ospf_opaque_wildcard_funclist; opaque_lsa_config_write_if_callback (funclist, vty, ifp); funclist = ospf_opaque_type9_funclist; opaque_lsa_config_write_if_callback (funclist, vty, ifp); funclist = ospf_opaque_type10_funclist; opaque_lsa_config_write_if_callback (funclist, vty, ifp); funclist = ospf_opaque_type11_funclist; opaque_lsa_config_write_if_callback (funclist, vty, ifp); return; } void ospf_opaque_config_write_debug (struct vty *vty) { struct list *funclist; funclist = ospf_opaque_wildcard_funclist; opaque_lsa_config_write_debug_callback (funclist, vty); funclist = ospf_opaque_type9_funclist; opaque_lsa_config_write_debug_callback (funclist, vty); funclist = ospf_opaque_type10_funclist; opaque_lsa_config_write_debug_callback (funclist, vty); funclist = ospf_opaque_type11_funclist; opaque_lsa_config_write_debug_callback (funclist, vty); return; } void show_opaque_info_detail (struct vty *vty, struct ospf_lsa *lsa) { struct lsa_header *lsah = (struct lsa_header *) lsa->data; u_int32_t lsid = ntohl (lsah->id.s_addr); u_char opaque_type = GET_OPAQUE_TYPE (lsid); u_int32_t opaque_id = GET_OPAQUE_ID (lsid); struct ospf_opaque_functab *functab; /* Switch output functionality by vty address. */ if (vty != NULL) { vty_out (vty, " Opaque-Type %u (%s)%s", opaque_type, ospf_opaque_type_name (opaque_type), VTY_NEWLINE); vty_out (vty, " Opaque-ID 0x%x%s", opaque_id, VTY_NEWLINE); vty_out (vty, " Opaque-Info: %u octets of data%s%s", ntohs (lsah->length) - OSPF_LSA_HEADER_SIZE, VALID_OPAQUE_INFO_LEN(lsah) ? "" : "(Invalid length?)", VTY_NEWLINE); } else { zlog_debug (" Opaque-Type %u (%s)", opaque_type, ospf_opaque_type_name (opaque_type)); zlog_debug (" Opaque-ID 0x%x", opaque_id); zlog_debug (" Opaque-Info: %u octets of data%s", ntohs (lsah->length) - OSPF_LSA_HEADER_SIZE, VALID_OPAQUE_INFO_LEN(lsah) ? "" : "(Invalid length?)"); } /* Call individual output functions. */ if ((functab = ospf_opaque_functab_lookup (lsa)) != NULL) if (functab->show_opaque_info != NULL) (* functab->show_opaque_info)(vty, lsa); return; } void ospf_opaque_lsa_dump (struct stream *s, u_int16_t length) { struct ospf_lsa lsa; lsa.data = (struct lsa_header *) STREAM_PNT (s); show_opaque_info_detail (NULL, &lsa); return; } static int ospf_opaque_lsa_install_hook (struct ospf_lsa *lsa) { struct list *funclist; int rc = -1; /* * Some Opaque-LSA user may want to monitor every LSA installation * into the LSDB, regardless with target LSA type. */ funclist = ospf_opaque_wildcard_funclist; if (new_lsa_callback (funclist, lsa) != 0) goto out; funclist = ospf_opaque_type9_funclist; if (new_lsa_callback (funclist, lsa) != 0) goto out; funclist = ospf_opaque_type10_funclist; if (new_lsa_callback (funclist, lsa) != 0) goto out; funclist = ospf_opaque_type11_funclist; if (new_lsa_callback (funclist, lsa) != 0) goto out; rc = 0; out: return rc; } static int ospf_opaque_lsa_delete_hook (struct ospf_lsa *lsa) { struct list *funclist; int rc = -1; /* * Some Opaque-LSA user may want to monitor every LSA deletion * from the LSDB, regardless with target LSA type. */ funclist = ospf_opaque_wildcard_funclist; if (del_lsa_callback (funclist, lsa) != 0) goto out; funclist = ospf_opaque_type9_funclist; if (del_lsa_callback (funclist, lsa) != 0) goto out; funclist = ospf_opaque_type10_funclist; if (del_lsa_callback (funclist, lsa) != 0) goto out; funclist = ospf_opaque_type11_funclist; if (del_lsa_callback (funclist, lsa) != 0) goto out; rc = 0; out: return rc; } /*------------------------------------------------------------------------* * Followings are Opaque-LSA origination/refresh management functions. *------------------------------------------------------------------------*/ static int ospf_opaque_type9_lsa_originate (struct thread *t); static int ospf_opaque_type10_lsa_originate (struct thread *t); static int ospf_opaque_type11_lsa_originate (struct thread *t); static void ospf_opaque_lsa_reoriginate_resume (struct list *listtop, void *arg); void ospf_opaque_lsa_originate_schedule (struct ospf_interface *oi, int *delay0) { struct ospf *top; struct ospf_area *area; struct listnode *node, *nnode; struct opaque_info_per_type *oipt; int delay = 0; if ((top = oi_to_top (oi)) == NULL || (area = oi->area) == NULL) { zlog_warn ("ospf_opaque_lsa_originate_schedule: Invalid argument?"); goto out; } /* It may not a right time to schedule origination now. */ if (! CHECK_FLAG (top->opaque, OPAQUE_OPERATION_READY_BIT)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_opaque_lsa_originate_schedule: Not operational."); goto out; /* This is not an error. */ } if (IS_OPAQUE_LSA_ORIGINATION_BLOCKED (top->opaque)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_opaque_lsa_originate_schedule: Under blockade."); goto out; /* This is not an error, too. */ } if (delay0 != NULL) delay = *delay0; /* * There might be some entries that have been waiting for triggering * of per opaque-type re-origination get resumed. */ ospf_opaque_lsa_reoriginate_resume ( oi->opaque_lsa_self, (void *) oi); ospf_opaque_lsa_reoriginate_resume (area->opaque_lsa_self, (void *) area); ospf_opaque_lsa_reoriginate_resume ( top->opaque_lsa_self, (void *) top); /* * Now, schedule origination of all Opaque-LSAs per opaque-type. */ if (! list_isempty (ospf_opaque_type9_funclist) && list_isempty (oi->opaque_lsa_self) && oi->t_opaque_lsa_self == NULL) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Schedule Type-9 Opaque-LSA origination in %d sec later.", delay); oi->t_opaque_lsa_self = thread_add_timer (master, ospf_opaque_type9_lsa_originate, oi, delay); delay += OSPF_MIN_LS_INTERVAL; } if (! list_isempty (ospf_opaque_type10_funclist) && list_isempty (area->opaque_lsa_self) && area->t_opaque_lsa_self == NULL) { /* * One AREA may contain multiple OIs, but above 2nd and 3rd * conditions prevent from scheduling the originate function * again and again. */ if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Schedule Type-10 Opaque-LSA origination in %d sec later.", delay); area->t_opaque_lsa_self = thread_add_timer (master, ospf_opaque_type10_lsa_originate, area, delay); delay += OSPF_MIN_LS_INTERVAL; } if (! list_isempty (ospf_opaque_type11_funclist) && list_isempty (top->opaque_lsa_self) && top->t_opaque_lsa_self == NULL) { /* * One OSPF may contain multiple AREAs, but above 2nd and 3rd * conditions prevent from scheduling the originate function * again and again. */ if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Schedule Type-11 Opaque-LSA origination in %d sec later.", delay); top->t_opaque_lsa_self = thread_add_timer (master, ospf_opaque_type11_lsa_originate, top, delay); delay += OSPF_MIN_LS_INTERVAL; } /* * Following section treats a special situation that this node's * opaque capability has changed as "ON -> OFF -> ON". */ if (! list_isempty (ospf_opaque_type9_funclist) && ! list_isempty (oi->opaque_lsa_self)) { for (ALL_LIST_ELEMENTS (oi->opaque_lsa_self, node, nnode, oipt)) { /* * removed the test for * (! list_isempty (oipt->id_list)) * Handler is already active. * * because opaque cababilities ON -> OFF -> ON result in list_isempty (oipt->id_list) * not being empty. */ if (oipt->t_opaque_lsa_self != NULL /* Waiting for a thread call. */ || oipt->status == PROC_SUSPEND) /* Cannot originate now. */ continue; ospf_opaque_lsa_reoriginate_schedule ((void *) oi, OSPF_OPAQUE_LINK_LSA, oipt->opaque_type); } } if (! list_isempty (ospf_opaque_type10_funclist) && ! list_isempty (area->opaque_lsa_self)) { for (ALL_LIST_ELEMENTS (area->opaque_lsa_self, node, nnode, oipt)) { /* * removed the test for * (! list_isempty (oipt->id_list)) * Handler is already active. * * because opaque cababilities ON -> OFF -> ON result in list_isempty (oipt->id_list) * not being empty. */ if (oipt->t_opaque_lsa_self != NULL /* Waiting for a thread call. */ || oipt->status == PROC_SUSPEND) /* Cannot originate now. */ continue; ospf_opaque_lsa_reoriginate_schedule ((void *) area, OSPF_OPAQUE_AREA_LSA, oipt->opaque_type); } } if (! list_isempty (ospf_opaque_type11_funclist) && ! list_isempty (top->opaque_lsa_self)) { for (ALL_LIST_ELEMENTS (top->opaque_lsa_self, node, nnode, oipt)) { /* * removed the test for * (! list_isempty (oipt->id_list)) * Handler is already active. * * because opaque cababilities ON -> OFF -> ON result in list_isempty (oipt->id_list) * not being empty. */ if (oipt->t_opaque_lsa_self != NULL /* Waiting for a thread call. */ || oipt->status == PROC_SUSPEND) /* Cannot originate now. */ continue; ospf_opaque_lsa_reoriginate_schedule ((void *) top, OSPF_OPAQUE_AS_LSA, oipt->opaque_type); } } if (delay0 != NULL) *delay0 = delay; out: return; } static int ospf_opaque_type9_lsa_originate (struct thread *t) { struct ospf_interface *oi; int rc; oi = THREAD_ARG (t); oi->t_opaque_lsa_self = NULL; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Timer[Type9-LSA]: Originate Opaque-LSAs for OI %s", IF_NAME (oi)); rc = opaque_lsa_originate_callback (ospf_opaque_type9_funclist, oi); return rc; } static int ospf_opaque_type10_lsa_originate (struct thread *t) { struct ospf_area *area; int rc; area = THREAD_ARG (t); area->t_opaque_lsa_self = NULL; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Timer[Type10-LSA]: Originate Opaque-LSAs for Area %s", inet_ntoa (area->area_id)); rc = opaque_lsa_originate_callback (ospf_opaque_type10_funclist, area); return rc; } static int ospf_opaque_type11_lsa_originate (struct thread *t) { struct ospf *top; int rc; top = THREAD_ARG (t); top->t_opaque_lsa_self = NULL; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Timer[Type11-LSA]: Originate AS-External Opaque-LSAs"); rc = opaque_lsa_originate_callback (ospf_opaque_type11_funclist, top); return rc; } static void ospf_opaque_lsa_reoriginate_resume (struct list *listtop, void *arg) { struct listnode *node, *nnode; struct opaque_info_per_type *oipt; struct ospf_opaque_functab *functab; if (listtop == NULL) goto out; /* * Pickup oipt entries those which in SUSPEND status, and give * them a chance to start re-origination now. */ for (ALL_LIST_ELEMENTS (listtop, node, nnode, oipt)) { if (oipt->status != PROC_SUSPEND) continue; oipt->status = PROC_NORMAL; if ((functab = oipt->functab) == NULL || functab->lsa_originator == NULL) continue; if ((* functab->lsa_originator)(arg) != 0) { zlog_warn ("ospf_opaque_lsa_reoriginate_resume: Failed (opaque-type=%u)", oipt->opaque_type); continue; } } out: return; } struct ospf_lsa * ospf_opaque_lsa_install (struct ospf_lsa *lsa, int rt_recalc) { struct ospf_lsa *new = NULL; struct opaque_info_per_type *oipt; struct opaque_info_per_id *oipi; struct ospf *top; /* Don't take "rt_recalc" into consideration for now. *//* XXX */ if (! IS_LSA_SELF (lsa)) { new = lsa; /* Don't touch this LSA. */ goto out; } if (IS_DEBUG_OSPF (lsa, LSA_INSTALL)) zlog_debug ("Install Type-%u Opaque-LSA: [opaque-type=%u, opaque-id=%x]", lsa->data->type, GET_OPAQUE_TYPE (ntohl (lsa->data->id.s_addr)), GET_OPAQUE_ID (ntohl (lsa->data->id.s_addr))); /* Replace the existing lsa with the new one. */ if ((oipt = lookup_opaque_info_by_type (lsa)) != NULL && (oipi = lookup_opaque_info_by_id (oipt, lsa)) != NULL) { ospf_lsa_unlock (&oipi->lsa); oipi->lsa = ospf_lsa_lock (lsa); } /* Register the new lsa entry and get its control info. */ else if ((oipi = register_opaque_lsa (lsa)) == NULL) { zlog_warn ("ospf_opaque_lsa_install: register_opaque_lsa() ?"); goto out; } /* * Make use of a common mechanism (ospf_lsa_refresh_walker) * for periodic refresh of self-originated Opaque-LSAs. */ switch (lsa->data->type) { case OSPF_OPAQUE_LINK_LSA: if ((top = oi_to_top (lsa->oi)) == NULL) { /* Above conditions must have passed. */ zlog_warn ("ospf_opaque_lsa_install: Sonmething wrong?"); goto out; } break; case OSPF_OPAQUE_AREA_LSA: if (lsa->area == NULL || (top = lsa->area->ospf) == NULL) { /* Above conditions must have passed. */ zlog_warn ("ospf_opaque_lsa_install: Sonmething wrong?"); goto out; } break; case OSPF_OPAQUE_AS_LSA: top = ospf_lookup (); if (lsa->area != NULL && (top = lsa->area->ospf) == NULL) { /* Above conditions must have passed. */ zlog_warn ("ospf_opaque_lsa_install: Sonmething wrong?"); goto out; } break; default: zlog_warn ("ospf_opaque_lsa_install: Unexpected LSA-type(%u)", lsa->data->type); goto out; } ospf_refresher_register_lsa (top, lsa); new = lsa; out: return new; } struct ospf_lsa * ospf_opaque_lsa_refresh (struct ospf_lsa *lsa) { struct ospf *ospf; struct ospf_opaque_functab *functab; struct ospf_lsa *new = NULL; ospf = ospf_lookup (); if ((functab = ospf_opaque_functab_lookup (lsa)) == NULL || functab->lsa_refresher == NULL) { /* * Though this LSA seems to have originated on this node, the * handling module for this "lsa-type and opaque-type" was * already deleted sometime ago. * Anyway, this node still has a responsibility to flush this * LSA from the routing domain. */ if (IS_DEBUG_OSPF_EVENT) zlog_debug ("LSA[Type%d:%s]: Flush stray Opaque-LSA", lsa->data->type, inet_ntoa (lsa->data->id)); lsa->data->ls_age = htons (OSPF_LSA_MAXAGE); ospf_lsa_flush (ospf, lsa); } else new = (* functab->lsa_refresher)(lsa); return new; } /*------------------------------------------------------------------------* * Followings are re-origination/refresh/flush operations of Opaque-LSAs, * triggered by external interventions (vty session, signaling, etc). *------------------------------------------------------------------------*/ #define OSPF_OPAQUE_TIMER_ON(T,F,L,V) \ if (!(T)) \ (T) = thread_add_timer (master, (F), (L), (V)) static struct ospf_lsa *pseudo_lsa (struct ospf_interface *oi, struct ospf_area *area, u_char lsa_type, u_char opaque_type); static int ospf_opaque_type9_lsa_reoriginate_timer (struct thread *t); static int ospf_opaque_type10_lsa_reoriginate_timer (struct thread *t); static int ospf_opaque_type11_lsa_reoriginate_timer (struct thread *t); static int ospf_opaque_lsa_refresh_timer (struct thread *t); void ospf_opaque_lsa_reoriginate_schedule (void *lsa_type_dependent, u_char lsa_type, u_char opaque_type) { struct ospf *top; struct ospf_area dummy, *area = NULL; struct ospf_interface *oi = NULL; struct ospf_lsa *lsa; struct opaque_info_per_type *oipt; int (*func) (struct thread * t) = NULL; int delay; switch (lsa_type) { case OSPF_OPAQUE_LINK_LSA: if ((oi = (struct ospf_interface *) lsa_type_dependent) == NULL) { zlog_warn ("ospf_opaque_lsa_reoriginate_schedule:" " Type-9 Opaque-LSA: Invalid parameter?"); goto out; } if ((top = oi_to_top (oi)) == NULL) { zlog_warn ("ospf_opaque_lsa_reoriginate_schedule: OI(%s) -> TOP?", IF_NAME (oi)); goto out; } if (!list_isempty (ospf_opaque_type9_funclist) && list_isempty (oi->opaque_lsa_self) && oi->t_opaque_lsa_self != NULL) { zlog_warn ("Type-9 Opaque-LSA (opaque_type=%u):" " Common origination for OI(%s) has already started", opaque_type, IF_NAME (oi)); goto out; } func = ospf_opaque_type9_lsa_reoriginate_timer; break; case OSPF_OPAQUE_AREA_LSA: if ((area = (struct ospf_area *) lsa_type_dependent) == NULL) { zlog_warn ("ospf_opaque_lsa_reoriginate_schedule:" " Type-10 Opaque-LSA: Invalid parameter?"); goto out; } if ((top = area->ospf) == NULL) { zlog_warn ("ospf_opaque_lsa_reoriginate_schedule:" " AREA(%s) -> TOP?", inet_ntoa (area->area_id)); goto out; } if (!list_isempty (ospf_opaque_type10_funclist) && list_isempty (area->opaque_lsa_self) && area->t_opaque_lsa_self != NULL) { zlog_warn ("Type-10 Opaque-LSA (opaque_type=%u):" " Common origination for AREA(%s) has already started", opaque_type, inet_ntoa (area->area_id)); goto out; } func = ospf_opaque_type10_lsa_reoriginate_timer; break; case OSPF_OPAQUE_AS_LSA: if ((top = (struct ospf *) lsa_type_dependent) == NULL) { zlog_warn ("ospf_opaque_lsa_reoriginate_schedule:" " Type-11 Opaque-LSA: Invalid parameter?"); goto out; } if (!list_isempty (ospf_opaque_type11_funclist) && list_isempty (top->opaque_lsa_self) && top->t_opaque_lsa_self != NULL) { zlog_warn ("Type-11 Opaque-LSA (opaque_type=%u):" " Common origination has already started", opaque_type); goto out; } /* Fake "area" to pass "ospf" to a lookup function later. */ dummy.ospf = top; area = &dummy; func = ospf_opaque_type11_lsa_reoriginate_timer; break; default: zlog_warn ("ospf_opaque_lsa_reoriginate_schedule:" " Unexpected LSA-type(%u)", lsa_type); goto out; } /* It may not a right time to schedule reorigination now. */ if (!CHECK_FLAG (top->opaque, OPAQUE_OPERATION_READY_BIT)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_opaque_lsa_reoriginate_schedule: Not operational."); goto out; /* This is not an error. */ } if (IS_OPAQUE_LSA_ORIGINATION_BLOCKED (top->opaque)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_opaque_lsa_reoriginate_schedule: Under blockade."); goto out; /* This is not an error, too. */ } /* Generate a dummy lsa to be passed for a lookup function. */ lsa = pseudo_lsa (oi, area, lsa_type, opaque_type); if ((oipt = lookup_opaque_info_by_type (lsa)) == NULL) { struct ospf_opaque_functab *functab; if ((functab = ospf_opaque_functab_lookup (lsa)) == NULL) { zlog_warn ("ospf_opaque_lsa_reoriginate_schedule:" " No associated function?: lsa_type(%u)," " opaque_type(%u)", lsa_type, opaque_type); goto out; } if ((oipt = register_opaque_info_per_type (functab, lsa)) == NULL) { zlog_warn ("ospf_opaque_lsa_reoriginate_schedule:" " Cannot get a control info?: lsa_type(%u)," " opaque_type(%u)", lsa_type, opaque_type); goto out; } } if (oipt->t_opaque_lsa_self != NULL) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Type-%u Opaque-LSA has already scheduled to" " RE-ORIGINATE: [opaque-type=%u]", lsa_type, GET_OPAQUE_TYPE (ntohl (lsa->data->id.s_addr))); goto out; } /* * Different from initial origination time, in which various conditions * (opaque capability, neighbor status etc) are assured by caller of * the originating function "ospf_opaque_lsa_originate_schedule ()", * it is highly possible that these conditions might not be satisfied * at the time of re-origination function is to be called. */ delay = OSPF_MIN_LS_INTERVAL; /* XXX */ if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Schedule Type-%u Opaque-LSA to RE-ORIGINATE in %d" " sec later: [opaque-type=%u]", lsa_type, delay, GET_OPAQUE_TYPE (ntohl (lsa->data->id.s_addr))); OSPF_OPAQUE_TIMER_ON (oipt->t_opaque_lsa_self, func, oipt, delay); out: return; } static struct ospf_lsa * pseudo_lsa (struct ospf_interface *oi, struct ospf_area *area, u_char lsa_type, u_char opaque_type) { static struct ospf_lsa lsa = { 0 }; static struct lsa_header lsah = { 0 }; u_int32_t tmp; lsa.oi = oi; lsa.area = area; lsa.data = &lsah; lsah.type = lsa_type; tmp = SET_OPAQUE_LSID (opaque_type, 0); /* Opaque-ID is unused here. */ lsah.id.s_addr = htonl (tmp); return &lsa; } static int ospf_opaque_type9_lsa_reoriginate_timer (struct thread *t) { struct opaque_info_per_type *oipt; struct ospf_opaque_functab *functab; struct ospf *top; struct ospf_interface *oi; int rc = -1; oipt = THREAD_ARG (t); oipt->t_opaque_lsa_self = NULL; if ((functab = oipt->functab) == NULL || functab->lsa_originator == NULL) { zlog_warn ("ospf_opaque_type9_lsa_reoriginate_timer: No associated function?"); goto out; } oi = (struct ospf_interface *) oipt->owner; if ((top = oi_to_top (oi)) == NULL) { zlog_warn ("ospf_opaque_type9_lsa_reoriginate_timer: Something wrong?"); goto out; } if (! CHECK_FLAG (top->config, OSPF_OPAQUE_CAPABLE) || ! ospf_if_is_enable (oi) || ospf_nbr_count_opaque_capable (oi) == 0) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Suspend re-origination of Type-9 Opaque-LSAs (opaque-type=%u) for a while...", oipt->opaque_type); oipt->status = PROC_SUSPEND; rc = 0; goto out; } if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Timer[Type9-LSA]: Re-originate Opaque-LSAs (opaque-type=%u) for OI (%s)", oipt->opaque_type, IF_NAME (oi)); rc = (* functab->lsa_originator)(oi); out: return rc; } static int ospf_opaque_type10_lsa_reoriginate_timer (struct thread *t) { struct opaque_info_per_type *oipt; struct ospf_opaque_functab *functab; struct listnode *node, *nnode; struct ospf *top; struct ospf_area *area; struct ospf_interface *oi; int n, rc = -1; oipt = THREAD_ARG (t); oipt->t_opaque_lsa_self = NULL; if ((functab = oipt->functab) == NULL || functab->lsa_originator == NULL) { zlog_warn ("ospf_opaque_type10_lsa_reoriginate_timer: No associated function?"); goto out; } area = (struct ospf_area *) oipt->owner; if (area == NULL || (top = area->ospf) == NULL) { zlog_warn ("ospf_opaque_type10_lsa_reoriginate_timer: Something wrong?"); goto out; } /* There must be at least one "opaque-capable, full-state" neighbor. */ n = 0; for (ALL_LIST_ELEMENTS (area->oiflist, node, nnode, oi)) { if ((n = ospf_nbr_count_opaque_capable (oi)) > 0) break; } if (n == 0 || ! CHECK_FLAG (top->config, OSPF_OPAQUE_CAPABLE)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Suspend re-origination of Type-10 Opaque-LSAs" " (opaque-type=%u) for a while...", oipt->opaque_type); oipt->status = PROC_SUSPEND; rc = 0; goto out; } if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Timer[Type10-LSA]: Re-originate Opaque-LSAs" " (opaque-type=%u) for Area %s", oipt->opaque_type, inet_ntoa (area->area_id)); rc = (* functab->lsa_originator)(area); out: return rc; } static int ospf_opaque_type11_lsa_reoriginate_timer (struct thread *t) { struct opaque_info_per_type *oipt; struct ospf_opaque_functab *functab; struct ospf *top; int rc = -1; oipt = THREAD_ARG (t); oipt->t_opaque_lsa_self = NULL; if ((functab = oipt->functab) == NULL || functab->lsa_originator == NULL) { zlog_warn ("ospf_opaque_type11_lsa_reoriginate_timer:" " No associated function?"); goto out; } if ((top = (struct ospf *) oipt->owner) == NULL) { zlog_warn ("ospf_opaque_type11_lsa_reoriginate_timer: Something wrong?"); goto out; } if (! CHECK_FLAG (top->config, OSPF_OPAQUE_CAPABLE)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Suspend re-origination of Type-11 Opaque-LSAs (opaque-type=%u) for a while...", oipt->opaque_type); oipt->status = PROC_SUSPEND; rc = 0; goto out; } if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Timer[Type11-LSA]: Re-originate Opaque-LSAs (opaque-type=%u).", oipt->opaque_type); rc = (* functab->lsa_originator)(top); out: return rc; } void ospf_opaque_lsa_refresh_schedule (struct ospf_lsa *lsa0) { struct opaque_info_per_type *oipt; struct opaque_info_per_id *oipi; struct ospf_lsa *lsa; int delay; if ((oipt = lookup_opaque_info_by_type (lsa0)) == NULL || (oipi = lookup_opaque_info_by_id (oipt, lsa0)) == NULL) { zlog_warn ("ospf_opaque_lsa_refresh_schedule: Invalid parameter?"); goto out; } /* Given "lsa0" and current "oipi->lsa" may different, but harmless. */ if ((lsa = oipi->lsa) == NULL) { zlog_warn ("ospf_opaque_lsa_refresh_schedule: Something wrong?"); goto out; } if (oipi->t_opaque_lsa_self != NULL) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Type-%u Opaque-LSA has already scheduled to REFRESH: [opaque-type=%u, opaque-id=%x]", lsa->data->type, GET_OPAQUE_TYPE (ntohl (lsa->data->id.s_addr)), GET_OPAQUE_ID (ntohl (lsa->data->id.s_addr))); goto out; } /* Delete this lsa from neighbor retransmit-list. */ switch (lsa->data->type) { case OSPF_OPAQUE_LINK_LSA: case OSPF_OPAQUE_AREA_LSA: ospf_ls_retransmit_delete_nbr_area (lsa->area, lsa); break; case OSPF_OPAQUE_AS_LSA: ospf_ls_retransmit_delete_nbr_as (lsa0->area->ospf, lsa); break; default: zlog_warn ("ospf_opaque_lsa_refresh_schedule: Unexpected LSA-type(%u)", lsa->data->type); goto out; } delay = ospf_lsa_refresh_delay (lsa); if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Schedule Type-%u Opaque-LSA to REFRESH in %d sec later: [opaque-type=%u, opaque-id=%x]", lsa->data->type, delay, GET_OPAQUE_TYPE (ntohl (lsa->data->id.s_addr)), GET_OPAQUE_ID (ntohl (lsa->data->id.s_addr))); OSPF_OPAQUE_TIMER_ON (oipi->t_opaque_lsa_self, ospf_opaque_lsa_refresh_timer, oipi, delay); out: return; } static int ospf_opaque_lsa_refresh_timer (struct thread *t) { struct opaque_info_per_id *oipi; struct ospf_opaque_functab *functab; struct ospf_lsa *lsa; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Timer[Opaque-LSA]: (Opaque-LSA Refresh expire)"); oipi = THREAD_ARG (t); oipi->t_opaque_lsa_self = NULL; if ((lsa = oipi->lsa) != NULL) if ((functab = oipi->opqctl_type->functab) != NULL) if (functab->lsa_refresher != NULL) (* functab->lsa_refresher)(lsa); return 0; } void ospf_opaque_lsa_flush_schedule (struct ospf_lsa *lsa0) { struct opaque_info_per_type *oipt; struct opaque_info_per_id *oipi; struct ospf_lsa *lsa; if ((oipt = lookup_opaque_info_by_type (lsa0)) == NULL || (oipi = lookup_opaque_info_by_id (oipt, lsa0)) == NULL) { zlog_warn ("ospf_opaque_lsa_flush_schedule: Invalid parameter?"); goto out; } /* Given "lsa0" and current "oipi->lsa" may different, but harmless. */ if ((lsa = oipi->lsa) == NULL) { zlog_warn ("ospf_opaque_lsa_flush_schedule: Something wrong?"); goto out; } /* Delete this lsa from neighbor retransmit-list. */ switch (lsa->data->type) { case OSPF_OPAQUE_LINK_LSA: case OSPF_OPAQUE_AREA_LSA: ospf_ls_retransmit_delete_nbr_area (lsa->area, lsa); break; case OSPF_OPAQUE_AS_LSA: ospf_ls_retransmit_delete_nbr_as (lsa0->area->ospf, lsa); break; default: zlog_warn ("ospf_opaque_lsa_flush_schedule: Unexpected LSA-type(%u)", lsa->data->type); goto out; } /* Dequeue listnode entry from the list. */ listnode_delete (oipt->id_list, oipi); /* Avoid misjudgement in the next lookup. */ if (listcount (oipt->id_list) == 0) oipt->id_list->head = oipt->id_list->tail = NULL; /* Disassociate internal control information with the given lsa. */ free_opaque_info_per_id ((void *) oipi); /* Force given lsa's age to MaxAge. */ lsa->data->ls_age = htons (OSPF_LSA_MAXAGE); if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Schedule Type-%u Opaque-LSA to FLUSH: [opaque-type=%u, opaque-id=%x]", lsa->data->type, GET_OPAQUE_TYPE (ntohl (lsa->data->id.s_addr)), GET_OPAQUE_ID (ntohl (lsa->data->id.s_addr))); /* This lsa will be flushed and removed eventually. */ ospf_lsa_flush (lsa0->area->ospf, lsa); out: return; } /*------------------------------------------------------------------------* * Followings are control functions to block origination after restart. *------------------------------------------------------------------------*/ static void ospf_opaque_exclude_lsa_from_lsreq (struct route_table *nbrs, struct ospf_neighbor *inbr, struct ospf_lsa *lsa); static void ospf_opaque_type9_lsa_rxmt_nbr_check (struct ospf_interface *oi); static void ospf_opaque_type10_lsa_rxmt_nbr_check (struct ospf_area *area); static void ospf_opaque_type11_lsa_rxmt_nbr_check (struct ospf *top); static unsigned long ospf_opaque_nrxmt_self (struct route_table *nbrs, int lsa_type); void ospf_opaque_adjust_lsreq (struct ospf_neighbor *nbr, struct list *lsas) { struct ospf *top; struct ospf_area *area; struct ospf_interface *oi; struct listnode *node1, *nnode1; struct listnode *node2, *nnode2; struct ospf_lsa *lsa; if ((top = oi_to_top (nbr->oi)) == NULL) goto out; /* * If an instance of self-originated Opaque-LSA is found in the given * LSA list, and it is not installed to LSDB yet, exclude it from the * list "nbr->ls_req". In this way, it is assured that an LSReq message, * which might be sent in the process of flooding, will not request for * the LSA to be flushed immediately; otherwise, depending on timing, * an LSUpd message will carry instances of target LSAs with MaxAge, * while other LSUpd message might carry old LSA instances (non-MaxAge). * Obviously, the latter would trigger miserable situations that repeat * installation and removal of unwanted LSAs indefinitely. */ for (ALL_LIST_ELEMENTS (lsas, node1, nnode1, lsa)) { /* Filter out unwanted LSAs. */ if (! IS_OPAQUE_LSA (lsa->data->type)) continue; if (! IPV4_ADDR_SAME (&lsa->data->adv_router, &top->router_id)) continue; /* * Don't touch an LSA which has MaxAge; two possible cases. * * 1) This LSA has originally flushed by myself (received LSUpd * message's router-id is equal to my router-id), and flooded * back by an opaque-capable router. * * 2) This LSA has expired in an opaque-capable router and thus * flushed by the router. */ if (IS_LSA_MAXAGE (lsa)) continue; /* If the LSA has installed in the LSDB, nothing to do here. */ if (ospf_lsa_lookup_by_header (nbr->oi->area, lsa->data) != NULL) continue; /* Ok, here we go. */ switch (lsa->data->type) { case OSPF_OPAQUE_LINK_LSA: oi = nbr->oi; ospf_opaque_exclude_lsa_from_lsreq (oi->nbrs, nbr, lsa); break; case OSPF_OPAQUE_AREA_LSA: area = nbr->oi->area; for (ALL_LIST_ELEMENTS (area->oiflist, node2, nnode2, oi)) ospf_opaque_exclude_lsa_from_lsreq (oi->nbrs, nbr, lsa); break; case OSPF_OPAQUE_AS_LSA: for (ALL_LIST_ELEMENTS (top->oiflist, node2, nnode2, oi)) ospf_opaque_exclude_lsa_from_lsreq (oi->nbrs, nbr, lsa); break; default: break; } } out: return; } static void ospf_opaque_exclude_lsa_from_lsreq (struct route_table *nbrs, struct ospf_neighbor *inbr, struct ospf_lsa *lsa) { struct route_node *rn; struct ospf_neighbor *onbr; struct ospf_lsa *ls_req; for (rn = route_top (nbrs); rn; rn = route_next (rn)) { if ((onbr = rn->info) == NULL) continue; if (onbr == inbr) continue; if ((ls_req = ospf_ls_request_lookup (onbr, lsa)) == NULL) continue; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("LSA[%s]: Exclude this entry from LSReq to send.", dump_lsa_key (lsa)); ospf_ls_request_delete (onbr, ls_req); /* ospf_check_nbr_loading (onbr);*//* XXX */ } return; } void ospf_opaque_self_originated_lsa_received (struct ospf_neighbor *nbr, struct ospf_lsa *lsa) { struct ospf *top; u_char before; if ((top = oi_to_top (nbr->oi)) == NULL) return; before = IS_OPAQUE_LSA_ORIGINATION_BLOCKED (top->opaque); /* * Since these LSA entries are not yet installed into corresponding * LSDB, just flush them without calling ospf_ls_maxage() afterward. */ lsa->data->ls_age = htons (OSPF_LSA_MAXAGE); switch (lsa->data->type) { case OSPF_OPAQUE_LINK_LSA: SET_FLAG (top->opaque, OPAQUE_BLOCK_TYPE_09_LSA_BIT); ospf_flood_through_area (nbr->oi->area, NULL/*inbr*/, lsa); break; case OSPF_OPAQUE_AREA_LSA: SET_FLAG (top->opaque, OPAQUE_BLOCK_TYPE_10_LSA_BIT); ospf_flood_through_area (nbr->oi->area, NULL/*inbr*/, lsa); break; case OSPF_OPAQUE_AS_LSA: SET_FLAG (top->opaque, OPAQUE_BLOCK_TYPE_11_LSA_BIT); ospf_flood_through_as (top, NULL/*inbr*/, lsa); break; default: zlog_warn ("ospf_opaque_self_originated_lsa_received: Unexpected LSA-type(%u)", lsa->data->type); return; } ospf_lsa_discard (lsa); /* List "lsas" will be deleted by caller. */ if (before == 0 && IS_OPAQUE_LSA_ORIGINATION_BLOCKED (top->opaque)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Block Opaque-LSA origination: OFF -> ON"); } } void ospf_opaque_ls_ack_received (struct ospf_neighbor *nbr, struct ospf_lsa *lsa) { struct ospf *top; int delay; struct ospf_interface *oi; struct listnode *node, *nnode; if ((top = oi_to_top (nbr->oi)) == NULL) return; if (!IS_OPAQUE_LSA_ORIGINATION_BLOCKED (top->opaque)) return; switch (lsa->data->type) { case OSPF_OPAQUE_LINK_LSA: if (CHECK_FLAG (top->opaque, OPAQUE_BLOCK_TYPE_09_LSA_BIT)) ospf_opaque_type9_lsa_rxmt_nbr_check (nbr->oi); /* Callback function... */ break; case OSPF_OPAQUE_AREA_LSA: if (CHECK_FLAG (top->opaque, OPAQUE_BLOCK_TYPE_10_LSA_BIT)) ospf_opaque_type10_lsa_rxmt_nbr_check (nbr->oi->area); /* Callback function... */ break; case OSPF_OPAQUE_AS_LSA: if (CHECK_FLAG (top->opaque, OPAQUE_BLOCK_TYPE_11_LSA_BIT)) ospf_opaque_type11_lsa_rxmt_nbr_check (top); /* Callback function... */ break; default: zlog_warn ("ospf_opaque_ls_ack_received: Unexpected LSA-type(%u)", lsa->data->type); return; } if (IS_OPAQUE_LSA_ORIGINATION_BLOCKED (top->opaque)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Block Opaque-LSA origination: ON -> OFF"); return; /* Blocking still in progress. */ } if (! CHECK_FLAG (top->config, OSPF_OPAQUE_CAPABLE)) return; /* Opaque capability condition must have changed. */ /* Ok, let's start origination of Opaque-LSAs. */ delay = OSPF_MIN_LS_INTERVAL; for (ALL_LIST_ELEMENTS (top->oiflist, node, nnode, oi)) { if (! ospf_if_is_enable (oi) || ospf_nbr_count_opaque_capable (oi) == 0) continue; ospf_opaque_lsa_originate_schedule (oi, &delay); } return; } static void ospf_opaque_type9_lsa_rxmt_nbr_check (struct ospf_interface *oi) { unsigned long n; n = ospf_opaque_nrxmt_self (oi->nbrs, OSPF_OPAQUE_LINK_LSA); if (n == 0) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Self-originated type-9 Opaque-LSAs: OI(%s): Flush completed", IF_NAME (oi)); UNSET_FLAG (oi->area->ospf->opaque, OPAQUE_BLOCK_TYPE_09_LSA_BIT); } return; } static void ospf_opaque_type10_lsa_rxmt_nbr_check (struct ospf_area *area) { struct listnode *node; struct ospf_interface *oi; unsigned long n = 0; for (ALL_LIST_ELEMENTS_RO (area->oiflist, node, oi)) { if (area->area_id.s_addr != OSPF_AREA_BACKBONE && oi->type == OSPF_IFTYPE_VIRTUALLINK) continue; n = ospf_opaque_nrxmt_self (oi->nbrs, OSPF_OPAQUE_AREA_LSA); if (n > 0) break; } if (n == 0) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Self-originated type-10 Opaque-LSAs: AREA(%s): Flush completed", inet_ntoa (area->area_id)); UNSET_FLAG (area->ospf->opaque, OPAQUE_BLOCK_TYPE_10_LSA_BIT); } return; } static void ospf_opaque_type11_lsa_rxmt_nbr_check (struct ospf *top) { struct listnode *node; struct ospf_interface *oi; unsigned long n = 0; for (ALL_LIST_ELEMENTS_RO (top->oiflist, node, oi)) { switch (oi->type) { case OSPF_IFTYPE_VIRTUALLINK: continue; default: break; } n = ospf_opaque_nrxmt_self (oi->nbrs, OSPF_OPAQUE_AS_LSA); if (n > 0) goto out; } if (n == 0) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Self-originated type-11 Opaque-LSAs: Flush completed"); UNSET_FLAG (top->opaque, OPAQUE_BLOCK_TYPE_11_LSA_BIT); } out: return; } static unsigned long ospf_opaque_nrxmt_self (struct route_table *nbrs, int lsa_type) { struct route_node *rn; struct ospf_neighbor *nbr; struct ospf *top; unsigned long n = 0; for (rn = route_top (nbrs); rn; rn = route_next (rn)) { if ((nbr = rn->info) == NULL) continue; if ((top = oi_to_top (nbr->oi)) == NULL) continue; if (IPV4_ADDR_SAME (&nbr->router_id, &top->router_id)) continue; n += ospf_ls_retransmit_count_self (nbr, lsa_type); } return n; } /*------------------------------------------------------------------------* * Followings are util functions; probably be used by Opaque-LSAs only... *------------------------------------------------------------------------*/ void htonf (float *src, float *dst) { u_int32_t lu1, lu2; memcpy (&lu1, src, sizeof (u_int32_t)); lu2 = htonl (lu1); memcpy (dst, &lu2, sizeof (u_int32_t)); return; } void ntohf (float *src, float *dst) { u_int32_t lu1, lu2; memcpy (&lu1, src, sizeof (u_int32_t)); lu2 = ntohl (lu1); memcpy (dst, &lu2, sizeof (u_int32_t)); return; } struct ospf * oi_to_top (struct ospf_interface *oi) { struct ospf *top = NULL; struct ospf_area *area; if (oi == NULL || (area = oi->area) == NULL || (top = area->ospf) == NULL) zlog_warn ("Broken relationship for \"OI -> AREA -> OSPF\"?"); return top; } #endif /* HAVE_OPAQUE_LSA */