Merge pull request #9028 from mobash-rasool/ospfv3-asbr-summarisation

Ospfv3 ASBR summarisation feature
This commit is contained in:
Russ White 2021-07-30 06:37:50 -04:00 committed by GitHub
commit e448fefbb4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
23 changed files with 4233 additions and 149 deletions

View file

@ -85,6 +85,83 @@ OSPF6 router
change to take effect, user can use this cli instead of restarting the
ospf6d daemon.
ASBR Summarisation Support in OSPFv3
====================================
External routes in OSPFv3 are carried by type 5/7 LSA (external LSAs).
External LSAs are generated by ASBR (Autonomous System Boundary Router).
Large topology database requires a large amount of router memory, which
slows down all processes, including SPF calculations.
It is necessary to reduce the size of the OSPFv3 topology database,
especially in a large network. Summarising routes keeps the routing
tables smaller and easier to troubleshoot.
External route summarization must be configured on ASBR.
Stub area do not allow ASBR because they dont allow type 5 LSAs.
An ASBR will inject a summary route into the OSPFv3 domain.
Summary route will only be advertised if you have at least one subnet
that falls within the summary range.
Users will be allowed an option in the CLI to not advertise range of
ipv6 prefixes as well.
The configuration of ASBR Summarisation is supported using the CLI command
.. clicmd:: summary-address X:X::X:X/M [tag (1-4294967295)] [{metric (0-16777215) | metric-type (1-2)}]
This command will advertise a single External LSA on behalf of all the
prefixes falling under this range configured by the CLI.
The user is allowed to configure tag, metric and metric-type as well.
By default, tag is not configured, default metric as 20 and metric-type
as type-2 gets advertised.
A summary route is created when one or more specific routes are learned and
removed when no more specific route exist.
The summary route is also installed in the local system with Null0 as
next-hop to avoid leaking traffic.
.. clicmd:: no summary-address X:X::X:X/M [tag (1-4294967295)] [{metric (0-16777215) | metric-type (1-2)}]
This command can be used to remove the summarisation configuration.
This will flush the single External LSA if it was originated and advertise
the External LSAs for all the existing individual prefixes.
.. clicmd:: summary-address X:X::X:X/M no-advertise
This command can be used when user do not want to advertise a certain
range of prefixes using the no-advertise option.
This command when configured will flush all the existing external LSAs
falling under this range.
.. clicmd:: no summary-address X:X::X:X/M no-advertise
This command can be used to remove the previous configuration.
When configured, tt will resume originating external LSAs for all the prefixes
falling under the configured range.
.. clicmd:: aggregation timer (5-1800)
The summarisation command takes effect after the aggregation timer expires.
By default the value of this timer is 5 seconds. User can modify the time
after which the external LSAs should get originated using this command.
.. clicmd:: no aggregation timer (5-1800)
This command removes the timer configuration. It reverts back to default
5 second timer.
.. clicmd:: show ipv6 ospf6 summary-address [detail] [json]
This command can be used to see all the summary-address related information.
When detail option is used, it shows all the prefixes falling under each
summary-configuration apart from other information.
.. clicmd:: debug ospf6 lsa aggregation
This command can be used to enable the debugs related to the summarisation
of these LSAs.
.. _ospf6-debugging:
OSPFv3 Debugging

View file

@ -715,7 +715,7 @@ void ospf6_abr_defaults_to_stub(struct ospf6 *o)
if (!o->backbone)
return;
def = ospf6_route_create();
def = ospf6_route_create(o);
def->type = OSPF6_DEST_TYPE_NETWORK;
def->prefix.family = AF_INET6;
def->prefix.prefixlen = 0;
@ -1150,7 +1150,7 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa)
/* (5),(6): the path preference is handled by the sorting
in the routing table. Always install the path by substituting
old route (if any). */
route = ospf6_route_create();
route = ospf6_route_create(oa->ospf6);
route->type = type;
route->prefix = prefix;
@ -1237,7 +1237,9 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa)
listcount(old_route->nh_list));
}
} else {
struct ospf6_route *tmp_route = ospf6_route_create();
struct ospf6_route *tmp_route;
tmp_route = ospf6_route_create(oa->ospf6);
ospf6_copy_nexthops(tmp_route->nh_list,
o_path->nh_list);

View file

@ -519,7 +519,7 @@ DEFUN (area_range,
range = ospf6_route_lookup(&prefix, oa->range_table);
if (range == NULL) {
range = ospf6_route_create();
range = ospf6_route_create(ospf6);
range->type = OSPF6_DEST_TYPE_RANGE;
range->prefix = prefix;
range->path.area_id = oa->area_id;

File diff suppressed because it is too large Load diff

View file

@ -46,6 +46,52 @@ struct ospf6_external_info {
route_tag_t tag;
ifindex_t ifindex;
};
/* OSPF6 ASBR Summarisation */
typedef enum {
OSPF6_ROUTE_AGGR_NONE = 0,
OSPF6_ROUTE_AGGR_ADD,
OSPF6_ROUTE_AGGR_DEL,
OSPF6_ROUTE_AGGR_MODIFY
} ospf6_aggr_action_t;
#define OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE 0x1
#define OSPF6_EXTERNAL_AGGRT_ORIGINATED 0x2
#define OSPF6_EXTERNAL_RT_COUNT(aggr) \
(((struct ospf6_external_aggr_rt *)aggr)->match_extnl_hash->count)
struct ospf6_external_aggr_rt {
/* range address and masklen */
struct prefix p;
/* use bits for OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE and
* OSPF6_EXTERNAL_AGGRT_ORIGINATED
*/
uint16_t aggrflags;
/* To store external metric-type */
uint8_t mtype;
/* Route tag for summary address */
route_tag_t tag;
/* To store aggregated metric config */
int metric;
/* To Store the LS ID when LSA is originated */
uint32_t id;
/* Action to be done after delay timer expiry */
int action;
/* OSPFv3 route generated by summary address. */
struct ospf6_route *route;
/* Hash table of matching external routes */
struct hash *match_extnl_hash;
};
/* AS-External-LSA */
@ -110,8 +156,31 @@ extern void ospf6_asbr_distribute_list_update(struct ospf6 *ospf6,
struct ospf6_redist *ospf6_redist_lookup(struct ospf6 *ospf6, int type,
unsigned short instance);
extern void ospf6_asbr_routemap_update(const char *mapname);
extern void ospf6_as_external_lsa_originate(struct ospf6_route *route,
struct ospf6 *ospf6);
extern struct ospf6_lsa *
ospf6_as_external_lsa_originate(struct ospf6_route *route,
struct ospf6 *ospf6);
extern void ospf6_asbr_status_update(struct ospf6 *ospf6, int status);
int ospf6_asbr_external_rt_advertise(struct ospf6 *ospf6,
struct prefix *p);
int ospf6_external_aggr_delay_timer_set(struct ospf6 *ospf6,
unsigned int interval);
int ospf6_asbr_external_rt_no_advertise(struct ospf6 *ospf6,
struct prefix *p);
struct ospf6_external_aggr_rt *
ospf6_external_aggr_config_lookup(struct ospf6 *ospf6, struct prefix *p);
int ospf6_external_aggr_config_set(struct ospf6 *ospf6, struct prefix *p,
route_tag_t tag, int metric, int mtype);
int ospf6_external_aggr_config_unset(struct ospf6 *ospf6,
struct prefix *p);
void ospf6_handle_external_lsa_origination(struct ospf6 *ospf6,
struct ospf6_route *rt,
struct prefix *p);
void ospf6_external_aggregator_free(struct ospf6_external_aggr_rt *aggr);
void ospf6_unset_all_aggr_flag(struct ospf6 *ospf6);
void ospf6_fill_aggr_route_details(struct ospf6 *ospf6,
struct ospf6_external_aggr_rt *aggr);
#endif /* OSPF6_ASBR_H */

View file

@ -116,7 +116,7 @@ void ospf6_lsa_originate(struct ospf6_lsa *lsa)
lsdb_self = ospf6_get_scoped_lsdb_self(lsa);
ospf6_lsdb_add(ospf6_lsa_copy(lsa), lsdb_self);
lsa->refresh = NULL;
THREAD_OFF(lsa->refresh);
thread_add_timer(master, ospf6_lsa_refresh, lsa, OSPF_LS_REFRESH_TIME,
&lsa->refresh);
@ -149,6 +149,31 @@ void ospf6_lsa_originate_interface(struct ospf6_lsa *lsa,
ospf6_lsa_originate(lsa);
}
void ospf6_remove_id_from_external_id_table(struct ospf6 *ospf6,
uint32_t id)
{
struct prefix prefix_id;
struct route_node *node;
/* remove binding in external_id_table */
prefix_id.family = AF_INET;
prefix_id.prefixlen = 32;
prefix_id.u.prefix4.s_addr = id;
node = route_node_lookup(ospf6->external_id_table, &prefix_id);
assert(node);
node->info = NULL;
route_unlock_node(node); /* to free the lookup lock */
route_unlock_node(node); /* to free the original lock */
}
void ospf6_external_lsa_purge(struct ospf6 *ospf6, struct ospf6_lsa *lsa)
{
ospf6_lsa_purge(lsa);
ospf6_remove_id_from_external_id_table(ospf6, lsa->header->id);
}
void ospf6_lsa_purge(struct ospf6_lsa *lsa)
{
struct ospf6_lsa *self;

View file

@ -39,6 +39,9 @@ extern void ospf6_lsa_originate_area(struct ospf6_lsa *lsa,
struct ospf6_area *oa);
extern void ospf6_lsa_originate_interface(struct ospf6_lsa *lsa,
struct ospf6_interface *oi);
void ospf6_remove_id_from_external_id_table(struct ospf6 *ospf6,
uint32_t id);
void ospf6_external_lsa_purge(struct ospf6 *ospf6, struct ospf6_lsa *lsa);
extern void ospf6_lsa_purge(struct ospf6_lsa *lsa);
extern void ospf6_lsa_purge_multi_ls_id(struct ospf6_area *oa,

View file

@ -435,7 +435,7 @@ void ospf6_interface_connected_route_update(struct interface *ifp)
}
}
route = ospf6_route_create();
route = ospf6_route_create(oi->area->ospf6);
memcpy(&route->prefix, c->address, sizeof(struct prefix));
apply_mask(&route->prefix);
route->type = OSPF6_DEST_TYPE_NETWORK;

View file

@ -1327,7 +1327,7 @@ int ospf6_intra_prefix_lsa_originate_transit(struct thread *thread)
|| current + OSPF6_PREFIX_SIZE(op) > end)
break;
route = ospf6_route_create();
route = ospf6_route_create(oi->area->ospf6);
route->type = OSPF6_DEST_TYPE_NETWORK;
route->prefix.family = AF_INET6;
@ -1790,7 +1790,7 @@ void ospf6_intra_prefix_lsa_add(struct ospf6_lsa *lsa)
continue;
}
route = ospf6_route_create();
route = ospf6_route_create(oa->ospf6);
memset(&route->prefix, 0, sizeof(struct prefix));
route->prefix.family = AF_INET6;

View file

@ -45,6 +45,10 @@
#include "ospf6_flood.h"
#include "ospf6d.h"
#ifndef VTYSH_EXTRACT_PL
#include "ospf6d/ospf6_lsa_clippy.c"
#endif
DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_LSA, "OSPF6 LSA");
DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_LSA_HEADER, "OSPF6 LSA header");
DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_LSA_SUMMARY, "OSPF6 LSA summary");
@ -822,6 +826,8 @@ int ospf6_lsa_expire(struct thread *thread)
if (CHECK_FLAG(lsa->flag, OSPF6_LSA_HEADERONLY))
return 0; /* dbexchange will do something ... */
ospf6 = ospf6_get_by_lsdb(lsa);
assert(ospf6);
/* reinstall lsa */
ospf6_install_lsa(lsa);
@ -994,6 +1000,30 @@ static char *ospf6_lsa_handler_name(const struct ospf6_lsa_handler *h)
return buf;
}
DEFPY (debug_ospf6_lsa_aggregation,
debug_ospf6_lsa_aggregation_cmd,
"[no] debug ospf6 lsa aggregation",
NO_STR
DEBUG_STR
OSPF6_STR
"Debug Link State Advertisements (LSAs)\n"
"External LSA Aggregation\n")
{
struct ospf6_lsa_handler *handler;
handler = ospf6_get_lsa_handler(OSPF6_LSTYPE_AS_EXTERNAL);
if (handler == NULL)
return CMD_WARNING_CONFIG_FAILED;
if (no)
UNSET_FLAG(handler->lh_debug, OSPF6_LSA_DEBUG_AGGR);
else
SET_FLAG(handler->lh_debug, OSPF6_LSA_DEBUG_AGGR);
return CMD_SUCCESS;
}
DEFUN (debug_ospf6_lsa_type,
debug_ospf6_lsa_hex_cmd,
"debug ospf6 lsa <router|network|inter-prefix|inter-router|as-external|link|intra-prefix|unknown> [<originate|examine|flooding>]",
@ -1105,6 +1135,9 @@ void install_element_ospf6_debug_lsa(void)
install_element(ENABLE_NODE, &no_debug_ospf6_lsa_hex_cmd);
install_element(CONFIG_NODE, &debug_ospf6_lsa_hex_cmd);
install_element(CONFIG_NODE, &no_debug_ospf6_lsa_hex_cmd);
install_element(ENABLE_NODE, &debug_ospf6_lsa_aggregation_cmd);
install_element(CONFIG_NODE, &debug_ospf6_lsa_aggregation_cmd);
}
int config_write_ospf6_debug_lsa(struct vty *vty)
@ -1128,6 +1161,8 @@ int config_write_ospf6_debug_lsa(struct vty *vty)
if (CHECK_FLAG(handler->lh_debug, OSPF6_LSA_DEBUG_FLOOD))
vty_out(vty, "debug ospf6 lsa %s flooding\n",
ospf6_lsa_handler_name(handler));
if (CHECK_FLAG(handler->lh_debug, OSPF6_LSA_DEBUG_AGGR))
vty_out(vty, "debug ospf6 lsa aggregation\n");
}
return 0;

View file

@ -28,6 +28,7 @@
#define OSPF6_LSA_DEBUG_ORIGINATE 0x02
#define OSPF6_LSA_DEBUG_EXAMIN 0x04
#define OSPF6_LSA_DEBUG_FLOOD 0x08
#define OSPF6_LSA_DEBUG_AGGR 0x10
/* OSPF LSA Default metric values */
#define DEFAULT_DEFAULT_METRIC 20
@ -51,6 +52,8 @@
(ospf6_lstype_debug(type) & OSPF6_LSA_DEBUG_EXAMIN)
#define IS_OSPF6_DEBUG_FLOOD_TYPE(type) \
(ospf6_lstype_debug(type) & OSPF6_LSA_DEBUG_FLOOD)
#define IS_OSPF6_DEBUG_AGGR \
(ospf6_lstype_debug(OSPF6_LSTYPE_AS_EXTERNAL) & OSPF6_LSA_DEBUG_AGGR) \
/* LSA definition */
@ -263,4 +266,6 @@ extern void install_element_ospf6_debug_lsa(void);
extern void ospf6_lsa_age_set(struct ospf6_lsa *lsa);
extern void ospf6_flush_self_originated_lsas_now(struct ospf6 *ospf6);
extern struct ospf6 *ospf6_get_by_lsdb(struct ospf6_lsa *lsa);
struct ospf6_lsa *ospf6_find_external_lsa(struct ospf6 *ospf6,
struct prefix *p);
#endif /* OSPF6_LSA_H */

View file

@ -30,6 +30,7 @@
#include "ospf6_proto.h"
#include "ospf6_lsa.h"
#include "ospf6_lsdb.h"
#include "ospf6_asbr.h"
#include "ospf6_route.h"
#include "ospf6d.h"
#include "bitfield.h"
@ -194,6 +195,28 @@ struct ospf6_lsa *ospf6_lsdb_lookup(uint16_t type, uint32_t id,
return (struct ospf6_lsa *)node->info;
}
struct ospf6_lsa *ospf6_find_external_lsa(struct ospf6 *ospf6, struct prefix *p)
{
struct ospf6_route *match;
struct ospf6_lsa *lsa;
struct ospf6_external_info *info;
match = ospf6_route_lookup(p, ospf6->external_table);
if (match == NULL) {
if (IS_OSPF6_DEBUG_ASBR)
zlog_debug("No such route %pFX to withdraw", p);
return NULL;
}
info = match->route_option;
assert(info);
lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL),
htonl(info->id), ospf6->router_id, ospf6->lsdb);
return lsa;
}
struct ospf6_lsa *ospf6_lsdb_lookup_next(uint16_t type, uint32_t id,
uint32_t adv_router,
struct ospf6_lsdb *lsdb)

View file

@ -1159,10 +1159,49 @@ static void ospf6_nssa_flush_area(struct ospf6_area *area)
}
}
static void ospf6_area_nssa_update(struct ospf6_area *area)
static void ospf6_check_and_originate_type7_lsa(struct ospf6_area *area)
{
struct ospf6_route *route;
struct route_node *rn = NULL;
struct ospf6_external_aggr_rt *aggr;
/* Loop through the external_table to find the LSAs originated
* without aggregation and originate type-7 LSAs for them.
*/
for (route = ospf6_route_head(
area->ospf6->external_table);
route; route = ospf6_route_next(route)) {
/* This means the Type-5 LSA was originated for this route */
if (route->path.origin.id != 0)
ospf6_nssa_lsa_originate(route, area);
}
/* Loop through the aggregation table to originate type-7 LSAs
* for the aggregated type-5 LSAs
*/
for (rn = route_top(area->ospf6->rt_aggr_tbl); rn;
rn = route_next(rn)) {
if (!rn->info)
continue;
aggr = rn->info;
if (CHECK_FLAG(aggr->aggrflags,
OSPF6_EXTERNAL_AGGRT_ORIGINATED)) {
if (IS_OSPF6_DEBUG_NSSA)
zlog_debug(
"Originating Type-7 LSAs for area %s",
area->name);
ospf6_nssa_lsa_originate(aggr->route, area);
}
}
}
static void ospf6_area_nssa_update(struct ospf6_area *area)
{
if (IS_AREA_NSSA(area)) {
if (!ospf6_check_and_set_router_abr(area->ospf6))
OSPF6_OPT_CLEAR(area->options, OSPF6_OPT_E);
@ -1194,10 +1233,7 @@ static void ospf6_area_nssa_update(struct ospf6_area *area)
zlog_debug("NSSA area %s", area->name);
/* Originate NSSA LSA */
for (route = ospf6_route_head(
area->ospf6->external_table);
route; route = ospf6_route_next(route))
ospf6_nssa_lsa_originate(route, area);
ospf6_check_and_originate_type7_lsa(area);
}
} else {
/* Disable NSSA */

View file

@ -284,12 +284,21 @@ void ospf6_add_nexthop(struct list *nh_list, int ifindex, struct in6_addr *addr)
struct ospf6_nexthop nh_match;
if (nh_list) {
nh_match.ifindex = ifindex;
if (addr != NULL)
if (addr) {
if (ifindex)
nh_match.type = NEXTHOP_TYPE_IPV6_IFINDEX;
else
nh_match.type = NEXTHOP_TYPE_IPV6;
memcpy(&nh_match.address, addr,
sizeof(struct in6_addr));
else
} else {
nh_match.type = NEXTHOP_TYPE_IFINDEX;
memset(&nh_match.address, 0, sizeof(struct in6_addr));
}
nh_match.ifindex = ifindex;
if (!ospf6_route_find_nexthop(nh_list, &nh_match)) {
nh = ospf6_nexthop_create();
@ -299,36 +308,76 @@ void ospf6_add_nexthop(struct list *nh_list, int ifindex, struct in6_addr *addr)
}
}
void ospf6_add_route_nexthop_blackhole(struct ospf6_route *route)
{
struct ospf6_nexthop *nh;
struct ospf6_nexthop nh_match = {};
/* List not allocated. */
if (route->nh_list == NULL)
return;
/* Entry already exists. */
nh_match.type = NEXTHOP_TYPE_BLACKHOLE;
if (ospf6_route_find_nexthop(route->nh_list, &nh_match))
return;
nh = ospf6_nexthop_create();
ospf6_nexthop_copy(nh, &nh_match);
listnode_add(route->nh_list, nh);
}
void ospf6_route_zebra_copy_nexthops(struct ospf6_route *route,
struct zapi_nexthop nexthops[],
int entries, vrf_id_t vrf_id)
{
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)) {
const char *ifname;
inet_ntop(AF_INET6, &nh->address, buf,
sizeof(buf));
ifname = ifindex2ifname(nh->ifindex, vrf_id);
zlog_debug(" nexthop: %s%%%.*s(%d)", buf,
IFNAMSIZ, ifname, nh->ifindex);
zlog_debug(" nexthop: %s %pI6%%%.*s(%d)",
nexthop_type_to_str(nh->type),
&nh->address, IFNAMSIZ,
ifindex2ifname(nh->ifindex, vrf_id),
nh->ifindex);
}
if (i >= entries)
return;
nexthops[i].vrf_id = vrf_id;
nexthops[i].ifindex = nh->ifindex;
if (!IN6_IS_ADDR_UNSPECIFIED(&nh->address)) {
nexthops[i].type = nh->type;
switch (nh->type) {
case NEXTHOP_TYPE_BLACKHOLE:
/* NOTHING */
break;
case NEXTHOP_TYPE_IFINDEX:
nexthops[i].ifindex = nh->ifindex;
break;
case NEXTHOP_TYPE_IPV4_IFINDEX:
case NEXTHOP_TYPE_IPV4:
/*
* OSPFv3 with IPv4 routes is not supported
* yet. Skip this next hop.
*/
if (IS_OSPF6_DEBUG_ZEBRA(SEND))
zlog_debug(" Skipping IPv4 next hop");
continue;
case NEXTHOP_TYPE_IPV6_IFINDEX:
nexthops[i].ifindex = nh->ifindex;
/* FALLTHROUGH */
case NEXTHOP_TYPE_IPV6:
nexthops[i].gate.ipv6 = nh->address;
nexthops[i].type = NEXTHOP_TYPE_IPV6_IFINDEX;
} else
nexthops[i].type = NEXTHOP_TYPE_IFINDEX;
break;
}
i++;
}
}
@ -404,7 +453,7 @@ void ospf6_copy_paths(struct list *dst, struct list *src)
}
}
struct ospf6_route *ospf6_route_create(void)
struct ospf6_route *ospf6_route_create(struct ospf6 *ospf6)
{
struct ospf6_route *route;
@ -415,6 +464,8 @@ struct ospf6_route *ospf6_route_create(void)
route->paths = list_new();
route->paths->cmp = (int (*)(void *, void *))ospf6_path_cmp;
route->paths->del = (void (*)(void *))ospf6_path_free;
route->ospf6 = ospf6;
return route;
}
@ -433,7 +484,7 @@ struct ospf6_route *ospf6_route_copy(struct ospf6_route *route)
{
struct ospf6_route *new;
new = ospf6_route_create();
new = ospf6_route_create(route->ospf6);
new->type = route->type;
memcpy(&new->prefix, &route->prefix, sizeof(struct prefix));
new->prefix_options = route->prefix_options;

View file

@ -24,6 +24,7 @@
#include "command.h"
#include "zclient.h"
#include "lib/json.h"
#include "lib/nexthop.h"
#define OSPF6_MULTI_PATH_LIMIT 4
@ -44,23 +45,60 @@ struct ospf6_nexthop {
/* IP address, if any */
struct in6_addr address;
/** Next-hop type information. */
enum nexthop_types_t type;
};
#define ospf6_nexthop_is_set(x) \
((x)->ifindex || !IN6_IS_ADDR_UNSPECIFIED(&(x)->address))
#define ospf6_nexthop_is_same(a, b) \
((a)->ifindex == (b)->ifindex \
&& IN6_ARE_ADDR_EQUAL(&(a)->address, &(b)->address))
#define ospf6_nexthop_clear(x) \
do { \
(x)->ifindex = 0; \
memset(&(x)->address, 0, sizeof(struct in6_addr)); \
} while (0)
#define ospf6_nexthop_copy(a, b) \
do { \
(a)->ifindex = (b)->ifindex; \
memcpy(&(a)->address, &(b)->address, sizeof(struct in6_addr)); \
} while (0)
static inline bool ospf6_nexthop_is_set(const struct ospf6_nexthop *nh)
{
return nh->type != 0;
}
static inline bool ospf6_nexthop_is_same(const struct ospf6_nexthop *nha,
const struct ospf6_nexthop *nhb)
{
if (nha->type != nhb->type)
return false;
switch (nha->type) {
case NEXTHOP_TYPE_BLACKHOLE:
/* NOTHING */
break;
case NEXTHOP_TYPE_IFINDEX:
if (nha->ifindex != nhb->ifindex)
return false;
break;
case NEXTHOP_TYPE_IPV4_IFINDEX:
case NEXTHOP_TYPE_IPV4:
/* OSPFv3 does not support IPv4 next hops. */
return false;
case NEXTHOP_TYPE_IPV6_IFINDEX:
if (nha->ifindex != nhb->ifindex)
return false;
/* FALLTHROUGH */
case NEXTHOP_TYPE_IPV6:
if (!IN6_ARE_ADDR_EQUAL(&nha->address, &nhb->address))
return false;
break;
}
return true;
}
static inline void ospf6_nexthop_clear(struct ospf6_nexthop *nh)
{
memset(nh, 0, sizeof(*nh));
}
static inline void ospf6_nexthop_copy(struct ospf6_nexthop *nha,
const struct ospf6_nexthop *nhb)
{
memcpy(nha, nhb, sizeof(*nha));
}
/* Path */
struct ospf6_ls_origin {
@ -124,6 +162,9 @@ struct ospf6_route {
struct ospf6_route *prev;
struct ospf6_route *next;
/* Back pointer to ospf6 */
struct ospf6 *ospf6;
unsigned int lock;
/* Destination Type */
@ -161,6 +202,12 @@ struct ospf6_route {
/* nexthop */
struct list *nh_list;
/* points to the summarised route */
struct ospf6_external_aggr_rt *aggr_route;
/* For Aggr routes */
bool to_be_processed;
};
#define OSPF6_DEST_TYPE_NONE 0
@ -279,6 +326,7 @@ 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 void ospf6_add_route_nexthop_blackhole(struct ospf6_route *route);
extern int ospf6_num_nexthops(struct list *nh_list);
extern int ospf6_route_cmp_nexthops(struct ospf6_route *a,
struct ospf6_route *b);
@ -294,7 +342,7 @@ extern int ospf6_route_get_first_nh_index(struct ospf6_route *route);
#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 struct ospf6_route *ospf6_route_create(struct ospf6 *ospf6);
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);

View file

@ -374,7 +374,7 @@ static int ospf6_spf_install(struct ospf6_vertex *v,
up to here. */
assert(route == NULL);
route = ospf6_route_create();
route = ospf6_route_create(v->area->ospf6);
memcpy(&route->prefix, &v->vertex_id, sizeof(struct prefix));
route->type = OSPF6_DEST_TYPE_LINKSTATE;
route->path.type = OSPF6_PATH_TYPE_INTRA;

View file

@ -409,13 +409,31 @@ static struct ospf6 *ospf6_create(const char *name)
o->external_table = OSPF6_ROUTE_TABLE_CREATE(GLOBAL, EXTERNAL_ROUTES);
o->external_table->scope = o;
/* Setting this to 1, so that the LS ID 0 can be considered as invalid
* for self originated external LSAs. This helps in differentiating if
* an LSA is originated for any route or not in the route data.
* rt->route_option->id is by default 0
* Consider a route having id as 0 and prefix as 1::1, an external LSA
* is originated with ID 0.0.0.0. Now consider another route 2::2
* and for this LSA was not originated because of some configuration
* but the ID field rt->route_option->id is still 0.Consider now this
* 2::2 is being deleted, it will search LSA with LS ID as 0 and it
* will find the LSA and hence delete it but the LSA belonged to prefix
* 1::1, this happened because of LS ID 0.
*/
o->external_id = OSPF6_EXT_INIT_LS_ID;
o->external_id_table = route_table_init();
o->write_oi_count = OSPF6_WRITE_INTERFACE_COUNT_DEFAULT;
o->ref_bandwidth = OSPF6_REFERENCE_BANDWIDTH;
o->distance_table = route_table_init();
o->rt_aggr_tbl = route_table_init();
o->aggr_delay_interval = OSPF6_EXTL_AGGR_DEFAULT_DELAY;
o->t_external_aggr = NULL;
o->aggr_action = OSPF6_ROUTE_AGGR_NONE;
o->fd = -1;
o->max_multipath = MULTIPATH_NUM;
@ -461,6 +479,7 @@ struct ospf6 *ospf6_instance_create(const char *name)
void ospf6_delete(struct ospf6 *o)
{
struct listnode *node, *nnode;
struct route_node *rn = NULL;
struct ospf6_area *oa;
struct vrf *vrf;
@ -499,6 +518,11 @@ void ospf6_delete(struct ospf6 *o)
ospf6_vrf_unlink(o, vrf);
}
for (rn = route_top(o->rt_aggr_tbl); rn; rn = route_next(rn))
if (rn->info)
ospf6_external_aggregator_free(rn->info);
route_table_finish(o->rt_aggr_tbl);
XFREE(MTYPE_OSPF6_TOP, o->name);
XFREE(MTYPE_OSPF6_TOP, o);
}
@ -527,6 +551,7 @@ static void ospf6_disable(struct ospf6 *o)
THREAD_OFF(o->t_ase_calc);
THREAD_OFF(o->t_distribute_update);
THREAD_OFF(o->t_ospf6_receive);
THREAD_OFF(o->t_external_aggr);
}
}
@ -690,6 +715,7 @@ static void ospf6_process_reset(struct ospf6 *ospf6)
struct interface *ifp;
struct vrf *vrf = vrf_lookup_by_id(ospf6->vrf_id);
ospf6_unset_all_aggr_flag(ospf6);
ospf6_flush_self_originated_lsas_now(ospf6);
ospf6->inst_shutdown = 0;
ospf6_db_clear(ospf6);
@ -1654,6 +1680,424 @@ DEFUN(show_ipv6_ospf6_route_type_detail, show_ipv6_ospf6_route_type_detail_cmd,
return CMD_SUCCESS;
}
bool ospf6_is_valid_summary_addr(struct vty *vty, struct prefix *p)
{
struct in6_addr addr_zero;
memset(&addr_zero, 0, sizeof(struct in6_addr));
/* Default prefix validation*/
if ((is_default_prefix((struct prefix *)p))
|| (!memcmp(&p->u.prefix6, &addr_zero, sizeof(struct in6_addr)))) {
vty_out(vty, "Default address should not be configured as summary address.\n");
return false;
}
/* Host route should not be configured as summary address */
if (p->prefixlen == IPV6_MAX_BITLEN) {
vty_out(vty, "Host route should not be configured as summary address.\n");
return false;
}
return true;
}
/* External Route Aggregation */
DEFPY (ospf6_external_route_aggregation,
ospf6_external_route_aggregation_cmd,
"summary-address X:X::X:X/M$prefix [tag (1-4294967295)] [{metric (0-16777215) | metric-type (1-2)$mtype}]",
"External summary address\n"
"Specify IPv6 prefix\n"
"Router tag \n"
"Router tag value\n"
"Metric \n"
"Advertised metric for this route\n"
"OSPFv3 exterior metric type for summarised routes\n"
"Set OSPFv3 External Type 1/2 metrics\n")
{
VTY_DECLVAR_CONTEXT(ospf6, ospf6);
struct prefix p;
int ret = CMD_SUCCESS;
p.family = AF_INET6;
ret = str2prefix(prefix_str, &p);
if (ret == 0) {
vty_out(vty, "Malformed prefix\n");
return CMD_WARNING_CONFIG_FAILED;
}
/* Apply mask for given prefix. */
apply_mask((struct prefix *)&p);
if (!ospf6_is_valid_summary_addr(vty, &p))
return CMD_WARNING_CONFIG_FAILED;
if (!tag_str)
tag = 0;
if (!metric_str)
metric = -1;
if (!mtype_str)
mtype = DEFAULT_METRIC_TYPE;
ret = ospf6_external_aggr_config_set(ospf6, &p, tag, metric, mtype);
if (ret == OSPF6_FAILURE) {
vty_out(vty, "Invalid configuration!!\n");
return CMD_WARNING_CONFIG_FAILED;
}
return CMD_SUCCESS;
}
DEFPY(no_ospf6_external_route_aggregation,
no_ospf6_external_route_aggregation_cmd,
"no summary-address X:X::X:X/M$prefix [tag (1-4294967295)] [{metric (0-16777215) | metric-type (1-2)}]",
NO_STR
"External summary address\n"
"Specify IPv6 prefix\n"
"Router tag\n"
"Router tag value\n"
"Metric \n"
"Advertised metric for this route\n"
"OSPFv3 exterior metric type for summarised routes\n"
"Set OSPFv3 External Type 1/2 metrics\n")
{
VTY_DECLVAR_CONTEXT(ospf6, ospf6);
struct prefix p;
int ret = CMD_SUCCESS;
ret = str2prefix(prefix_str, &p);
if (ret == 0) {
vty_out(vty, "Malformed prefix\n");
return CMD_WARNING_CONFIG_FAILED;
}
/* Apply mask for given prefix. */
apply_mask((struct prefix *)&p);
if (!ospf6_is_valid_summary_addr(vty, &p))
return CMD_WARNING_CONFIG_FAILED;
ret = ospf6_external_aggr_config_unset(ospf6, &p);
if (ret == OSPF6_INVALID)
vty_out(vty, "Invalid configuration!!\n");
return CMD_SUCCESS;
}
DEFPY (ospf6_external_route_aggregation_no_advertise,
ospf6_external_route_aggregation_no_advertise_cmd,
"summary-address X:X::X:X/M$prefix no-advertise",
"External summary address\n"
"Specify IPv6 prefix\n"
"Don't advertise summary route \n")
{
VTY_DECLVAR_CONTEXT(ospf6, ospf6);
struct prefix p;
int ret = CMD_SUCCESS;
ret = str2prefix(prefix_str, &p);
if (ret == 0) {
vty_out(vty, "Malformed prefix\n");
return CMD_WARNING_CONFIG_FAILED;
}
/* Apply mask for given prefix. */
apply_mask((struct prefix *)&p);
if (!ospf6_is_valid_summary_addr(vty, &p))
return CMD_WARNING_CONFIG_FAILED;
ret = ospf6_asbr_external_rt_no_advertise(ospf6, &p);
if (ret == OSPF6_INVALID)
vty_out(vty, "!!Invalid configuration\n");
return CMD_SUCCESS;
}
DEFPY (no_ospf6_external_route_aggregation_no_advertise,
no_ospf6_external_route_aggregation_no_advertise_cmd,
"no summary-address X:X::X:X/M$prefix no-advertise",
NO_STR
"External summary address\n"
"Specify IPv6 prefix\n"
"Adverise summary route to the AS \n")
{
VTY_DECLVAR_CONTEXT(ospf6, ospf6);
struct prefix p;
int ret = CMD_SUCCESS;
ret = str2prefix(prefix_str, &p);
if (ret == 0) {
vty_out(vty, "Malformed prefix\n");
return CMD_WARNING_CONFIG_FAILED;
}
/* Apply mask for given prefix. */
apply_mask((struct prefix *)&p);
if (!ospf6_is_valid_summary_addr(vty, &p))
return CMD_WARNING_CONFIG_FAILED;
ret = ospf6_asbr_external_rt_advertise(ospf6, &p);
if (ret == OSPF6_INVALID)
vty_out(vty, "!!Invalid configuration\n");
return CMD_SUCCESS;
}
DEFPY (ospf6_route_aggregation_timer,
ospf6_route_aggregation_timer_cmd,
"aggregation timer (5-1800)",
"External route aggregation\n"
"Delay timer (in seconds)\n"
"Timer interval(in seconds)\n")
{
VTY_DECLVAR_CONTEXT(ospf6, ospf6);
ospf6_external_aggr_delay_timer_set(ospf6, timer);
return CMD_SUCCESS;
}
DEFPY (no_ospf6_route_aggregation_timer,
no_ospf6_route_aggregation_timer_cmd,
"no aggregation timer [5-1800]",
NO_STR
"External route aggregation\n"
"Delay timer\n"
"Timer interval(in seconds)\n")
{
VTY_DECLVAR_CONTEXT(ospf6, ospf6);
ospf6_external_aggr_delay_timer_set(ospf6,
OSPF6_EXTL_AGGR_DEFAULT_DELAY);
return CMD_SUCCESS;
}
static int
ospf6_print_vty_external_routes_walkcb(struct hash_bucket *bucket, void *arg)
{
struct ospf6_route *rt = bucket->data;
struct vty *vty = (struct vty *)arg;
static unsigned int count;
vty_out(vty, "%pFX ", &rt->prefix);
count++;
if (count%5 == 0)
vty_out(vty, "\n");
if (OSPF6_EXTERNAL_RT_COUNT(rt->aggr_route) == count)
count = 0;
return HASHWALK_CONTINUE;
}
static int
ospf6_print_json_external_routes_walkcb(struct hash_bucket *bucket, void *arg)
{
struct ospf6_route *rt = bucket->data;
struct json_object *json = (struct json_object *)arg;
char buf[PREFIX2STR_BUFFER];
char exnalbuf[20];
static unsigned int count;
prefix2str(&rt->prefix, buf, sizeof(buf));
snprintf(exnalbuf, sizeof(exnalbuf), "Exnl Addr-%d", count);
json_object_string_add(json, exnalbuf, buf);
count++;
if (OSPF6_EXTERNAL_RT_COUNT(rt->aggr_route) == count)
count = 0;
return HASHWALK_CONTINUE;
}
static void
ospf6_show_vrf_name(struct vty *vty, struct ospf6 *ospf6,
json_object *json)
{
if (json) {
if (ospf6->vrf_id == VRF_DEFAULT)
json_object_string_add(json, "vrfName",
"default");
else
json_object_string_add(json, "vrfName",
ospf6->name);
json_object_int_add(json, "vrfId", ospf6->vrf_id);
} else {
if (ospf6->vrf_id == VRF_DEFAULT)
vty_out(vty, "VRF Name: %s\n", "default");
else if (ospf6->name)
vty_out(vty, "VRF Name: %s\n", ospf6->name);
}
}
static int
ospf6_show_summary_address(struct vty *vty, struct ospf6 *ospf6,
json_object *json,
bool uj, const char *detail)
{
struct route_node *rn;
static const char header[] = "Summary-address Metric-type Metric Tag External_Rt_count\n";
json_object *json_vrf = NULL;
if (!uj) {
ospf6_show_vrf_name(vty, ospf6, json_vrf);
vty_out(vty, "aggregation delay interval :%d(in seconds)\n\n",
ospf6->aggr_delay_interval);
vty_out(vty, "%s\n", header);
} else {
json_vrf = json_object_new_object();
ospf6_show_vrf_name(vty, ospf6, json_vrf);
json_object_int_add(json_vrf, "aggregation delay interval",
ospf6->aggr_delay_interval);
}
for (rn = route_top(ospf6->rt_aggr_tbl); rn; rn = route_next(rn)) {
if (!rn->info)
continue;
struct ospf6_external_aggr_rt *aggr = rn->info;
json_object *json_aggr = NULL;
char buf[PREFIX2STR_BUFFER];
prefix2str(&aggr->p, buf, sizeof(buf));
if (uj) {
json_aggr = json_object_new_object();
json_object_object_add(json_vrf,
buf,
json_aggr);
json_object_string_add(json_aggr,
"Summary address",
buf);
json_object_string_add(
json_aggr, "Metric-type",
(aggr->mtype == DEFAULT_METRIC_TYPE)
? "E2"
: "E1");
json_object_int_add(json_aggr, "Metric",
(aggr->metric != -1)
? aggr->metric
: DEFAULT_DEFAULT_METRIC);
json_object_int_add(json_aggr, "Tag",
aggr->tag);
json_object_int_add(json_aggr,
"External route count",
OSPF6_EXTERNAL_RT_COUNT(aggr));
if (OSPF6_EXTERNAL_RT_COUNT(aggr) && detail) {
json_object_int_add(json_aggr, "ID",
aggr->id);
json_object_int_add(json_aggr, "Flags",
aggr->aggrflags);
hash_walk(aggr->match_extnl_hash,
ospf6_print_json_external_routes_walkcb,
json_aggr);
}
} else {
vty_out(vty, "%-22s", buf);
(aggr->mtype == DEFAULT_METRIC_TYPE)
? vty_out(vty, "%-16s", "E2")
: vty_out(vty, "%-16s", "E1");
vty_out(vty, "%-11d", (aggr->metric != -1)
? aggr->metric
: DEFAULT_DEFAULT_METRIC);
vty_out(vty, "%-12u", aggr->tag);
vty_out(vty, "%-5ld\n",
OSPF6_EXTERNAL_RT_COUNT(aggr));
if (OSPF6_EXTERNAL_RT_COUNT(aggr) && detail) {
vty_out(vty,
"Matched External routes:\n");
hash_walk(aggr->match_extnl_hash,
ospf6_print_vty_external_routes_walkcb,
vty);
vty_out(vty, "\n");
}
vty_out(vty, "\n");
}
}
if (uj)
json_object_object_add(json, ospf6->name,
json_vrf);
return CMD_SUCCESS;
}
DEFPY (show_ipv6_ospf6_external_aggregator,
show_ipv6_ospf6_external_aggregator_cmd,
"show ipv6 ospf6 [vrf <NAME|all>] summary-address [detail$detail] [json]",
SHOW_STR
IP6_STR
OSPF6_STR
VRF_CMD_HELP_STR
"All VRFs\n"
"Show external summary addresses\n"
"detailed informtion\n"
JSON_STR)
{
bool uj = use_json(argc, argv);
struct ospf6 *ospf6 = NULL;
json_object *json = NULL;
const char *vrf_name = NULL;
struct listnode *node;
bool all_vrf = false;
int idx_vrf = 0;
if (uj)
json = json_object_new_object();
OSPF6_CMD_CHECK_RUNNING();
OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
for (ALL_LIST_ELEMENTS_RO(om6->ospf6, node, ospf6)) {
if (all_vrf || strcmp(ospf6->name, vrf_name) == 0) {
ospf6_show_summary_address(vty, ospf6, json, uj,
detail);
if (!all_vrf)
break;
}
}
if (uj) {
vty_out(vty, "%s\n", json_object_to_json_string_ext(
json, JSON_C_TO_STRING_PRETTY));
json_object_free(json);
}
return CMD_SUCCESS;
}
static void ospf6_stub_router_config_write(struct vty *vty, struct ospf6 *ospf6)
{
if (CHECK_FLAG(ospf6->flag, OSPF6_STUB_ROUTER)) {
@ -1693,6 +2137,44 @@ static int ospf6_distance_config_write(struct vty *vty, struct ospf6 *ospf6)
return 0;
}
static int ospf6_asbr_summary_config_write(struct vty *vty, struct ospf6 *ospf6)
{
struct route_node *rn;
struct ospf6_external_aggr_rt *aggr;
char buf[PREFIX2STR_BUFFER];
if (ospf6->aggr_delay_interval != OSPF6_EXTL_AGGR_DEFAULT_DELAY)
vty_out(vty, " aggregation timer %u\n",
ospf6->aggr_delay_interval);
/* print 'summary-address A:B::C:D/M' */
for (rn = route_top(ospf6->rt_aggr_tbl); rn; rn = route_next(rn)) {
if (!rn->info)
continue;
aggr = rn->info;
prefix2str(&aggr->p, buf, sizeof(buf));
vty_out(vty, " summary-address %s", buf);
if (aggr->tag)
vty_out(vty, " tag %u", aggr->tag);
if (aggr->metric != -1)
vty_out(vty, " metric %d", aggr->metric);
if (aggr->mtype != DEFAULT_METRIC_TYPE)
vty_out(vty, " metric-type %d", aggr->mtype);
if (CHECK_FLAG(aggr->aggrflags,
OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE))
vty_out(vty, " no-advertise");
vty_out(vty, "\n");
}
return 0;
}
/* OSPF configuration write function. */
static int config_write_ospf6(struct vty *vty)
{
@ -1750,6 +2232,7 @@ static int config_write_ospf6(struct vty *vty)
ospf6_spf_config_write(vty, ospf6);
ospf6_distance_config_write(vty, ospf6);
ospf6_distribute_config_write(vty, ospf6);
ospf6_asbr_summary_config_write(vty, ospf6);
vty_out(vty, "!\n");
}
@ -1808,6 +2291,17 @@ void ospf6_top_init(void)
install_element(OSPF6_NODE, &ospf6_max_multipath_cmd);
install_element(OSPF6_NODE, &no_ospf6_max_multipath_cmd);
/* ASBR Summarisation */
install_element(OSPF6_NODE, &ospf6_external_route_aggregation_cmd);
install_element(OSPF6_NODE, &no_ospf6_external_route_aggregation_cmd);
install_element(OSPF6_NODE,
&ospf6_external_route_aggregation_no_advertise_cmd);
install_element(OSPF6_NODE,
&no_ospf6_external_route_aggregation_no_advertise_cmd);
install_element(OSPF6_NODE, &ospf6_route_aggregation_timer_cmd);
install_element(OSPF6_NODE, &no_ospf6_route_aggregation_timer_cmd);
install_element(VIEW_NODE, &show_ipv6_ospf6_external_aggregator_cmd);
install_element(OSPF6_NODE, &ospf6_distance_cmd);
install_element(OSPF6_NODE, &no_ospf6_distance_cmd);
install_element(OSPF6_NODE, &ospf6_distance_ospf6_cmd);

View file

@ -91,6 +91,7 @@ struct ospf6 {
struct ospf6_route_table *external_table;
struct route_table *external_id_table;
#define OSPF6_EXT_INIT_LS_ID 1
uint32_t external_id;
/* OSPF6 redistribute configuration */
@ -130,6 +131,7 @@ struct ospf6 {
struct thread *maxage_remover;
struct thread *t_distribute_update; /* Distirbute update timer. */
struct thread *t_ospf6_receive; /* OSPF6 receive timer */
struct thread *t_external_aggr; /* OSPF6 aggregation timer */
#define OSPF6_WRITE_INTERFACE_COUNT_DEFAULT 20
struct thread *t_write;
@ -158,6 +160,16 @@ struct ospf6 {
struct list *oi_write_q;
uint32_t redist_count;
/* Action for aggregation of external LSAs */
int aggr_action;
#define OSPF6_EXTL_AGGR_DEFAULT_DELAY 5
/* For ASBR summary delay timer */
int aggr_delay_interval;
/* Table of configured Aggregate addresses */
struct route_table *rt_aggr_tbl;
QOBJ_FIELDS;
};
DECLARE_QOBJ_TYPE(ospf6);
@ -184,4 +196,5 @@ struct ospf6 *ospf6_lookup_by_vrf_id(vrf_id_t vrf_id);
struct ospf6 *ospf6_lookup_by_vrf_name(const char *name);
const char *ospf6_vrf_id_to_name(vrf_id_t vrf_id);
void ospf6_vrf_init(void);
bool ospf6_is_valid_summary_addr(struct vty *vty, struct prefix *p);
#endif /* OSPF6_TOP_H */

View file

@ -49,6 +49,10 @@ extern struct thread_master *master;
#define MSG_OK 0
#define MSG_NG 1
#define OSPF6_SUCCESS 1
#define OSPF6_FAILURE 0
#define OSPF6_INVALID -1
/* cast macro: XXX - these *must* die, ick ick. */
#define OSPF6_PROCESS(x) ((struct ospf6 *) (x))
#define OSPF6_AREA(x) ((struct ospf6_area *) (x))

View file

@ -90,6 +90,7 @@ ospf6d_ospf6d_snmp_la_LIBADD = lib/libfrrsnmp.la
clippy_scan += \
ospf6d/ospf6_top.c \
ospf6d/ospf6_asbr.c \
ospf6d/ospf6_lsa.c \
# end
nodist_ospf6d_ospf6d_SOURCES = \

View file

@ -1517,7 +1517,7 @@ def verify_ospf_database(tgen, topo, dut, input_dict, expected=True):
@retry(retry_timeout=20)
def verify_ospf_summary(tgen, topo, dut, input_dict, expected=True):
def verify_ospf_summary(tgen, topo, dut, input_dict, ospf=None, expected=True):
"""
This API is to verify ospf routes by running
show ip ospf interface command.
@ -1528,7 +1528,6 @@ def verify_ospf_summary(tgen, topo, dut, input_dict, expected=True):
* `topo` : topology descriptions
* `dut`: device under test
* `input_dict` : Input dict data, required when configuring from testcase
* `expected` : expected results from API, by-default True
Usage
-----
@ -1548,18 +1547,30 @@ def verify_ospf_summary(tgen, topo, dut, input_dict, expected=True):
True or False (Error Message)
"""
logger.debug("Entering lib API: verify_ospf_summary()")
logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
result = False
router = dut
logger.info("Verifying OSPF summary on router %s:", router)
if "ospf" not in topo["routers"][dut]:
errormsg = "[DUT: {}] OSPF is not configured on the router.".format(router)
return errormsg
rnode = tgen.routers()[dut]
show_ospf_json = run_frr_cmd(rnode, "show ip ospf summary detail json", isjson=True)
if ospf:
if 'ospf6' not in topo['routers'][dut]:
errormsg = "[DUT: {}] OSPF6 is not configured on the router.".format(
router)
return errormsg
show_ospf_json = run_frr_cmd(rnode, "show ipv6 ospf summary detail json",
isjson=True)
else:
if 'ospf' not in topo['routers'][dut]:
errormsg = "[DUT: {}] OSPF is not configured on the router.".format(
router)
return errormsg
show_ospf_json = run_frr_cmd(rnode, "show ip ospf summary detail json",
isjson=True)
# Verifying output dictionary show_ospf_json is empty or not
if not bool(show_ospf_json):
@ -1568,35 +1579,31 @@ def verify_ospf_summary(tgen, topo, dut, input_dict, expected=True):
# To find neighbor ip type
ospf_summary_data = input_dict
if ospf:
show_ospf_json = show_ospf_json['default']
for ospf_summ, summ_data in ospf_summary_data.items():
if ospf_summ not in show_ospf_json:
continue
summary = ospf_summary_data[ospf_summ]["Summary address"]
summary = ospf_summary_data[ospf_summ]['Summary address']
if summary in show_ospf_json:
for summ in summ_data:
if summ_data[summ] == show_ospf_json[summary][summ]:
logger.info(
"[DUT: %s] OSPF summary %s:%s is %s",
router,
summary,
summ,
summ_data[summ],
)
logger.info("[DUT: %s] OSPF summary %s:%s is %s",
router, summary, summ, summ_data[summ])
result = True
else:
errormsg = (
"[DUT: {}] OSPF summary {}:{} is %s, "
"Expected is {}".format(
router, summary, summ, show_ospf_json[summary][summ]
)
)
errormsg = ("[DUT: {}] OSPF summary {} : {} is {}, "
"Expected is {}".format(router, summary, summ,show_ospf_json[
summary][summ], summ_data[summ] ))
return errormsg
logger.debug("Exiting API: verify_ospf_summary()")
logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
return result
@retry(retry_timeout=30)
def verify_ospf6_rib(tgen, dut, input_dict, next_hop=None,
tag=None, metric=None, fib=None):

View file

@ -0,0 +1,198 @@
{
"address_types": [
"ipv6"
],
"ipv6base": "fd00::",
"ipv6mask": 64,
"link_ip_start": {
"ipv6": "fd00::",
"v6mask": 64
},
"lo_prefix": {
"ipv6": "2001:db8:f::",
"v6mask": 128
},
"routers": {
"r0": {
"links": {
"lo": {
"ipv6": "auto",
"type": "loopback"
},
"r1": {
"ipv6": "auto",
"ospf6": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
},
"r2": {
"ipv6": "auto",
"ospf6": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
},
"r3": {
"ipv6": "auto",
"ospf6": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4,
"network": "point-to-point"
}
},
"r3-link0": {
"ipv6": "auto",
"description": "DummyIntftoR3"
}
},
"ospf6": {
"router_id": "100.1.1.0",
"neighbors": {
"r1": {},
"r2": {},
"r3": {}
}
}
},
"r1": {
"links": {
"lo": {
"ipv6": "auto",
"type": "loopback"
},
"r0": {
"ipv6": "auto",
"ospf6": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
},
"r2": {
"ipv6": "auto",
"ospf6": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
},
"r3": {
"ipv6": "auto",
"ospf6": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
},
"r3-link0": {
"ipv6": "auto",
"description": "DummyIntftoR3"
}
},
"ospf6": {
"router_id": "100.1.1.1",
"neighbors": {
"r0": {},
"r2": {},
"r3": {}
}
}
},
"r2": {
"links": {
"lo": {
"ipv6": "auto",
"type": "loopback"
},
"r0": {
"ipv6": "auto",
"ospf6": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
},
"r1": {
"ipv6": "auto",
"ospf6": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
},
"r3": {
"ipv6": "auto",
"ospf6": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
}
},
"ospf6": {
"router_id": "100.1.1.2",
"neighbors": {
"r1": {},
"r0": {},
"r3": {}
}
}
},
"r3": {
"links": {
"lo": {
"ipv6": "auto",
"type": "loopback"
},
"r0": {
"ipv6": "auto",
"ospf6": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4,
"network": "point-to-point"
}
},
"r0-link0": {
"ipv6": "auto",
"description": "DummyIntftoR0"
},
"r1": {
"ipv6": "auto",
"ospf6": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
},
"r2": {
"ipv6": "auto",
"ospf6": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
},
"r1-link0": {
"ipv6": "auto",
"description": "DummyIntftoR1",
"ospf6": {
"area": "0.0.0.0"
}
}
},
"ospf6": {
"router_id": "100.1.1.3",
"neighbors": {
"r0": {},
"r1": {},
"r2": {}
}
}
}
}
}

File diff suppressed because it is too large Load diff