mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-09 09:46:54 +00:00
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:
parent
7b92589c22
commit
c81ee5c94f
@ -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);
|
||||||
|
|
||||||
|
@ -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
|
||||||
*,
|
*,
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
111
ospfd/ospf_spf.c
111
ospfd/ospf_spf.c
@ -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,6 +517,27 @@ 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
|
||||||
@ -522,23 +545,10 @@ ospf_nexthop_calculation (struct ospf_area *area, struct vertex *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,17 +559,19 @@ 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;
|
||||||
|
nexthop.s_addr = 0; /* Nexthop not required */
|
||||||
|
}
|
||||||
|
else if (oi->type == OSPF_IFTYPE_POINTOMULTIPOINT)
|
||||||
{
|
{
|
||||||
struct prefix_ipv4 la;
|
struct prefix_ipv4 la;
|
||||||
|
|
||||||
@ -573,44 +585,27 @@ ospf_nexthop_calculation (struct ospf_area *area, struct vertex *v,
|
|||||||
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)
|
||||||
|
continue;
|
||||||
/* link_data is on our PtMP network */
|
/* link_data is on our PtMP network */
|
||||||
break;
|
added = 1;
|
||||||
}
|
nexthop = l2->link_data;
|
||||||
} /* end l is on point-to-multipoint link */
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* 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)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (!IPV4_ADDR_SAME (&oi->address->u.prefix4,
|
|
||||||
&l->link_data))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (oi && l2)
|
if (added)
|
||||||
{
|
{
|
||||||
/* 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 = vertex_nexthop_new ();
|
||||||
nh->oi = oi;
|
nh->oi = oi;
|
||||||
nh->router.s_addr = 0;
|
nh->router.s_addr = 0; /* Nexthop not required */
|
||||||
ospf_spf_add_parent (v, w, nh, distance);
|
ospf_spf_add_parent (v, w, nh, distance);
|
||||||
return 1;
|
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.
|
||||||
|
Loading…
Reference in New Issue
Block a user