mirror of
https://git.proxmox.com/git/mirror_frr
synced 2026-01-04 20:16:01 +00:00
ospf6d: ospfv3-abr-ecmp-support.patch
OSPFv3: Add ABR support and make ECMP > 4. Signed-off-by: Dinesh G Dutt <ddutt at cumulusnetworks.com> Signed-off-by: Pradosh Mohapatra <pmohapat at cumulusnetworks.com>
This commit is contained in:
parent
60e42c52d6
commit
c3c0ac8395
102
lib/bitfield.h
Normal file
102
lib/bitfield.h
Normal file
@ -0,0 +1,102 @@
|
||||
/**
|
||||
* A simple bit array implementation to allocate and free IDs. An example
|
||||
* of its usage is in allocating link state IDs for OSPFv3 as OSPFv3 has
|
||||
* removed all address semantics from LS ID. Another usage can be in
|
||||
* allocating IDs for BGP neighbors (and dynamic update groups) for
|
||||
* efficient storage of adj-rib-out.
|
||||
*
|
||||
* An example:
|
||||
* #include "bitfield.h"
|
||||
*
|
||||
* bitfield_t bitfield;
|
||||
*
|
||||
* bf_init(bitfield, 32);
|
||||
* ...
|
||||
* bf_assign_index(bitfield, id1);
|
||||
* bf_assign_index(bitfield, id2);
|
||||
* ...
|
||||
* bf_release_index(bitfield, id1);
|
||||
*/
|
||||
|
||||
#ifndef _BITFIELD_H
|
||||
#define _BITFIELD_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef unsigned int word_t;
|
||||
#define WORD_MAX 0xFFFFFFFF
|
||||
#define WORD_SIZE (sizeof(word_t) * 8)
|
||||
|
||||
/**
|
||||
* The bitfield structure.
|
||||
* @data: the bits to manage.
|
||||
* @n: The current word number that is being used.
|
||||
* @m: total number of words in 'data'
|
||||
*/
|
||||
#define bitfield_t struct { word_t *data; size_t n, m; }
|
||||
|
||||
/**
|
||||
* Initialize the bits.
|
||||
* @v: an instance of bitfield_t struct.
|
||||
* @N: number of bits to start with, which equates to how many
|
||||
* IDs can be allocated.
|
||||
*/
|
||||
#define bf_init(v, N) \
|
||||
do { \
|
||||
(v).n = 0; \
|
||||
(v).m = ((N) / WORD_SIZE + 1); \
|
||||
(v).data = calloc(1, ((v).m * sizeof(word_t))); \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* allocate and assign an id from bitfield v.
|
||||
*/
|
||||
#define bf_assign_index(v, id) \
|
||||
do { \
|
||||
bf_find_bit(v, id); \
|
||||
bf_set_bit(v, id); \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* return an id to bitfield v
|
||||
*/
|
||||
#define bf_release_index(v, id) \
|
||||
(v).data[bf_index(id)] &= ~(1 << (bf_offset(id)))
|
||||
|
||||
#define bf_index(b) ((b) / WORD_SIZE)
|
||||
#define bf_offset(b) ((b) % WORD_SIZE)
|
||||
|
||||
/**
|
||||
* Set a bit in the array. If it fills up that word and we are
|
||||
* out of words, extend it by one more word.
|
||||
*/
|
||||
#define bf_set_bit(v, b) \
|
||||
do { \
|
||||
size_t w = bf_index(b); \
|
||||
(v).data[w] |= 1 << (bf_offset(b)); \
|
||||
(v).n += ((v).data[w] == WORD_MAX); \
|
||||
if ((v).n == (v).m) { \
|
||||
(v).m = (v).m + 1; \
|
||||
(v).data = realloc((v).data, (v).m * sizeof(word_t)); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* Find a clear bit in v and assign it to b. */
|
||||
#define bf_find_bit(v, b) \
|
||||
do { \
|
||||
word_t word; \
|
||||
unsigned int w, sh; \
|
||||
for (w = 0; w <= (v).n; w++) { \
|
||||
if ((word = (v).data[w]) != WORD_MAX) break; \
|
||||
} \
|
||||
(b) = ((word & 0xFFFF) == 0xFFFF) << 4; word >>= (b); \
|
||||
sh = ((word & 0xFF) == 0xFF) << 3; word >>= sh; (b) |= sh; \
|
||||
sh = ((word & 0xF) == 0xF) << 2; word >>= sh; (b) |= sh; \
|
||||
sh = ((word & 0x3) == 0x3) << 1; word >>= sh; (b) |= sh; \
|
||||
sh = ((word & 0x1) == 0x1) << 0; word >>= sh; (b) |= sh; \
|
||||
(b) += (w * WORD_SIZE); \
|
||||
} while (0)
|
||||
|
||||
#endif
|
||||
@ -80,6 +80,7 @@
|
||||
#define OSPF_FAST_HELLO_DEFAULT 0
|
||||
|
||||
#define OSPF_AREA_BACKBONE 0x00000000 /* 0.0.0.0 */
|
||||
#define OSPF_AREA_RANGE_COST_UNSPEC -1U
|
||||
|
||||
/* SPF Throttling timer values. */
|
||||
#define OSPF_SPF_DELAY_DEFAULT 200
|
||||
|
||||
@ -584,7 +584,15 @@ zapi_ipv6_route (u_char cmd, struct zclient *zclient, struct prefix_ipv6 *p,
|
||||
/* Nexthop, ifindex, distance and metric information. */
|
||||
if (CHECK_FLAG (api->message, ZAPI_MESSAGE_NEXTHOP))
|
||||
{
|
||||
stream_putc (s, api->nexthop_num + api->ifindex_num);
|
||||
if (CHECK_FLAG (api->flags, ZEBRA_FLAG_BLACKHOLE))
|
||||
{
|
||||
stream_putc (s, 1);
|
||||
stream_putc (s, ZEBRA_NEXTHOP_BLACKHOLE);
|
||||
/* XXX assert(api->nexthop_num == 0); */
|
||||
/* XXX assert(api->ifindex_num == 0); */
|
||||
}
|
||||
else
|
||||
stream_putc (s, api->nexthop_num + api->ifindex_num);
|
||||
|
||||
for (i = 0; i < api->nexthop_num; i++)
|
||||
{
|
||||
|
||||
@ -38,6 +38,7 @@
|
||||
#include "ospf6_route.h"
|
||||
#include "ospf6_lsdb.h"
|
||||
#include "ospf6_message.h"
|
||||
#include "ospf6_zebra.h"
|
||||
|
||||
#include "ospf6_top.h"
|
||||
#include "ospf6_area.h"
|
||||
@ -67,6 +68,33 @@ ospf6_is_router_abr (struct ospf6 *o)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ospf6_abr_nexthops_belong_to_area (struct ospf6_route *route,
|
||||
struct ospf6_area *area)
|
||||
{
|
||||
struct ospf6_interface *oi;
|
||||
|
||||
oi = ospf6_interface_lookup_by_ifindex (ospf6_route_get_first_nh_index(route));
|
||||
if (oi && oi->area && oi->area == area)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
ospf6_abr_delete_route (struct ospf6_route *range, struct ospf6_route *summary,
|
||||
struct ospf6_route_table *summary_table,
|
||||
struct ospf6_lsa *old)
|
||||
{
|
||||
if (summary)
|
||||
{
|
||||
ospf6_route_remove (summary, summary_table);
|
||||
}
|
||||
|
||||
if (old)
|
||||
ospf6_lsa_purge (old);
|
||||
}
|
||||
|
||||
void
|
||||
ospf6_abr_enable_area (struct ospf6_area *area)
|
||||
{
|
||||
@ -139,12 +167,11 @@ ospf6_abr_disable_area (struct ospf6_area *area)
|
||||
}
|
||||
|
||||
/* RFC 2328 12.4.3. Summary-LSAs */
|
||||
void
|
||||
int
|
||||
ospf6_abr_originate_summary_to_area (struct ospf6_route *route,
|
||||
struct ospf6_area *area)
|
||||
{
|
||||
struct ospf6_lsa *lsa, *old = NULL;
|
||||
struct ospf6_interface *oi;
|
||||
struct ospf6_route *summary, *range = NULL;
|
||||
struct ospf6_area *route_area;
|
||||
char buffer[OSPF6_MAX_LSASIZE];
|
||||
@ -157,6 +184,54 @@ ospf6_abr_originate_summary_to_area (struct ospf6_route *route,
|
||||
char buf[64];
|
||||
int is_debug = 0;
|
||||
|
||||
/* Only destination type network, range or ASBR are considered */
|
||||
if (route->type != OSPF6_DEST_TYPE_NETWORK &&
|
||||
route->type != OSPF6_DEST_TYPE_RANGE &&
|
||||
((route->type != OSPF6_DEST_TYPE_ROUTER) ||
|
||||
!CHECK_FLAG (route->path.router_bits, OSPF6_ROUTER_BIT_E)))
|
||||
{
|
||||
if (is_debug)
|
||||
zlog_debug ("Route type is none of network, range nor ASBR, ignore");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* AS External routes are never considered */
|
||||
if (route->path.type == OSPF6_PATH_TYPE_EXTERNAL1 ||
|
||||
route->path.type == OSPF6_PATH_TYPE_EXTERNAL2)
|
||||
{
|
||||
if (is_debug)
|
||||
zlog_debug ("Path type is external, skip");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* do not generate if the path's area is the same as target area */
|
||||
if (route->path.area_id == area->area_id)
|
||||
{
|
||||
if (is_debug)
|
||||
zlog_debug ("The route is in the area itself, ignore");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* do not generate if the nexthops belongs to the target area */
|
||||
if (ospf6_abr_nexthops_belong_to_area (route, area))
|
||||
{
|
||||
if (is_debug)
|
||||
zlog_debug ("The route's nexthop is in the same area, ignore");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (route->type == OSPF6_DEST_TYPE_ROUTER)
|
||||
{
|
||||
if (ADV_ROUTER_IN_PREFIX (&route->prefix) == area->ospf6->router_id)
|
||||
{
|
||||
inet_ntop (AF_INET, &(ADV_ROUTER_IN_PREFIX (&route->prefix)), buf,
|
||||
sizeof (buf));
|
||||
zlog_debug ("%s: Skipping ASBR announcement for ABR (%s)", __func__,
|
||||
buf);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (route->type == OSPF6_DEST_TYPE_ROUTER)
|
||||
{
|
||||
if (IS_OSPF6_DEBUG_ABR || IS_OSPF6_DEBUG_ORIGINATE (INTER_ROUTER))
|
||||
@ -192,76 +267,53 @@ ospf6_abr_originate_summary_to_area (struct ospf6_route *route,
|
||||
{
|
||||
if (is_debug)
|
||||
zlog_debug ("The route has just removed, purge previous LSA");
|
||||
if (summary)
|
||||
ospf6_route_remove (summary, summary_table);
|
||||
if (old)
|
||||
ospf6_lsa_purge (old);
|
||||
return;
|
||||
|
||||
if (route->type == OSPF6_DEST_TYPE_RANGE)
|
||||
{
|
||||
/* Whether the route have active longer prefix */
|
||||
if (! CHECK_FLAG (route->flag, OSPF6_ROUTE_ACTIVE_SUMMARY))
|
||||
{
|
||||
if (is_debug)
|
||||
zlog_debug ("The range is not active. withdraw");
|
||||
|
||||
ospf6_abr_delete_route (route, summary, summary_table, old);
|
||||
}
|
||||
}
|
||||
else
|
||||
if (old)
|
||||
ospf6_lsa_purge (old);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Only destination type network, range or ASBR are considered */
|
||||
if (route->type != OSPF6_DEST_TYPE_NETWORK &&
|
||||
route->type != OSPF6_DEST_TYPE_RANGE &&
|
||||
(route->type != OSPF6_DEST_TYPE_ROUTER ||
|
||||
! CHECK_FLAG (route->path.router_bits, OSPF6_ROUTER_BIT_E)))
|
||||
if ((route->type == OSPF6_DEST_TYPE_ROUTER) && IS_AREA_STUB(area))
|
||||
{
|
||||
if (is_debug)
|
||||
zlog_debug ("Route type is none of network, range nor ASBR, withdraw");
|
||||
if (summary)
|
||||
ospf6_route_remove (summary, summary_table);
|
||||
if (old)
|
||||
ospf6_lsa_purge (old);
|
||||
return;
|
||||
}
|
||||
zlog_debug ("Area has been stubbed, purge Inter-Router LSA");
|
||||
|
||||
/* AS External routes are never considered */
|
||||
if (route->path.type == OSPF6_PATH_TYPE_EXTERNAL1 ||
|
||||
route->path.type == OSPF6_PATH_TYPE_EXTERNAL2)
|
||||
{
|
||||
if (is_debug)
|
||||
zlog_debug ("Path type is external, withdraw");
|
||||
if (summary)
|
||||
ospf6_route_remove (summary, summary_table);
|
||||
if (old)
|
||||
ospf6_lsa_purge (old);
|
||||
return;
|
||||
}
|
||||
|
||||
/* do not generate if the path's area is the same as target area */
|
||||
if (route->path.area_id == area->area_id)
|
||||
{
|
||||
if (is_debug)
|
||||
zlog_debug ("The route is in the area itself, ignore");
|
||||
if (summary)
|
||||
ospf6_route_remove (summary, summary_table);
|
||||
if (old)
|
||||
ospf6_lsa_purge (old);
|
||||
return;
|
||||
}
|
||||
|
||||
/* do not generate if the nexthops belongs to the target area */
|
||||
oi = ospf6_interface_lookup_by_ifindex (route->nexthop[0].ifindex);
|
||||
if (oi && oi->area && oi->area == area)
|
||||
{
|
||||
if (is_debug)
|
||||
zlog_debug ("The route's nexthop is in the same area, ignore");
|
||||
if (summary)
|
||||
ospf6_route_remove (summary, summary_table);
|
||||
if (old)
|
||||
ospf6_lsa_purge (old);
|
||||
return;
|
||||
ospf6_abr_delete_route (route, summary, summary_table, old);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* do not generate if the route cost is greater or equal to LSInfinity */
|
||||
if (route->path.cost >= OSPF_LS_INFINITY)
|
||||
{
|
||||
if (is_debug)
|
||||
zlog_debug ("The cost exceeds LSInfinity, withdraw");
|
||||
if (summary)
|
||||
ospf6_route_remove (summary, summary_table);
|
||||
if (old)
|
||||
ospf6_lsa_purge (old);
|
||||
return;
|
||||
/* When we're clearing the range route because all active prefixes
|
||||
* under the range are gone, we set the range's cost to
|
||||
* OSPF_AREA_RANGE_COST_UNSPEC, which is > OSPF_LS_INFINITY. We
|
||||
* don't want to trigger the code here for that. This code is for
|
||||
* handling routes that have gone to infinity. The range removal happens
|
||||
* elsewhere.
|
||||
*/
|
||||
if ((route->type != OSPF6_DEST_TYPE_RANGE) &&
|
||||
(route->path.cost != OSPF_AREA_RANGE_COST_UNSPEC))
|
||||
{
|
||||
if (is_debug)
|
||||
zlog_debug ("The cost exceeds LSInfinity, withdraw");
|
||||
if (old)
|
||||
ospf6_lsa_purge (old);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* if this is a route to ASBR */
|
||||
@ -272,11 +324,8 @@ ospf6_abr_originate_summary_to_area (struct ospf6_route *route,
|
||||
{
|
||||
if (is_debug)
|
||||
zlog_debug ("This is the secondary path to the ASBR, ignore");
|
||||
if (summary)
|
||||
ospf6_route_remove (summary, summary_table);
|
||||
if (old)
|
||||
ospf6_lsa_purge (old);
|
||||
return;
|
||||
ospf6_abr_delete_route (route, summary, summary_table, old);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Do not generate if the area is stub */
|
||||
@ -305,12 +354,8 @@ ospf6_abr_originate_summary_to_area (struct ospf6_route *route,
|
||||
zlog_debug ("Suppressed by range %s of area %s",
|
||||
buf, route_area->name);
|
||||
}
|
||||
|
||||
if (summary)
|
||||
ospf6_route_remove (summary, summary_table);
|
||||
if (old)
|
||||
ospf6_lsa_purge (old);
|
||||
return;
|
||||
ospf6_abr_delete_route (route, summary, summary_table, old);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -322,23 +367,17 @@ ospf6_abr_originate_summary_to_area (struct ospf6_route *route,
|
||||
{
|
||||
if (is_debug)
|
||||
zlog_debug ("This is the range with DoNotAdvertise set. ignore");
|
||||
if (summary)
|
||||
ospf6_route_remove (summary, summary_table);
|
||||
if (old)
|
||||
ospf6_lsa_purge (old);
|
||||
return;
|
||||
ospf6_abr_delete_route (route, summary, summary_table, old);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Whether the route have active longer prefix */
|
||||
/* If there are no active prefixes in this range, remove */
|
||||
if (! CHECK_FLAG (route->flag, OSPF6_ROUTE_ACTIVE_SUMMARY))
|
||||
{
|
||||
if (is_debug)
|
||||
zlog_debug ("The range is not active. withdraw");
|
||||
if (summary)
|
||||
ospf6_route_remove (summary, summary_table);
|
||||
if (old)
|
||||
ospf6_lsa_purge (old);
|
||||
return;
|
||||
ospf6_abr_delete_route (route, summary, summary_table, old);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -359,7 +398,7 @@ ospf6_abr_originate_summary_to_area (struct ospf6_route *route,
|
||||
buf, sizeof(buf));
|
||||
zlog_debug ("prefix %s was denied by export list", buf);
|
||||
}
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -380,7 +419,7 @@ ospf6_abr_originate_summary_to_area (struct ospf6_route *route,
|
||||
buf, sizeof (buf));
|
||||
zlog_debug ("prefix %s was denied by filter-list out", buf);
|
||||
}
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -388,16 +427,25 @@ ospf6_abr_originate_summary_to_area (struct ospf6_route *route,
|
||||
if (summary == NULL)
|
||||
{
|
||||
summary = ospf6_route_copy (route);
|
||||
if (route->type == OSPF6_DEST_TYPE_NETWORK ||
|
||||
route->type == OSPF6_DEST_TYPE_RANGE)
|
||||
summary->path.origin.type = htons (OSPF6_LSTYPE_INTER_PREFIX);
|
||||
else
|
||||
summary->path.origin.type = htons (OSPF6_LSTYPE_INTER_ROUTER);
|
||||
summary->path.origin.adv_router = area->ospf6->router_id;
|
||||
summary->path.origin.id =
|
||||
ospf6_new_ls_id (summary->path.origin.type,
|
||||
summary->path.origin.adv_router, area->lsdb);
|
||||
|
||||
if (route->type == OSPF6_DEST_TYPE_ROUTER)
|
||||
{
|
||||
summary->path.origin.type = htons (OSPF6_LSTYPE_INTER_ROUTER);
|
||||
summary->path.origin.id = ADV_ROUTER_IN_PREFIX (&route->prefix);
|
||||
}
|
||||
else
|
||||
{
|
||||
summary->path.origin.type = htons (OSPF6_LSTYPE_INTER_PREFIX);
|
||||
if (route->type == OSPF6_DEST_TYPE_RANGE)
|
||||
summary->path.origin.id = route->linkstate_id;
|
||||
else
|
||||
summary->path.origin.id =
|
||||
ospf6_new_ls_id (summary->path.origin.type,
|
||||
summary->path.origin.adv_router, area->lsdb);
|
||||
}
|
||||
summary = ospf6_route_add (summary, summary_table);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -413,7 +461,7 @@ ospf6_abr_originate_summary_to_area (struct ospf6_route *route,
|
||||
summary->path.area_id = area->area_id;
|
||||
summary->path.type = OSPF6_PATH_TYPE_INTER;
|
||||
summary->path.cost = route->path.cost;
|
||||
summary->nexthop[0] = route->nexthop[0];
|
||||
/* summary->nexthop[0] = route->nexthop[0]; */
|
||||
|
||||
/* prepare buffer */
|
||||
memset (buffer, 0, sizeof (buffer));
|
||||
@ -470,35 +518,100 @@ ospf6_abr_originate_summary_to_area (struct ospf6_route *route,
|
||||
|
||||
/* Originate */
|
||||
ospf6_lsa_originate_area (lsa, area);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
void
|
||||
ospf6_abr_range_update (struct ospf6_route *range)
|
||||
{
|
||||
u_int32_t cost = 0;
|
||||
struct ospf6_route *ro;
|
||||
int gen_range_summary = 0;
|
||||
char buf[INET6_ADDRSTRLEN];
|
||||
|
||||
assert (range->type == OSPF6_DEST_TYPE_RANGE);
|
||||
prefix2str (&range->prefix, buf, sizeof (buf));
|
||||
|
||||
/* update range's cost and active flag */
|
||||
for (ro = ospf6_route_match_head (&range->prefix, ospf6->route_table);
|
||||
ro; ro = ospf6_route_match_next (&range->prefix, ro))
|
||||
if (CHECK_FLAG(range->flag, OSPF6_ROUTE_REMOVE))
|
||||
{
|
||||
if (ro->path.area_id == range->path.area_id &&
|
||||
! CHECK_FLAG (ro->flag, OSPF6_ROUTE_REMOVE))
|
||||
cost = MAX (cost, ro->path.cost);
|
||||
UNSET_FLAG (range->flag, OSPF6_ROUTE_ACTIVE_SUMMARY);
|
||||
gen_range_summary = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* update range's cost and active flag */
|
||||
for (ro = ospf6_route_match_head (&range->prefix, ospf6->route_table);
|
||||
ro; ro = ospf6_route_match_next (&range->prefix, ro))
|
||||
{
|
||||
if (ro->path.area_id == range->path.area_id &&
|
||||
(ro->path.type == OSPF6_PATH_TYPE_INTRA) &&
|
||||
! CHECK_FLAG (ro->flag, OSPF6_ROUTE_REMOVE))
|
||||
cost = MAX (cost, ro->path.cost);
|
||||
}
|
||||
}
|
||||
|
||||
if (range->path.cost != cost)
|
||||
/* Non-zero cost is a proxy for active longer prefixes in this range.
|
||||
* If there are active routes covered by this range AND either the configured
|
||||
* cost has changed or the summarized cost has changed then redo summaries.
|
||||
* Alternately, if there are no longer active prefixes and there are
|
||||
* summary announcements, withdraw those announcements.
|
||||
*
|
||||
* The don't advertise code relies on the path.cost being set to UNSPEC to
|
||||
* work the first time. Subsequent times the path.cost is not 0 anyway if there
|
||||
* were active ranges.
|
||||
*/
|
||||
if (CHECK_FLAG (range->flag, OSPF6_ROUTE_DO_NOT_ADVERTISE))
|
||||
{
|
||||
range->path.cost = cost;
|
||||
|
||||
if (range->path.cost)
|
||||
SET_FLAG (range->flag, OSPF6_ROUTE_ACTIVE_SUMMARY);
|
||||
if (range->path.cost != 0)
|
||||
{
|
||||
range->path.cost = 0;
|
||||
gen_range_summary = 1;
|
||||
}
|
||||
}
|
||||
else if (cost &&
|
||||
(((range->path.u.cost_config != OSPF_AREA_RANGE_COST_UNSPEC) &&
|
||||
(range->path.cost != range->path.u.cost_config)) ||
|
||||
((range->path.u.cost_config == OSPF_AREA_RANGE_COST_UNSPEC) &&
|
||||
(range->path.cost != cost))))
|
||||
{
|
||||
if (range->path.u.cost_config == OSPF_AREA_RANGE_COST_UNSPEC)
|
||||
{
|
||||
range->path.cost = cost;
|
||||
}
|
||||
else
|
||||
UNSET_FLAG (range->flag, OSPF6_ROUTE_ACTIVE_SUMMARY);
|
||||
{
|
||||
range->path.cost = range->path.u.cost_config;
|
||||
}
|
||||
|
||||
SET_FLAG (range->flag, OSPF6_ROUTE_ACTIVE_SUMMARY);
|
||||
gen_range_summary = 1;
|
||||
}
|
||||
else if (!cost && CHECK_FLAG (range->flag, OSPF6_ROUTE_ACTIVE_SUMMARY))
|
||||
{
|
||||
UNSET_FLAG (range->flag, OSPF6_ROUTE_ACTIVE_SUMMARY);
|
||||
range->path.cost = OSPF_AREA_RANGE_COST_UNSPEC;
|
||||
gen_range_summary = 1;
|
||||
}
|
||||
|
||||
if (gen_range_summary)
|
||||
{
|
||||
ospf6_abr_originate_summary (range);
|
||||
|
||||
if (CHECK_FLAG (range->flag, OSPF6_ROUTE_ACTIVE_SUMMARY))
|
||||
{
|
||||
if (IS_OSPF6_DEBUG_ABR)
|
||||
zlog_debug ("Add discard route");
|
||||
|
||||
ospf6_zebra_add_discard (range);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (IS_OSPF6_DEBUG_ABR)
|
||||
zlog_debug ("Delete discard route");
|
||||
|
||||
ospf6_zebra_delete_discard (range);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -514,7 +627,9 @@ ospf6_abr_originate_summary (struct ospf6_route *route)
|
||||
oa = ospf6_area_lookup (route->path.area_id, ospf6);
|
||||
range = ospf6_route_lookup_bestmatch (&route->prefix, oa->range_table);
|
||||
if (range)
|
||||
ospf6_abr_range_update (range);
|
||||
{
|
||||
ospf6_abr_range_update (range);
|
||||
}
|
||||
}
|
||||
|
||||
for (ALL_LIST_ELEMENTS (ospf6->area_list, node, nnode, oa))
|
||||
@ -534,7 +649,6 @@ ospf6_abr_examin_summary (struct ospf6_lsa *lsa, struct ospf6_area *oa)
|
||||
u_int8_t prefix_options = 0;
|
||||
u_int32_t cost = 0;
|
||||
u_char router_bits = 0;
|
||||
int i;
|
||||
char buf[64];
|
||||
int is_debug = 0;
|
||||
struct ospf6_inter_prefix_lsa *prefix_lsa = NULL;
|
||||
@ -575,6 +689,7 @@ ospf6_abr_examin_summary (struct ospf6_lsa *lsa, struct ospf6_area *oa)
|
||||
ospf6_linkstate_prefix (router_lsa->router_id, htonl (0), &prefix);
|
||||
if (is_debug)
|
||||
inet_ntop (AF_INET, &router_lsa->router_id, buf, sizeof (buf));
|
||||
|
||||
table = oa->ospf6->brouter_table;
|
||||
type = OSPF6_DEST_TYPE_ROUTER;
|
||||
options[0] = router_lsa->options[0];
|
||||
@ -600,6 +715,8 @@ ospf6_abr_examin_summary (struct ospf6_lsa *lsa, struct ospf6_area *oa)
|
||||
old = route;
|
||||
route = ospf6_route_next (route);
|
||||
}
|
||||
if (route)
|
||||
ospf6_route_unlock (route);
|
||||
|
||||
/* (1) if cost == LSInfinity or if the LSA is MaxAge */
|
||||
if (cost == OSPF_LS_INFINITY)
|
||||
@ -666,8 +783,22 @@ ospf6_abr_examin_summary (struct ospf6_lsa *lsa, struct ospf6_area *oa)
|
||||
zlog_debug ("Prefix has NU/LA bit set, ignore");
|
||||
if (old)
|
||||
ospf6_route_remove (old, table);
|
||||
|
||||
return;
|
||||
}
|
||||
/* Avoid infinite recursion if someone has maliciously announced an
|
||||
Inter-Router LSA for an ABR
|
||||
*/
|
||||
if (lsa->header->adv_router == router_lsa->router_id)
|
||||
{
|
||||
if (is_debug)
|
||||
zlog_debug ("Ignorning Inter-Router LSA for an ABR (%s)",
|
||||
buf);
|
||||
if (old)
|
||||
ospf6_route_remove (old, table);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* (4) if the routing table entry for the ABR does not exist */
|
||||
@ -718,7 +849,7 @@ ospf6_abr_examin_summary (struct ospf6_lsa *lsa, struct ospf6_area *oa)
|
||||
}
|
||||
}
|
||||
|
||||
/* (5),(6),(7) the path preference is handled by the sorting
|
||||
/* (5),(6): the path preference is handled by the sorting
|
||||
in the routing table. Always install the path by substituting
|
||||
old route (if any). */
|
||||
if (old)
|
||||
@ -739,12 +870,33 @@ ospf6_abr_examin_summary (struct ospf6_lsa *lsa, struct ospf6_area *oa)
|
||||
route->path.area_id = oa->area_id;
|
||||
route->path.type = OSPF6_PATH_TYPE_INTER;
|
||||
route->path.cost = abr_entry->path.cost + cost;
|
||||
for (i = 0; i < OSPF6_MULTI_PATH_LIMIT; i++)
|
||||
route->nexthop[i] = abr_entry->nexthop[i];
|
||||
|
||||
if (is_debug)
|
||||
zlog_debug ("Install route: %s", buf);
|
||||
ospf6_route_add (route, table);
|
||||
ospf6_route_copy_nexthops (route, abr_entry);
|
||||
|
||||
/* (7) If the routes are identical, copy the next hops over to existing
|
||||
route. ospf6's route table implementation will otherwise string both
|
||||
routes, but keep the older one as the best route since the routes
|
||||
are identical.
|
||||
*/
|
||||
old = ospf6_route_lookup (&prefix, table);
|
||||
|
||||
if (old && (ospf6_route_cmp (route, old) == 0))
|
||||
{
|
||||
ospf6_route_merge_nexthops (old, route);
|
||||
/* Update RIB/FIB */
|
||||
if (table->hook_add)
|
||||
(*table->hook_add) (old);
|
||||
|
||||
/* Delete new route */
|
||||
ospf6_route_delete (route);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (is_debug)
|
||||
zlog_debug ("Install route: %s", buf);
|
||||
/* ospf6_ia_add_nw_route (table, &prefix, route); */
|
||||
ospf6_route_add (route, table);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@ -752,21 +904,22 @@ ospf6_abr_examin_brouter (u_int32_t router_id)
|
||||
{
|
||||
struct ospf6_lsa *lsa;
|
||||
struct ospf6_area *oa;
|
||||
struct listnode *node, *nnode;
|
||||
u_int16_t type;
|
||||
|
||||
for (ALL_LIST_ELEMENTS (ospf6->area_list, node, nnode, oa))
|
||||
{
|
||||
type = htons (OSPF6_LSTYPE_INTER_ROUTER);
|
||||
for (lsa = ospf6_lsdb_type_router_head (type, router_id, oa->lsdb); lsa;
|
||||
lsa = ospf6_lsdb_type_router_next (type, router_id, lsa))
|
||||
ospf6_abr_examin_summary (lsa, oa);
|
||||
if (ospf6_is_router_abr (ospf6))
|
||||
oa = ospf6->backbone;
|
||||
else
|
||||
oa = listgetdata(listhead(ospf6->area_list));
|
||||
|
||||
type = htons (OSPF6_LSTYPE_INTER_PREFIX);
|
||||
for (lsa = ospf6_lsdb_type_router_head (type, router_id, oa->lsdb); lsa;
|
||||
lsa = ospf6_lsdb_type_router_next (type, router_id, lsa))
|
||||
ospf6_abr_examin_summary (lsa, oa);
|
||||
}
|
||||
type = htons (OSPF6_LSTYPE_INTER_ROUTER);
|
||||
for (lsa = ospf6_lsdb_type_router_head (type, router_id, oa->lsdb); lsa;
|
||||
lsa = ospf6_lsdb_type_router_next (type, router_id, lsa))
|
||||
ospf6_abr_examin_summary (lsa, oa);
|
||||
|
||||
type = htons (OSPF6_LSTYPE_INTER_PREFIX);
|
||||
for (lsa = ospf6_lsdb_type_router_head (type, router_id, oa->lsdb); lsa;
|
||||
lsa = ospf6_lsdb_type_router_next (type, router_id, lsa))
|
||||
ospf6_abr_examin_summary (lsa, oa);
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@ -62,12 +62,13 @@ extern int ospf6_is_router_abr (struct ospf6 *o);
|
||||
extern void ospf6_abr_enable_area (struct ospf6_area *oa);
|
||||
extern void ospf6_abr_disable_area (struct ospf6_area *oa);
|
||||
|
||||
extern void ospf6_abr_originate_summary_to_area (struct ospf6_route *route,
|
||||
extern int ospf6_abr_originate_summary_to_area (struct ospf6_route *route,
|
||||
struct ospf6_area *area);
|
||||
extern void ospf6_abr_originate_summary (struct ospf6_route *route);
|
||||
extern void ospf6_abr_examin_summary (struct ospf6_lsa *lsa, struct ospf6_area *oa);
|
||||
extern void ospf6_abr_examin_brouter (u_int32_t router_id);
|
||||
extern void ospf6_abr_reimport (struct ospf6_area *oa);
|
||||
extern void ospf6_abr_range_update (struct ospf6_route *range);
|
||||
|
||||
extern int config_write_ospf6_debug_abr (struct vty *vty);
|
||||
extern void install_element_ospf6_debug_abr (void);
|
||||
|
||||
@ -160,6 +160,7 @@ ospf6_area_create (u_int32_t area_id, struct ospf6 *o)
|
||||
|
||||
oa->range_table = OSPF6_ROUTE_TABLE_CREATE (AREA, PREFIX_RANGES);
|
||||
oa->range_table->scope = oa;
|
||||
bf_init(oa->range_table->idspace, 32);
|
||||
oa->summary_prefix = OSPF6_ROUTE_TABLE_CREATE (AREA, SUMMARY_PREFIXES);
|
||||
oa->summary_prefix->scope = oa;
|
||||
oa->summary_router = OSPF6_ROUTE_TABLE_CREATE (AREA, SUMMARY_ROUTERS);
|
||||
@ -182,6 +183,11 @@ ospf6_area_create (u_int32_t area_id, struct ospf6 *o)
|
||||
oa->ospf6 = o;
|
||||
listnode_add_sort (o->area_list, oa);
|
||||
|
||||
if (area_id == OSPF_AREA_BACKBONE)
|
||||
{
|
||||
o->backbone = oa;
|
||||
}
|
||||
|
||||
/* import athoer area's routes as inter-area routes */
|
||||
for (route = ospf6_route_head (o->route_table); route;
|
||||
route = ospf6_route_next (route))
|
||||
@ -196,10 +202,6 @@ ospf6_area_delete (struct ospf6_area *oa)
|
||||
struct listnode *n;
|
||||
struct ospf6_interface *oi;
|
||||
|
||||
ospf6_route_table_delete (oa->range_table);
|
||||
ospf6_route_table_delete (oa->summary_prefix);
|
||||
ospf6_route_table_delete (oa->summary_router);
|
||||
|
||||
/* The ospf6_interface structs store configuration
|
||||
* information which should not be lost/reset when
|
||||
* deleting an area.
|
||||
@ -217,8 +219,9 @@ ospf6_area_delete (struct ospf6_area *oa)
|
||||
ospf6_route_table_delete (oa->spf_table);
|
||||
ospf6_route_table_delete (oa->route_table);
|
||||
|
||||
THREAD_OFF (oa->thread_spf_calculation);
|
||||
THREAD_OFF (oa->thread_route_calculation);
|
||||
ospf6_route_table_delete (oa->range_table);
|
||||
ospf6_route_table_delete (oa->summary_prefix);
|
||||
ospf6_route_table_delete (oa->summary_router);
|
||||
|
||||
listnode_delete (oa->ospf6->area_list, oa);
|
||||
oa->ospf6 = NULL;
|
||||
@ -281,9 +284,6 @@ ospf6_area_disable (struct ospf6_area *oa)
|
||||
ospf6_spf_table_finish(oa->spf_table);
|
||||
ospf6_route_remove_all(oa->route_table);
|
||||
|
||||
THREAD_OFF (oa->thread_spf_calculation);
|
||||
THREAD_OFF (oa->thread_route_calculation);
|
||||
|
||||
THREAD_OFF (oa->thread_router_lsa);
|
||||
THREAD_OFF (oa->thread_intra_prefix_lsa);
|
||||
}
|
||||
@ -346,20 +346,17 @@ DEFUN (area_range,
|
||||
int ret;
|
||||
struct ospf6_area *oa;
|
||||
struct prefix prefix;
|
||||
struct ospf6_route *range;
|
||||
struct ospf6_route *range, *route;
|
||||
u_int32_t cost = OSPF_AREA_RANGE_COST_UNSPEC;
|
||||
|
||||
OSPF6_CMD_AREA_GET (argv[0], oa);
|
||||
argc--;
|
||||
argv++;
|
||||
|
||||
ret = str2prefix (argv[0], &prefix);
|
||||
ret = str2prefix (argv[1], &prefix);
|
||||
if (ret != 1 || prefix.family != AF_INET6)
|
||||
{
|
||||
vty_out (vty, "Malformed argument: %s%s", argv[0], VNL);
|
||||
vty_out (vty, "Malformed argument: %s%s", argv[1], VNL);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
argc--;
|
||||
argv++;
|
||||
|
||||
range = ospf6_route_lookup (&prefix, oa->range_table);
|
||||
if (range == NULL)
|
||||
@ -367,23 +364,45 @@ DEFUN (area_range,
|
||||
range = ospf6_route_create ();
|
||||
range->type = OSPF6_DEST_TYPE_RANGE;
|
||||
range->prefix = prefix;
|
||||
range->path.area_id = oa->area_id;
|
||||
range->path.cost = OSPF_AREA_RANGE_COST_UNSPEC;
|
||||
range->linkstate_id =
|
||||
(u_int32_t) htonl(ospf6_new_range_ls_id (oa->range_table));
|
||||
}
|
||||
|
||||
if (argc)
|
||||
if (argc > 2)
|
||||
{
|
||||
if (! strcmp (argv[0], "not-advertise"))
|
||||
SET_FLAG (range->flag, OSPF6_ROUTE_DO_NOT_ADVERTISE);
|
||||
else if (! strcmp (argv[0], "advertise"))
|
||||
UNSET_FLAG (range->flag, OSPF6_ROUTE_DO_NOT_ADVERTISE);
|
||||
if (strcmp (argv[2], "not-advertise") == 0)
|
||||
{
|
||||
SET_FLAG (range->flag, OSPF6_ROUTE_DO_NOT_ADVERTISE);
|
||||
}
|
||||
else if (strcmp (argv[2], "advertise") == 0)
|
||||
{
|
||||
UNSET_FLAG (range->flag, OSPF6_ROUTE_DO_NOT_ADVERTISE);
|
||||
}
|
||||
else
|
||||
{
|
||||
VTY_GET_INTEGER_RANGE ("cost", cost, argv[2], 0, OSPF_LS_INFINITY);
|
||||
UNSET_FLAG (range->flag, OSPF6_ROUTE_DO_NOT_ADVERTISE);
|
||||
}
|
||||
}
|
||||
|
||||
if (range->rnode)
|
||||
range->path.u.cost_config = cost;
|
||||
|
||||
zlog_debug ("%s: for prefix %s, flag = %x\n", __func__, argv[1], range->flag);
|
||||
if (range->rnode == NULL)
|
||||
{
|
||||
vty_out (vty, "Range already defined: %s%s", argv[-1], VNL);
|
||||
return CMD_WARNING;
|
||||
ospf6_route_add (range, oa->range_table);
|
||||
}
|
||||
|
||||
if (ospf6_is_router_abr (ospf6))
|
||||
{
|
||||
/* Redo summaries if required */
|
||||
for (route = ospf6_route_head (ospf6->route_table); route;
|
||||
route = ospf6_route_next (route))
|
||||
ospf6_abr_originate_summary(route);
|
||||
}
|
||||
|
||||
ospf6_route_add (range, oa->range_table);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
@ -396,6 +415,26 @@ ALIAS (area_range,
|
||||
"Specify IPv6 prefix\n"
|
||||
)
|
||||
|
||||
ALIAS (area_range,
|
||||
area_range_cost_cmd,
|
||||
"area (A.B.C.D|<0-4294967295>) range X:X::X:X/M cost <0-16777215>",
|
||||
"OSPF area parameters\n"
|
||||
OSPF6_AREA_ID_STR
|
||||
"Summarize routes matching address/mask (border routers only)\n"
|
||||
"Area range prefix\n"
|
||||
"User specified metric for this range\n"
|
||||
"Advertised metric for this range\n")
|
||||
|
||||
ALIAS (area_range,
|
||||
area_range_advertise_cost_cmd,
|
||||
"area (A.B.C.D|<0-4294967295>) range X:X::X:X/M advertise cost <0-16777215>",
|
||||
"OSPF area parameters\n"
|
||||
OSPF6_AREA_ID_STR
|
||||
"Summarize routes matching address/mask (border routers only)\n"
|
||||
"Area range prefix\n"
|
||||
"User specified metric for this range\n"
|
||||
"Advertised metric for this range\n")
|
||||
|
||||
DEFUN (no_area_range,
|
||||
no_area_range_cmd,
|
||||
"no area A.B.C.D range X:X::X:X/M",
|
||||
@ -408,7 +447,7 @@ DEFUN (no_area_range,
|
||||
int ret;
|
||||
struct ospf6_area *oa;
|
||||
struct prefix prefix;
|
||||
struct ospf6_route *range;
|
||||
struct ospf6_route *range, *route;
|
||||
|
||||
OSPF6_CMD_AREA_GET (argv[0], oa);
|
||||
argc--;
|
||||
@ -428,6 +467,21 @@ DEFUN (no_area_range,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
if (ospf6_is_router_abr(oa->ospf6))
|
||||
{
|
||||
/* Blow away the aggregated LSA and route */
|
||||
SET_FLAG (range->flag, OSPF6_ROUTE_REMOVE);
|
||||
|
||||
/* Redo summaries if required */
|
||||
for (route = ospf6_route_head (ospf6->route_table); route;
|
||||
route = ospf6_route_next (route))
|
||||
ospf6_abr_originate_summary(route);
|
||||
|
||||
/* purge the old aggregated summary LSA */
|
||||
ospf6_abr_originate_summary(range);
|
||||
}
|
||||
ospf6_release_range_ls_id(oa->range_table,
|
||||
(u_int32_t) ntohl(range->linkstate_id));
|
||||
ospf6_route_remove (range, oa->range_table);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
@ -801,6 +855,8 @@ ospf6_area_init (void)
|
||||
|
||||
install_element (OSPF6_NODE, &area_range_cmd);
|
||||
install_element (OSPF6_NODE, &area_range_advertise_cmd);
|
||||
install_element (OSPF6_NODE, &area_range_cost_cmd);
|
||||
install_element (OSPF6_NODE, &area_range_advertise_cost_cmd);
|
||||
install_element (OSPF6_NODE, &no_area_range_cmd);
|
||||
|
||||
install_element (OSPF6_NODE, &area_import_list_cmd);
|
||||
|
||||
@ -55,8 +55,6 @@ struct ospf6_area
|
||||
struct ospf6_route_table *spf_table;
|
||||
struct ospf6_route_table *route_table;
|
||||
|
||||
struct thread *thread_spf_calculation;
|
||||
struct thread *thread_route_calculation;
|
||||
u_int32_t spf_calculation; /* SPF calculation count */
|
||||
|
||||
struct thread *thread_router_lsa;
|
||||
@ -98,6 +96,8 @@ struct ospf6_area
|
||||
#define PREFIX_NAME_OUT(A) (A)->plist_out.name
|
||||
#define PREFIX_LIST_OUT(A) (A)->plist_out.list
|
||||
|
||||
/* Time stamps. */
|
||||
struct timeval ts_spf; /* SPF calculation time stamp. */
|
||||
};
|
||||
|
||||
#define OSPF6_AREA_ENABLE 0x01
|
||||
|
||||
@ -159,7 +159,6 @@ ospf6_asbr_lsa_add (struct ospf6_lsa *lsa)
|
||||
struct prefix asbr_id;
|
||||
struct ospf6_route *asbr_entry, *route;
|
||||
char buf[64];
|
||||
int i;
|
||||
|
||||
external = (struct ospf6_as_external_lsa *)
|
||||
OSPF6_LSA_HEADER_END (lsa->header);
|
||||
@ -218,18 +217,17 @@ ospf6_asbr_lsa_add (struct ospf6_lsa *lsa)
|
||||
route->path.type = OSPF6_PATH_TYPE_EXTERNAL2;
|
||||
route->path.metric_type = 2;
|
||||
route->path.cost = asbr_entry->path.cost;
|
||||
route->path.cost_e2 = OSPF6_ASBR_METRIC (external);
|
||||
route->path.u.cost_e2 = OSPF6_ASBR_METRIC (external);
|
||||
}
|
||||
else
|
||||
{
|
||||
route->path.type = OSPF6_PATH_TYPE_EXTERNAL1;
|
||||
route->path.metric_type = 1;
|
||||
route->path.cost = asbr_entry->path.cost + OSPF6_ASBR_METRIC (external);
|
||||
route->path.cost_e2 = 0;
|
||||
route->path.u.cost_e2 = 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < OSPF6_MULTI_PATH_LIMIT; i++)
|
||||
ospf6_nexthop_copy (&route->nexthop[i], &asbr_entry->nexthop[i]);
|
||||
ospf6_route_copy_nexthops (route, asbr_entry);
|
||||
|
||||
if (IS_OSPF6_DEBUG_EXAMIN (AS_EXTERNAL))
|
||||
{
|
||||
@ -408,8 +406,7 @@ ospf6_asbr_redistribute_unset (int type)
|
||||
if (info->type != type)
|
||||
continue;
|
||||
|
||||
ospf6_asbr_redistribute_remove (info->type, route->nexthop[0].ifindex,
|
||||
&route->prefix);
|
||||
ospf6_asbr_redistribute_remove (info->type, 0, &route->prefix);
|
||||
}
|
||||
|
||||
ospf6_asbr_routemap_unset (type);
|
||||
@ -488,9 +485,11 @@ ospf6_asbr_redistribute_add (int type, int ifindex, struct prefix *prefix,
|
||||
}
|
||||
|
||||
info->type = type;
|
||||
match->nexthop[0].ifindex = ifindex;
|
||||
|
||||
if (nexthop_num && nexthop)
|
||||
memcpy (&match->nexthop[0].address, nexthop, sizeof (struct in6_addr));
|
||||
ospf6_route_add_nexthop (match, ifindex, nexthop);
|
||||
else
|
||||
ospf6_route_add_nexthop (match, ifindex, NULL);
|
||||
|
||||
/* create/update binding in external_id_table */
|
||||
prefix_id.family = AF_INET;
|
||||
@ -533,9 +532,10 @@ ospf6_asbr_redistribute_add (int type, int ifindex, struct prefix *prefix,
|
||||
}
|
||||
|
||||
info->type = type;
|
||||
route->nexthop[0].ifindex = ifindex;
|
||||
if (nexthop_num && nexthop)
|
||||
memcpy (&route->nexthop[0].address, nexthop, sizeof (struct in6_addr));
|
||||
ospf6_route_add_nexthop (route, ifindex, nexthop);
|
||||
else
|
||||
ospf6_route_add_nexthop (route, ifindex, NULL);
|
||||
|
||||
/* create/update binding in external_id_table */
|
||||
prefix_id.family = AF_INET;
|
||||
@ -1274,13 +1274,13 @@ ospf6_asbr_external_route_show (struct vty *vty, struct ospf6_route *route)
|
||||
inet_ntop (AF_INET6, &info->forwarding, forwarding, sizeof (forwarding));
|
||||
else
|
||||
snprintf (forwarding, sizeof (forwarding), ":: (ifindex %d)",
|
||||
route->nexthop[0].ifindex);
|
||||
ospf6_route_get_first_nh_index (route));
|
||||
|
||||
vty_out (vty, "%c %-32s %-15s type-%d %5lu %s%s",
|
||||
zebra_route_char(info->type),
|
||||
prefix, id, route->path.metric_type,
|
||||
(u_long) (route->path.metric_type == 2 ?
|
||||
route->path.cost_e2 : route->path.cost),
|
||||
route->path.u.cost_e2 : route->path.cost),
|
||||
forwarding, VNL);
|
||||
}
|
||||
|
||||
|
||||
@ -892,6 +892,9 @@ ospf6_receive_lsa (struct ospf6_neighbor *from,
|
||||
table calculation (replacing database copy) */
|
||||
ospf6_install_lsa (new);
|
||||
|
||||
if (OSPF6_LSA_IS_MAXAGE (new))
|
||||
ospf6_maxage_remove (from->ospf6_if->area->ospf6);
|
||||
|
||||
/* (e) possibly acknowledge */
|
||||
ospf6_acknowledge_lsa (new, ismore_recent, from);
|
||||
|
||||
|
||||
@ -391,6 +391,7 @@ ospf6_interface_connected_route_update (struct interface *ifp)
|
||||
struct ospf6_route *route;
|
||||
struct connected *c;
|
||||
struct listnode *node, *nnode;
|
||||
struct in6_addr nh_addr;
|
||||
|
||||
oi = (struct ospf6_interface *) ifp->info;
|
||||
if (oi == NULL)
|
||||
@ -446,8 +447,8 @@ ospf6_interface_connected_route_update (struct interface *ifp)
|
||||
route->path.area_id = oi->area->area_id;
|
||||
route->path.type = OSPF6_PATH_TYPE_INTRA;
|
||||
route->path.cost = oi->cost;
|
||||
route->nexthop[0].ifindex = oi->interface->ifindex;
|
||||
inet_pton (AF_INET6, "::1", &route->nexthop[0].address);
|
||||
inet_pton (AF_INET6, "::1", &nh_addr);
|
||||
ospf6_route_add_nexthop (route, oi->interface->ifindex, &nh_addr);
|
||||
ospf6_route_add (route, oi->route_connected);
|
||||
}
|
||||
|
||||
|
||||
@ -228,7 +228,7 @@ ospf6_router_lsa_originate (struct thread *thread)
|
||||
for (ALL_LIST_ELEMENTS_RO (oi->neighbor_list, j, on))
|
||||
if (on->state == OSPF6_NEIGHBOR_FULL)
|
||||
count++;
|
||||
|
||||
|
||||
if (count == 0)
|
||||
continue;
|
||||
|
||||
@ -355,14 +355,25 @@ ospf6_router_lsa_originate (struct thread *thread)
|
||||
/* Do premature-aging of rest, undesired Router-LSAs */
|
||||
type = ntohs (OSPF6_LSTYPE_ROUTER);
|
||||
router = oa->ospf6->router_id;
|
||||
count = 0;
|
||||
for (lsa = ospf6_lsdb_type_router_head (type, router, oa->lsdb); lsa;
|
||||
lsa = ospf6_lsdb_type_router_next (type, router, lsa))
|
||||
{
|
||||
if (ntohl (lsa->header->id) < link_state_id)
|
||||
continue;
|
||||
ospf6_lsa_purge (lsa);
|
||||
count++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Waiting till the LSA is actually removed from the database to trigger
|
||||
* SPF delays network convergence. Unlike IPv4, for an ABR, when all
|
||||
* interfaces associated with an area are gone, triggering an SPF right away
|
||||
* helps convergence with inter-area routes.
|
||||
*/
|
||||
if (count && !link_state_id)
|
||||
ospf6_spf_schedule (oa->ospf6, OSPF6_SPF_FLAGS_ROUTER_LSA_ORIGINATED);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -459,7 +470,15 @@ ospf6_network_lsa_originate (struct thread *thread)
|
||||
if (oi->state != OSPF6_INTERFACE_DR)
|
||||
{
|
||||
if (old)
|
||||
ospf6_lsa_purge (old);
|
||||
{
|
||||
ospf6_lsa_purge (old);
|
||||
/*
|
||||
* Waiting till the LSA is actually removed from the database to
|
||||
* trigger SPF delays network convergence.
|
||||
*/
|
||||
ospf6_spf_schedule (oi->area->ospf6,
|
||||
OSPF6_SPF_FLAGS_NETWORK_LSA_ORIGINATED);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -468,11 +487,11 @@ ospf6_network_lsa_originate (struct thread *thread)
|
||||
|
||||
/* If none of neighbor is adjacent to us */
|
||||
count = 0;
|
||||
|
||||
|
||||
for (ALL_LIST_ELEMENTS_RO (oi->neighbor_list, i, on))
|
||||
if (on->state == OSPF6_NEIGHBOR_FULL)
|
||||
count++;
|
||||
|
||||
|
||||
if (count == 0)
|
||||
{
|
||||
if (IS_OSPF6_DEBUG_ORIGINATE (NETWORK))
|
||||
@ -1078,7 +1097,7 @@ ospf6_intra_prefix_lsa_originate_transit (struct thread *thread)
|
||||
for (ALL_LIST_ELEMENTS_RO (oi->neighbor_list, i, on))
|
||||
if (on->state == OSPF6_NEIGHBOR_FULL)
|
||||
full_count++;
|
||||
|
||||
|
||||
if (full_count == 0)
|
||||
{
|
||||
if (IS_OSPF6_DEBUG_ORIGINATE (INTRA_PREFIX))
|
||||
@ -1214,7 +1233,7 @@ ospf6_intra_prefix_lsa_add (struct ospf6_lsa *lsa)
|
||||
struct ospf6_intra_prefix_lsa *intra_prefix_lsa;
|
||||
struct prefix ls_prefix;
|
||||
struct ospf6_route *route, *ls_entry;
|
||||
int i, prefix_num;
|
||||
int prefix_num;
|
||||
struct ospf6_prefix *op;
|
||||
char *start, *current, *end;
|
||||
char buf[64];
|
||||
@ -1310,13 +1329,11 @@ ospf6_intra_prefix_lsa_add (struct ospf6_lsa *lsa)
|
||||
{
|
||||
ifp = if_lookup_prefix(&route->prefix);
|
||||
if (ifp)
|
||||
route->nexthop[0].ifindex = ifp->ifindex;
|
||||
ospf6_route_add_nexthop (route, ifp->ifindex, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; ospf6_nexthop_is_set (&ls_entry->nexthop[i]) &&
|
||||
i < OSPF6_MULTI_PATH_LIMIT; i++)
|
||||
ospf6_nexthop_copy (&route->nexthop[i], &ls_entry->nexthop[i]);
|
||||
ospf6_route_copy_nexthops (route, ls_entry);
|
||||
}
|
||||
|
||||
if (IS_OSPF6_DEBUG_EXAMIN (INTRA_PREFIX))
|
||||
@ -1509,7 +1526,7 @@ ospf6_brouter_debug_print (struct ospf6_route *brouter)
|
||||
id, adv_router);
|
||||
zlog_info (" options: %s router-bits: %s metric-type: %d metric: %d/%d",
|
||||
options, capa, brouter->path.metric_type,
|
||||
brouter->path.cost, brouter->path.cost_e2);
|
||||
brouter->path.cost, brouter->path.u.cost_e2);
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@ -31,7 +31,9 @@
|
||||
#include "ospf6_proto.h"
|
||||
#include "ospf6_lsa.h"
|
||||
#include "ospf6_lsdb.h"
|
||||
#include "ospf6_route.h"
|
||||
#include "ospf6d.h"
|
||||
#include "bitfield.h"
|
||||
|
||||
struct ospf6_lsdb *
|
||||
ospf6_lsdb_create (void *data)
|
||||
@ -538,21 +540,42 @@ ospf6_lsdb_show (struct vty *vty, int level,
|
||||
}
|
||||
}
|
||||
|
||||
/* Decide new Link State ID to originate.
|
||||
note return value is network byte order */
|
||||
/* Decide new Link State ID to originate for the range. */
|
||||
u_int32_t
|
||||
ospf6_new_range_ls_id (struct ospf6_route_table *range_table)
|
||||
{
|
||||
u_int32_t id;
|
||||
|
||||
bf_assign_index(range_table->idspace, id);
|
||||
return (id);
|
||||
}
|
||||
|
||||
/* Release the LS ID back to the ID pool */
|
||||
void
|
||||
ospf6_release_range_ls_id (struct ospf6_route_table *range_table,
|
||||
u_int32_t id)
|
||||
{
|
||||
bf_release_index(range_table->idspace, id);
|
||||
}
|
||||
|
||||
u_int32_t
|
||||
ospf6_new_ls_id (u_int16_t type, u_int32_t adv_router,
|
||||
struct ospf6_lsdb *lsdb)
|
||||
{
|
||||
struct ospf6_lsa *lsa;
|
||||
u_int32_t id = 1;
|
||||
u_int32_t id = 1, tmp_id;
|
||||
|
||||
/* This routine is curently invoked only for Inter-Prefix LSAs for
|
||||
* non-summarized routes (no area/range).
|
||||
*/
|
||||
for (lsa = ospf6_lsdb_type_router_head (type, adv_router, lsdb); lsa;
|
||||
lsa = ospf6_lsdb_type_router_next (type, adv_router, lsa))
|
||||
{
|
||||
if (ntohl (lsa->header->id) < id)
|
||||
continue;
|
||||
if (ntohl (lsa->header->id) > id)
|
||||
tmp_id = ntohl (lsa->header->id);
|
||||
if (tmp_id < id)
|
||||
continue;
|
||||
|
||||
if (tmp_id > id)
|
||||
{
|
||||
ospf6_lsdb_lsa_unlock (lsa);
|
||||
break;
|
||||
|
||||
@ -24,6 +24,7 @@
|
||||
|
||||
#include "prefix.h"
|
||||
#include "table.h"
|
||||
#include "ospf6_route.h"
|
||||
|
||||
struct ospf6_lsdb
|
||||
{
|
||||
@ -77,6 +78,9 @@ extern void ospf6_lsdb_show (struct vty *vty, int level, u_int16_t *type,
|
||||
|
||||
extern u_int32_t ospf6_new_ls_id (u_int16_t type, u_int32_t adv_router,
|
||||
struct ospf6_lsdb *lsdb);
|
||||
extern u_int32_t ospf6_new_range_ls_id (struct ospf6_route_table *range_table);
|
||||
extern void ospf6_release_range_ls_id (struct ospf6_route_table *range_table,
|
||||
u_int32_t id);
|
||||
extern u_int32_t ospf6_new_ls_seqnum (u_int16_t type, u_int32_t id,
|
||||
u_int32_t adv_router,
|
||||
struct ospf6_lsdb *lsdb);
|
||||
|
||||
@ -21,6 +21,7 @@
|
||||
|
||||
#include <zebra.h>
|
||||
#include <lib/version.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "getopt.h"
|
||||
#include "thread.h"
|
||||
@ -237,6 +238,9 @@ main (int argc, char *argv[], char *envp[])
|
||||
/* Preserve name of myself. */
|
||||
progname = ((p = strrchr (argv[0], '/')) ? ++p : argv[0]);
|
||||
|
||||
/* Seed random number for LSA ID */
|
||||
srand (time(NULL));
|
||||
|
||||
/* Command line argument treatment. */
|
||||
while (1)
|
||||
{
|
||||
|
||||
@ -37,6 +37,7 @@
|
||||
#include "ospf6_area.h"
|
||||
#include "ospf6_interface.h"
|
||||
#include "ospf6d.h"
|
||||
#include "ospf6_zebra.h"
|
||||
|
||||
unsigned char conf_debug_ospf6_route = 0;
|
||||
|
||||
@ -173,18 +174,232 @@ const char *ospf6_path_type_substr[OSPF6_PATH_TYPE_MAX] =
|
||||
{ "??", "IA", "IE", "E1", "E2", };
|
||||
|
||||
|
||||
struct ospf6_nexthop *
|
||||
ospf6_nexthop_create (void)
|
||||
{
|
||||
struct ospf6_nexthop *nh;
|
||||
|
||||
nh = XCALLOC (MTYPE_OSPF6_NEXTHOP, sizeof (struct ospf6_nexthop));
|
||||
return nh;
|
||||
}
|
||||
|
||||
void
|
||||
ospf6_nexthop_delete (struct ospf6_nexthop *nh)
|
||||
{
|
||||
if (nh)
|
||||
XFREE (MTYPE_OSPF6_NEXTHOP, nh);
|
||||
}
|
||||
|
||||
void
|
||||
ospf6_free_nexthops (struct list *nh_list)
|
||||
{
|
||||
struct ospf6_nexthop *nh;
|
||||
struct listnode *node, *nnode;
|
||||
|
||||
if (nh_list)
|
||||
{
|
||||
for (ALL_LIST_ELEMENTS (nh_list, node, nnode, nh))
|
||||
ospf6_nexthop_delete (nh);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ospf6_clear_nexthops (struct list *nh_list)
|
||||
{
|
||||
struct listnode *node;
|
||||
struct ospf6_nexthop *nh;
|
||||
|
||||
if (nh_list)
|
||||
{
|
||||
for (ALL_LIST_ELEMENTS_RO (nh_list, node, nh))
|
||||
ospf6_nexthop_clear (nh);
|
||||
}
|
||||
}
|
||||
|
||||
static struct ospf6_nexthop *
|
||||
ospf6_route_find_nexthop (struct list *nh_list, struct ospf6_nexthop *nh_match)
|
||||
{
|
||||
struct listnode *node;
|
||||
struct ospf6_nexthop *nh;
|
||||
|
||||
if (nh_list && nh_match)
|
||||
{
|
||||
for (ALL_LIST_ELEMENTS_RO (nh_list, node, nh))
|
||||
{
|
||||
if (ospf6_nexthop_is_same (nh, nh_match))
|
||||
return (nh);
|
||||
}
|
||||
}
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
void
|
||||
ospf6_copy_nexthops (struct list *dst, struct list *src)
|
||||
{
|
||||
struct ospf6_nexthop *nh_new, *nh;
|
||||
struct listnode *node;
|
||||
|
||||
if (dst && src)
|
||||
{
|
||||
for (ALL_LIST_ELEMENTS_RO (src, node, nh))
|
||||
{
|
||||
if (ospf6_nexthop_is_set (nh))
|
||||
{
|
||||
nh_new = ospf6_nexthop_create ();
|
||||
ospf6_nexthop_copy (nh_new, nh);
|
||||
listnode_add (dst, nh_new);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ospf6_merge_nexthops (struct list *dst, struct list *src)
|
||||
{
|
||||
struct listnode *node;
|
||||
struct ospf6_nexthop *nh, *nh_new;
|
||||
|
||||
if (src && dst)
|
||||
{
|
||||
for (ALL_LIST_ELEMENTS_RO (src, node, nh))
|
||||
{
|
||||
if (!ospf6_route_find_nexthop (dst, nh))
|
||||
{
|
||||
nh_new = ospf6_nexthop_create ();
|
||||
ospf6_nexthop_copy (nh_new, nh);
|
||||
listnode_add (dst, nh_new);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
ospf6_route_cmp_nexthops (struct ospf6_route *a, struct ospf6_route *b)
|
||||
{
|
||||
struct listnode *anode, *bnode;
|
||||
struct ospf6_nexthop *anh, *bnh;
|
||||
|
||||
if (a && b)
|
||||
{
|
||||
if (listcount(a->nh_list) == listcount(b->nh_list))
|
||||
{
|
||||
for (ALL_LIST_ELEMENTS_RO (a->nh_list, anode, anh))
|
||||
{
|
||||
for (ALL_LIST_ELEMENTS_RO (b->nh_list, bnode, bnh))
|
||||
if (!ospf6_nexthop_is_same (anh, bnh))
|
||||
return (1);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
else
|
||||
return (1);
|
||||
}
|
||||
/* One of the routes doesn't exist ? */
|
||||
return (1);
|
||||
}
|
||||
|
||||
int
|
||||
ospf6_num_nexthops (struct list *nh_list)
|
||||
{
|
||||
return (listcount(nh_list));
|
||||
}
|
||||
|
||||
void
|
||||
ospf6_add_nexthop (struct list *nh_list, int ifindex,
|
||||
struct in6_addr *addr)
|
||||
{
|
||||
struct ospf6_nexthop *nh;
|
||||
struct ospf6_nexthop nh_match;
|
||||
|
||||
if (nh_list)
|
||||
{
|
||||
nh_match.ifindex = ifindex;
|
||||
if (addr != NULL)
|
||||
memcpy (&nh_match.address, addr, sizeof (struct in6_addr));
|
||||
else
|
||||
memset (&nh_match.address, 0, sizeof (struct in6_addr));
|
||||
|
||||
if (!ospf6_route_find_nexthop (nh_list, &nh_match))
|
||||
{
|
||||
nh = ospf6_nexthop_create();
|
||||
ospf6_nexthop_copy (nh, &nh_match);
|
||||
listnode_add (nh_list, nh);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ospf6_route_zebra_copy_nexthops (struct ospf6_route *route,
|
||||
unsigned int *ifindexes,
|
||||
struct in6_addr **nexthop_addr,
|
||||
int entries)
|
||||
{
|
||||
struct ospf6_nexthop *nh;
|
||||
struct listnode *node;
|
||||
char buf[64];
|
||||
int i;
|
||||
|
||||
if (route)
|
||||
{
|
||||
i = 0;
|
||||
for (ALL_LIST_ELEMENTS_RO (route->nh_list, node, nh))
|
||||
{
|
||||
if (IS_OSPF6_DEBUG_ZEBRA (SEND))
|
||||
{
|
||||
char ifname[IFNAMSIZ];
|
||||
inet_ntop (AF_INET6, &nh->address, buf, sizeof (buf));
|
||||
if (!if_indextoname(nh->ifindex, ifname))
|
||||
strlcpy(ifname, "unknown", sizeof(ifname));
|
||||
zlog_debug (" nexthop: %s%%%.*s(%d)", buf, IFNAMSIZ, ifname,
|
||||
nh->ifindex);
|
||||
}
|
||||
if (i < entries)
|
||||
{
|
||||
nexthop_addr[i] = &nh->address;
|
||||
ifindexes[i] = nh->ifindex;
|
||||
i++;
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
ospf6_route_get_first_nh_index (struct ospf6_route *route)
|
||||
{
|
||||
struct ospf6_nexthop *nh;
|
||||
|
||||
if (route)
|
||||
{
|
||||
if (nh = (struct ospf6_nexthop *)listhead (route->nh_list))
|
||||
return (nh->ifindex);
|
||||
}
|
||||
|
||||
return (-1);
|
||||
}
|
||||
|
||||
struct ospf6_route *
|
||||
ospf6_route_create (void)
|
||||
{
|
||||
struct ospf6_route *route;
|
||||
route = XCALLOC (MTYPE_OSPF6_ROUTE, sizeof (struct ospf6_route));
|
||||
route->nh_list = list_new();
|
||||
return route;
|
||||
}
|
||||
|
||||
void
|
||||
ospf6_route_delete (struct ospf6_route *route)
|
||||
{
|
||||
XFREE (MTYPE_OSPF6_ROUTE, route);
|
||||
if (route)
|
||||
{
|
||||
ospf6_free_nexthops (route->nh_list);
|
||||
list_free (route->nh_list);
|
||||
XFREE (MTYPE_OSPF6_ROUTE, route);
|
||||
}
|
||||
}
|
||||
|
||||
struct ospf6_route *
|
||||
@ -193,7 +408,15 @@ ospf6_route_copy (struct ospf6_route *route)
|
||||
struct ospf6_route *new;
|
||||
|
||||
new = ospf6_route_create ();
|
||||
memcpy (new, route, sizeof (struct ospf6_route));
|
||||
new->type = route->type;
|
||||
memcpy (&new->prefix, &route->prefix, sizeof (struct prefix));
|
||||
new->installed = route->installed;
|
||||
new->changed = route->changed;
|
||||
new->flag = route->flag;
|
||||
new->route_option = route->route_option;
|
||||
new->linkstate_id = route->linkstate_id;
|
||||
new->path = route->path;
|
||||
ospf6_copy_nexthops (new->nh_list, route->nh_list);
|
||||
new->rnode = NULL;
|
||||
new->prev = NULL;
|
||||
new->next = NULL;
|
||||
@ -226,7 +449,7 @@ ospf6_route_unlock (struct ospf6_route *route)
|
||||
/* Route compare function. If ra is more preferred, it returns
|
||||
less than 0. If rb is more preferred returns greater than 0.
|
||||
Otherwise (neither one is preferred), returns 0 */
|
||||
static int
|
||||
int
|
||||
ospf6_route_cmp (struct ospf6_route *ra, struct ospf6_route *rb)
|
||||
{
|
||||
assert (ospf6_route_is_same (ra, rb));
|
||||
@ -246,8 +469,8 @@ ospf6_route_cmp (struct ospf6_route *ra, struct ospf6_route *rb)
|
||||
|
||||
if (ra->path.type == OSPF6_PATH_TYPE_EXTERNAL2)
|
||||
{
|
||||
if (ra->path.cost_e2 != rb->path.cost_e2)
|
||||
return (ra->path.cost_e2 - rb->path.cost_e2);
|
||||
if (ra->path.u.cost_e2 != rb->path.u.cost_e2)
|
||||
return (ra->path.u.cost_e2 - rb->path.u.cost_e2);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -789,6 +1012,8 @@ ospf6_route_show (struct vty *vty, struct ospf6_route *route)
|
||||
char destination[64], nexthop[64];
|
||||
char duration[16], ifname[IFNAMSIZ];
|
||||
struct timeval now, res;
|
||||
struct listnode *node;
|
||||
struct ospf6_nexthop *nh;
|
||||
|
||||
quagga_gettime (QUAGGA_CLK_MONOTONIC, &now);
|
||||
timersub (&now, &route->changed, &res);
|
||||
@ -804,29 +1029,28 @@ ospf6_route_show (struct vty *vty, struct ospf6_route *route)
|
||||
else
|
||||
prefix2str (&route->prefix, destination, sizeof (destination));
|
||||
|
||||
/* nexthop */
|
||||
inet_ntop (AF_INET6, &route->nexthop[0].address, nexthop,
|
||||
sizeof (nexthop));
|
||||
if (! if_indextoname (route->nexthop[0].ifindex, ifname))
|
||||
snprintf (ifname, sizeof (ifname), "%d", route->nexthop[0].ifindex);
|
||||
|
||||
vty_out (vty, "%c%1s %2s %-30s %-25s %6.*s %s%s",
|
||||
(ospf6_route_is_best (route) ? '*' : ' '),
|
||||
OSPF6_DEST_TYPE_SUBSTR (route->type),
|
||||
OSPF6_PATH_TYPE_SUBSTR (route->path.type),
|
||||
destination, nexthop, IFNAMSIZ, ifname, duration, VNL);
|
||||
|
||||
for (i = 1; ospf6_nexthop_is_set (&route->nexthop[i]) &&
|
||||
i < OSPF6_MULTI_PATH_LIMIT; i++)
|
||||
i = 0;
|
||||
for (ALL_LIST_ELEMENTS_RO (route->nh_list, node, nh))
|
||||
{
|
||||
/* nexthop */
|
||||
inet_ntop (AF_INET6, &route->nexthop[i].address, nexthop,
|
||||
inet_ntop (AF_INET6, &nh->address, nexthop,
|
||||
sizeof (nexthop));
|
||||
if (! if_indextoname (route->nexthop[i].ifindex, ifname))
|
||||
snprintf (ifname, sizeof (ifname), "%d", route->nexthop[i].ifindex);
|
||||
if (! if_indextoname (nh->ifindex, ifname))
|
||||
snprintf (ifname, sizeof (ifname), "%d", nh->ifindex);
|
||||
|
||||
vty_out (vty, "%c%1s %2s %-30s %-25s %6.*s %s%s",
|
||||
' ', "", "", "", nexthop, IFNAMSIZ, ifname, "", VNL);
|
||||
if (!i)
|
||||
{
|
||||
vty_out (vty, "%c%1s %2s %-30s %-25s %6.*s %s%s",
|
||||
(ospf6_route_is_best (route) ? '*' : ' '),
|
||||
OSPF6_DEST_TYPE_SUBSTR (route->type),
|
||||
OSPF6_PATH_TYPE_SUBSTR (route->path.type),
|
||||
destination, nexthop, IFNAMSIZ, ifname, duration, VNL);
|
||||
i++;
|
||||
}
|
||||
else
|
||||
vty_out (vty, "%c%1s %2s %-30s %-25s %6.*s %s%s",
|
||||
' ', "", "", "", nexthop, IFNAMSIZ, ifname, "", VNL);
|
||||
}
|
||||
}
|
||||
|
||||
@ -837,7 +1061,8 @@ ospf6_route_show_detail (struct vty *vty, struct ospf6_route *route)
|
||||
char area_id[16], id[16], adv_router[16], capa[16], options[16];
|
||||
struct timeval now, res;
|
||||
char duration[16];
|
||||
int i;
|
||||
struct listnode *node;
|
||||
struct ospf6_nexthop *nh;
|
||||
|
||||
quagga_gettime (QUAGGA_CLK_MONOTONIC, &now);
|
||||
|
||||
@ -909,18 +1134,16 @@ ospf6_route_show_detail (struct vty *vty, struct ospf6_route *route)
|
||||
vty_out (vty, "Metric Type: %d%s", route->path.metric_type,
|
||||
VNL);
|
||||
vty_out (vty, "Metric: %d (%d)%s",
|
||||
route->path.cost, route->path.cost_e2, VNL);
|
||||
route->path.cost, route->path.u.cost_e2, VNL);
|
||||
|
||||
/* Nexthops */
|
||||
vty_out (vty, "Nexthop:%s", VNL);
|
||||
for (i = 0; ospf6_nexthop_is_set (&route->nexthop[i]) &&
|
||||
i < OSPF6_MULTI_PATH_LIMIT; i++)
|
||||
for (ALL_LIST_ELEMENTS_RO (route->nh_list, node, nh))
|
||||
{
|
||||
/* nexthop */
|
||||
inet_ntop (AF_INET6, &route->nexthop[i].address, nexthop,
|
||||
sizeof (nexthop));
|
||||
if (! if_indextoname (route->nexthop[i].ifindex, ifname))
|
||||
snprintf (ifname, sizeof (ifname), "%d", route->nexthop[i].ifindex);
|
||||
inet_ntop (AF_INET6, &nh->address, nexthop, sizeof (nexthop));
|
||||
if (! if_indextoname (nh->ifindex, ifname))
|
||||
snprintf (ifname, sizeof (ifname), "%d", nh->ifindex);
|
||||
vty_out (vty, " %s %.*s%s", nexthop, IFNAMSIZ, ifname, VNL);
|
||||
}
|
||||
vty_out (vty, "%s", VNL);
|
||||
@ -933,7 +1156,7 @@ ospf6_route_show_table_summary (struct vty *vty,
|
||||
struct ospf6_route *route, *prev = NULL;
|
||||
int i, pathtype[OSPF6_PATH_TYPE_MAX];
|
||||
unsigned int number = 0;
|
||||
int nhinval = 0, ecmp = 0;
|
||||
int nh_count =0 , nhinval = 0, ecmp = 0;
|
||||
int alternative = 0, destination = 0;
|
||||
|
||||
for (i = 0; i < OSPF6_PATH_TYPE_MAX; i++)
|
||||
@ -946,9 +1169,10 @@ ospf6_route_show_table_summary (struct vty *vty,
|
||||
destination++;
|
||||
else
|
||||
alternative++;
|
||||
if (! ospf6_nexthop_is_set (&route->nexthop[0]))
|
||||
nh_count = ospf6_num_nexthops (route->nh_list);
|
||||
if (!nh_count)
|
||||
nhinval++;
|
||||
else if (ospf6_nexthop_is_set (&route->nexthop[1]))
|
||||
else if (nh_count > 1)
|
||||
ecmp++;
|
||||
pathtype[route->path.type]++;
|
||||
number++;
|
||||
|
||||
@ -96,7 +96,10 @@ struct ospf6_path
|
||||
/* Cost */
|
||||
u_int8_t metric_type;
|
||||
u_int32_t cost;
|
||||
u_int32_t cost_e2;
|
||||
union {
|
||||
u_int32_t cost_e2;
|
||||
u_int32_t cost_config;
|
||||
} u;
|
||||
};
|
||||
|
||||
#define OSPF6_PATH_TYPE_NONE 0
|
||||
@ -109,6 +112,7 @@ struct ospf6_path
|
||||
|
||||
#include "prefix.h"
|
||||
#include "table.h"
|
||||
#include "bitfield.h"
|
||||
|
||||
struct ospf6_route
|
||||
{
|
||||
@ -132,17 +136,18 @@ struct ospf6_route
|
||||
/* flag */
|
||||
u_char flag;
|
||||
|
||||
/* path */
|
||||
struct ospf6_path path;
|
||||
|
||||
/* nexthop */
|
||||
struct ospf6_nexthop nexthop[OSPF6_MULTI_PATH_LIMIT];
|
||||
|
||||
/* route option */
|
||||
void *route_option;
|
||||
|
||||
/* link state id for advertising */
|
||||
u_int32_t linkstate_id;
|
||||
|
||||
/* path */
|
||||
struct ospf6_path path;
|
||||
|
||||
/* nexthop */
|
||||
struct list *nh_list;
|
||||
|
||||
};
|
||||
|
||||
#define OSPF6_DEST_TYPE_NONE 0
|
||||
@ -160,6 +165,7 @@ struct ospf6_route
|
||||
#define OSPF6_ROUTE_ACTIVE_SUMMARY 0x10
|
||||
#define OSPF6_ROUTE_DO_NOT_ADVERTISE 0x20
|
||||
#define OSPF6_ROUTE_WAS_REMOVED 0x40
|
||||
#define OSPF6_ROUTE_BLACKHOLE_ADDED 0x80
|
||||
|
||||
struct ospf6_route_table
|
||||
{
|
||||
@ -172,6 +178,8 @@ struct ospf6_route_table
|
||||
|
||||
u_int32_t count;
|
||||
|
||||
bitfield_t idspace;
|
||||
|
||||
/* hooks */
|
||||
void (*hook_add) (struct ospf6_route *);
|
||||
void (*hook_change) (struct ospf6_route *);
|
||||
@ -231,8 +239,8 @@ extern const char *ospf6_path_type_substr[OSPF6_PATH_TYPE_MAX];
|
||||
((ra)->type == (rb)->type && \
|
||||
memcmp (&(ra)->prefix, &(rb)->prefix, sizeof (struct prefix)) == 0 && \
|
||||
memcmp (&(ra)->path, &(rb)->path, sizeof (struct ospf6_path)) == 0 && \
|
||||
memcmp (&(ra)->nexthop, &(rb)->nexthop, \
|
||||
sizeof (struct ospf6_nexthop) * OSPF6_MULTI_PATH_LIMIT) == 0)
|
||||
ospf6_route_cmp_nexthops (ra, rb) == 0)
|
||||
|
||||
#define ospf6_route_is_best(r) (CHECK_FLAG ((r)->flag, OSPF6_ROUTE_BEST))
|
||||
|
||||
#define ospf6_linkstate_prefix_adv_router(x) \
|
||||
@ -251,9 +259,35 @@ extern void ospf6_linkstate_prefix (u_int32_t adv_router, u_int32_t id,
|
||||
extern void ospf6_linkstate_prefix2str (struct prefix *prefix, char *buf,
|
||||
int size);
|
||||
|
||||
extern struct ospf6_nexthop *ospf6_nexthop_create (void);
|
||||
extern void ospf6_nexthop_delete (struct ospf6_nexthop *nh);
|
||||
extern void ospf6_free_nexthops (struct list *nh_list);
|
||||
extern void ospf6_clear_nexthops (struct list *nh_list);
|
||||
extern int ospf6_num_nexthops (struct list *nh_list);
|
||||
extern void ospf6_copy_nexthops (struct list *dst, struct list *src);
|
||||
extern void ospf6_merge_nexthops (struct list *dst, struct list *src);
|
||||
extern void ospf6_add_nexthop (struct list *nh_list, int ifindex,
|
||||
struct in6_addr *addr);
|
||||
extern int ospf6_num_nexthops (struct list *nh_list);
|
||||
extern int ospf6_route_cmp_nexthops (struct ospf6_route *a,
|
||||
struct ospf6_route *b);
|
||||
extern void ospf6_route_zebra_copy_nexthops (struct ospf6_route *route,
|
||||
unsigned int *ifindices,
|
||||
struct in6_addr **addr,
|
||||
int entries);
|
||||
extern int ospf6_route_get_first_nh_index (struct ospf6_route *route);
|
||||
|
||||
/* Hide abstraction of nexthop implementation in route from outsiders */
|
||||
#define ospf6_route_copy_nexthops(dst, src) ospf6_copy_nexthops(dst->nh_list, src->nh_list)
|
||||
#define ospf6_route_merge_nexthops(dst, src) ospf6_merge_nexthops(dst->nh_list, src->nh_list)
|
||||
#define ospf6_route_num_nexthops(route) ospf6_num_nexthops(route->nh_list)
|
||||
#define ospf6_route_add_nexthop(route, ifindex, addr) \
|
||||
ospf6_add_nexthop(route->nh_list, ifindex, addr)
|
||||
|
||||
extern struct ospf6_route *ospf6_route_create (void);
|
||||
extern void ospf6_route_delete (struct ospf6_route *);
|
||||
extern struct ospf6_route *ospf6_route_copy (struct ospf6_route *route);
|
||||
extern int ospf6_route_cmp (struct ospf6_route *ra, struct ospf6_route *rb);
|
||||
|
||||
extern void ospf6_route_lock (struct ospf6_route *route);
|
||||
extern void ospf6_route_unlock (struct ospf6_route *route);
|
||||
|
||||
@ -43,6 +43,41 @@
|
||||
|
||||
unsigned char conf_debug_ospf6_spf = 0;
|
||||
|
||||
static void
|
||||
ospf6_spf_copy_nexthops_to_route (struct ospf6_route *rt,
|
||||
struct ospf6_vertex *v)
|
||||
{
|
||||
if (rt && v)
|
||||
ospf6_copy_nexthops (rt->nh_list, v->nh_list);
|
||||
}
|
||||
|
||||
static void
|
||||
ospf6_spf_merge_nexthops_to_route (struct ospf6_route *rt,
|
||||
struct ospf6_vertex *v)
|
||||
{
|
||||
if (rt && v)
|
||||
ospf6_merge_nexthops (rt->nh_list, v->nh_list);
|
||||
}
|
||||
|
||||
static int
|
||||
ospf6_spf_get_ifindex_from_nh (struct ospf6_vertex *v)
|
||||
{
|
||||
struct ospf6_nexthop *nh;
|
||||
struct listnode *node;
|
||||
|
||||
if (v)
|
||||
{
|
||||
node = listhead(v->nh_list);
|
||||
if (node)
|
||||
{
|
||||
nh = listgetdata (node);
|
||||
if (nh)
|
||||
return (nh->ifindex);
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
ospf6_vertex_cmp (void *a, void *b)
|
||||
{
|
||||
@ -76,7 +111,6 @@ static struct ospf6_vertex *
|
||||
ospf6_vertex_create (struct ospf6_lsa *lsa)
|
||||
{
|
||||
struct ospf6_vertex *v;
|
||||
int i;
|
||||
|
||||
v = (struct ospf6_vertex *)
|
||||
XMALLOC (MTYPE_OSPF6_VERTEX, sizeof (struct ospf6_vertex));
|
||||
@ -96,6 +130,10 @@ ospf6_vertex_create (struct ospf6_lsa *lsa)
|
||||
/* name */
|
||||
ospf6_linkstate_prefix2str (&v->vertex_id, v->name, sizeof (v->name));
|
||||
|
||||
if (IS_OSPF6_DEBUG_SPF (PROCESS))
|
||||
zlog_debug ("%s: Creating vertex %s of type %s", __func__, v->name,
|
||||
((ntohs (lsa->header->type) == OSPF6_LSTYPE_ROUTER) ? "Router" : "N/W"));
|
||||
|
||||
/* Associated LSA */
|
||||
v->lsa = lsa;
|
||||
|
||||
@ -105,8 +143,7 @@ ospf6_vertex_create (struct ospf6_lsa *lsa)
|
||||
v->options[1] = *(u_char *)(OSPF6_LSA_HEADER_END (lsa->header) + 2);
|
||||
v->options[2] = *(u_char *)(OSPF6_LSA_HEADER_END (lsa->header) + 3);
|
||||
|
||||
for (i = 0; i < OSPF6_MULTI_PATH_LIMIT; i++)
|
||||
ospf6_nexthop_clear (&v->nexthop[i]);
|
||||
v->nh_list = list_new();
|
||||
|
||||
v->parent = NULL;
|
||||
v->child_list = list_new ();
|
||||
@ -224,7 +261,8 @@ static void
|
||||
ospf6_nexthop_calc (struct ospf6_vertex *w, struct ospf6_vertex *v,
|
||||
caddr_t lsdesc)
|
||||
{
|
||||
int i, ifindex;
|
||||
int i;
|
||||
int ifindex;
|
||||
struct ospf6_interface *oi;
|
||||
u_int16_t type;
|
||||
u_int32_t adv_router;
|
||||
@ -233,8 +271,14 @@ ospf6_nexthop_calc (struct ospf6_vertex *w, struct ospf6_vertex *v,
|
||||
char buf[64];
|
||||
|
||||
assert (VERTEX_IS_TYPE (ROUTER, w));
|
||||
ifindex = (VERTEX_IS_TYPE (NETWORK, v) ? v->nexthop[0].ifindex :
|
||||
ifindex = (VERTEX_IS_TYPE (NETWORK, v) ? ospf6_spf_get_ifindex_from_nh (v) :
|
||||
ROUTER_LSDESC_GET_IFID (lsdesc));
|
||||
if (ifindex == -1)
|
||||
{
|
||||
zlog_err ("No nexthop ifindex at vertex %s", v->name);
|
||||
return;
|
||||
}
|
||||
|
||||
oi = ospf6_interface_lookup_by_ifindex (ifindex);
|
||||
if (oi == NULL)
|
||||
{
|
||||
@ -263,13 +307,8 @@ ospf6_nexthop_calc (struct ospf6_vertex *w, struct ospf6_vertex *v,
|
||||
zlog_debug (" nexthop %s from %s", buf, lsa->name);
|
||||
}
|
||||
|
||||
if (i < OSPF6_MULTI_PATH_LIMIT)
|
||||
{
|
||||
memcpy (&w->nexthop[i].address, &link_lsa->linklocal_addr,
|
||||
sizeof (struct in6_addr));
|
||||
w->nexthop[i].ifindex = ifindex;
|
||||
i++;
|
||||
}
|
||||
ospf6_add_nexthop (w->nh_list, ifindex, &link_lsa->linklocal_addr);
|
||||
i++;
|
||||
}
|
||||
|
||||
if (i == 0 && IS_OSPF6_DEBUG_SPF (PROCESS))
|
||||
@ -280,8 +319,7 @@ static int
|
||||
ospf6_spf_install (struct ospf6_vertex *v,
|
||||
struct ospf6_route_table *result_table)
|
||||
{
|
||||
struct ospf6_route *route;
|
||||
int i, j;
|
||||
struct ospf6_route *route, *parent_route;
|
||||
struct ospf6_vertex *prev;
|
||||
|
||||
if (IS_OSPF6_DEBUG_SPF (PROCESS))
|
||||
@ -302,23 +340,7 @@ ospf6_spf_install (struct ospf6_vertex *v,
|
||||
if (IS_OSPF6_DEBUG_SPF (PROCESS))
|
||||
zlog_debug (" another path found, merge");
|
||||
|
||||
for (i = 0; ospf6_nexthop_is_set (&v->nexthop[i]) &&
|
||||
i < OSPF6_MULTI_PATH_LIMIT; i++)
|
||||
{
|
||||
for (j = 0; j < OSPF6_MULTI_PATH_LIMIT; j++)
|
||||
{
|
||||
if (ospf6_nexthop_is_set (&route->nexthop[j]))
|
||||
{
|
||||
if (ospf6_nexthop_is_same (&route->nexthop[j],
|
||||
&v->nexthop[i]))
|
||||
break;
|
||||
else
|
||||
continue;
|
||||
}
|
||||
ospf6_nexthop_copy (&route->nexthop[j], &v->nexthop[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
ospf6_spf_merge_nexthops_to_route (route, v);
|
||||
|
||||
prev = (struct ospf6_vertex *) route->route_option;
|
||||
assert (prev->hops <= v->hops);
|
||||
@ -345,15 +367,35 @@ ospf6_spf_install (struct ospf6_vertex *v,
|
||||
route->path.origin.adv_router = v->lsa->header->adv_router;
|
||||
route->path.metric_type = 1;
|
||||
route->path.cost = v->cost;
|
||||
route->path.cost_e2 = v->hops;
|
||||
route->path.u.cost_e2 = v->hops;
|
||||
route->path.router_bits = v->capability;
|
||||
route->path.options[0] = v->options[0];
|
||||
route->path.options[1] = v->options[1];
|
||||
route->path.options[2] = v->options[2];
|
||||
|
||||
for (i = 0; ospf6_nexthop_is_set (&v->nexthop[i]) &&
|
||||
i < OSPF6_MULTI_PATH_LIMIT; i++)
|
||||
ospf6_nexthop_copy (&route->nexthop[i], &v->nexthop[i]);
|
||||
ospf6_spf_copy_nexthops_to_route (route, v);
|
||||
|
||||
/*
|
||||
* The SPF logic implementation does not transfer the multipathing properties
|
||||
* of a parent to a child node. Thus if there was a 3-way multipath to a
|
||||
* node's parent and a single hop from the parent to the child, the logic of
|
||||
* creating new vertices and computing next hops prevents there from being 3
|
||||
* paths to the child node. This is primarily because the resolution of
|
||||
* multipath is done in this routine, not in the main spf loop.
|
||||
*
|
||||
* The following logic addresses that problem by merging the parent's nexthop
|
||||
* information with the child's, if the parent is not the root of the tree.
|
||||
* This is based on the assumption that before a node's route is installed,
|
||||
* its parent's route's nexthops have already been installed.
|
||||
*/
|
||||
if (v->parent && v->parent->hops)
|
||||
{
|
||||
parent_route = ospf6_route_lookup (&v->parent->vertex_id, result_table);
|
||||
if (parent_route)
|
||||
{
|
||||
ospf6_route_merge_nexthops (route, parent_route);
|
||||
}
|
||||
}
|
||||
|
||||
if (v->parent)
|
||||
listnode_add_sort (v->parent->child_list, v);
|
||||
@ -416,19 +458,24 @@ ospf6_spf_calculation (u_int32_t router_id,
|
||||
{
|
||||
struct pqueue *candidate_list;
|
||||
struct ospf6_vertex *root, *v, *w;
|
||||
int i;
|
||||
int size;
|
||||
caddr_t lsdesc;
|
||||
struct ospf6_lsa *lsa;
|
||||
struct in6_addr address;
|
||||
|
||||
ospf6_spf_table_finish (result_table);
|
||||
|
||||
/* Install the calculating router itself as the root of the SPF tree */
|
||||
/* construct root vertex */
|
||||
lsa = ospf6_lsdb_lookup (htons (OSPF6_LSTYPE_ROUTER), htonl (0),
|
||||
router_id, oa->lsdb);
|
||||
router_id, oa->lsdb_self);
|
||||
if (lsa == NULL)
|
||||
return;
|
||||
{
|
||||
if (IS_OSPF6_DEBUG_SPF (PROCESS))
|
||||
zlog_debug ("%s: No router LSA for area %s\n",
|
||||
__func__, oa->name);
|
||||
return;
|
||||
}
|
||||
|
||||
/* initialize */
|
||||
candidate_list = pqueue_create ();
|
||||
@ -438,8 +485,7 @@ ospf6_spf_calculation (u_int32_t router_id,
|
||||
root->area = oa;
|
||||
root->cost = 0;
|
||||
root->hops = 0;
|
||||
root->nexthop[0].ifindex = 0; /* loopbak I/F is better ... */
|
||||
inet_pton (AF_INET6, "::1", &root->nexthop[0].address);
|
||||
inet_pton (AF_INET6, "::1", &address);
|
||||
|
||||
/* Actually insert root to the candidate-list as the only candidate */
|
||||
pqueue_enqueue (root, candidate_list);
|
||||
@ -470,6 +516,9 @@ ospf6_spf_calculation (u_int32_t router_id,
|
||||
if (lsa == NULL)
|
||||
continue;
|
||||
|
||||
if (OSPF6_LSA_IS_MAXAGE (lsa))
|
||||
continue;
|
||||
|
||||
if (! ospf6_lsdesc_backlink (lsa, lsdesc, v))
|
||||
continue;
|
||||
|
||||
@ -489,14 +538,12 @@ ospf6_spf_calculation (u_int32_t router_id,
|
||||
|
||||
/* nexthop calculation */
|
||||
if (w->hops == 0)
|
||||
w->nexthop[0].ifindex = ROUTER_LSDESC_GET_IFID (lsdesc);
|
||||
ospf6_add_nexthop (w->nh_list, ROUTER_LSDESC_GET_IFID (lsdesc), NULL);
|
||||
else if (w->hops == 1 && v->hops == 0)
|
||||
ospf6_nexthop_calc (w, v, lsdesc);
|
||||
else
|
||||
{
|
||||
for (i = 0; ospf6_nexthop_is_set (&v->nexthop[i]) &&
|
||||
i < OSPF6_MULTI_PATH_LIMIT; i++)
|
||||
ospf6_nexthop_copy (&w->nexthop[i], &v->nexthop[i]);
|
||||
ospf6_copy_nexthops (w->nh_list, v->nh_list);
|
||||
}
|
||||
|
||||
/* add new candidate to the candidate_list */
|
||||
|
||||
@ -60,9 +60,6 @@ struct ospf6_vertex
|
||||
/* Router hops to this node */
|
||||
u_char hops;
|
||||
|
||||
/* nexthops to this node */
|
||||
struct ospf6_nexthop nexthop[OSPF6_MULTI_PATH_LIMIT];
|
||||
|
||||
/* capability bits */
|
||||
u_char capability;
|
||||
|
||||
@ -72,6 +69,9 @@ struct ospf6_vertex
|
||||
/* For tree display */
|
||||
struct ospf6_vertex *parent;
|
||||
struct list *child_list;
|
||||
|
||||
/* nexthops to this node */
|
||||
struct list *nh_list;
|
||||
};
|
||||
|
||||
#define OSPF6_VERTEX_TYPE_ROUTER 0x01
|
||||
|
||||
@ -92,6 +92,7 @@ ospf6_top_route_hook_add (struct ospf6_route *route)
|
||||
static void
|
||||
ospf6_top_route_hook_remove (struct ospf6_route *route)
|
||||
{
|
||||
route->flag |= OSPF6_ROUTE_REMOVE;
|
||||
ospf6_abr_originate_summary (route);
|
||||
ospf6_zebra_route_update_remove (route);
|
||||
}
|
||||
@ -107,6 +108,7 @@ ospf6_top_brouter_hook_add (struct ospf6_route *route)
|
||||
static void
|
||||
ospf6_top_brouter_hook_remove (struct ospf6_route *route)
|
||||
{
|
||||
route->flag |= OSPF6_ROUTE_REMOVE;
|
||||
ospf6_abr_examin_brouter (ADV_ROUTER_IN_PREFIX (&route->prefix));
|
||||
ospf6_asbr_lsentry_remove (route);
|
||||
ospf6_abr_originate_summary (route);
|
||||
|
||||
@ -362,7 +362,7 @@ ospf6_zebra_route_update (int type, struct ospf6_route *request)
|
||||
int nhcount;
|
||||
struct in6_addr **nexthops;
|
||||
unsigned int *ifindexes;
|
||||
int i, ret = 0;
|
||||
int ret = 0;
|
||||
struct prefix_ipv6 *dest;
|
||||
|
||||
if (IS_OSPF6_DEBUG_ZEBRA (SEND))
|
||||
@ -408,11 +408,7 @@ ospf6_zebra_route_update (int type, struct ospf6_route *request)
|
||||
return;
|
||||
}
|
||||
|
||||
nhcount = 0;
|
||||
for (i = 0; i < OSPF6_MULTI_PATH_LIMIT; i++)
|
||||
if (ospf6_nexthop_is_set (&request->nexthop[i]))
|
||||
nhcount++;
|
||||
|
||||
nhcount = ospf6_route_num_nexthops (request);
|
||||
if (nhcount == 0)
|
||||
{
|
||||
if (IS_OSPF6_DEBUG_ZEBRA (SEND))
|
||||
@ -439,21 +435,7 @@ ospf6_zebra_route_update (int type, struct ospf6_route *request)
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < nhcount; i++)
|
||||
{
|
||||
if (IS_OSPF6_DEBUG_ZEBRA (SEND))
|
||||
{
|
||||
char ifname[IFNAMSIZ];
|
||||
inet_ntop (AF_INET6, &request->nexthop[i].address,
|
||||
buf, sizeof (buf));
|
||||
if (!if_indextoname(request->nexthop[i].ifindex, ifname))
|
||||
strlcpy(ifname, "unknown", sizeof(ifname));
|
||||
zlog_debug (" nexthop: %s%%%.*s(%d)", buf, IFNAMSIZ, ifname,
|
||||
request->nexthop[i].ifindex);
|
||||
}
|
||||
nexthops[i] = &request->nexthop[i].address;
|
||||
ifindexes[i] = request->nexthop[i].ifindex;
|
||||
}
|
||||
ospf6_route_zebra_copy_nexthops (request, ifindexes, nexthops, nhcount);
|
||||
|
||||
api.type = ZEBRA_ROUTE_OSPF6;
|
||||
api.flags = 0;
|
||||
@ -467,7 +449,7 @@ ospf6_zebra_route_update (int type, struct ospf6_route *request)
|
||||
api.ifindex = ifindexes;
|
||||
SET_FLAG (api.message, ZAPI_MESSAGE_METRIC);
|
||||
api.metric = (request->path.metric_type == 2 ?
|
||||
request->path.cost_e2 : request->path.cost);
|
||||
request->path.u.cost_e2 : request->path.cost);
|
||||
|
||||
dest = (struct prefix_ipv6 *) &request->prefix;
|
||||
if (type == REM)
|
||||
@ -509,6 +491,90 @@ ospf6_zebra_route_update_remove (struct ospf6_route *request)
|
||||
ospf6_zebra_route_update (REM, request);
|
||||
}
|
||||
|
||||
void
|
||||
ospf6_zebra_add_discard (struct ospf6_route *request)
|
||||
{
|
||||
struct zapi_ipv6 api;
|
||||
char buf[INET6_ADDRSTRLEN];
|
||||
struct prefix_ipv6 *dest;
|
||||
|
||||
if (zclient->redist[ZEBRA_ROUTE_OSPF6])
|
||||
{
|
||||
if (!CHECK_FLAG (request->flag, OSPF6_ROUTE_BLACKHOLE_ADDED))
|
||||
{
|
||||
api.type = ZEBRA_ROUTE_OSPF6;
|
||||
api.flags = ZEBRA_FLAG_BLACKHOLE;
|
||||
api.message = 0;
|
||||
api.safi = SAFI_UNICAST;
|
||||
SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
|
||||
api.nexthop_num = 0;
|
||||
api.ifindex_num = 0;
|
||||
|
||||
dest = (struct prefix_ipv6 *) &request->prefix;
|
||||
|
||||
zapi_ipv6_route (ZEBRA_IPV6_ROUTE_ADD, zclient, dest, &api);
|
||||
|
||||
if (IS_OSPF6_DEBUG_ZEBRA (SEND))
|
||||
zlog_debug ("Zebra: Route add discard %s/%d",
|
||||
inet_ntop (AF_INET6, &dest->prefix,
|
||||
buf, INET6_ADDRSTRLEN),
|
||||
dest->prefixlen);
|
||||
SET_FLAG (request->flag, OSPF6_ROUTE_BLACKHOLE_ADDED);
|
||||
}
|
||||
else
|
||||
{
|
||||
dest = (struct prefix_ipv6 *) &request->prefix;
|
||||
|
||||
if (IS_OSPF6_DEBUG_ZEBRA (SEND))
|
||||
zlog_debug ("Zebra: Blackhole route present already %s/%d",
|
||||
inet_ntop (AF_INET6, &dest->prefix,
|
||||
buf, INET6_ADDRSTRLEN),
|
||||
dest->prefixlen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ospf6_zebra_delete_discard (struct ospf6_route *request)
|
||||
{
|
||||
struct zapi_ipv6 api;
|
||||
char buf[INET6_ADDRSTRLEN];
|
||||
struct prefix_ipv6 *dest;
|
||||
|
||||
if (zclient->redist[ZEBRA_ROUTE_OSPF6])
|
||||
{
|
||||
if (CHECK_FLAG (request->flag, OSPF6_ROUTE_BLACKHOLE_ADDED))
|
||||
{
|
||||
|
||||
api.type = ZEBRA_ROUTE_OSPF6;
|
||||
api.flags = ZEBRA_FLAG_BLACKHOLE;
|
||||
api.message = 0;
|
||||
api.safi = SAFI_UNICAST;
|
||||
SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
|
||||
api.nexthop_num = 0;
|
||||
api.ifindex_num = 0;
|
||||
|
||||
dest = (struct prefix_ipv6 *) &request->prefix;
|
||||
|
||||
zapi_ipv6_route (ZEBRA_IPV6_ROUTE_DELETE, zclient, dest, &api);
|
||||
|
||||
if (IS_OSPF6_DEBUG_ZEBRA (SEND))
|
||||
zlog_debug ("Zebra: Route delete discard %s/%d",
|
||||
inet_ntop (AF_INET6, &dest->prefix, buf,
|
||||
INET6_ADDRSTRLEN), dest->prefixlen);
|
||||
UNSET_FLAG (request->flag, OSPF6_ROUTE_BLACKHOLE_ADDED);
|
||||
}
|
||||
else
|
||||
{
|
||||
dest = (struct prefix_ipv6 *) &request->prefix;
|
||||
if (IS_OSPF6_DEBUG_ZEBRA (SEND))
|
||||
zlog_debug ("Zebra: Blackhole route already deleted %s/%d",
|
||||
inet_ntop (AF_INET6, &dest->prefix, buf,
|
||||
INET6_ADDRSTRLEN), dest->prefixlen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DEFUN (redistribute_ospf6,
|
||||
redistribute_ospf6_cmd,
|
||||
"redistribute ospf6",
|
||||
|
||||
@ -44,6 +44,8 @@ extern void ospf6_zebra_redistribute (int);
|
||||
extern void ospf6_zebra_no_redistribute (int);
|
||||
#define ospf6_zebra_is_redistribute(type) (zclient->redist[type])
|
||||
extern void ospf6_zebra_init (void);
|
||||
extern void ospf6_zebra_add_discard (struct ospf6_route *request);
|
||||
extern void ospf6_zebra_delete_discard (struct ospf6_route *request);
|
||||
|
||||
extern int config_write_ospf6_debug_zebra (struct vty *vty);
|
||||
extern void install_element_ospf6_debug_zebra (void);
|
||||
|
||||
@ -52,7 +52,6 @@ struct ospf_area_range
|
||||
|
||||
/* Configured range cost. */
|
||||
u_int32_t cost_config;
|
||||
#define OSPF_AREA_RANGE_COST_UNSPEC -1U
|
||||
};
|
||||
|
||||
/* Prototypes. */
|
||||
|
||||
@ -1420,6 +1420,10 @@ netlink_route (int cmd, int family, void *dest, int length, void *gate,
|
||||
req.r.rtm_type = RTN_UNREACHABLE;
|
||||
else
|
||||
assert (RTN_BLACKHOLE != RTN_UNREACHABLE); /* false */
|
||||
|
||||
if (IS_ZEBRA_DEBUG_KERNEL)
|
||||
zlog_debug ("%s: Adding discard route for family %s\n",
|
||||
__FUNCTION__, family == AF_INET ? "IPv4" : "IPv6");
|
||||
}
|
||||
else
|
||||
req.r.rtm_type = RTN_UNICAST;
|
||||
@ -1912,13 +1916,17 @@ kernel_delete_ipv4 (struct prefix *p, struct rib *rib)
|
||||
int
|
||||
kernel_add_ipv6 (struct prefix *p, struct rib *rib)
|
||||
{
|
||||
return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET6);
|
||||
{
|
||||
return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET6);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
kernel_delete_ipv6 (struct prefix *p, struct rib *rib)
|
||||
{
|
||||
return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET6);
|
||||
{
|
||||
return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET6);
|
||||
}
|
||||
}
|
||||
|
||||
/* Delete IPv6 route from the kernel. */
|
||||
|
||||
@ -1298,6 +1298,9 @@ zread_ipv6_add (struct zserv *client, u_short length)
|
||||
ifindices[if_count++] = stream_getl (s);
|
||||
}
|
||||
break;
|
||||
case ZEBRA_NEXTHOP_BLACKHOLE:
|
||||
nexthop_blackhole_add (rib);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user