/* * $Id: lsa_database.c,v 2.2 2000/05/23 08:06:22 masaki Exp $ */ /* code for inserting, searching, aging, deleting, etc the link state databases */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "sospf.h" /* local functions */ static void _ospf_database_dump (); static void _show_ospf_database (uii_connection_t *uii, FILE *fd); /* ospf_database_dump * Dump a copy of the current LSA database to disk for statistics/analysis * This is usually called via the dump timer (if configured) */ void ospf_database_dump () { schedule_event2 ("ospf_databse_dump", OSPF.schedule, _ospf_database_dump, 0, NULL); } static void _ospf_database_dump () { char name[MAXLINE]; FILE *fd; struct tm *tm; u_long now; time (&now); tm = localtime (&now); strftime (name, sizeof (name), OSPF.tableformat, tm); if ((fd = fopen (name, "w")) == NULL) { trace (ERROR, default_trace, "OSPF error -- could not open %s for dumping database\n", name); return; } _show_ospf_database (NULL, fd); fclose (fd); trace (NORM, default_trace, "OSPF Dumped LSA database to %s\n", name); return; } /* * show_ospf_database * Show the current LSA database. Called by UII handler */ void show_ospf_database (uii_connection_t *uii) { schedule_event2 ("_show_ospf_database", OSPF.schedule, _show_ospf_database, 2, uii, NULL); } static void _show_ospf_database (uii_connection_t *uii, FILE *fd) { ospf_router_lsa_t *router_lsa; ospf_network_lsa_t *network_lsa; ospf_summary_lsa_t *summary_lsa; ospf_external_lsa_t *external_lsa; char tmp[MAXLINE]; u_short i; if (uii) uii_add_bulk_output (uii, "\r\n OSPF Router with ID (%s) \r\n\r\n", long_inet_ntoa (OSPF.router_id)); else fprintf (fd, "\r\n OSPF Router with ID (%s) \r\n\r\n", long_inet_ntoa (OSPF.router_id)); /* Print out the Router LSAs. */ if (LL_GetHead (OSPF.ll_router_lsas) != NULL) { if (uii) { uii_add_bulk_output (uii, " Router Link States (Area %d)\r\n", OSPF.area_id); uii_add_bulk_output (uii, "\r\nLink ID ADV Router Age Seq# " " Checksum Link count\r\n"); } else { fprintf (fd, " Router Link States (Area %d)\r\n", (int) OSPF.area_id); fprintf (fd, "\r\nLink ID ADV Router Age Seq# " " Checksum Link count\r\n"); } LL_Iterate (OSPF.ll_router_lsas, router_lsa) { for (i = 0; i < router_lsa->num_links; i++) { sprintf (tmp, "%s", long_inet_ntoa (router_lsa->links[i].link_id)); if (uii) uii_add_bulk_output (uii, "%-15s %-15s %-6u 0x%-8X 0x%-4X %u\r\n", tmp, long_inet_ntoa (router_lsa->header->adv_router), router_lsa->header->age, router_lsa->header->seq_num, router_lsa->header->checksum, i + 1); else fprintf (fd, "%-15s %-15s %-6u 0x%-8X 0x%-4X %u\r\n", tmp, long_inet_ntoa (router_lsa->header->adv_router), router_lsa->header->age, router_lsa->header->seq_num, router_lsa->header->checksum, (u_long) i + 1); } /* for */ } /* LL_Iterate */ } /* Print out the Network LSAs. */ if (LL_GetHead (OSPF.ll_network_lsas) != NULL) { if (uii) { uii_add_bulk_output (uii, "\r\n Net Link States (Area %d)\r\n", OSPF.area_id); uii_add_bulk_output (uii,"\r\nLink ID ADV Router Age Seq# " " Checksum\r\n"); } else { fprintf (fd, "\r\n Net Link States (Area %d)\r\n", OSPF.area_id); fprintf (fd, "\r\nLink ID ADV Router Age Seq# " " Checksum\r\n"); } LL_Iterate (OSPF.ll_network_lsas, network_lsa) { sprintf (tmp, "%s", long_inet_ntoa (network_lsa->network_mask)); if (uii) uii_add_bulk_output (uii, "%-15s %-15s %-6u 0x%-8X 0x%-4X\r\n", tmp, long_inet_ntoa (network_lsa->header->adv_router), network_lsa->header->age, network_lsa->header->seq_num, network_lsa->header->checksum); else fprintf (fd, "%-15s %-15s %-6u 0x%-8X 0x%-4X\r\n", tmp, long_inet_ntoa (network_lsa->header->adv_router), network_lsa->header->age, network_lsa->header->seq_num, network_lsa->header->checksum); } /* LL_Iterate */ } /* if */ /* Print out the Summary LSAs. */ if (LL_GetHead (OSPF.ll_summary_lsas) != NULL) { uii_add_bulk_output (uii, "\r\n Summary Link States (Area %d)\r\n", OSPF.area_id); uii_add_bulk_output (uii, "\r\nLink ID ADV Router Age Seq# " " Checksum Metric\r\n"); LL_Iterate (OSPF.ll_summary_lsas, summary_lsa) { uii_add_bulk_output (uii, "%-15s %-15s %-6u 0x%-8X 0x%-4X %u\r\n", long_inet_ntoa (summary_lsa->network_mask), long_inet_ntoa (summary_lsa->header->adv_router), summary_lsa->header->age, summary_lsa->header->seq_num, summary_lsa->header->checksum, summary_lsa->metric); } /* LL_Iterate */ } /* if */ /* Print out the External LSAs. */ if (LL_GetHead (OSPF.ll_external_lsas) != NULL) { if (uii) { uii_add_bulk_output (uii, "\r\n " "External Link States (Area %d)\r\n", OSPF.area_id); uii_add_bulk_output (uii, "\r\nLink ID ADV Router Age Seq# " " Checksum Metric\r\n"); } else { fprintf (fd, "\r\n " "External Link States (Area %d)\r\n", OSPF.area_id); fprintf (fd, "\r\nLink ID ADV Router Age Seq# " " Checksum Metric\r\n"); } LL_Iterate (OSPF.ll_external_lsas, external_lsa) { sprintf (tmp, "%s", long_inet_ntoa (external_lsa->network_mask)); if (uii) { uii_add_bulk_output (uii, "%-15s %-15s %-6u 0x%-8X 0x%-4X %u\r\n", tmp, long_inet_ntoa (external_lsa->header->adv_router), external_lsa->header->age, external_lsa->header->seq_num, external_lsa->header->checksum, external_lsa->metric); } else { fprintf (fd, "%-15s %-15s %-6u 0x%-8X 0x%-4X %u\r\n", tmp, long_inet_ntoa (external_lsa->header->adv_router), external_lsa->header->age, external_lsa->header->seq_num, external_lsa->header->checksum, external_lsa->metric); } } /* LL_Iterate */ } /* if external_lsas */ if (uii) uii_send_bulk_data (uii); } int ospf_replace_lsa (ospf_lsa_t *old, ospf_lsa_t *new) { int replace = 0; if (old->seq_num < new->seq_num) { /* LSA in database is older, replace it. */ replace = 1; } else if (old->seq_num == new->seq_num) { /* Sequence numbers are identical. */ if (old->checksum < new->checksum) { /* LSA in database has smaller checksum, replace it. */ replace = 1; } else if (old->checksum == new->checksum) { /* Checksums are identical. */ if (new->age == OSPF_MaxAge && old->age != OSPF_MaxAge) { /* Only the new has age MaxAge, replace. */ replace = 1; } else if (abs(new->age - old->age) > OSPF_MaxAgeDiff) { /* The two ages differ by more than MaxAgeDiff. */ if (new->age < old->age) { /* new_lsa has a younger age. */ replace = 1; } /* if new age < curr age */ } /* if age difference > MaxAgeDiff */ } /* if checksums identical */ } /* if seq_nums are identical */ return(replace); } void ospf_add_router_lsa (ospf_router_lsa_t *new_lsa) { ospf_router_lsa_t *curr_lsa; int replace = 0; int found = 0; #ifdef OSPF_ANAL ospf_stat_router_lsa (new_lsa); #endif /* OSPF_ANAL */ LL_Iterate (OSPF.ll_router_lsas, curr_lsa) { if (curr_lsa->header->id == new_lsa->header->id && curr_lsa->header->adv_router == new_lsa->header->adv_router) { /* The two packets are the same, figure out which one is newer. */ found = 1; replace = ospf_replace_lsa(curr_lsa->header, new_lsa->header); } /* if packets are the same */ if (found) { if (replace) { /* FIX We should probably let the LL code do this. */ /* Delete (curr_lsa->header); */ /* Delete (curr_lsa->links); */ LL_Remove (OSPF.ll_router_lsas, curr_lsa); /* Delete (curr_lsa);*/ LL_Add (OSPF.ll_router_lsas, new_lsa); } break; } } /* LL_Iterate */ if (!found) { /* We didn't find it, so just add it to the database. */ LL_Add (OSPF.ll_router_lsas, new_lsa); } } /* ospf_add_router_lsa */ void ospf_destroy_router_lsa (ospf_router_lsa_t *lsa) { Delete (lsa->header); Delete (lsa->links); Delete (lsa); } /* ospf_destroy_router_lsa */ void ospf_add_network_lsa (ospf_network_lsa_t *new_lsa) { ospf_network_lsa_t *curr_lsa; int replace; int found = 0; LL_Iterate (OSPF.ll_network_lsas, curr_lsa) { if (curr_lsa->header->id == new_lsa->header->id && curr_lsa->header->adv_router == new_lsa->header->adv_router) { /* The two packets are the same, figure out which one is newer. */ found = 1; replace = ospf_replace_lsa(curr_lsa->header, new_lsa->header); } /* if packets are the same */ if (found) { if (replace) { /* FIX We should probably let the LL code do this. */ /* Delete (curr_lsa->header); */ /* Delete (curr_lsa->routers); */ LL_Remove (OSPF.ll_network_lsas, curr_lsa); /* Delete (curr_lsa); */ LL_Add (OSPF.ll_network_lsas, new_lsa); } break; } } /* LL_Iterate */ if (!found) { /* We didn't find it, so just add it to the database. */ LL_Add (OSPF.ll_network_lsas, new_lsa); } } /* ospf_add_network_lsa */ void ospf_destroy_network_lsa (ospf_network_lsa_t *lsa) { Delete (lsa->header); Delete (lsa->routers); Delete (lsa); } /* ospf_destroy_network_lsa */ void ospf_add_summary_lsa (ospf_summary_lsa_t *new_lsa) { ospf_summary_lsa_t *curr_lsa; int replace; int found = 0; LL_Iterate (OSPF.ll_summary_lsas, curr_lsa) { if (curr_lsa->header->id == new_lsa->header->id && curr_lsa->header->adv_router == new_lsa->header->adv_router) { /* The two packets are the same, figure out which one is newer. */ found = 1; replace = ospf_replace_lsa(curr_lsa->header, new_lsa->header); } /* if packets are the same */ if (found) { if (replace) { /* FIX We should probably let the LL code do this. */ /* Delete (curr_lsa->header); */ LL_Remove (OSPF.ll_summary_lsas, curr_lsa); /* Delete (curr_lsa); */ LL_Add (OSPF.ll_summary_lsas, new_lsa); } break; } } /* LL_Iterate */ if (!found) { /* We didn't find it, so just add it to the database. */ LL_Add (OSPF.ll_summary_lsas, new_lsa); } } /* ospf_add_summary_lsa */ void ospf_destroy_summary_lsa (ospf_summary_lsa_t *lsa) { Delete (lsa->header); Delete(lsa); } /* ospf_destroy_summary_lsa */ void ospf_add_external_lsa (ospf_external_lsa_t *new_lsa) { ospf_external_lsa_t *curr_lsa; int replace; int found = 0; LL_Iterate (OSPF.ll_external_lsas, curr_lsa) { if (curr_lsa->header->id == new_lsa->header->id && curr_lsa->header->adv_router == new_lsa->header->adv_router) { /* The two packets are the same, figure out which one is newer. */ found = 1; replace = ospf_replace_lsa(curr_lsa->header, new_lsa->header); } /* if packets are the same */ if (found) { if (replace) { LL_Remove (OSPF.ll_external_lsas, curr_lsa); LL_Add (OSPF.ll_external_lsas, new_lsa); } break; } } /* LL_Iterate */ if (!found) { /* We didn't find it, so just add it to the database. */ LL_Add (OSPF.ll_external_lsas, new_lsa); } } /* ospf_add_external_lsa */ void ospf_destroy_external_lsa (ospf_external_lsa_t *lsa) { Delete (lsa->header); Delete(lsa); } /* ospf_destroy_external_lsa */ /* lsa is a pointer to one of the three LSA packet structures. */ void ospf_add_lsa_to_db (ospf_lsa_t *header, void *lsa) { switch (header->type) { case OSPF_ROUTER_LSA: ospf_add_router_lsa ((ospf_router_lsa_t *)lsa); break; case OSPF_NETWORK_LSA: ospf_add_network_lsa ((ospf_network_lsa_t *)lsa); break; case OSPF_SUMMARY_LSA3: ospf_add_summary_lsa ((ospf_summary_lsa_t *)lsa); break; case OSPF_SUMMARY_LSA4: ospf_add_summary_lsa ((ospf_summary_lsa_t *)lsa); break; case OSPF_EXTERNAL_LSA: ospf_add_external_lsa ((ospf_external_lsa_t *)lsa); break; default: trace (ERROR, default_trace, "ERROR -- Attempting to add " "unknown OSPF LSA type (%d) to database\n", header->type); break; } } /* ospf_add_lsa_to_db */ /* The header _must_ specify the type of LSA. * Age and options are ignored, and for all other fields a 0 value is * considered a field that doesn't need to be compared. * The function returns a pointer to a LSA of that type or NULL if it's not * found. */ void *ospf_find_lsa_in_db (ospf_lsa_t *header) { ospf_router_lsa_t *router_lsa; ospf_network_lsa_t *network_lsa; ospf_summary_lsa_t *summary_lsa; switch (header->type) { case OSPF_ROUTER_LSA: LL_Iterate (OSPF.ll_router_lsas, router_lsa) { if ((header->id == 0 || (header->id == router_lsa->header->id)) && (header->adv_router == 0 || (header->adv_router == router_lsa->header->adv_router)) && (header->seq_num == 0 || (header->seq_num == router_lsa->header->seq_num)) && (header->checksum == 0 || (header->checksum == router_lsa->header->checksum))) { /* We've found a match! */ return ((void *)router_lsa); } } /* LL_Iterate */ break; case OSPF_NETWORK_LSA: LL_Iterate (OSPF.ll_network_lsas, network_lsa) { if ((header->id == 0 || (header->id == network_lsa->header->id)) && (header->adv_router == 0 || (header->adv_router == network_lsa->header->adv_router)) && (header->seq_num == 0 || (header->seq_num == network_lsa->header->seq_num)) && (header->checksum == 0 || (header->checksum == network_lsa->header->checksum))) { /* We've found a match! */ return ((void *)network_lsa); } } /* LL_Iterate */ break; case OSPF_SUMMARY_LSA3: case OSPF_SUMMARY_LSA4: LL_Iterate (OSPF.ll_summary_lsas, summary_lsa) { if ((header->id == 0 || (header->id == summary_lsa->header->id)) && (header->adv_router == 0 || (header->adv_router == summary_lsa->header->adv_router)) && (header->seq_num == 0 || (header->seq_num == summary_lsa->header->seq_num)) && (header->checksum == 0 || (header->checksum == summary_lsa->header->checksum))) { /* We've found a match! */ return ((void *)summary_lsa); } } /* LL_Iterate */ break; default: trace (ERROR, default_trace, "ERROR -- Attempting to find " "unknown OSPF LSA type (%d) in database\n", header->type); break; } /* We didn't find anything. */ return (NULL); } /* ospf_find_lsa_in_db */ .