forked from Mirror/frr
Merge pull request #9028 from mobash-rasool/ospfv3-asbr-summarisation
Ospfv3 ASBR summarisation feature
This commit is contained in:
commit
e448fefbb4
|
@ -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 don’t 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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
1215
ospf6d/ospf6_asbr.c
1215
ospf6d/ospf6_asbr.c
File diff suppressed because it is too large
Load diff
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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 = \
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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
Loading…
Reference in a new issue