version 1.1.1.3, 2013/07/21 23:54:40
|
version 1.1.1.4, 2016/11/02 10:09:12
|
Line 46 Software Foundation, Inc., 59 Temple Place - Suite 330
|
Line 46 Software Foundation, Inc., 59 Temple Place - Suite 330
|
#include "ospfd/ospf_abr.h" |
#include "ospfd/ospf_abr.h" |
#include "ospfd/ospf_dump.h" |
#include "ospfd/ospf_dump.h" |
|
|
|
/* Variables to ensure a SPF scheduled log message is printed only once */ |
|
|
|
static unsigned int spf_reason_flags = 0; |
|
|
|
static void |
|
ospf_clear_spf_reason_flags () |
|
{ |
|
spf_reason_flags = 0; |
|
} |
|
|
|
static void |
|
ospf_spf_set_reason (ospf_spf_reason_t reason) |
|
{ |
|
spf_reason_flags |= 1 << reason; |
|
} |
|
|
|
static void |
|
ospf_get_spf_reason_str (char *buf) |
|
{ |
|
if (!buf) |
|
return; |
|
|
|
buf[0] = '\0'; |
|
if (spf_reason_flags) |
|
{ |
|
if (spf_reason_flags & SPF_FLAG_ROUTER_LSA_INSTALL) |
|
strcat (buf, "R, "); |
|
if (spf_reason_flags & SPF_FLAG_NETWORK_LSA_INSTALL) |
|
strcat (buf, "N, "); |
|
if (spf_reason_flags & SPF_FLAG_SUMMARY_LSA_INSTALL) |
|
strcat (buf, "S, "); |
|
if (spf_reason_flags & SPF_FLAG_ASBR_SUMMARY_LSA_INSTALL) |
|
strcat (buf, "AS, "); |
|
if (spf_reason_flags & SPF_FLAG_ABR_STATUS_CHANGE) |
|
strcat (buf, "ABR, "); |
|
if (spf_reason_flags & SPF_FLAG_ASBR_STATUS_CHANGE) |
|
strcat (buf, "ASBR, "); |
|
if (spf_reason_flags & SPF_FLAG_MAXAGE) |
|
strcat (buf, "M, "); |
|
buf[strlen(buf)-2] = '\0'; /* skip the last ", " */ |
|
} |
|
} |
|
|
static void ospf_vertex_free (void *); |
static void ospf_vertex_free (void *); |
/* List of allocated vertices, to simplify cleanup of SPF. |
/* List of allocated vertices, to simplify cleanup of SPF. |
* Not thread-safe obviously. If it ever needs to be, it'd have to be |
* Not thread-safe obviously. If it ever needs to be, it'd have to be |
* dynamically allocated at begin of ospf_spf_calculate |
* dynamically allocated at begin of ospf_spf_calculate |
*/ |
*/ |
static struct list vertex_list = { .del = ospf_vertex_free }; |
static struct list vertex_list = { .del = ospf_vertex_free }; |
| |
/* Heap related functions, for the managment of the candidates, to |
/* Heap related functions, for the managment of the candidates, to |
* be used with pqueue. */ |
* be used with pqueue. */ |
static int |
static int |
Line 90 update_stat (void *node , int position)
|
Line 133 update_stat (void *node , int position)
|
/* Set the status of the vertex, when its position changes. */ |
/* Set the status of the vertex, when its position changes. */ |
*(v->stat) = position; |
*(v->stat) = position; |
} |
} |
| |
static struct vertex_nexthop * |
static struct vertex_nexthop * |
vertex_nexthop_new (void) |
vertex_nexthop_new (void) |
{ |
{ |
Line 134 ospf_canonical_nexthops_free (struct vertex *root)
|
Line 177 ospf_canonical_nexthops_free (struct vertex *root)
|
vertex_nexthop_free (vp->nexthop); |
vertex_nexthop_free (vp->nexthop); |
} |
} |
} |
} |
| |
/* TODO: Parent list should be excised, in favour of maintaining only |
/* TODO: Parent list should be excised, in favour of maintaining only |
* vertex_nexthop, with refcounts. |
* vertex_nexthop, with refcounts. |
*/ |
*/ |
Line 159 vertex_parent_free (void *p)
|
Line 202 vertex_parent_free (void *p)
|
{ |
{ |
XFREE (MTYPE_OSPF_VERTEX_PARENT, p); |
XFREE (MTYPE_OSPF_VERTEX_PARENT, p); |
} |
} |
| |
static struct vertex * |
static struct vertex * |
ospf_vertex_new (struct ospf_lsa *lsa) |
ospf_vertex_new (struct ospf_lsa *lsa) |
{ |
{ |
Line 276 ospf_vertex_add_parent (struct vertex *v)
|
Line 319 ospf_vertex_add_parent (struct vertex *v)
|
listnode_add (vp->parent->children, v); |
listnode_add (vp->parent->children, v); |
} |
} |
} |
} |
| |
static void |
static void |
ospf_spf_init (struct ospf_area *area) |
ospf_spf_init (struct ospf_area *area) |
{ |
{ |
Line 547 ospf_nexthop_calculation (struct ospf_area *area, stru
|
Line 590 ospf_nexthop_calculation (struct ospf_area *area, stru
|
|
|
if (l->m[0].type == LSA_LINK_TYPE_POINTOPOINT) |
if (l->m[0].type == LSA_LINK_TYPE_POINTOPOINT) |
{ |
{ |
struct in_addr nexthop; | struct in_addr nexthop = { .s_addr = 0 }; |
|
|
/* If the destination is a router which connects to |
/* If the destination is a router which connects to |
the calculating router via a Point-to-MultiPoint |
the calculating router via a Point-to-MultiPoint |
Line 568 ospf_nexthop_calculation (struct ospf_area *area, stru
|
Line 611 ospf_nexthop_calculation (struct ospf_area *area, stru
|
*/ |
*/ |
if (oi->type == OSPF_IFTYPE_POINTOPOINT) |
if (oi->type == OSPF_IFTYPE_POINTOPOINT) |
{ |
{ |
added = 1; | /* Having nexthop = 0 is tempting, but NOT acceptable. |
nexthop.s_addr = 0; /* Nexthop not required */ | It breaks AS-External routes with a forwarding address, |
| since ospf_ase_complete_direct_routes() will mistakenly |
| assume we've reached the last hop and should place the |
| forwarding address as nexthop. |
| Also, users may configure multi-access links in p2p mode, |
| so we need the IP to ARP the nexthop. |
| */ |
| struct ospf_neighbor *nbr_w; |
| |
| nbr_w = ospf_nbr_lookup_by_routerid (oi->nbrs, &l->link_id); |
| if (nbr_w != NULL) |
| { |
| added = 1; |
| nexthop = nbr_w->src; |
| } |
} |
} |
else if (oi->type == OSPF_IFTYPE_POINTOMULTIPOINT) |
else if (oi->type == OSPF_IFTYPE_POINTOMULTIPOINT) |
{ |
{ |
Line 957 ospf_spf_dump (struct vertex *v, int i)
|
Line 1014 ospf_spf_dump (struct vertex *v, int i)
|
for (ALL_LIST_ELEMENTS_RO (v->parents, nnode, parent)) |
for (ALL_LIST_ELEMENTS_RO (v->parents, nnode, parent)) |
{ |
{ |
zlog_debug (" nexthop %p %s %s", |
zlog_debug (" nexthop %p %s %s", |
parent->nexthop, | (void *)parent->nexthop, |
inet_ntoa (parent->nexthop->router), |
inet_ntoa (parent->nexthop->router), |
parent->nexthop->oi ? IF_NAME(parent->nexthop->oi) |
parent->nexthop->oi ? IF_NAME(parent->nexthop->oi) |
: "NULL"); |
: "NULL"); |
Line 1218 ospf_spf_calculate (struct ospf_area *area, struct rou
|
Line 1275 ospf_spf_calculate (struct ospf_area *area, struct rou
|
|
|
/* Free candidate queue. */ |
/* Free candidate queue. */ |
pqueue_delete (candidate); |
pqueue_delete (candidate); |
| |
ospf_vertex_dump (__func__, area->spf, 0, 1); |
ospf_vertex_dump (__func__, area->spf, 0, 1); |
/* Free nexthop information, canonical versions of which are attached |
/* Free nexthop information, canonical versions of which are attached |
* the first level of router vertices attached to the root vertex, see |
* the first level of router vertices attached to the root vertex, see |
* ospf_nexthop_calculation. |
* ospf_nexthop_calculation. |
*/ |
*/ |
ospf_canonical_nexthops_free (area->spf); |
ospf_canonical_nexthops_free (area->spf); |
| |
/* Free SPF vertices, but not the list. List has ospf_vertex_free | |
* as deconstructor. | |
*/ | |
list_delete_all_node (&vertex_list); | |
| |
/* Increment SPF Calculation Counter. */ |
/* Increment SPF Calculation Counter. */ |
area->spf_calculation++; |
area->spf_calculation++; |
|
|
quagga_gettime (QUAGGA_CLK_MONOTONIC, &area->ospf->ts_spf); |
quagga_gettime (QUAGGA_CLK_MONOTONIC, &area->ospf->ts_spf); |
|
area->ts_spf = area->ospf->ts_spf; |
|
|
if (IS_DEBUG_OSPF_EVENT) |
if (IS_DEBUG_OSPF_EVENT) |
zlog_debug ("ospf_spf_calculate: Stop. %ld vertices", |
zlog_debug ("ospf_spf_calculate: Stop. %ld vertices", |
mtype_stats_alloc(MTYPE_OSPF_VERTEX)); |
mtype_stats_alloc(MTYPE_OSPF_VERTEX)); |
|
|
|
/* Free SPF vertices, but not the list. List has ospf_vertex_free |
|
* as deconstructor. |
|
*/ |
|
list_delete_all_node (&vertex_list); |
} |
} |
| |
/* Timer for SPF calculation. */ |
/* Timer for SPF calculation. */ |
static int |
static int |
ospf_spf_calculate_timer (struct thread *thread) |
ospf_spf_calculate_timer (struct thread *thread) |
Line 1249 ospf_spf_calculate_timer (struct thread *thread)
|
Line 1307 ospf_spf_calculate_timer (struct thread *thread)
|
struct route_table *new_table, *new_rtrs; |
struct route_table *new_table, *new_rtrs; |
struct ospf_area *area; |
struct ospf_area *area; |
struct listnode *node, *nnode; |
struct listnode *node, *nnode; |
| struct timeval start_time, stop_time, spf_start_time; |
| int areas_processed = 0; |
| unsigned long ia_time, prune_time, rt_time; |
| unsigned long abr_time, total_spf_time, spf_time; |
| char rbuf[32]; /* reason_buf */ |
| |
if (IS_DEBUG_OSPF_EVENT) |
if (IS_DEBUG_OSPF_EVENT) |
zlog_debug ("SPF: Timer (SPF calculation expire)"); |
zlog_debug ("SPF: Timer (SPF calculation expire)"); |
|
|
ospf->t_spf_calc = NULL; |
ospf->t_spf_calc = NULL; |
|
|
|
quagga_gettime (QUAGGA_CLK_MONOTONIC, &spf_start_time); |
/* Allocate new table tree. */ |
/* Allocate new table tree. */ |
new_table = route_table_init (); |
new_table = route_table_init (); |
new_rtrs = route_table_init (); |
new_rtrs = route_table_init (); |
Line 1269 ospf_spf_calculate_timer (struct thread *thread)
|
Line 1333 ospf_spf_calculate_timer (struct thread *thread)
|
*/ |
*/ |
if (ospf->backbone && ospf->backbone == area) |
if (ospf->backbone && ospf->backbone == area) |
continue; |
continue; |
| |
ospf_spf_calculate (area, new_table, new_rtrs); |
ospf_spf_calculate (area, new_table, new_rtrs); |
|
areas_processed++; |
} |
} |
| |
/* SPF for backbone, if required */ |
/* SPF for backbone, if required */ |
if (ospf->backbone) |
if (ospf->backbone) |
ospf_spf_calculate (ospf->backbone, new_table, new_rtrs); | { |
| ospf_spf_calculate (ospf->backbone, new_table, new_rtrs); |
| areas_processed++; |
| } |
| |
| quagga_gettime (QUAGGA_CLK_MONOTONIC, &stop_time); |
| spf_time = timeval_elapsed (stop_time, spf_start_time); |
| |
ospf_vl_shut_unapproved (ospf); |
ospf_vl_shut_unapproved (ospf); |
|
|
|
start_time = stop_time; /* saving a call */ |
|
|
ospf_ia_routing (ospf, new_table, new_rtrs); |
ospf_ia_routing (ospf, new_table, new_rtrs); |
|
|
|
quagga_gettime (QUAGGA_CLK_MONOTONIC, &stop_time); |
|
ia_time = timeval_elapsed (stop_time, start_time); |
|
|
|
quagga_gettime (QUAGGA_CLK_MONOTONIC, &start_time); |
ospf_prune_unreachable_networks (new_table); |
ospf_prune_unreachable_networks (new_table); |
ospf_prune_unreachable_routers (new_rtrs); |
ospf_prune_unreachable_routers (new_rtrs); |
|
|
|
quagga_gettime (QUAGGA_CLK_MONOTONIC, &stop_time); |
|
prune_time = timeval_elapsed (stop_time, start_time); |
/* AS-external-LSA calculation should not be performed here. */ |
/* AS-external-LSA calculation should not be performed here. */ |
|
|
/* If new Router Route is installed, |
/* If new Router Route is installed, |
Line 1293 ospf_spf_calculate_timer (struct thread *thread)
|
Line 1372 ospf_spf_calculate_timer (struct thread *thread)
|
|
|
ospf_ase_calculate_timer_add (ospf); |
ospf_ase_calculate_timer_add (ospf); |
|
|
|
quagga_gettime (QUAGGA_CLK_MONOTONIC, &start_time); |
|
|
/* Update routing table. */ |
/* Update routing table. */ |
ospf_route_install (ospf, new_table); |
ospf_route_install (ospf, new_table); |
|
|
|
quagga_gettime (QUAGGA_CLK_MONOTONIC, &stop_time); |
|
rt_time = timeval_elapsed (stop_time, start_time); |
/* Update ABR/ASBR routing table */ |
/* Update ABR/ASBR routing table */ |
if (ospf->old_rtrs) |
if (ospf->old_rtrs) |
{ |
{ |
Line 1307 ospf_spf_calculate_timer (struct thread *thread)
|
Line 1390 ospf_spf_calculate_timer (struct thread *thread)
|
ospf->old_rtrs = ospf->new_rtrs; |
ospf->old_rtrs = ospf->new_rtrs; |
ospf->new_rtrs = new_rtrs; |
ospf->new_rtrs = new_rtrs; |
|
|
|
quagga_gettime (QUAGGA_CLK_MONOTONIC, &start_time); |
if (IS_OSPF_ABR (ospf)) |
if (IS_OSPF_ABR (ospf)) |
ospf_abr_task (ospf); |
ospf_abr_task (ospf); |
|
|
|
quagga_gettime (QUAGGA_CLK_MONOTONIC, &stop_time); |
|
abr_time = timeval_elapsed (stop_time, start_time); |
|
|
|
quagga_gettime (QUAGGA_CLK_MONOTONIC, &stop_time); |
|
total_spf_time = timeval_elapsed (stop_time, spf_start_time); |
|
ospf->ts_spf_duration.tv_sec = total_spf_time/1000000; |
|
ospf->ts_spf_duration.tv_usec = total_spf_time % 1000000; |
|
|
|
ospf_get_spf_reason_str (rbuf); |
|
|
if (IS_DEBUG_OSPF_EVENT) |
if (IS_DEBUG_OSPF_EVENT) |
zlog_debug ("SPF: calculation complete"); | { |
| zlog_info ("SPF Processing Time(usecs): %ld", total_spf_time); |
| zlog_info ("\t SPF Time: %ld", spf_time); |
| zlog_info ("\t InterArea: %ld", ia_time); |
| zlog_info ("\t Prune: %ld", prune_time); |
| zlog_info ("\tRouteInstall: %ld", rt_time); |
| if (IS_OSPF_ABR (ospf)) |
| zlog_info ("\t ABR: %ld (%d areas)", |
| abr_time, areas_processed); |
| zlog_info ("Reason(s) for SPF: %s", rbuf); |
| } |
|
|
|
ospf_clear_spf_reason_flags (); |
|
|
return 0; |
return 0; |
} |
} |
|
|
/* Add schedule for SPF calculation. To avoid frequenst SPF calc, we |
/* Add schedule for SPF calculation. To avoid frequenst SPF calc, we |
set timer for SPF calc. */ |
set timer for SPF calc. */ |
void |
void |
ospf_spf_calculate_schedule (struct ospf *ospf) | ospf_spf_calculate_schedule (struct ospf *ospf, ospf_spf_reason_t reason) |
{ |
{ |
unsigned long delay, elapsed, ht; |
unsigned long delay, elapsed, ht; |
struct timeval result; |
struct timeval result; |
Line 1331 ospf_spf_calculate_schedule (struct ospf *ospf)
|
Line 1437 ospf_spf_calculate_schedule (struct ospf *ospf)
|
if (ospf == NULL) |
if (ospf == NULL) |
return; |
return; |
|
|
|
ospf_spf_set_reason (reason); |
|
|
/* SPF calculation timer is already scheduled. */ |
/* SPF calculation timer is already scheduled. */ |
if (ospf->t_spf_calc) |
if (ospf->t_spf_calc) |
{ |
{ |
if (IS_DEBUG_OSPF_EVENT) |
if (IS_DEBUG_OSPF_EVENT) |
zlog_debug ("SPF: calculation timer is already scheduled: %p", |
zlog_debug ("SPF: calculation timer is already scheduled: %p", |
ospf->t_spf_calc); | (void *)ospf->t_spf_calc); |
return; |
return; |
} |
} |
|
|
Line 1374 ospf_spf_calculate_schedule (struct ospf *ospf)
|
Line 1482 ospf_spf_calculate_schedule (struct ospf *ospf)
|
|
|
if (IS_DEBUG_OSPF_EVENT) |
if (IS_DEBUG_OSPF_EVENT) |
zlog_debug ("SPF: calculation timer delay = %ld", delay); |
zlog_debug ("SPF: calculation timer delay = %ld", delay); |
|
|
|
zlog_info ("SPF: Scheduled in %ld msec", delay); |
|
|
ospf->t_spf_calc = |
ospf->t_spf_calc = |
thread_add_timer_msec (master, ospf_spf_calculate_timer, ospf, delay); |
thread_add_timer_msec (master, ospf_spf_calculate_timer, ospf, delay); |