ospfd: Optimize and improve SPF nexthop calculation

Maintain router LSA positions in OSPF interface.
Find the OSPF interface in nexthop_calculation using
the position in the router LSA. This is possible because
the only time nexthop_calculation needs to look up interfaces
is when dealing with its own Router LSA.

This has the following advantages:
 - Multiple PtP interfaces with the same IP address between two routers.
 - Use Unnumbered PtP on just one end of the link.
 - Faster OI lookup for the OSPF interface and only
   done once for PtoP links.

*ospf_interface.h: (struct ospf_interface) Add storage for
		   storing router LSA position.

*ospf_interface.c: (ospf_if_lookup_by_lsa_pos)
		   lookup OSPF I/F in an area using LSA position.

*ospf_lsa.c: (router_lsa_link_set) record Router LSA position.

*ospf_spf.c: (ospf_spf_next) Count and pass along lsa position.
	     (ospf_nexthop_calculation) Add lsa position argument.
	     call ospf_if_lookup_by_lsa_pos() for OSFP interface handle.
	     Clean up and remove all calls ospf_if_is_configured() the
	     rest. Adjust a few debug logs.

Signed-off-by: Joakim Tjernlund <Joakim.Tjernlund@transmode.se>
Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
This commit is contained in:
Joakim Tjernlund 2012-07-07 17:06:11 +02:00 committed by David Lamparter
parent 7b92589c22
commit c81ee5c94f
4 changed files with 96 additions and 79 deletions

View File

@ -392,6 +392,21 @@ ospf_if_exists (struct ospf_interface *oic)
return NULL; return NULL;
} }
/* Lookup OSPF interface by router LSA posistion */
struct ospf_interface *
ospf_if_lookup_by_lsa_pos (struct ospf_area *area, int lsa_pos)
{
struct listnode *node;
struct ospf_interface *oi;
for (ALL_LIST_ELEMENTS_RO (area->oiflist, node, oi))
{
if (lsa_pos >= oi->lsa_pos_beg && lsa_pos < oi->lsa_pos_end)
return oi;
}
return NULL;
}
struct ospf_interface * struct ospf_interface *
ospf_if_lookup_by_local_addr (struct ospf *ospf, ospf_if_lookup_by_local_addr (struct ospf *ospf,
struct interface *ifp, struct in_addr address) struct interface *ifp, struct in_addr address)
@ -801,6 +816,9 @@ ospf_if_down (struct ospf_interface *oi)
return 0; return 0;
OSPF_ISM_EVENT_EXECUTE (oi, ISM_InterfaceDown); OSPF_ISM_EVENT_EXECUTE (oi, ISM_InterfaceDown);
/* delete position in router LSA */
oi->lsa_pos_beg = 0;
oi->lsa_pos_end = 0;
/* Shutdown packet reception and sending */ /* Shutdown packet reception and sending */
ospf_if_stream_unset (oi); ospf_if_stream_unset (oi);

View File

@ -127,6 +127,10 @@ struct ospf_interface
/* OSPF Area. */ /* OSPF Area. */
struct ospf_area *area; struct ospf_area *area;
/* Position range in Router LSA */
uint16_t lsa_pos_beg; /* inclusive, >= */
uint16_t lsa_pos_end; /* exclusive, < */
/* Interface data from zebra. */ /* Interface data from zebra. */
struct interface *ifp; struct interface *ifp;
struct ospf_vl_data *vl_data; /* Data for Virtual Link */ struct ospf_vl_data *vl_data; /* Data for Virtual Link */
@ -244,6 +248,8 @@ extern int ospf_if_down (struct ospf_interface *);
extern int ospf_if_is_up (struct ospf_interface *); extern int ospf_if_is_up (struct ospf_interface *);
extern struct ospf_interface *ospf_if_exists (struct ospf_interface *); extern struct ospf_interface *ospf_if_exists (struct ospf_interface *);
extern struct ospf_interface *ospf_if_lookup_by_lsa_pos (struct ospf_area *,
int);
extern struct ospf_interface *ospf_if_lookup_by_local_addr (struct ospf *, extern struct ospf_interface *ospf_if_lookup_by_local_addr (struct ospf *,
struct interface struct interface
*, *,

View File

@ -670,6 +670,7 @@ router_lsa_link_set (struct stream *s, struct ospf_area *area)
{ {
if (oi->state != ISM_Down) if (oi->state != ISM_Down)
{ {
oi->lsa_pos_beg = links;
/* Describe each link. */ /* Describe each link. */
switch (oi->type) switch (oi->type)
{ {
@ -691,6 +692,7 @@ router_lsa_link_set (struct stream *s, struct ospf_area *area)
case OSPF_IFTYPE_LOOPBACK: case OSPF_IFTYPE_LOOPBACK:
links += lsa_link_loopback_set (s, oi); links += lsa_link_loopback_set (s, oi);
} }
oi->lsa_pos_end = links;
} }
} }
} }

View File

@ -490,13 +490,15 @@ ospf_spf_add_parent (struct vertex *v, struct vertex *w,
static unsigned int static unsigned int
ospf_nexthop_calculation (struct ospf_area *area, struct vertex *v, ospf_nexthop_calculation (struct ospf_area *area, struct vertex *v,
struct vertex *w, struct router_lsa_link *l, struct vertex *w, struct router_lsa_link *l,
unsigned int distance) unsigned int distance, int lsa_pos)
{ {
struct listnode *node, *nnode; struct listnode *node, *nnode;
struct vertex_nexthop *nh; struct vertex_nexthop *nh;
struct vertex_parent *vp; struct vertex_parent *vp;
struct ospf_interface *oi = NULL; struct ospf_interface *oi = NULL;
unsigned int added = 0; unsigned int added = 0;
char buf1[BUFSIZ];
char buf2[BUFSIZ];
if (IS_DEBUG_OSPF_EVENT) if (IS_DEBUG_OSPF_EVENT)
{ {
@ -515,30 +517,38 @@ ospf_nexthop_calculation (struct ospf_area *area, struct vertex *v,
the OSPF interface connecting to the destination network/router. the OSPF interface connecting to the destination network/router.
*/ */
/* we *must* be supplied with the link data */
assert (l != NULL);
oi = ospf_if_lookup_by_lsa_pos (area, lsa_pos);
if (!oi)
{
zlog_debug("%s: OI not found in LSA: lsa_pos:%d link_id:%s link_data:%s",
__func__, lsa_pos,
inet_ntop (AF_INET, &l->link_id, buf1, BUFSIZ),
inet_ntop (AF_INET, &l->link_data, buf2, BUFSIZ));
return 0;
}
if (IS_DEBUG_OSPF_EVENT)
{
zlog_debug("%s: considering link:%s "
"type:%d link_id:%s link_data:%s",
__func__, oi->ifp->name, l->m[0].type,
inet_ntop (AF_INET, &l->link_id, buf1, BUFSIZ),
inet_ntop (AF_INET, &l->link_data, buf2, BUFSIZ));
}
if (w->type == OSPF_VERTEX_ROUTER) if (w->type == OSPF_VERTEX_ROUTER)
{ {
/* l is a link from v to w /* l is a link from v to w
* l2 will be link from w to v * l2 will be link from w to v
*/ */
struct router_lsa_link *l2 = NULL; struct router_lsa_link *l2 = NULL;
/* we *must* be supplied with the link data */
assert (l != NULL);
if (IS_DEBUG_OSPF_EVENT)
{
char buf1[BUFSIZ];
char buf2[BUFSIZ];
zlog_debug("ospf_nexthop_calculation(): considering link "
"type %d link_id %s link_data %s",
l->m[0].type,
inet_ntop (AF_INET, &l->link_id, buf1, BUFSIZ),
inet_ntop (AF_INET, &l->link_data, buf2, BUFSIZ));
}
if (l->m[0].type == LSA_LINK_TYPE_POINTOPOINT) if (l->m[0].type == LSA_LINK_TYPE_POINTOPOINT)
{ {
struct in_addr nexthop;
/* 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
network, the destination's next hop IP address(es) network, the destination's next hop IP address(es)
@ -549,68 +559,53 @@ ospf_nexthop_calculation (struct ospf_area *area, struct vertex *v,
provides an IP address of the next hop router. provides an IP address of the next hop router.
At this point l is a link from V to W, and V is the At this point l is a link from V to W, and V is the
root ("us"). Find the local interface associated root ("us"). If it is a point-to-multipoint interface,
with l (its address is in l->link_data). If it then look through the links in the opposite direction (W to V).
is a point-to-multipoint interface, then look through If any of them have an address that lands within the
the links in the opposite direction (W to V). If
any of them have an address that lands within the
subnet declared by the PtMP link, then that link subnet declared by the PtMP link, then that link
is a constituent of the PtMP link, and its address is is a constituent of the PtMP link, and its address is
a nexthop address for V. a nexthop address for V.
*/ */
oi = ospf_if_is_configured (area->ospf, &l->link_data); if (oi->type == OSPF_IFTYPE_POINTOPOINT)
if (oi && oi->type == OSPF_IFTYPE_POINTOMULTIPOINT) {
{ added = 1;
struct prefix_ipv4 la; nexthop.s_addr = 0; /* Nexthop not required */
}
else if (oi->type == OSPF_IFTYPE_POINTOMULTIPOINT)
{
struct prefix_ipv4 la;
la.family = AF_INET; la.family = AF_INET;
la.prefixlen = oi->address->prefixlen; la.prefixlen = oi->address->prefixlen;
/* V links to W on PtMP interface /* V links to W on PtMP interface
- find the interface address on W */ - find the interface address on W */
while ((l2 = ospf_get_next_link (w, v, l2))) while ((l2 = ospf_get_next_link (w, v, l2)))
{ {
la.prefix = l2->link_data; la.prefix = l2->link_data;
if (prefix_cmp ((struct prefix *) &la, if (prefix_cmp ((struct prefix *) &la,
oi->address) == 0) oi->address) != 0)
/* link_data is on our PtMP network */ continue;
break; /* link_data is on our PtMP network */
} added = 1;
} /* end l is on point-to-multipoint link */ nexthop = l2->link_data;
else break;
{ }
/* l is a regular point-to-point link. }
Look for a link from W to V.
*/
while ((l2 = ospf_get_next_link (w, v, l2)))
{
oi = ospf_if_is_configured (area->ospf,
&(l2->link_data));
if (oi == NULL) if (added)
continue;
if (!IPV4_ADDR_SAME (&oi->address->u.prefix4,
&l->link_data))
continue;
break;
}
}
if (oi && l2)
{ {
/* found all necessary info to build nexthop */ /* found all necessary info to build nexthop */
nh = vertex_nexthop_new (); nh = vertex_nexthop_new ();
nh->oi = oi; nh->oi = oi;
nh->router = l2->link_data; nh->router = nexthop;
ospf_spf_add_parent (v, w, nh, distance); ospf_spf_add_parent (v, w, nh, distance);
return 1; return 1;
} }
else else
zlog_info("ospf_nexthop_calculation(): " zlog_info("%s: could not determine nexthop for link %s",
"could not determine nexthop for link"); __func__, oi->ifp->name);
} /* end point-to-point link from V to W */ } /* end point-to-point link from V to W */
else if (l->m[0].type == LSA_LINK_TYPE_VIRTUALLINK) else if (l->m[0].type == LSA_LINK_TYPE_VIRTUALLINK)
{ {
@ -643,19 +638,13 @@ ospf_nexthop_calculation (struct ospf_area *area, struct vertex *v,
else else
{ {
assert(w->type == OSPF_VERTEX_NETWORK); assert(w->type == OSPF_VERTEX_NETWORK);
oi = ospf_if_is_configured (area->ospf, &(l->link_data));
if (oi) nh = vertex_nexthop_new ();
{ nh->oi = oi;
nh = vertex_nexthop_new (); nh->router.s_addr = 0; /* Nexthop not required */
nh->oi = oi; ospf_spf_add_parent (v, w, nh, distance);
nh->router.s_addr = 0; return 1;
ospf_spf_add_parent (v, w, nh, distance);
return 1;
}
} }
zlog_info("ospf_nexthop_calculation(): "
"Unknown attached link");
return 0;
} /* end V is the root */ } /* end V is the root */
/* Check if W's parent is a network connected to root. */ /* Check if W's parent is a network connected to root. */
else if (v->type == OSPF_VERTEX_NETWORK) else if (v->type == OSPF_VERTEX_NETWORK)
@ -736,7 +725,7 @@ ospf_spf_next (struct vertex *v, struct ospf_area *area,
u_char *lim; u_char *lim;
struct router_lsa_link *l = NULL; struct router_lsa_link *l = NULL;
struct in_addr *r; struct in_addr *r;
int type = 0; int type = 0, lsa_pos=-1, lsa_pos_next=0;
/* If this is a router-LSA, and bit V of the router-LSA (see Section /* If this is a router-LSA, and bit V of the router-LSA (see Section
A.4.2:RFC2328) is set, set Area A's TransitCapability to TRUE. */ A.4.2:RFC2328) is set, set Area A's TransitCapability to TRUE. */
@ -765,6 +754,8 @@ ospf_spf_next (struct vertex *v, struct ospf_area *area,
{ {
l = (struct router_lsa_link *) p; l = (struct router_lsa_link *) p;
lsa_pos = lsa_pos_next; /* LSA link position */
lsa_pos_next++;
p += (OSPF_ROUTER_LSA_LINK_SIZE + p += (OSPF_ROUTER_LSA_LINK_SIZE +
(l->m[0].tos_count * OSPF_ROUTER_LSA_TOS_SIZE)); (l->m[0].tos_count * OSPF_ROUTER_LSA_TOS_SIZE));
@ -886,7 +877,7 @@ ospf_spf_next (struct vertex *v, struct ospf_area *area,
w = ospf_vertex_new (w_lsa); w = ospf_vertex_new (w_lsa);
/* Calculate nexthop to W. */ /* Calculate nexthop to W. */
if (ospf_nexthop_calculation (area, v, w, l, distance)) if (ospf_nexthop_calculation (area, v, w, l, distance, lsa_pos))
pqueue_enqueue (w, candidate); pqueue_enqueue (w, candidate);
else if (IS_DEBUG_OSPF_EVENT) else if (IS_DEBUG_OSPF_EVENT)
zlog_debug ("Nexthop Calc failed"); zlog_debug ("Nexthop Calc failed");
@ -906,7 +897,7 @@ ospf_spf_next (struct vertex *v, struct ospf_area *area,
{ {
/* Found an equal-cost path to W. /* Found an equal-cost path to W.
* Calculate nexthop of to W from V. */ * Calculate nexthop of to W from V. */
ospf_nexthop_calculation (area, v, w, l, distance); ospf_nexthop_calculation (area, v, w, l, distance, lsa_pos);
} }
/* less than. */ /* less than. */
else else
@ -916,7 +907,7 @@ ospf_spf_next (struct vertex *v, struct ospf_area *area,
* valid nexthop it will call spf_add_parents, which * valid nexthop it will call spf_add_parents, which
* will flush the old parents * will flush the old parents
*/ */
if (ospf_nexthop_calculation (area, v, w, l, distance)) if (ospf_nexthop_calculation (area, v, w, l, distance, lsa_pos))
/* Decrease the key of the node in the heap. /* Decrease the key of the node in the heap.
* trickle-sort it up towards root, just in case this * trickle-sort it up towards root, just in case this
* node should now be the new root due the cost change. * node should now be the new root due the cost change.