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
|
change to take effect, user can use this cli instead of restarting the
|
||||||
ospf6d daemon.
|
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:
|
.. _ospf6-debugging:
|
||||||
|
|
||||||
OSPFv3 Debugging
|
OSPFv3 Debugging
|
||||||
|
|
|
@ -715,7 +715,7 @@ void ospf6_abr_defaults_to_stub(struct ospf6 *o)
|
||||||
if (!o->backbone)
|
if (!o->backbone)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
def = ospf6_route_create();
|
def = ospf6_route_create(o);
|
||||||
def->type = OSPF6_DEST_TYPE_NETWORK;
|
def->type = OSPF6_DEST_TYPE_NETWORK;
|
||||||
def->prefix.family = AF_INET6;
|
def->prefix.family = AF_INET6;
|
||||||
def->prefix.prefixlen = 0;
|
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
|
/* (5),(6): the path preference is handled by the sorting
|
||||||
in the routing table. Always install the path by substituting
|
in the routing table. Always install the path by substituting
|
||||||
old route (if any). */
|
old route (if any). */
|
||||||
route = ospf6_route_create();
|
route = ospf6_route_create(oa->ospf6);
|
||||||
|
|
||||||
route->type = type;
|
route->type = type;
|
||||||
route->prefix = prefix;
|
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));
|
listcount(old_route->nh_list));
|
||||||
}
|
}
|
||||||
} else {
|
} 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,
|
ospf6_copy_nexthops(tmp_route->nh_list,
|
||||||
o_path->nh_list);
|
o_path->nh_list);
|
||||||
|
|
|
@ -519,7 +519,7 @@ DEFUN (area_range,
|
||||||
|
|
||||||
range = ospf6_route_lookup(&prefix, oa->range_table);
|
range = ospf6_route_lookup(&prefix, oa->range_table);
|
||||||
if (range == NULL) {
|
if (range == NULL) {
|
||||||
range = ospf6_route_create();
|
range = ospf6_route_create(ospf6);
|
||||||
range->type = OSPF6_DEST_TYPE_RANGE;
|
range->type = OSPF6_DEST_TYPE_RANGE;
|
||||||
range->prefix = prefix;
|
range->prefix = prefix;
|
||||||
range->path.area_id = oa->area_id;
|
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;
|
route_tag_t tag;
|
||||||
|
|
||||||
ifindex_t ifindex;
|
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 */
|
/* 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,
|
struct ospf6_redist *ospf6_redist_lookup(struct ospf6 *ospf6, int type,
|
||||||
unsigned short instance);
|
unsigned short instance);
|
||||||
extern void ospf6_asbr_routemap_update(const char *mapname);
|
extern void ospf6_asbr_routemap_update(const char *mapname);
|
||||||
extern void ospf6_as_external_lsa_originate(struct ospf6_route *route,
|
extern struct ospf6_lsa *
|
||||||
struct ospf6 *ospf6);
|
ospf6_as_external_lsa_originate(struct ospf6_route *route,
|
||||||
|
struct ospf6 *ospf6);
|
||||||
extern void ospf6_asbr_status_update(struct ospf6 *ospf6, int status);
|
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 */
|
#endif /* OSPF6_ASBR_H */
|
||||||
|
|
|
@ -116,7 +116,7 @@ void ospf6_lsa_originate(struct ospf6_lsa *lsa)
|
||||||
lsdb_self = ospf6_get_scoped_lsdb_self(lsa);
|
lsdb_self = ospf6_get_scoped_lsdb_self(lsa);
|
||||||
ospf6_lsdb_add(ospf6_lsa_copy(lsa), lsdb_self);
|
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,
|
thread_add_timer(master, ospf6_lsa_refresh, lsa, OSPF_LS_REFRESH_TIME,
|
||||||
&lsa->refresh);
|
&lsa->refresh);
|
||||||
|
|
||||||
|
@ -149,6 +149,31 @@ void ospf6_lsa_originate_interface(struct ospf6_lsa *lsa,
|
||||||
ospf6_lsa_originate(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)
|
void ospf6_lsa_purge(struct ospf6_lsa *lsa)
|
||||||
{
|
{
|
||||||
struct ospf6_lsa *self;
|
struct ospf6_lsa *self;
|
||||||
|
|
|
@ -39,6 +39,9 @@ extern void ospf6_lsa_originate_area(struct ospf6_lsa *lsa,
|
||||||
struct ospf6_area *oa);
|
struct ospf6_area *oa);
|
||||||
extern void ospf6_lsa_originate_interface(struct ospf6_lsa *lsa,
|
extern void ospf6_lsa_originate_interface(struct ospf6_lsa *lsa,
|
||||||
struct ospf6_interface *oi);
|
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(struct ospf6_lsa *lsa);
|
||||||
|
|
||||||
extern void ospf6_lsa_purge_multi_ls_id(struct ospf6_area *oa,
|
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));
|
memcpy(&route->prefix, c->address, sizeof(struct prefix));
|
||||||
apply_mask(&route->prefix);
|
apply_mask(&route->prefix);
|
||||||
route->type = OSPF6_DEST_TYPE_NETWORK;
|
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)
|
|| current + OSPF6_PREFIX_SIZE(op) > end)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
route = ospf6_route_create();
|
route = ospf6_route_create(oi->area->ospf6);
|
||||||
|
|
||||||
route->type = OSPF6_DEST_TYPE_NETWORK;
|
route->type = OSPF6_DEST_TYPE_NETWORK;
|
||||||
route->prefix.family = AF_INET6;
|
route->prefix.family = AF_INET6;
|
||||||
|
@ -1790,7 +1790,7 @@ void ospf6_intra_prefix_lsa_add(struct ospf6_lsa *lsa)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
route = ospf6_route_create();
|
route = ospf6_route_create(oa->ospf6);
|
||||||
|
|
||||||
memset(&route->prefix, 0, sizeof(struct prefix));
|
memset(&route->prefix, 0, sizeof(struct prefix));
|
||||||
route->prefix.family = AF_INET6;
|
route->prefix.family = AF_INET6;
|
||||||
|
|
|
@ -45,6 +45,10 @@
|
||||||
#include "ospf6_flood.h"
|
#include "ospf6_flood.h"
|
||||||
#include "ospf6d.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, "OSPF6 LSA");
|
||||||
DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_LSA_HEADER, "OSPF6 LSA header");
|
DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_LSA_HEADER, "OSPF6 LSA header");
|
||||||
DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_LSA_SUMMARY, "OSPF6 LSA summary");
|
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))
|
if (CHECK_FLAG(lsa->flag, OSPF6_LSA_HEADERONLY))
|
||||||
return 0; /* dbexchange will do something ... */
|
return 0; /* dbexchange will do something ... */
|
||||||
ospf6 = ospf6_get_by_lsdb(lsa);
|
ospf6 = ospf6_get_by_lsdb(lsa);
|
||||||
|
assert(ospf6);
|
||||||
|
|
||||||
/* reinstall lsa */
|
/* reinstall lsa */
|
||||||
ospf6_install_lsa(lsa);
|
ospf6_install_lsa(lsa);
|
||||||
|
|
||||||
|
@ -994,6 +1000,30 @@ static char *ospf6_lsa_handler_name(const struct ospf6_lsa_handler *h)
|
||||||
return buf;
|
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,
|
DEFUN (debug_ospf6_lsa_type,
|
||||||
debug_ospf6_lsa_hex_cmd,
|
debug_ospf6_lsa_hex_cmd,
|
||||||
"debug ospf6 lsa <router|network|inter-prefix|inter-router|as-external|link|intra-prefix|unknown> [<originate|examine|flooding>]",
|
"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(ENABLE_NODE, &no_debug_ospf6_lsa_hex_cmd);
|
||||||
install_element(CONFIG_NODE, &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(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)
|
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))
|
if (CHECK_FLAG(handler->lh_debug, OSPF6_LSA_DEBUG_FLOOD))
|
||||||
vty_out(vty, "debug ospf6 lsa %s flooding\n",
|
vty_out(vty, "debug ospf6 lsa %s flooding\n",
|
||||||
ospf6_lsa_handler_name(handler));
|
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;
|
return 0;
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#define OSPF6_LSA_DEBUG_ORIGINATE 0x02
|
#define OSPF6_LSA_DEBUG_ORIGINATE 0x02
|
||||||
#define OSPF6_LSA_DEBUG_EXAMIN 0x04
|
#define OSPF6_LSA_DEBUG_EXAMIN 0x04
|
||||||
#define OSPF6_LSA_DEBUG_FLOOD 0x08
|
#define OSPF6_LSA_DEBUG_FLOOD 0x08
|
||||||
|
#define OSPF6_LSA_DEBUG_AGGR 0x10
|
||||||
|
|
||||||
/* OSPF LSA Default metric values */
|
/* OSPF LSA Default metric values */
|
||||||
#define DEFAULT_DEFAULT_METRIC 20
|
#define DEFAULT_DEFAULT_METRIC 20
|
||||||
|
@ -51,6 +52,8 @@
|
||||||
(ospf6_lstype_debug(type) & OSPF6_LSA_DEBUG_EXAMIN)
|
(ospf6_lstype_debug(type) & OSPF6_LSA_DEBUG_EXAMIN)
|
||||||
#define IS_OSPF6_DEBUG_FLOOD_TYPE(type) \
|
#define IS_OSPF6_DEBUG_FLOOD_TYPE(type) \
|
||||||
(ospf6_lstype_debug(type) & OSPF6_LSA_DEBUG_FLOOD)
|
(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 */
|
/* 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_lsa_age_set(struct ospf6_lsa *lsa);
|
||||||
extern void ospf6_flush_self_originated_lsas_now(struct ospf6 *ospf6);
|
extern void ospf6_flush_self_originated_lsas_now(struct ospf6 *ospf6);
|
||||||
extern struct ospf6 *ospf6_get_by_lsdb(struct ospf6_lsa *lsa);
|
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 */
|
#endif /* OSPF6_LSA_H */
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
#include "ospf6_proto.h"
|
#include "ospf6_proto.h"
|
||||||
#include "ospf6_lsa.h"
|
#include "ospf6_lsa.h"
|
||||||
#include "ospf6_lsdb.h"
|
#include "ospf6_lsdb.h"
|
||||||
|
#include "ospf6_asbr.h"
|
||||||
#include "ospf6_route.h"
|
#include "ospf6_route.h"
|
||||||
#include "ospf6d.h"
|
#include "ospf6d.h"
|
||||||
#include "bitfield.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;
|
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,
|
struct ospf6_lsa *ospf6_lsdb_lookup_next(uint16_t type, uint32_t id,
|
||||||
uint32_t adv_router,
|
uint32_t adv_router,
|
||||||
struct ospf6_lsdb *lsdb)
|
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 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 (IS_AREA_NSSA(area)) {
|
||||||
if (!ospf6_check_and_set_router_abr(area->ospf6))
|
if (!ospf6_check_and_set_router_abr(area->ospf6))
|
||||||
OSPF6_OPT_CLEAR(area->options, OSPF6_OPT_E);
|
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);
|
zlog_debug("NSSA area %s", area->name);
|
||||||
|
|
||||||
/* Originate NSSA LSA */
|
/* Originate NSSA LSA */
|
||||||
for (route = ospf6_route_head(
|
ospf6_check_and_originate_type7_lsa(area);
|
||||||
area->ospf6->external_table);
|
|
||||||
route; route = ospf6_route_next(route))
|
|
||||||
ospf6_nssa_lsa_originate(route, area);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Disable NSSA */
|
/* 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;
|
struct ospf6_nexthop nh_match;
|
||||||
|
|
||||||
if (nh_list) {
|
if (nh_list) {
|
||||||
nh_match.ifindex = ifindex;
|
if (addr) {
|
||||||
if (addr != NULL)
|
if (ifindex)
|
||||||
|
nh_match.type = NEXTHOP_TYPE_IPV6_IFINDEX;
|
||||||
|
else
|
||||||
|
nh_match.type = NEXTHOP_TYPE_IPV6;
|
||||||
|
|
||||||
memcpy(&nh_match.address, addr,
|
memcpy(&nh_match.address, addr,
|
||||||
sizeof(struct in6_addr));
|
sizeof(struct in6_addr));
|
||||||
else
|
} else {
|
||||||
|
nh_match.type = NEXTHOP_TYPE_IFINDEX;
|
||||||
|
|
||||||
memset(&nh_match.address, 0, sizeof(struct in6_addr));
|
memset(&nh_match.address, 0, sizeof(struct in6_addr));
|
||||||
|
}
|
||||||
|
|
||||||
|
nh_match.ifindex = ifindex;
|
||||||
|
|
||||||
if (!ospf6_route_find_nexthop(nh_list, &nh_match)) {
|
if (!ospf6_route_find_nexthop(nh_list, &nh_match)) {
|
||||||
nh = ospf6_nexthop_create();
|
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,
|
void ospf6_route_zebra_copy_nexthops(struct ospf6_route *route,
|
||||||
struct zapi_nexthop nexthops[],
|
struct zapi_nexthop nexthops[],
|
||||||
int entries, vrf_id_t vrf_id)
|
int entries, vrf_id_t vrf_id)
|
||||||
{
|
{
|
||||||
struct ospf6_nexthop *nh;
|
struct ospf6_nexthop *nh;
|
||||||
struct listnode *node;
|
struct listnode *node;
|
||||||
char buf[64];
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (route) {
|
if (route) {
|
||||||
i = 0;
|
i = 0;
|
||||||
for (ALL_LIST_ELEMENTS_RO(route->nh_list, node, nh)) {
|
for (ALL_LIST_ELEMENTS_RO(route->nh_list, node, nh)) {
|
||||||
if (IS_OSPF6_DEBUG_ZEBRA(SEND)) {
|
if (IS_OSPF6_DEBUG_ZEBRA(SEND)) {
|
||||||
const char *ifname;
|
zlog_debug(" nexthop: %s %pI6%%%.*s(%d)",
|
||||||
inet_ntop(AF_INET6, &nh->address, buf,
|
nexthop_type_to_str(nh->type),
|
||||||
sizeof(buf));
|
&nh->address, IFNAMSIZ,
|
||||||
ifname = ifindex2ifname(nh->ifindex, vrf_id);
|
ifindex2ifname(nh->ifindex, vrf_id),
|
||||||
zlog_debug(" nexthop: %s%%%.*s(%d)", buf,
|
nh->ifindex);
|
||||||
IFNAMSIZ, ifname, nh->ifindex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i >= entries)
|
if (i >= entries)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
nexthops[i].vrf_id = vrf_id;
|
nexthops[i].vrf_id = vrf_id;
|
||||||
nexthops[i].ifindex = nh->ifindex;
|
nexthops[i].type = nh->type;
|
||||||
if (!IN6_IS_ADDR_UNSPECIFIED(&nh->address)) {
|
|
||||||
|
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].gate.ipv6 = nh->address;
|
||||||
nexthops[i].type = NEXTHOP_TYPE_IPV6_IFINDEX;
|
break;
|
||||||
} else
|
}
|
||||||
nexthops[i].type = NEXTHOP_TYPE_IFINDEX;
|
|
||||||
i++;
|
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;
|
struct ospf6_route *route;
|
||||||
|
|
||||||
|
@ -415,6 +464,8 @@ struct ospf6_route *ospf6_route_create(void)
|
||||||
route->paths = list_new();
|
route->paths = list_new();
|
||||||
route->paths->cmp = (int (*)(void *, void *))ospf6_path_cmp;
|
route->paths->cmp = (int (*)(void *, void *))ospf6_path_cmp;
|
||||||
route->paths->del = (void (*)(void *))ospf6_path_free;
|
route->paths->del = (void (*)(void *))ospf6_path_free;
|
||||||
|
route->ospf6 = ospf6;
|
||||||
|
|
||||||
return route;
|
return route;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -433,7 +484,7 @@ struct ospf6_route *ospf6_route_copy(struct ospf6_route *route)
|
||||||
{
|
{
|
||||||
struct ospf6_route *new;
|
struct ospf6_route *new;
|
||||||
|
|
||||||
new = ospf6_route_create();
|
new = ospf6_route_create(route->ospf6);
|
||||||
new->type = route->type;
|
new->type = route->type;
|
||||||
memcpy(&new->prefix, &route->prefix, sizeof(struct prefix));
|
memcpy(&new->prefix, &route->prefix, sizeof(struct prefix));
|
||||||
new->prefix_options = route->prefix_options;
|
new->prefix_options = route->prefix_options;
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include "command.h"
|
#include "command.h"
|
||||||
#include "zclient.h"
|
#include "zclient.h"
|
||||||
#include "lib/json.h"
|
#include "lib/json.h"
|
||||||
|
#include "lib/nexthop.h"
|
||||||
|
|
||||||
#define OSPF6_MULTI_PATH_LIMIT 4
|
#define OSPF6_MULTI_PATH_LIMIT 4
|
||||||
|
|
||||||
|
@ -44,23 +45,60 @@ struct ospf6_nexthop {
|
||||||
|
|
||||||
/* IP address, if any */
|
/* IP address, if any */
|
||||||
struct in6_addr address;
|
struct in6_addr address;
|
||||||
|
|
||||||
|
/** Next-hop type information. */
|
||||||
|
enum nexthop_types_t type;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define ospf6_nexthop_is_set(x) \
|
static inline bool ospf6_nexthop_is_set(const struct ospf6_nexthop *nh)
|
||||||
((x)->ifindex || !IN6_IS_ADDR_UNSPECIFIED(&(x)->address))
|
{
|
||||||
#define ospf6_nexthop_is_same(a, b) \
|
return nh->type != 0;
|
||||||
((a)->ifindex == (b)->ifindex \
|
}
|
||||||
&& IN6_ARE_ADDR_EQUAL(&(a)->address, &(b)->address))
|
|
||||||
#define ospf6_nexthop_clear(x) \
|
static inline bool ospf6_nexthop_is_same(const struct ospf6_nexthop *nha,
|
||||||
do { \
|
const struct ospf6_nexthop *nhb)
|
||||||
(x)->ifindex = 0; \
|
{
|
||||||
memset(&(x)->address, 0, sizeof(struct in6_addr)); \
|
if (nha->type != nhb->type)
|
||||||
} while (0)
|
return false;
|
||||||
#define ospf6_nexthop_copy(a, b) \
|
|
||||||
do { \
|
switch (nha->type) {
|
||||||
(a)->ifindex = (b)->ifindex; \
|
case NEXTHOP_TYPE_BLACKHOLE:
|
||||||
memcpy(&(a)->address, &(b)->address, sizeof(struct in6_addr)); \
|
/* NOTHING */
|
||||||
} while (0)
|
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 */
|
/* Path */
|
||||||
struct ospf6_ls_origin {
|
struct ospf6_ls_origin {
|
||||||
|
@ -124,6 +162,9 @@ struct ospf6_route {
|
||||||
struct ospf6_route *prev;
|
struct ospf6_route *prev;
|
||||||
struct ospf6_route *next;
|
struct ospf6_route *next;
|
||||||
|
|
||||||
|
/* Back pointer to ospf6 */
|
||||||
|
struct ospf6 *ospf6;
|
||||||
|
|
||||||
unsigned int lock;
|
unsigned int lock;
|
||||||
|
|
||||||
/* Destination Type */
|
/* Destination Type */
|
||||||
|
@ -161,6 +202,12 @@ struct ospf6_route {
|
||||||
|
|
||||||
/* nexthop */
|
/* nexthop */
|
||||||
struct list *nh_list;
|
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
|
#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_merge_nexthops(struct list *dst, struct list *src);
|
||||||
extern void ospf6_add_nexthop(struct list *nh_list, int ifindex,
|
extern void ospf6_add_nexthop(struct list *nh_list, int ifindex,
|
||||||
struct in6_addr *addr);
|
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_num_nexthops(struct list *nh_list);
|
||||||
extern int ospf6_route_cmp_nexthops(struct ospf6_route *a,
|
extern int ospf6_route_cmp_nexthops(struct ospf6_route *a,
|
||||||
struct ospf6_route *b);
|
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) \
|
#define ospf6_route_add_nexthop(route, ifindex, addr) \
|
||||||
ospf6_add_nexthop(route->nh_list, 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 void ospf6_route_delete(struct ospf6_route *);
|
||||||
extern struct ospf6_route *ospf6_route_copy(struct ospf6_route *route);
|
extern struct ospf6_route *ospf6_route_copy(struct ospf6_route *route);
|
||||||
extern int ospf6_route_cmp(struct ospf6_route *ra, struct ospf6_route *rb);
|
extern 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. */
|
up to here. */
|
||||||
assert(route == NULL);
|
assert(route == NULL);
|
||||||
|
|
||||||
route = ospf6_route_create();
|
route = ospf6_route_create(v->area->ospf6);
|
||||||
memcpy(&route->prefix, &v->vertex_id, sizeof(struct prefix));
|
memcpy(&route->prefix, &v->vertex_id, sizeof(struct prefix));
|
||||||
route->type = OSPF6_DEST_TYPE_LINKSTATE;
|
route->type = OSPF6_DEST_TYPE_LINKSTATE;
|
||||||
route->path.type = OSPF6_PATH_TYPE_INTRA;
|
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 = OSPF6_ROUTE_TABLE_CREATE(GLOBAL, EXTERNAL_ROUTES);
|
||||||
o->external_table->scope = o;
|
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->external_id_table = route_table_init();
|
||||||
|
|
||||||
o->write_oi_count = OSPF6_WRITE_INTERFACE_COUNT_DEFAULT;
|
o->write_oi_count = OSPF6_WRITE_INTERFACE_COUNT_DEFAULT;
|
||||||
o->ref_bandwidth = OSPF6_REFERENCE_BANDWIDTH;
|
o->ref_bandwidth = OSPF6_REFERENCE_BANDWIDTH;
|
||||||
|
|
||||||
o->distance_table = route_table_init();
|
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->fd = -1;
|
||||||
|
|
||||||
o->max_multipath = MULTIPATH_NUM;
|
o->max_multipath = MULTIPATH_NUM;
|
||||||
|
@ -461,6 +479,7 @@ struct ospf6 *ospf6_instance_create(const char *name)
|
||||||
void ospf6_delete(struct ospf6 *o)
|
void ospf6_delete(struct ospf6 *o)
|
||||||
{
|
{
|
||||||
struct listnode *node, *nnode;
|
struct listnode *node, *nnode;
|
||||||
|
struct route_node *rn = NULL;
|
||||||
struct ospf6_area *oa;
|
struct ospf6_area *oa;
|
||||||
struct vrf *vrf;
|
struct vrf *vrf;
|
||||||
|
|
||||||
|
@ -499,6 +518,11 @@ void ospf6_delete(struct ospf6 *o)
|
||||||
ospf6_vrf_unlink(o, vrf);
|
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->name);
|
||||||
XFREE(MTYPE_OSPF6_TOP, o);
|
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_ase_calc);
|
||||||
THREAD_OFF(o->t_distribute_update);
|
THREAD_OFF(o->t_distribute_update);
|
||||||
THREAD_OFF(o->t_ospf6_receive);
|
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 interface *ifp;
|
||||||
struct vrf *vrf = vrf_lookup_by_id(ospf6->vrf_id);
|
struct vrf *vrf = vrf_lookup_by_id(ospf6->vrf_id);
|
||||||
|
|
||||||
|
ospf6_unset_all_aggr_flag(ospf6);
|
||||||
ospf6_flush_self_originated_lsas_now(ospf6);
|
ospf6_flush_self_originated_lsas_now(ospf6);
|
||||||
ospf6->inst_shutdown = 0;
|
ospf6->inst_shutdown = 0;
|
||||||
ospf6_db_clear(ospf6);
|
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;
|
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)
|
static void ospf6_stub_router_config_write(struct vty *vty, struct ospf6 *ospf6)
|
||||||
{
|
{
|
||||||
if (CHECK_FLAG(ospf6->flag, OSPF6_STUB_ROUTER)) {
|
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;
|
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. */
|
/* OSPF configuration write function. */
|
||||||
static int config_write_ospf6(struct vty *vty)
|
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_spf_config_write(vty, ospf6);
|
||||||
ospf6_distance_config_write(vty, ospf6);
|
ospf6_distance_config_write(vty, ospf6);
|
||||||
ospf6_distribute_config_write(vty, ospf6);
|
ospf6_distribute_config_write(vty, ospf6);
|
||||||
|
ospf6_asbr_summary_config_write(vty, ospf6);
|
||||||
|
|
||||||
vty_out(vty, "!\n");
|
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, &ospf6_max_multipath_cmd);
|
||||||
install_element(OSPF6_NODE, &no_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, &ospf6_distance_cmd);
|
||||||
install_element(OSPF6_NODE, &no_ospf6_distance_cmd);
|
install_element(OSPF6_NODE, &no_ospf6_distance_cmd);
|
||||||
install_element(OSPF6_NODE, &ospf6_distance_ospf6_cmd);
|
install_element(OSPF6_NODE, &ospf6_distance_ospf6_cmd);
|
||||||
|
|
|
@ -91,6 +91,7 @@ struct ospf6 {
|
||||||
|
|
||||||
struct ospf6_route_table *external_table;
|
struct ospf6_route_table *external_table;
|
||||||
struct route_table *external_id_table;
|
struct route_table *external_id_table;
|
||||||
|
#define OSPF6_EXT_INIT_LS_ID 1
|
||||||
uint32_t external_id;
|
uint32_t external_id;
|
||||||
|
|
||||||
/* OSPF6 redistribute configuration */
|
/* OSPF6 redistribute configuration */
|
||||||
|
@ -130,6 +131,7 @@ struct ospf6 {
|
||||||
struct thread *maxage_remover;
|
struct thread *maxage_remover;
|
||||||
struct thread *t_distribute_update; /* Distirbute update timer. */
|
struct thread *t_distribute_update; /* Distirbute update timer. */
|
||||||
struct thread *t_ospf6_receive; /* OSPF6 receive timer */
|
struct thread *t_ospf6_receive; /* OSPF6 receive timer */
|
||||||
|
struct thread *t_external_aggr; /* OSPF6 aggregation timer */
|
||||||
#define OSPF6_WRITE_INTERFACE_COUNT_DEFAULT 20
|
#define OSPF6_WRITE_INTERFACE_COUNT_DEFAULT 20
|
||||||
struct thread *t_write;
|
struct thread *t_write;
|
||||||
|
|
||||||
|
@ -158,6 +160,16 @@ struct ospf6 {
|
||||||
struct list *oi_write_q;
|
struct list *oi_write_q;
|
||||||
|
|
||||||
uint32_t redist_count;
|
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;
|
QOBJ_FIELDS;
|
||||||
};
|
};
|
||||||
DECLARE_QOBJ_TYPE(ospf6);
|
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);
|
struct ospf6 *ospf6_lookup_by_vrf_name(const char *name);
|
||||||
const char *ospf6_vrf_id_to_name(vrf_id_t vrf_id);
|
const char *ospf6_vrf_id_to_name(vrf_id_t vrf_id);
|
||||||
void ospf6_vrf_init(void);
|
void ospf6_vrf_init(void);
|
||||||
|
bool ospf6_is_valid_summary_addr(struct vty *vty, struct prefix *p);
|
||||||
#endif /* OSPF6_TOP_H */
|
#endif /* OSPF6_TOP_H */
|
||||||
|
|
|
@ -49,6 +49,10 @@ extern struct thread_master *master;
|
||||||
#define MSG_OK 0
|
#define MSG_OK 0
|
||||||
#define MSG_NG 1
|
#define MSG_NG 1
|
||||||
|
|
||||||
|
#define OSPF6_SUCCESS 1
|
||||||
|
#define OSPF6_FAILURE 0
|
||||||
|
#define OSPF6_INVALID -1
|
||||||
|
|
||||||
/* cast macro: XXX - these *must* die, ick ick. */
|
/* cast macro: XXX - these *must* die, ick ick. */
|
||||||
#define OSPF6_PROCESS(x) ((struct ospf6 *) (x))
|
#define OSPF6_PROCESS(x) ((struct ospf6 *) (x))
|
||||||
#define OSPF6_AREA(x) ((struct ospf6_area *) (x))
|
#define OSPF6_AREA(x) ((struct ospf6_area *) (x))
|
||||||
|
|
|
@ -90,6 +90,7 @@ ospf6d_ospf6d_snmp_la_LIBADD = lib/libfrrsnmp.la
|
||||||
clippy_scan += \
|
clippy_scan += \
|
||||||
ospf6d/ospf6_top.c \
|
ospf6d/ospf6_top.c \
|
||||||
ospf6d/ospf6_asbr.c \
|
ospf6d/ospf6_asbr.c \
|
||||||
|
ospf6d/ospf6_lsa.c \
|
||||||
# end
|
# end
|
||||||
|
|
||||||
nodist_ospf6d_ospf6d_SOURCES = \
|
nodist_ospf6d_ospf6d_SOURCES = \
|
||||||
|
|
|
@ -1517,7 +1517,7 @@ def verify_ospf_database(tgen, topo, dut, input_dict, expected=True):
|
||||||
|
|
||||||
|
|
||||||
@retry(retry_timeout=20)
|
@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
|
This API is to verify ospf routes by running
|
||||||
show ip ospf interface command.
|
show ip ospf interface command.
|
||||||
|
@ -1528,7 +1528,6 @@ def verify_ospf_summary(tgen, topo, dut, input_dict, expected=True):
|
||||||
* `topo` : topology descriptions
|
* `topo` : topology descriptions
|
||||||
* `dut`: device under test
|
* `dut`: device under test
|
||||||
* `input_dict` : Input dict data, required when configuring from testcase
|
* `input_dict` : Input dict data, required when configuring from testcase
|
||||||
* `expected` : expected results from API, by-default True
|
|
||||||
|
|
||||||
Usage
|
Usage
|
||||||
-----
|
-----
|
||||||
|
@ -1548,18 +1547,30 @@ def verify_ospf_summary(tgen, topo, dut, input_dict, expected=True):
|
||||||
True or False (Error Message)
|
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
|
result = False
|
||||||
router = dut
|
router = dut
|
||||||
|
|
||||||
logger.info("Verifying OSPF summary on router %s:", router)
|
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]
|
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
|
# Verifying output dictionary show_ospf_json is empty or not
|
||||||
if not bool(show_ospf_json):
|
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
|
# To find neighbor ip type
|
||||||
ospf_summary_data = input_dict
|
ospf_summary_data = input_dict
|
||||||
|
|
||||||
|
if ospf:
|
||||||
|
show_ospf_json = show_ospf_json['default']
|
||||||
|
|
||||||
for ospf_summ, summ_data in ospf_summary_data.items():
|
for ospf_summ, summ_data in ospf_summary_data.items():
|
||||||
if ospf_summ not in show_ospf_json:
|
if ospf_summ not in show_ospf_json:
|
||||||
continue
|
continue
|
||||||
summary = ospf_summary_data[ospf_summ]["Summary address"]
|
summary = ospf_summary_data[ospf_summ]['Summary address']
|
||||||
|
|
||||||
if summary in show_ospf_json:
|
if summary in show_ospf_json:
|
||||||
for summ in summ_data:
|
for summ in summ_data:
|
||||||
if summ_data[summ] == show_ospf_json[summary][summ]:
|
if summ_data[summ] == show_ospf_json[summary][summ]:
|
||||||
logger.info(
|
logger.info("[DUT: %s] OSPF summary %s:%s is %s",
|
||||||
"[DUT: %s] OSPF summary %s:%s is %s",
|
router, summary, summ, summ_data[summ])
|
||||||
router,
|
|
||||||
summary,
|
|
||||||
summ,
|
|
||||||
summ_data[summ],
|
|
||||||
)
|
|
||||||
result = True
|
result = True
|
||||||
else:
|
else:
|
||||||
errormsg = (
|
errormsg = ("[DUT: {}] OSPF summary {} : {} is {}, "
|
||||||
"[DUT: {}] OSPF summary {}:{} is %s, "
|
"Expected is {}".format(router, summary, summ,show_ospf_json[
|
||||||
"Expected is {}".format(
|
summary][summ], summ_data[summ] ))
|
||||||
router, summary, summ, show_ospf_json[summary][summ]
|
|
||||||
)
|
|
||||||
)
|
|
||||||
return errormsg
|
return errormsg
|
||||||
|
|
||||||
logger.debug("Exiting API: verify_ospf_summary()")
|
logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@retry(retry_timeout=30)
|
@retry(retry_timeout=30)
|
||||||
def verify_ospf6_rib(tgen, dut, input_dict, next_hop=None,
|
def verify_ospf6_rib(tgen, dut, input_dict, next_hop=None,
|
||||||
tag=None, metric=None, fib=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