mirror of
https://github.com/FRRouting/frr.git
synced 2025-04-30 05:27:16 +02:00
Merge pull request #14546 from adrianomarto/ospf6-point-to-multipoint
OSPF6 point to multipoint
This commit is contained in:
commit
8e3a96e846
|
@ -312,10 +312,135 @@ OSPF6 interface
|
|||
|
||||
Sets interface's Inf-Trans-Delay. Default value is 1.
|
||||
|
||||
.. clicmd:: ipv6 ospf6 network (broadcast|point-to-point)
|
||||
.. clicmd:: ipv6 ospf6 network (broadcast|point-to-point|point-to-multipoint)
|
||||
|
||||
Set explicitly network type for specified interface.
|
||||
|
||||
The only functional difference between ``point-to-point`` (PtP) and
|
||||
``point-to-multipoint`` (PtMP) mode is the packet addressing for database
|
||||
flooding and updates. PtP will use multicast packets while PtMP will
|
||||
unicast them. Apart from this,
|
||||
:clicmd:`ipv6 ospf6 p2p-p2mp connected-prefixes <include|exclude>` has a
|
||||
different default for PtP and PtMP. There are no other differences, in
|
||||
particular FRR does not impose a limit of one neighbor in PtP mode.
|
||||
|
||||
FRR does not support NBMA mode for IPv6 and likely never will, as NBMA is
|
||||
considered deprecated for IPv6. Refer to `this IETF OSPF working group
|
||||
discussion
|
||||
<https://mailarchive.ietf.org/arch/msg/ospf/8GAbr4qSMMt5J7SvAcZQ1H7ARhk/>`_
|
||||
for context.
|
||||
|
||||
OSPF6 point-to-point and point-to-multipoint operation
|
||||
======================================================
|
||||
|
||||
OSPFv3, by default, operates in broadcast mode where it elects a DR and BDR
|
||||
for each network segment. This can be changed to point-to-point (PtP) /
|
||||
point-to-multipoint (PtMP) mode by configuration. The actual physical
|
||||
interface characteristics do not matter for this setting, all interfaces can
|
||||
be configured for all modes. However, routers must be configured for the same
|
||||
mode to form adjacencies.
|
||||
|
||||
The main advantages of PtP/PtMP mode are:
|
||||
|
||||
- no DR/BDR election
|
||||
- adjacencies can be suppressed in a pairwise manner for any two routers, e.g.
|
||||
to represent the underlying topology if it isn't a true full mesh
|
||||
- distinct costs can be set for each pair of routers and direction
|
||||
|
||||
The main downside is less efficient flooding on networks with a large number
|
||||
of OSPFv3 routers.
|
||||
|
||||
.. warning::
|
||||
|
||||
All options in this section should be considered "advanced" configuration
|
||||
options. Inconsistent or nonsensical combinations can easily result in a
|
||||
non-functional setup.
|
||||
|
||||
.. clicmd:: ipv6 ospf6 p2p-p2mp disable-multicast-hello
|
||||
|
||||
Disables sending normal multicast hellos when in PtP/PtMP mode. Some
|
||||
vendors do this automatically for PtMP mode while others have a separate
|
||||
``no-broadcast`` option matching this.
|
||||
|
||||
If this setting is used, you must issue
|
||||
:clicmd:`ipv6 ospf6 neighbor X:X::X:X poll-interval (1-65535)` for each
|
||||
neighbor to send unicast hello packets.
|
||||
|
||||
.. clicmd:: ipv6 ospf6 p2p-p2mp config-neighbors-only
|
||||
|
||||
Only form adjacencies with neighbors that are explicitly configured with
|
||||
the :clicmd:`ipv6 ospf6 neighbor X:X::X:X` command. Hellos from other
|
||||
routers are ignored.
|
||||
|
||||
.. warning::
|
||||
|
||||
This setting is not intended to provide any security benefit. Do not
|
||||
run OSPFv3 over untrusted links without additional security measures
|
||||
(e.g. IPsec.)
|
||||
|
||||
.. clicmd:: ipv6 ospf6 p2p-p2mp connected-prefixes <include|exclude>
|
||||
|
||||
For global/ULA prefixes configured on this interfaces, do (not) advertise
|
||||
the full prefix to the area. Regardless of this setting, the router's own
|
||||
address, as a /128 host route with the "LA" (Local Address) bit set, will
|
||||
always be advertised.
|
||||
|
||||
The default is to include connected prefixes for PtP mode and exclude them
|
||||
for PtMP mode. Since these prefixes will cover other router's addresses,
|
||||
these addresses can become unreachable if the link is partitioned if the
|
||||
other router does not advertise the address as a /128. However, conversely,
|
||||
if all routers have this flag set, the overall prefix will not be advertised
|
||||
anywhere. End hosts on this link will therefore be unreachable (and
|
||||
blackholing best-practices for non-existing prefixes apply.) It may be
|
||||
preferable to have only one router announce the connected prefix.
|
||||
|
||||
The Link LSA (which is not propagated into the area) always includes all
|
||||
prefixes on the interface. This setting only affects the Router LSA that
|
||||
is visible to all routers in the area.
|
||||
|
||||
.. note::
|
||||
|
||||
Before interacting with this setting, consider either not configuring
|
||||
any global/ULA IPv6 address on the interface, or directly configuring a
|
||||
/128 if needed. OSPFv3 relies exclusively on link-local addresses to do
|
||||
its signaling and there is absolutely no reason to configure global/ULA
|
||||
addresses as far as OSPFv3 is concerned.
|
||||
|
||||
.. clicmd:: ipv6 ospf6 neighbor X:X::X:X
|
||||
|
||||
Explicitly configure a neighbor by its link-local address on this interface.
|
||||
This statement has no effect other than allowing an adjacency when
|
||||
:clicmd:`ipv6 ospf6 p2p-p2mp config-neighbors-only` is set. This command
|
||||
does **not** cause unicast hellos to be sent.
|
||||
|
||||
Only link-local addresses can be used to establish explicit neighbors.
|
||||
When using this command, you should probably assign static IPv6 link-local
|
||||
addresses to all routers on this link. It would technically be possible to
|
||||
use the neighbor's Router ID (IPv4 address) here to ease working with
|
||||
changing link-local addresses but this is not planned as a feature at the
|
||||
time of writing. Global/ULA IPv6 addresses cannot be supported here due to
|
||||
the way OSPFv3 works.
|
||||
|
||||
.. clicmd:: ipv6 ospf6 neighbor X:X::X:X poll-interval (1-65535)
|
||||
|
||||
Send unicast hellos to this neighbor at the specified interval (in seconds.)
|
||||
The interval is only used while there is no adjacency with this neighbor.
|
||||
As soon as an adjacency is formed, the interface's
|
||||
:clicmd:`ipv6 ospf6 hello-interval HELLOINTERVAL` value is used.
|
||||
(``hello-interval`` must be the same on all routers on this link.)
|
||||
|
||||
:rfc:`2328` recommends a "much larger" value than ``hello-interval`` for
|
||||
this setting, but this is a legacy of ATM and X.25 networks and nowadays you
|
||||
should probably just use the same value as for ``hello-interval``.
|
||||
|
||||
.. clicmd:: ipv6 ospf6 neighbor X:X::X:X cost (1-65535)
|
||||
|
||||
Use a distinct cost for paths traversing this neighbor. The default is
|
||||
to use the interface's cost value (which may be automatically calculated
|
||||
based on link bandwidth.) Note that costs are directional in OSPF and the
|
||||
reverse direction must be set on the other router.
|
||||
|
||||
|
||||
OSPF6 route-map
|
||||
===============
|
||||
|
||||
|
|
1
lib/if.h
1
lib/if.h
|
@ -579,7 +579,6 @@ extern ifindex_t ifname2ifindex(const char *ifname, vrf_id_t vrf_id);
|
|||
/* Connected address functions. */
|
||||
extern struct connected *connected_new(void);
|
||||
extern void connected_free(struct connected **connected);
|
||||
extern void connected_add(struct interface *, struct connected *);
|
||||
extern struct connected *
|
||||
connected_add_by_prefix(struct interface *, struct prefix *, struct prefix *);
|
||||
extern struct connected *connected_delete_by_prefix(struct interface *,
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -34,6 +34,25 @@ struct ospf6_auth_data {
|
|||
uint32_t rx_drop; /* Pkt drop due to auth fail while reading */
|
||||
};
|
||||
|
||||
PREDECL_RBTREE_UNIQ(ospf6_if_p2xp_neighcfgs);
|
||||
|
||||
struct ospf6_if_p2xp_neighcfg {
|
||||
struct ospf6_if_p2xp_neighcfgs_item item;
|
||||
|
||||
struct ospf6_interface *ospf6_if;
|
||||
struct in6_addr addr;
|
||||
|
||||
bool cfg_cost : 1;
|
||||
|
||||
uint32_t cost;
|
||||
uint16_t poll_interval;
|
||||
|
||||
/* NULL if down */
|
||||
struct ospf6_neighbor *active;
|
||||
|
||||
struct event *t_unicast_hello;
|
||||
};
|
||||
|
||||
/* Interface structure */
|
||||
struct ospf6_interface {
|
||||
/* IF info from zebra */
|
||||
|
@ -66,6 +85,20 @@ struct ospf6_interface {
|
|||
uint8_t type;
|
||||
bool type_cfg;
|
||||
|
||||
/* P2P/P2MP behavior: */
|
||||
|
||||
/* disable hellos on standard multicast? */
|
||||
bool p2xp_no_multicast_hello;
|
||||
/* only allow explicitly configured neighbors? */
|
||||
bool p2xp_only_cfg_neigh;
|
||||
/* override mode default for advertising connected prefixes.
|
||||
* both false by default (= do include for PtP, exclude for PtMP)
|
||||
*/
|
||||
bool p2xp_connected_pfx_include;
|
||||
bool p2xp_connected_pfx_exclude;
|
||||
|
||||
struct ospf6_if_p2xp_neighcfgs_head p2xp_neighs;
|
||||
|
||||
/* Router Priority */
|
||||
uint8_t priority;
|
||||
|
||||
|
@ -171,15 +204,16 @@ struct ospf6_interface {
|
|||
DECLARE_QOBJ_TYPE(ospf6_interface);
|
||||
|
||||
/* interface state */
|
||||
#define OSPF6_INTERFACE_NONE 0
|
||||
#define OSPF6_INTERFACE_DOWN 1
|
||||
#define OSPF6_INTERFACE_LOOPBACK 2
|
||||
#define OSPF6_INTERFACE_WAITING 3
|
||||
#define OSPF6_INTERFACE_POINTTOPOINT 4
|
||||
#define OSPF6_INTERFACE_DROTHER 5
|
||||
#define OSPF6_INTERFACE_BDR 6
|
||||
#define OSPF6_INTERFACE_DR 7
|
||||
#define OSPF6_INTERFACE_MAX 8
|
||||
#define OSPF6_INTERFACE_NONE 0
|
||||
#define OSPF6_INTERFACE_DOWN 1
|
||||
#define OSPF6_INTERFACE_LOOPBACK 2
|
||||
#define OSPF6_INTERFACE_WAITING 3
|
||||
#define OSPF6_INTERFACE_POINTTOPOINT 4
|
||||
#define OSPF6_INTERFACE_POINTTOMULTIPOINT 5
|
||||
#define OSPF6_INTERFACE_DROTHER 6
|
||||
#define OSPF6_INTERFACE_BDR 7
|
||||
#define OSPF6_INTERFACE_DR 8
|
||||
#define OSPF6_INTERFACE_MAX 9
|
||||
|
||||
extern const char *const ospf6_interface_state_str[];
|
||||
|
||||
|
|
|
@ -321,13 +321,14 @@ void ospf6_router_lsa_originate(struct event *thread)
|
|||
}
|
||||
|
||||
/* Point-to-Point interfaces */
|
||||
if (oi->type == OSPF_IFTYPE_POINTOPOINT) {
|
||||
if (oi->type == OSPF_IFTYPE_POINTOPOINT
|
||||
|| oi->type == OSPF_IFTYPE_POINTOMULTIPOINT) {
|
||||
for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, j, on)) {
|
||||
if (on->state != OSPF6_NEIGHBOR_FULL)
|
||||
continue;
|
||||
|
||||
lsdesc->type = OSPF6_ROUTER_LSDESC_POINTTOPOINT;
|
||||
lsdesc->metric = htons(oi->cost);
|
||||
lsdesc->metric = htons(ospf6_neighbor_cost(on));
|
||||
lsdesc->interface_id =
|
||||
htonl(oi->interface->ifindex);
|
||||
lsdesc->neighbor_interface_id =
|
||||
|
@ -1068,6 +1069,7 @@ void ospf6_intra_prefix_lsa_originate_stub(struct event *thread)
|
|||
|
||||
if (oi->state != OSPF6_INTERFACE_LOOPBACK
|
||||
&& oi->state != OSPF6_INTERFACE_POINTTOPOINT
|
||||
&& oi->state != OSPF6_INTERFACE_POINTTOMULTIPOINT
|
||||
&& full_count != 0) {
|
||||
if (IS_OSPF6_DEBUG_ORIGINATE(INTRA_PREFIX))
|
||||
zlog_debug(" Interface %s is not stub, ignore",
|
||||
|
|
|
@ -268,6 +268,18 @@ static struct ospf6_packet *ospf6_packet_new(size_t size)
|
|||
return new;
|
||||
}
|
||||
|
||||
static struct ospf6_packet *ospf6_packet_dup(struct ospf6_packet *old)
|
||||
{
|
||||
struct ospf6_packet *new;
|
||||
|
||||
new = XCALLOC(MTYPE_OSPF6_PACKET, sizeof(struct ospf6_packet));
|
||||
new->s = stream_dup(old->s);
|
||||
new->dst = old->dst;
|
||||
new->length = old->length;
|
||||
|
||||
return new;
|
||||
}
|
||||
|
||||
static void ospf6_packet_free(struct ospf6_packet *op)
|
||||
{
|
||||
if (op->s)
|
||||
|
@ -407,6 +419,25 @@ static void ospf6_hello_recv(struct in6_addr *src, struct in6_addr *dst,
|
|||
hello = (struct ospf6_hello *)((caddr_t)oh
|
||||
+ sizeof(struct ospf6_header));
|
||||
|
||||
if ((oi->state == OSPF6_INTERFACE_POINTTOPOINT
|
||||
|| oi->state == OSPF6_INTERFACE_POINTTOMULTIPOINT)
|
||||
&& oi->p2xp_only_cfg_neigh) {
|
||||
/* NEVER, never, ever, do this on broadcast (or NBMA)!
|
||||
* DR/BDR election requires everyone to talk to everyone else
|
||||
* only for PtP/PtMP we can be selective in adjacencies!
|
||||
*/
|
||||
struct ospf6_if_p2xp_neighcfg *p2xp_cfg;
|
||||
|
||||
p2xp_cfg = ospf6_if_p2xp_find(oi, src);
|
||||
if (!p2xp_cfg) {
|
||||
if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
|
||||
zlog_debug(
|
||||
"ignoring PtP/PtMP hello from %pI6, neighbor not configured",
|
||||
src);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* HelloInterval check */
|
||||
if (ntohs(hello->hello_interval) != oi->hello_interval) {
|
||||
zlog_warn(
|
||||
|
@ -479,7 +510,7 @@ static void ospf6_hello_recv(struct in6_addr *src, struct in6_addr *dst,
|
|||
on->hello_in++;
|
||||
|
||||
/* Always override neighbor's source address */
|
||||
memcpy(&on->linklocal_addr, src, sizeof(struct in6_addr));
|
||||
ospf6_neighbor_lladdr_set(on, src);
|
||||
|
||||
/* Neighbor ifindex check */
|
||||
if (on->ifindex != (ifindex_t)ntohl(hello->interface_id)) {
|
||||
|
@ -2239,8 +2270,6 @@ static void ospf6_write(struct event *thread)
|
|||
void ospf6_hello_send(struct event *thread)
|
||||
{
|
||||
struct ospf6_interface *oi;
|
||||
struct ospf6_packet *op;
|
||||
uint16_t length = OSPF6_HEADER_SIZE;
|
||||
|
||||
oi = (struct ospf6_interface *)EVENT_ARG(thread);
|
||||
|
||||
|
@ -2266,6 +2295,20 @@ void ospf6_hello_send(struct event *thread)
|
|||
return;
|
||||
}
|
||||
|
||||
event_add_timer(master, ospf6_hello_send, oi, oi->hello_interval,
|
||||
&oi->thread_send_hello);
|
||||
|
||||
ospf6_hello_send_addr(oi, NULL);
|
||||
}
|
||||
|
||||
/* used to send polls for PtP/PtMP too */
|
||||
void ospf6_hello_send_addr(struct ospf6_interface *oi,
|
||||
const struct in6_addr *addr)
|
||||
{
|
||||
struct ospf6_packet *op;
|
||||
uint16_t length = OSPF6_HEADER_SIZE;
|
||||
bool anything = false;
|
||||
|
||||
op = ospf6_packet_new(oi->ifmtu);
|
||||
|
||||
ospf6_make_header(OSPF6_MESSAGE_TYPE_HELLO, oi, op->s);
|
||||
|
@ -2284,20 +2327,40 @@ void ospf6_hello_send(struct event *thread)
|
|||
/* Set packet length. */
|
||||
op->length = length;
|
||||
|
||||
op->dst = allspfrouters6;
|
||||
if ((oi->state == OSPF6_INTERFACE_POINTTOPOINT
|
||||
|| oi->state == OSPF6_INTERFACE_POINTTOMULTIPOINT)
|
||||
&& !addr && oi->p2xp_no_multicast_hello) {
|
||||
struct listnode *node;
|
||||
struct ospf6_neighbor *on;
|
||||
struct ospf6_packet *opdup;
|
||||
|
||||
ospf6_fill_hdr_checksum(oi, op);
|
||||
for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, node, on)) {
|
||||
if (on->state < OSPF6_NEIGHBOR_INIT)
|
||||
/* poll-interval for these */
|
||||
continue;
|
||||
|
||||
/* Add packet to the top of the interface output queue, so that they
|
||||
* can't get delayed by things like long queues of LS Update packets
|
||||
*/
|
||||
ospf6_packet_add_top(oi, op);
|
||||
opdup = ospf6_packet_dup(op);
|
||||
opdup->dst = on->linklocal_addr;
|
||||
ospf6_fill_hdr_checksum(oi, opdup);
|
||||
ospf6_packet_add_top(oi, opdup);
|
||||
anything = true;
|
||||
}
|
||||
|
||||
/* set next thread */
|
||||
event_add_timer(master, ospf6_hello_send, oi, oi->hello_interval,
|
||||
&oi->thread_send_hello);
|
||||
ospf6_packet_free(op);
|
||||
} else {
|
||||
op->dst = addr ? *addr : allspfrouters6;
|
||||
|
||||
OSPF6_MESSAGE_WRITE_ON(oi);
|
||||
/* Add packet to the top of the interface output queue, so that
|
||||
* they can't get delayed by things like long queues of LS
|
||||
* Update packets
|
||||
*/
|
||||
ospf6_fill_hdr_checksum(oi, op);
|
||||
ospf6_packet_add_top(oi, op);
|
||||
anything = true;
|
||||
}
|
||||
|
||||
if (anything)
|
||||
OSPF6_MESSAGE_WRITE_ON(oi);
|
||||
}
|
||||
|
||||
static uint16_t ospf6_make_dbdesc(struct ospf6_neighbor *on, struct stream *s)
|
||||
|
|
|
@ -50,6 +50,8 @@ extern unsigned char conf_debug_ospf6_message[];
|
|||
#define OSPF6_MESSAGE_TYPE_ALL 0x6 /* For debug option */
|
||||
#define OSPF6_MESSAGE_TYPE_MAX 0x6 /* same as OSPF6_MESSAGE_TYPE_ALL */
|
||||
|
||||
struct ospf6_interface;
|
||||
|
||||
struct ospf6_packet {
|
||||
struct ospf6_packet *next;
|
||||
|
||||
|
@ -169,6 +171,9 @@ extern void ospf6_lsupdate_send_neighbor(struct event *thread);
|
|||
extern void ospf6_lsack_send_interface(struct event *thread);
|
||||
extern void ospf6_lsack_send_neighbor(struct event *thread);
|
||||
|
||||
extern void ospf6_hello_send_addr(struct ospf6_interface *oi,
|
||||
const struct in6_addr *addr);
|
||||
|
||||
extern int config_write_ospf6_debug_message(struct vty *);
|
||||
extern void install_element_ospf6_debug_message(void);
|
||||
extern const char *ospf6_message_type(int type);
|
||||
|
|
|
@ -34,6 +34,16 @@
|
|||
#include "lib/json.h"
|
||||
|
||||
DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_NEIGHBOR, "OSPF6 neighbor");
|
||||
DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_NEIGHBOR_P2XP_CFG,
|
||||
"OSPF6 PtP/PtMP neighbor config");
|
||||
|
||||
static int ospf6_if_p2xp_neighcfg_cmp(const struct ospf6_if_p2xp_neighcfg *a,
|
||||
const struct ospf6_if_p2xp_neighcfg *b);
|
||||
|
||||
DECLARE_RBTREE_UNIQ(ospf6_if_p2xp_neighcfgs, struct ospf6_if_p2xp_neighcfg,
|
||||
item, ospf6_if_p2xp_neighcfg_cmp);
|
||||
|
||||
static void p2xp_neigh_refresh(struct ospf6_neighbor *on, uint32_t prev_cost);
|
||||
|
||||
DEFINE_HOOK(ospf6_neighbor_change,
|
||||
(struct ospf6_neighbor * on, int state, int next_state),
|
||||
|
@ -42,13 +52,14 @@ DEFINE_HOOK(ospf6_neighbor_change,
|
|||
unsigned char conf_debug_ospf6_neighbor = 0;
|
||||
|
||||
const char *const ospf6_neighbor_state_str[] = {
|
||||
"None", "Down", "Attempt", "Init", "Twoway",
|
||||
"ExStart", "ExChange", "Loading", "Full", NULL};
|
||||
"None", "Down", "Attempt", "Init", "Twoway",
|
||||
"ExStart", "ExChange", "Loading", "Full", NULL
|
||||
};
|
||||
|
||||
const char *const ospf6_neighbor_event_str[] = {
|
||||
"NoEvent", "HelloReceived", "2-WayReceived", "NegotiationDone",
|
||||
"ExchangeDone", "LoadingDone", "AdjOK?", "SeqNumberMismatch",
|
||||
"BadLSReq", "1-WayReceived", "InactivityTimer",
|
||||
"NoEvent", "HelloReceived", "2-WayReceived", "NegotiationDone",
|
||||
"ExchangeDone", "LoadingDone", "AdjOK?", "SeqNumberMismatch",
|
||||
"BadLSReq", "1-WayReceived", "InactivityTimer",
|
||||
};
|
||||
|
||||
int ospf6_neighbor_cmp(void *va, void *vb)
|
||||
|
@ -119,8 +130,7 @@ struct ospf6_neighbor *ospf6_neighbor_create(uint32_t router_id,
|
|||
|
||||
on = XCALLOC(MTYPE_OSPF6_NEIGHBOR, sizeof(struct ospf6_neighbor));
|
||||
inet_ntop(AF_INET, &router_id, buf, sizeof(buf));
|
||||
snprintf(on->name, sizeof(on->name), "%s%%%s", buf,
|
||||
oi->interface->name);
|
||||
snprintf(on->name, sizeof(on->name), "%s%%%s", buf, oi->interface->name);
|
||||
on->ospf6_if = oi;
|
||||
on->state = OSPF6_NEIGHBOR_DOWN;
|
||||
on->state_change = 0;
|
||||
|
@ -150,6 +160,9 @@ struct ospf6_neighbor *ospf6_neighbor_create(uint32_t router_id,
|
|||
|
||||
void ospf6_neighbor_delete(struct ospf6_neighbor *on)
|
||||
{
|
||||
if (on->p2xp_cfg)
|
||||
on->p2xp_cfg->active = NULL;
|
||||
|
||||
ospf6_neighbor_clear_ls_lists(on);
|
||||
|
||||
ospf6_lsdb_remove_all(on->dbdesc_list);
|
||||
|
@ -182,6 +195,22 @@ void ospf6_neighbor_delete(struct ospf6_neighbor *on)
|
|||
XFREE(MTYPE_OSPF6_NEIGHBOR, on);
|
||||
}
|
||||
|
||||
void ospf6_neighbor_lladdr_set(struct ospf6_neighbor *on,
|
||||
const struct in6_addr *addr)
|
||||
{
|
||||
if (IPV6_ADDR_SAME(addr, &on->linklocal_addr))
|
||||
return;
|
||||
|
||||
memcpy(&on->linklocal_addr, addr, sizeof(struct in6_addr));
|
||||
|
||||
if (on->ospf6_if->type == OSPF_IFTYPE_POINTOPOINT ||
|
||||
on->ospf6_if->type == OSPF_IFTYPE_POINTOMULTIPOINT) {
|
||||
uint32_t prev_cost = ospf6_neighbor_cost(on);
|
||||
|
||||
p2xp_neigh_refresh(on, prev_cost);
|
||||
}
|
||||
}
|
||||
|
||||
static void ospf6_neighbor_state_change(uint8_t next_state,
|
||||
struct ospf6_neighbor *on, int event)
|
||||
{
|
||||
|
@ -198,31 +227,28 @@ static void ospf6_neighbor_state_change(uint8_t next_state,
|
|||
|
||||
/* log */
|
||||
if (IS_OSPF6_DEBUG_NEIGHBOR(STATE)) {
|
||||
zlog_debug(
|
||||
"Neighbor state change %s (Router-ID: %pI4): [%s]->[%s] (%s)",
|
||||
on->name, &on->router_id,
|
||||
ospf6_neighbor_state_str[prev_state],
|
||||
ospf6_neighbor_state_str[next_state],
|
||||
ospf6_neighbor_event_string(event));
|
||||
zlog_debug("Neighbor state change %s (Router-ID: %pI4): [%s]->[%s] (%s)",
|
||||
on->name, &on->router_id,
|
||||
ospf6_neighbor_state_str[prev_state],
|
||||
ospf6_neighbor_state_str[next_state],
|
||||
ospf6_neighbor_event_string(event));
|
||||
}
|
||||
|
||||
/* Optionally notify about adjacency changes */
|
||||
if (CHECK_FLAG(on->ospf6_if->area->ospf6->config_flags,
|
||||
OSPF6_LOG_ADJACENCY_CHANGES)
|
||||
&& (CHECK_FLAG(on->ospf6_if->area->ospf6->config_flags,
|
||||
OSPF6_LOG_ADJACENCY_DETAIL)
|
||||
|| (next_state == OSPF6_NEIGHBOR_FULL)
|
||||
|| (next_state < prev_state)))
|
||||
zlog_notice(
|
||||
"AdjChg: Nbr %pI4(%s) on %s: %s -> %s (%s)",
|
||||
&on->router_id,
|
||||
vrf_id_to_name(on->ospf6_if->interface->vrf->vrf_id),
|
||||
on->name, ospf6_neighbor_state_str[prev_state],
|
||||
ospf6_neighbor_state_str[next_state],
|
||||
ospf6_neighbor_event_string(event));
|
||||
OSPF6_LOG_ADJACENCY_CHANGES) &&
|
||||
(CHECK_FLAG(on->ospf6_if->area->ospf6->config_flags,
|
||||
OSPF6_LOG_ADJACENCY_DETAIL) ||
|
||||
(next_state == OSPF6_NEIGHBOR_FULL) || (next_state < prev_state)))
|
||||
zlog_notice("AdjChg: Nbr %pI4(%s) on %s: %s -> %s (%s)",
|
||||
&on->router_id,
|
||||
vrf_id_to_name(on->ospf6_if->interface->vrf->vrf_id),
|
||||
on->name, ospf6_neighbor_state_str[prev_state],
|
||||
ospf6_neighbor_state_str[next_state],
|
||||
ospf6_neighbor_event_string(event));
|
||||
|
||||
if (prev_state == OSPF6_NEIGHBOR_FULL
|
||||
|| next_state == OSPF6_NEIGHBOR_FULL) {
|
||||
if (prev_state == OSPF6_NEIGHBOR_FULL ||
|
||||
next_state == OSPF6_NEIGHBOR_FULL) {
|
||||
if (!OSPF6_GR_IS_ACTIVE_HELPER(on)) {
|
||||
OSPF6_ROUTER_LSA_SCHEDULE(on->ospf6_if->area);
|
||||
if (on->ospf6_if->state == OSPF6_INTERFACE_DR) {
|
||||
|
@ -235,12 +261,11 @@ static void ospf6_neighbor_state_change(uint8_t next_state,
|
|||
on->ospf6_if->area->intra_prefix_originate = 1;
|
||||
|
||||
if (!OSPF6_GR_IS_ACTIVE_HELPER(on))
|
||||
OSPF6_INTRA_PREFIX_LSA_SCHEDULE_STUB(
|
||||
on->ospf6_if->area);
|
||||
OSPF6_INTRA_PREFIX_LSA_SCHEDULE_STUB(on->ospf6_if->area);
|
||||
|
||||
if ((prev_state == OSPF6_NEIGHBOR_LOADING
|
||||
|| prev_state == OSPF6_NEIGHBOR_EXCHANGE)
|
||||
&& next_state == OSPF6_NEIGHBOR_FULL) {
|
||||
if ((prev_state == OSPF6_NEIGHBOR_LOADING ||
|
||||
prev_state == OSPF6_NEIGHBOR_EXCHANGE) &&
|
||||
next_state == OSPF6_NEIGHBOR_FULL) {
|
||||
OSPF6_AS_EXTERN_LSA_SCHEDULE(on->ospf6_if);
|
||||
on->ospf6_if->area->full_nbrs++;
|
||||
}
|
||||
|
@ -249,10 +274,10 @@ static void ospf6_neighbor_state_change(uint8_t next_state,
|
|||
on->ospf6_if->area->full_nbrs--;
|
||||
}
|
||||
|
||||
if ((prev_state == OSPF6_NEIGHBOR_EXCHANGE
|
||||
|| prev_state == OSPF6_NEIGHBOR_LOADING)
|
||||
&& (next_state != OSPF6_NEIGHBOR_EXCHANGE
|
||||
&& next_state != OSPF6_NEIGHBOR_LOADING))
|
||||
if ((prev_state == OSPF6_NEIGHBOR_EXCHANGE ||
|
||||
prev_state == OSPF6_NEIGHBOR_LOADING) &&
|
||||
(next_state != OSPF6_NEIGHBOR_EXCHANGE &&
|
||||
next_state != OSPF6_NEIGHBOR_LOADING))
|
||||
ospf6_maxage_remove(on->ospf6_if->area->ospf6);
|
||||
|
||||
hook_call(ospf6_neighbor_change, on, next_state, prev_state);
|
||||
|
@ -262,13 +287,14 @@ static void ospf6_neighbor_state_change(uint8_t next_state,
|
|||
/* RFC2328 section 10.4 */
|
||||
static int need_adjacency(struct ospf6_neighbor *on)
|
||||
{
|
||||
if (on->ospf6_if->state == OSPF6_INTERFACE_POINTTOPOINT
|
||||
|| on->ospf6_if->state == OSPF6_INTERFACE_DR
|
||||
|| on->ospf6_if->state == OSPF6_INTERFACE_BDR)
|
||||
if (on->ospf6_if->state == OSPF6_INTERFACE_POINTTOPOINT ||
|
||||
on->ospf6_if->state == OSPF6_INTERFACE_POINTTOMULTIPOINT ||
|
||||
on->ospf6_if->state == OSPF6_INTERFACE_DR ||
|
||||
on->ospf6_if->state == OSPF6_INTERFACE_BDR)
|
||||
return 1;
|
||||
|
||||
if (on->ospf6_if->drouter == on->router_id
|
||||
|| on->ospf6_if->bdrouter == on->router_id)
|
||||
if (on->ospf6_if->drouter == on->router_id ||
|
||||
on->ospf6_if->bdrouter == on->router_id)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
|
@ -422,13 +448,12 @@ void exchange_done(struct event *thread)
|
|||
/* Check loading state. */
|
||||
void ospf6_check_nbr_loading(struct ospf6_neighbor *on)
|
||||
{
|
||||
|
||||
/* RFC2328 Section 10.9: When the neighbor responds to these requests
|
||||
with the proper Link State Update packet(s), the Link state request
|
||||
list is truncated and a new Link State Request packet is sent.
|
||||
*/
|
||||
if ((on->state == OSPF6_NEIGHBOR_LOADING)
|
||||
|| (on->state == OSPF6_NEIGHBOR_EXCHANGE)) {
|
||||
if ((on->state == OSPF6_NEIGHBOR_LOADING) ||
|
||||
(on->state == OSPF6_NEIGHBOR_EXCHANGE)) {
|
||||
if (on->request_list->count == 0)
|
||||
event_add_event(master, loading_done, on, 0,
|
||||
&on->event_loading_done);
|
||||
|
@ -587,9 +612,8 @@ void inactivity_timer(struct event *thread)
|
|||
on->drouter = on->prev_drouter = 0;
|
||||
on->bdrouter = on->prev_bdrouter = 0;
|
||||
|
||||
ospf6_neighbor_state_change(
|
||||
OSPF6_NEIGHBOR_DOWN, on,
|
||||
OSPF6_NEIGHBOR_EVENT_INACTIVITY_TIMER);
|
||||
ospf6_neighbor_state_change(OSPF6_NEIGHBOR_DOWN, on,
|
||||
OSPF6_NEIGHBOR_EVENT_INACTIVITY_TIMER);
|
||||
event_add_event(master, neighbor_change, on->ospf6_if, 0, NULL);
|
||||
|
||||
listnode_delete(on->ospf6_if->neighbor_list, on);
|
||||
|
@ -597,9 +621,8 @@ void inactivity_timer(struct event *thread)
|
|||
|
||||
} else {
|
||||
if (IS_DEBUG_OSPF6_GR)
|
||||
zlog_debug(
|
||||
"%s, Acting as HELPER for this neighbour, So restart the dead timer.",
|
||||
__PRETTY_FUNCTION__);
|
||||
zlog_debug("%s, Acting as HELPER for this neighbour, So restart the dead timer.",
|
||||
__PRETTY_FUNCTION__);
|
||||
|
||||
event_add_timer(master, inactivity_timer, on,
|
||||
on->ospf6_if->dead_interval,
|
||||
|
@ -607,8 +630,224 @@ void inactivity_timer(struct event *thread)
|
|||
}
|
||||
}
|
||||
|
||||
/* P2P/P2MP stuff */
|
||||
|
||||
uint32_t ospf6_neighbor_cost(struct ospf6_neighbor *on)
|
||||
{
|
||||
if (on->p2xp_cfg && on->p2xp_cfg->cfg_cost)
|
||||
return on->p2xp_cfg->cost;
|
||||
return on->ospf6_if->cost;
|
||||
}
|
||||
|
||||
static int ospf6_if_p2xp_neighcfg_cmp(const struct ospf6_if_p2xp_neighcfg *a,
|
||||
const struct ospf6_if_p2xp_neighcfg *b)
|
||||
{
|
||||
return IPV6_ADDR_CMP(&a->addr, &b->addr);
|
||||
}
|
||||
|
||||
struct ospf6_if_p2xp_neighcfg *ospf6_if_p2xp_find(struct ospf6_interface *oi,
|
||||
const struct in6_addr *addr)
|
||||
{
|
||||
struct ospf6_if_p2xp_neighcfg ref;
|
||||
|
||||
if (!oi)
|
||||
return NULL;
|
||||
|
||||
ref.addr = *addr;
|
||||
return ospf6_if_p2xp_neighcfgs_find(&oi->p2xp_neighs, &ref);
|
||||
}
|
||||
|
||||
static struct ospf6_if_p2xp_neighcfg *
|
||||
ospf6_if_p2xp_get(struct ospf6_interface *oi, const struct in6_addr *addr)
|
||||
{
|
||||
struct ospf6_if_p2xp_neighcfg ref, *ret;
|
||||
|
||||
if (!oi)
|
||||
return NULL;
|
||||
|
||||
ref.addr = *addr;
|
||||
ret = ospf6_if_p2xp_neighcfgs_find(&oi->p2xp_neighs, &ref);
|
||||
if (!ret) {
|
||||
ret = XCALLOC(MTYPE_OSPF6_NEIGHBOR_P2XP_CFG, sizeof(*ret));
|
||||
ret->addr = *addr;
|
||||
ret->ospf6_if = oi;
|
||||
|
||||
ospf6_if_p2xp_neighcfgs_add(&oi->p2xp_neighs, ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ospf6_if_p2xp_destroy(struct ospf6_if_p2xp_neighcfg *p2xp_cfg)
|
||||
{
|
||||
EVENT_OFF(p2xp_cfg->t_unicast_hello);
|
||||
ospf6_if_p2xp_neighcfgs_del(&p2xp_cfg->ospf6_if->p2xp_neighs, p2xp_cfg);
|
||||
|
||||
XFREE(MTYPE_OSPF6_NEIGHBOR_P2XP_CFG, p2xp_cfg);
|
||||
}
|
||||
|
||||
static void p2xp_neigh_refresh(struct ospf6_neighbor *on, uint32_t prev_cost)
|
||||
{
|
||||
if (on->p2xp_cfg)
|
||||
on->p2xp_cfg->active = NULL;
|
||||
on->p2xp_cfg = ospf6_if_p2xp_find(on->ospf6_if, &on->linklocal_addr);
|
||||
if (on->p2xp_cfg)
|
||||
on->p2xp_cfg->active = on;
|
||||
|
||||
if (ospf6_neighbor_cost(on) != prev_cost)
|
||||
OSPF6_ROUTER_LSA_SCHEDULE(on->ospf6_if->area);
|
||||
}
|
||||
|
||||
/* vty functions */
|
||||
|
||||
#ifndef VTYSH_EXTRACT_PL
|
||||
#include "ospf6d/ospf6_neighbor_clippy.c"
|
||||
#endif
|
||||
|
||||
DEFPY(ipv6_ospf6_p2xp_neigh, ipv6_ospf6_p2xp_neigh_cmd,
|
||||
"[no] ipv6 ospf6 neighbor X:X::X:X",
|
||||
NO_STR IP6_STR OSPF6_STR "Configure static neighbor\n"
|
||||
"Neighbor link-local address\n")
|
||||
{
|
||||
VTY_DECLVAR_CONTEXT(interface, ifp);
|
||||
struct ospf6_interface *oi = ifp->info;
|
||||
struct ospf6_if_p2xp_neighcfg *p2xp_cfg;
|
||||
|
||||
if (!oi) {
|
||||
if (no)
|
||||
return CMD_SUCCESS;
|
||||
oi = ospf6_interface_create(ifp);
|
||||
}
|
||||
|
||||
if (no) {
|
||||
struct ospf6_neighbor *on;
|
||||
uint32_t prev_cost = 0;
|
||||
|
||||
p2xp_cfg = ospf6_if_p2xp_find(oi, &neighbor);
|
||||
if (!p2xp_cfg)
|
||||
return CMD_SUCCESS;
|
||||
|
||||
on = p2xp_cfg->active;
|
||||
if (on)
|
||||
prev_cost = ospf6_neighbor_cost(on);
|
||||
|
||||
p2xp_cfg->active = NULL;
|
||||
ospf6_if_p2xp_destroy(p2xp_cfg);
|
||||
|
||||
if (on) {
|
||||
on->p2xp_cfg = NULL;
|
||||
p2xp_neigh_refresh(on, prev_cost);
|
||||
}
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
p2xp_cfg = ospf6_if_p2xp_get(oi, &neighbor);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFPY(ipv6_ospf6_p2xp_neigh_cost, ipv6_ospf6_p2xp_neigh_cost_cmd,
|
||||
"[no] ipv6 ospf6 neighbor X:X::X:X cost (1-65535)",
|
||||
NO_STR IP6_STR OSPF6_STR "Configure static neighbor\n"
|
||||
"Neighbor link-local address\n"
|
||||
"Outgoing metric for this neighbor\n"
|
||||
"Outgoing metric for this neighbor\n")
|
||||
{
|
||||
VTY_DECLVAR_CONTEXT(interface, ifp);
|
||||
struct ospf6_interface *oi = ifp->info;
|
||||
struct ospf6_if_p2xp_neighcfg *p2xp_cfg;
|
||||
uint32_t prev_cost;
|
||||
|
||||
if (!oi) {
|
||||
if (no)
|
||||
return CMD_SUCCESS;
|
||||
oi = ospf6_interface_create(ifp);
|
||||
}
|
||||
|
||||
p2xp_cfg = ospf6_if_p2xp_get(oi, &neighbor);
|
||||
|
||||
if (p2xp_cfg->active)
|
||||
prev_cost = ospf6_neighbor_cost(p2xp_cfg->active);
|
||||
|
||||
if (no) {
|
||||
p2xp_cfg->cfg_cost = false;
|
||||
p2xp_cfg->cost = 0;
|
||||
} else {
|
||||
p2xp_cfg->cfg_cost = true;
|
||||
p2xp_cfg->cost = cost;
|
||||
}
|
||||
|
||||
if (p2xp_cfg->active)
|
||||
p2xp_neigh_refresh(p2xp_cfg->active, prev_cost);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
static void p2xp_unicast_hello_send(struct event *event);
|
||||
|
||||
static void p2xp_unicast_hello_sched(struct ospf6_if_p2xp_neighcfg *p2xp_cfg)
|
||||
{
|
||||
if (!p2xp_cfg->poll_interval ||
|
||||
(p2xp_cfg->ospf6_if->state != OSPF6_INTERFACE_POINTTOMULTIPOINT &&
|
||||
p2xp_cfg->ospf6_if->state != OSPF6_INTERFACE_POINTTOPOINT))
|
||||
/* state check covers DOWN state too */
|
||||
EVENT_OFF(p2xp_cfg->t_unicast_hello);
|
||||
else
|
||||
event_add_timer(master, p2xp_unicast_hello_send, p2xp_cfg,
|
||||
p2xp_cfg->poll_interval,
|
||||
&p2xp_cfg->t_unicast_hello);
|
||||
}
|
||||
|
||||
void ospf6_if_p2xp_up(struct ospf6_interface *oi)
|
||||
{
|
||||
struct ospf6_if_p2xp_neighcfg *p2xp_cfg;
|
||||
|
||||
frr_each (ospf6_if_p2xp_neighcfgs, &oi->p2xp_neighs, p2xp_cfg)
|
||||
p2xp_unicast_hello_sched(p2xp_cfg);
|
||||
}
|
||||
|
||||
static void p2xp_unicast_hello_send(struct event *event)
|
||||
{
|
||||
struct ospf6_if_p2xp_neighcfg *p2xp_cfg = EVENT_ARG(event);
|
||||
struct ospf6_interface *oi = p2xp_cfg->ospf6_if;
|
||||
|
||||
if (oi->state != OSPF6_INTERFACE_POINTTOPOINT &&
|
||||
oi->state != OSPF6_INTERFACE_POINTTOMULTIPOINT)
|
||||
return;
|
||||
|
||||
p2xp_unicast_hello_sched(p2xp_cfg);
|
||||
|
||||
if (p2xp_cfg->active && p2xp_cfg->active->state >= OSPF6_NEIGHBOR_INIT)
|
||||
return;
|
||||
|
||||
ospf6_hello_send_addr(oi, &p2xp_cfg->addr);
|
||||
}
|
||||
|
||||
DEFPY(ipv6_ospf6_p2xp_neigh_poll_interval,
|
||||
ipv6_ospf6_p2xp_neigh_poll_interval_cmd,
|
||||
"[no] ipv6 ospf6 neighbor X:X::X:X poll-interval (1-65535)",
|
||||
NO_STR IP6_STR OSPF6_STR "Configure static neighbor\n"
|
||||
"Neighbor link-local address\n"
|
||||
"Send unicast hellos to neighbor when down\n"
|
||||
"Unicast hello interval when down (seconds)\n")
|
||||
{
|
||||
VTY_DECLVAR_CONTEXT(interface, ifp);
|
||||
struct ospf6_interface *oi = ifp->info;
|
||||
struct ospf6_if_p2xp_neighcfg *p2xp_cfg;
|
||||
|
||||
if (!oi) {
|
||||
if (no)
|
||||
return CMD_SUCCESS;
|
||||
oi = ospf6_interface_create(ifp);
|
||||
}
|
||||
if (no)
|
||||
poll_interval = 0;
|
||||
|
||||
p2xp_cfg = ospf6_if_p2xp_get(oi, &neighbor);
|
||||
p2xp_cfg->poll_interval = poll_interval;
|
||||
|
||||
p2xp_unicast_hello_sched(p2xp_cfg);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
/* show neighbor structure */
|
||||
static void ospf6_neighbor_show(struct vty *vty, struct ospf6_neighbor *on,
|
||||
json_object *json_array, bool use_json)
|
||||
|
@ -631,8 +870,8 @@ static void ospf6_neighbor_show(struct vty *vty, struct ospf6_neighbor *on,
|
|||
/* Dead time */
|
||||
h = m = s = 0;
|
||||
if (on->inactivity_timer) {
|
||||
s = monotime_until(&on->inactivity_timer->u.sands, NULL)
|
||||
/ 1000000LL;
|
||||
s = monotime_until(&on->inactivity_timer->u.sands, NULL) /
|
||||
1000000LL;
|
||||
h = s / 3600;
|
||||
s -= h * 3600;
|
||||
m = s / 60;
|
||||
|
@ -643,6 +882,8 @@ static void ospf6_neighbor_show(struct vty *vty, struct ospf6_neighbor *on,
|
|||
/* Neighbor State */
|
||||
if (on->ospf6_if->type == OSPF_IFTYPE_POINTOPOINT)
|
||||
snprintf(nstate, sizeof(nstate), "PointToPoint");
|
||||
else if (on->ospf6_if->type == OSPF_IFTYPE_POINTOMULTIPOINT)
|
||||
snprintf(nstate, sizeof(nstate), "PtMultipoint");
|
||||
else {
|
||||
if (on->router_id == on->drouter)
|
||||
snprintf(nstate, sizeof(nstate), "DR");
|
||||
|
@ -673,9 +914,9 @@ static void ospf6_neighbor_show(struct vty *vty, struct ospf6_neighbor *on,
|
|||
json_object_string_add(json_route, "duration", duration);
|
||||
json_object_string_add(json_route, "interfaceName",
|
||||
on->ospf6_if->interface->name);
|
||||
json_object_string_add(
|
||||
json_route, "interfaceState",
|
||||
ospf6_interface_state_str[on->ospf6_if->state]);
|
||||
json_object_string_add(json_route, "interfaceState",
|
||||
ospf6_interface_state_str
|
||||
[on->ospf6_if->state]);
|
||||
|
||||
json_object_array_add(json_array, json_route);
|
||||
} else
|
||||
|
@ -720,9 +961,9 @@ static void ospf6_neighbor_show_drchoice(struct vty *vty,
|
|||
json_object_string_add(json_route, "bdRouter", bdrouter);
|
||||
json_object_string_add(json_route, "interfaceName",
|
||||
on->ospf6_if->interface->name);
|
||||
json_object_string_add(
|
||||
json_route, "interfaceState",
|
||||
ospf6_interface_state_str[on->ospf6_if->state]);
|
||||
json_object_string_add(json_route, "interfaceState",
|
||||
ospf6_interface_state_str
|
||||
[on->ospf6_if->state]);
|
||||
|
||||
json_object_array_add(json_array, json_route);
|
||||
} else
|
||||
|
@ -777,9 +1018,8 @@ static void ospf6_neighbor_show_detail(struct vty *vty,
|
|||
(CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_IBIT)
|
||||
? "Initial "
|
||||
: ""),
|
||||
(CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MBIT)
|
||||
? "More"
|
||||
: ""),
|
||||
(CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MBIT) ? "More"
|
||||
: ""),
|
||||
(CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MSBIT)
|
||||
? "Master"
|
||||
: "Slave"));
|
||||
|
@ -793,8 +1033,8 @@ static void ospf6_neighbor_show_detail(struct vty *vty,
|
|||
json_object_int_add(json_neighbor, "summaryListCount",
|
||||
on->summary_list->count);
|
||||
for (ALL_LSDB(on->summary_list, lsa, lsanext))
|
||||
json_object_array_add(
|
||||
json_array, json_object_new_string(lsa->name));
|
||||
json_object_array_add(json_array,
|
||||
json_object_new_string(lsa->name));
|
||||
json_object_object_add(json_neighbor, "summaryListLsa",
|
||||
json_array);
|
||||
|
||||
|
@ -802,8 +1042,8 @@ static void ospf6_neighbor_show_detail(struct vty *vty,
|
|||
json_object_int_add(json_neighbor, "requestListCount",
|
||||
on->request_list->count);
|
||||
for (ALL_LSDB(on->request_list, lsa, lsanext))
|
||||
json_object_array_add(
|
||||
json_array, json_object_new_string(lsa->name));
|
||||
json_object_array_add(json_array,
|
||||
json_object_new_string(lsa->name));
|
||||
json_object_object_add(json_neighbor, "requestListLsa",
|
||||
json_array);
|
||||
|
||||
|
@ -811,8 +1051,8 @@ static void ospf6_neighbor_show_detail(struct vty *vty,
|
|||
json_object_int_add(json_neighbor, "reTransListCount",
|
||||
on->retrans_list->count);
|
||||
for (ALL_LSDB(on->retrans_list, lsa, lsanext))
|
||||
json_object_array_add(
|
||||
json_array, json_object_new_string(lsa->name));
|
||||
json_object_array_add(json_array,
|
||||
json_object_new_string(lsa->name));
|
||||
json_object_object_add(json_neighbor, "reTransListLsa",
|
||||
json_array);
|
||||
|
||||
|
@ -825,14 +1065,14 @@ static void ospf6_neighbor_show_detail(struct vty *vty,
|
|||
on->dbdesc_list->count);
|
||||
json_object_string_add(json_neighbor, "pendingLsaDbDescTime",
|
||||
duration);
|
||||
json_object_string_add(
|
||||
json_neighbor, "dbDescSendThread",
|
||||
(event_is_scheduled(on->thread_send_dbdesc) ? "on"
|
||||
: "off"));
|
||||
json_object_string_add(json_neighbor, "dbDescSendThread",
|
||||
(event_is_scheduled(on->thread_send_dbdesc)
|
||||
? "on"
|
||||
: "off"));
|
||||
json_array = json_object_new_array();
|
||||
for (ALL_LSDB(on->dbdesc_list, lsa, lsanext))
|
||||
json_object_array_add(
|
||||
json_array, json_object_new_string(lsa->name));
|
||||
json_object_array_add(json_array,
|
||||
json_object_new_string(lsa->name));
|
||||
json_object_object_add(json_neighbor, "pendingLsaDbDesc",
|
||||
json_array);
|
||||
|
||||
|
@ -844,35 +1084,35 @@ static void ospf6_neighbor_show_detail(struct vty *vty,
|
|||
on->request_list->count);
|
||||
json_object_string_add(json_neighbor, "pendingLsaLsReqTime",
|
||||
duration);
|
||||
json_object_string_add(
|
||||
json_neighbor, "lsReqSendThread",
|
||||
(event_is_scheduled(on->thread_send_lsreq) ? "on"
|
||||
: "off"));
|
||||
json_object_string_add(json_neighbor, "lsReqSendThread",
|
||||
(event_is_scheduled(on->thread_send_lsreq)
|
||||
? "on"
|
||||
: "off"));
|
||||
json_array = json_object_new_array();
|
||||
for (ALL_LSDB(on->request_list, lsa, lsanext))
|
||||
json_object_array_add(
|
||||
json_array, json_object_new_string(lsa->name));
|
||||
json_object_array_add(json_array,
|
||||
json_object_new_string(lsa->name));
|
||||
json_object_object_add(json_neighbor, "pendingLsaLsReq",
|
||||
json_array);
|
||||
|
||||
|
||||
timerclear(&res);
|
||||
if (event_is_scheduled(on->thread_send_lsupdate))
|
||||
timersub(&on->thread_send_lsupdate->u.sands, &now,
|
||||
&res);
|
||||
timersub(&on->thread_send_lsupdate->u.sands, &now, &res);
|
||||
timerstring(&res, duration, sizeof(duration));
|
||||
json_object_int_add(json_neighbor, "pendingLsaLsUpdateCount",
|
||||
on->lsupdate_list->count);
|
||||
json_object_string_add(json_neighbor, "pendingLsaLsUpdateTime",
|
||||
duration);
|
||||
json_object_string_add(
|
||||
json_neighbor, "lsUpdateSendThread",
|
||||
(event_is_scheduled(on->thread_send_lsupdate) ? "on"
|
||||
: "off"));
|
||||
json_object_string_add(json_neighbor, "lsUpdateSendThread",
|
||||
(event_is_scheduled(
|
||||
on->thread_send_lsupdate)
|
||||
? "on"
|
||||
: "off"));
|
||||
json_array = json_object_new_array();
|
||||
for (ALL_LSDB(on->lsupdate_list, lsa, lsanext))
|
||||
json_object_array_add(
|
||||
json_array, json_object_new_string(lsa->name));
|
||||
json_object_array_add(json_array,
|
||||
json_object_new_string(lsa->name));
|
||||
json_object_object_add(json_neighbor, "pendingLsaLsUpdate",
|
||||
json_array);
|
||||
|
||||
|
@ -884,14 +1124,14 @@ static void ospf6_neighbor_show_detail(struct vty *vty,
|
|||
on->lsack_list->count);
|
||||
json_object_string_add(json_neighbor, "pendingLsaLsAckTime",
|
||||
duration);
|
||||
json_object_string_add(
|
||||
json_neighbor, "lsAckSendThread",
|
||||
(event_is_scheduled(on->thread_send_lsack) ? "on"
|
||||
: "off"));
|
||||
json_object_string_add(json_neighbor, "lsAckSendThread",
|
||||
(event_is_scheduled(on->thread_send_lsack)
|
||||
? "on"
|
||||
: "off"));
|
||||
json_array = json_object_new_array();
|
||||
for (ALL_LSDB(on->lsack_list, lsa, lsanext))
|
||||
json_object_array_add(
|
||||
json_array, json_object_new_string(lsa->name));
|
||||
json_object_array_add(json_array,
|
||||
json_object_new_string(lsa->name));
|
||||
json_object_object_add(json_neighbor, "pendingLsaLsAck",
|
||||
json_array);
|
||||
|
||||
|
@ -900,36 +1140,36 @@ static void ospf6_neighbor_show_detail(struct vty *vty,
|
|||
if (on->auth_present == true) {
|
||||
json_object_string_add(json_neighbor, "authStatus",
|
||||
"enabled");
|
||||
json_object_int_add(
|
||||
json_neighbor, "recvdHelloHigherSeqNo",
|
||||
on->seqnum_h[OSPF6_MESSAGE_TYPE_HELLO]);
|
||||
json_object_int_add(
|
||||
json_neighbor, "recvdHelloLowerSeqNo",
|
||||
on->seqnum_l[OSPF6_MESSAGE_TYPE_HELLO]);
|
||||
json_object_int_add(
|
||||
json_neighbor, "recvdDBDescHigherSeqNo",
|
||||
on->seqnum_h[OSPF6_MESSAGE_TYPE_DBDESC]);
|
||||
json_object_int_add(
|
||||
json_neighbor, "recvdDBDescLowerSeqNo",
|
||||
on->seqnum_l[OSPF6_MESSAGE_TYPE_DBDESC]);
|
||||
json_object_int_add(
|
||||
json_neighbor, "recvdLSReqHigherSeqNo",
|
||||
on->seqnum_h[OSPF6_MESSAGE_TYPE_LSREQ]);
|
||||
json_object_int_add(
|
||||
json_neighbor, "recvdLSReqLowerSeqNo",
|
||||
on->seqnum_l[OSPF6_MESSAGE_TYPE_LSREQ]);
|
||||
json_object_int_add(
|
||||
json_neighbor, "recvdLSUpdHigherSeqNo",
|
||||
on->seqnum_h[OSPF6_MESSAGE_TYPE_LSUPDATE]);
|
||||
json_object_int_add(
|
||||
json_neighbor, "recvdLSUpdLowerSeqNo",
|
||||
on->seqnum_l[OSPF6_MESSAGE_TYPE_LSUPDATE]);
|
||||
json_object_int_add(
|
||||
json_neighbor, "recvdLSAckHigherSeqNo",
|
||||
on->seqnum_h[OSPF6_MESSAGE_TYPE_LSACK]);
|
||||
json_object_int_add(
|
||||
json_neighbor, "recvdLSAckLowerSeqNo",
|
||||
on->seqnum_l[OSPF6_MESSAGE_TYPE_LSACK]);
|
||||
json_object_int_add(json_neighbor,
|
||||
"recvdHelloHigherSeqNo",
|
||||
on->seqnum_h[OSPF6_MESSAGE_TYPE_HELLO]);
|
||||
json_object_int_add(json_neighbor,
|
||||
"recvdHelloLowerSeqNo",
|
||||
on->seqnum_l[OSPF6_MESSAGE_TYPE_HELLO]);
|
||||
json_object_int_add(json_neighbor,
|
||||
"recvdDBDescHigherSeqNo",
|
||||
on->seqnum_h[OSPF6_MESSAGE_TYPE_DBDESC]);
|
||||
json_object_int_add(json_neighbor,
|
||||
"recvdDBDescLowerSeqNo",
|
||||
on->seqnum_l[OSPF6_MESSAGE_TYPE_DBDESC]);
|
||||
json_object_int_add(json_neighbor,
|
||||
"recvdLSReqHigherSeqNo",
|
||||
on->seqnum_h[OSPF6_MESSAGE_TYPE_LSREQ]);
|
||||
json_object_int_add(json_neighbor,
|
||||
"recvdLSReqLowerSeqNo",
|
||||
on->seqnum_l[OSPF6_MESSAGE_TYPE_LSREQ]);
|
||||
json_object_int_add(json_neighbor,
|
||||
"recvdLSUpdHigherSeqNo",
|
||||
on->seqnum_h[OSPF6_MESSAGE_TYPE_LSUPDATE]);
|
||||
json_object_int_add(json_neighbor,
|
||||
"recvdLSUpdLowerSeqNo",
|
||||
on->seqnum_l[OSPF6_MESSAGE_TYPE_LSUPDATE]);
|
||||
json_object_int_add(json_neighbor,
|
||||
"recvdLSAckHigherSeqNo",
|
||||
on->seqnum_h[OSPF6_MESSAGE_TYPE_LSACK]);
|
||||
json_object_int_add(json_neighbor,
|
||||
"recvdLSAckLowerSeqNo",
|
||||
on->seqnum_l[OSPF6_MESSAGE_TYPE_LSACK]);
|
||||
} else
|
||||
json_object_string_add(json_neighbor, "authStatus",
|
||||
"disabled");
|
||||
|
@ -951,9 +1191,8 @@ static void ospf6_neighbor_show_detail(struct vty *vty,
|
|||
(CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_IBIT)
|
||||
? "Initial "
|
||||
: ""),
|
||||
(CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MBIT)
|
||||
? "More "
|
||||
: ""),
|
||||
(CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MBIT) ? "More "
|
||||
: ""),
|
||||
(CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MSBIT)
|
||||
? "Master"
|
||||
: "Slave"),
|
||||
|
@ -1000,8 +1239,7 @@ static void ospf6_neighbor_show_detail(struct vty *vty,
|
|||
|
||||
timerclear(&res);
|
||||
if (event_is_scheduled(on->thread_send_lsupdate))
|
||||
timersub(&on->thread_send_lsupdate->u.sands, &now,
|
||||
&res);
|
||||
timersub(&on->thread_send_lsupdate->u.sands, &now, &res);
|
||||
timerstring(&res, duration, sizeof(duration));
|
||||
vty_out(vty,
|
||||
" %d Pending LSAs for LSUpdate in Time %s [thread %s]\n",
|
||||
|
@ -1141,8 +1379,7 @@ DEFUN(show_ipv6_ospf6_neighbor, show_ipv6_ospf6_neighbor_cmd,
|
|||
|
||||
static int ospf6_neighbor_show_common(struct vty *vty, int argc,
|
||||
struct cmd_token **argv,
|
||||
struct ospf6 *ospf6, int idx_ipv4,
|
||||
bool uj)
|
||||
struct ospf6 *ospf6, int idx_ipv4, bool uj)
|
||||
{
|
||||
struct ospf6_neighbor *on;
|
||||
struct ospf6_interface *oi;
|
||||
|
@ -1214,16 +1451,18 @@ void ospf6_neighbor_init(void)
|
|||
{
|
||||
install_element(VIEW_NODE, &show_ipv6_ospf6_neighbor_cmd);
|
||||
install_element(VIEW_NODE, &show_ipv6_ospf6_neighbor_one_cmd);
|
||||
|
||||
install_element(INTERFACE_NODE, &ipv6_ospf6_p2xp_neigh_cmd);
|
||||
install_element(INTERFACE_NODE, &ipv6_ospf6_p2xp_neigh_cost_cmd);
|
||||
install_element(INTERFACE_NODE,
|
||||
&ipv6_ospf6_p2xp_neigh_poll_interval_cmd);
|
||||
}
|
||||
|
||||
DEFUN (debug_ospf6_neighbor,
|
||||
debug_ospf6_neighbor_cmd,
|
||||
"debug ospf6 neighbor [<state|event>]",
|
||||
DEBUG_STR
|
||||
OSPF6_STR
|
||||
"Debug OSPFv3 Neighbor\n"
|
||||
"Debug OSPFv3 Neighbor State Change\n"
|
||||
"Debug OSPFv3 Neighbor Event\n")
|
||||
DEFUN(debug_ospf6_neighbor, debug_ospf6_neighbor_cmd,
|
||||
"debug ospf6 neighbor [<state|event>]",
|
||||
DEBUG_STR OSPF6_STR "Debug OSPFv3 Neighbor\n"
|
||||
"Debug OSPFv3 Neighbor State Change\n"
|
||||
"Debug OSPFv3 Neighbor Event\n")
|
||||
{
|
||||
int idx_type = 3;
|
||||
unsigned char level = 0;
|
||||
|
@ -1241,15 +1480,11 @@ DEFUN (debug_ospf6_neighbor,
|
|||
}
|
||||
|
||||
|
||||
DEFUN (no_debug_ospf6_neighbor,
|
||||
no_debug_ospf6_neighbor_cmd,
|
||||
"no debug ospf6 neighbor [<state|event>]",
|
||||
NO_STR
|
||||
DEBUG_STR
|
||||
OSPF6_STR
|
||||
"Debug OSPFv3 Neighbor\n"
|
||||
"Debug OSPFv3 Neighbor State Change\n"
|
||||
"Debug OSPFv3 Neighbor Event\n")
|
||||
DEFUN(no_debug_ospf6_neighbor, no_debug_ospf6_neighbor_cmd,
|
||||
"no debug ospf6 neighbor [<state|event>]",
|
||||
NO_STR DEBUG_STR OSPF6_STR "Debug OSPFv3 Neighbor\n"
|
||||
"Debug OSPFv3 Neighbor State Change\n"
|
||||
"Debug OSPFv3 Neighbor Event\n")
|
||||
{
|
||||
int idx_type = 4;
|
||||
unsigned char level = 0;
|
||||
|
@ -1267,12 +1502,8 @@ DEFUN (no_debug_ospf6_neighbor,
|
|||
}
|
||||
|
||||
|
||||
DEFUN (no_debug_ospf6,
|
||||
no_debug_ospf6_cmd,
|
||||
"no debug ospf6",
|
||||
NO_STR
|
||||
DEBUG_STR
|
||||
OSPF6_STR)
|
||||
DEFUN(no_debug_ospf6, no_debug_ospf6_cmd, "no debug ospf6",
|
||||
NO_STR DEBUG_STR OSPF6_STR)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
|
@ -1287,12 +1518,11 @@ DEFUN (no_debug_ospf6,
|
|||
ospf6_lsa_debug_set_all(false);
|
||||
|
||||
for (i = 0; i < 6; i++)
|
||||
OSPF6_DEBUG_MESSAGE_OFF(i,
|
||||
OSPF6_DEBUG_NEIGHBOR_STATE
|
||||
| OSPF6_DEBUG_NEIGHBOR_EVENT);
|
||||
OSPF6_DEBUG_MESSAGE_OFF(i, OSPF6_DEBUG_NEIGHBOR_STATE |
|
||||
OSPF6_DEBUG_NEIGHBOR_EVENT);
|
||||
|
||||
OSPF6_DEBUG_NEIGHBOR_OFF(OSPF6_DEBUG_NEIGHBOR_STATE
|
||||
| OSPF6_DEBUG_NEIGHBOR_EVENT);
|
||||
OSPF6_DEBUG_NEIGHBOR_OFF(OSPF6_DEBUG_NEIGHBOR_STATE |
|
||||
OSPF6_DEBUG_NEIGHBOR_EVENT);
|
||||
OSPF6_DEBUG_ROUTE_OFF(OSPF6_DEBUG_ROUTE_TABLE);
|
||||
OSPF6_DEBUG_ROUTE_OFF(OSPF6_DEBUG_ROUTE_INTRA);
|
||||
OSPF6_DEBUG_ROUTE_OFF(OSPF6_DEBUG_ROUTE_INTER);
|
||||
|
@ -1316,6 +1546,25 @@ int config_write_ospf6_debug_neighbor(struct vty *vty)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int config_write_ospf6_p2xp_neighbor(struct vty *vty, struct ospf6_interface *oi)
|
||||
{
|
||||
struct ospf6_if_p2xp_neighcfg *p2xp_cfg;
|
||||
|
||||
frr_each (ospf6_if_p2xp_neighcfgs, &oi->p2xp_neighs, p2xp_cfg) {
|
||||
vty_out(vty, " ipv6 ospf6 neighbor %pI6\n", &p2xp_cfg->addr);
|
||||
|
||||
if (p2xp_cfg->poll_interval)
|
||||
vty_out(vty,
|
||||
" ipv6 ospf6 neighbor %pI6 poll-interval %u\n",
|
||||
&p2xp_cfg->addr, p2xp_cfg->poll_interval);
|
||||
|
||||
if (p2xp_cfg->cfg_cost)
|
||||
vty_out(vty, " ipv6 ospf6 neighbor %pI6 cost %u\n",
|
||||
&p2xp_cfg->addr, p2xp_cfg->cost);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void install_element_ospf6_debug_neighbor(void)
|
||||
{
|
||||
install_element(ENABLE_NODE, &debug_ospf6_neighbor_cmd);
|
||||
|
|
|
@ -6,8 +6,11 @@
|
|||
#ifndef OSPF6_NEIGHBOR_H
|
||||
#define OSPF6_NEIGHBOR_H
|
||||
|
||||
#include "typesafe.h"
|
||||
#include "hook.h"
|
||||
|
||||
#include "ospf6_message.h"
|
||||
|
||||
/* Forward declaration(s). */
|
||||
struct ospf6_area;
|
||||
|
||||
|
@ -52,6 +55,8 @@ struct ospf6_helper_info {
|
|||
uint32_t rejected_reason;
|
||||
};
|
||||
|
||||
struct ospf6_if_p2xp_neighcfg;
|
||||
|
||||
/* Neighbor structure */
|
||||
struct ospf6_neighbor {
|
||||
/* Neighbor Router ID String */
|
||||
|
@ -60,6 +65,11 @@ struct ospf6_neighbor {
|
|||
/* OSPFv3 Interface this neighbor belongs to */
|
||||
struct ospf6_interface *ospf6_if;
|
||||
|
||||
/* P2P/P2MP config for this neighbor.
|
||||
* can be NULL if not explicitly configured!
|
||||
*/
|
||||
struct ospf6_if_p2xp_neighcfg *p2xp_cfg;
|
||||
|
||||
/* Neighbor state */
|
||||
uint8_t state;
|
||||
|
||||
|
@ -190,6 +200,14 @@ struct ospf6_neighbor *ospf6_neighbor_create(uint32_t router_id,
|
|||
struct ospf6_interface *oi);
|
||||
void ospf6_neighbor_delete(struct ospf6_neighbor *on);
|
||||
|
||||
void ospf6_neighbor_lladdr_set(struct ospf6_neighbor *on,
|
||||
const struct in6_addr *addr);
|
||||
struct ospf6_if_p2xp_neighcfg *ospf6_if_p2xp_find(struct ospf6_interface *oi,
|
||||
const struct in6_addr *addr);
|
||||
void ospf6_if_p2xp_up(struct ospf6_interface *oi);
|
||||
|
||||
uint32_t ospf6_neighbor_cost(struct ospf6_neighbor *on);
|
||||
|
||||
/* Neighbor event */
|
||||
extern void hello_received(struct event *thread);
|
||||
extern void twoway_received(struct event *thread);
|
||||
|
@ -205,6 +223,8 @@ extern void ospf6_check_nbr_loading(struct ospf6_neighbor *on);
|
|||
|
||||
extern void ospf6_neighbor_init(void);
|
||||
extern int config_write_ospf6_debug_neighbor(struct vty *vty);
|
||||
extern int config_write_ospf6_p2xp_neighbor(struct vty *vty,
|
||||
struct ospf6_interface *oi);
|
||||
extern void install_element_ospf6_debug_neighbor(void);
|
||||
|
||||
DECLARE_HOOK(ospf6_neighbor_change,
|
||||
|
|
|
@ -540,6 +540,10 @@ int ospf6_route_cmp(struct ospf6_route *ra, struct ospf6_route *rb)
|
|||
if (ra->path.area_id != rb->path.area_id)
|
||||
return (ntohl(ra->path.area_id) - ntohl(rb->path.area_id));
|
||||
|
||||
if ((ra->prefix_options & OSPF6_PREFIX_OPTION_LA)
|
||||
!= (rb->prefix_options & OSPF6_PREFIX_OPTION_LA))
|
||||
return ra->prefix_options & OSPF6_PREFIX_OPTION_LA ? -1 : 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -1126,6 +1126,8 @@ static uint8_t *ospfv3IfEntry(struct variable *v, oid *name, size_t *length,
|
|||
return SNMP_INTEGER(1);
|
||||
else if (oi->type == OSPF_IFTYPE_POINTOPOINT)
|
||||
return SNMP_INTEGER(3);
|
||||
else if (oi->type == OSPF_IFTYPE_POINTOMULTIPOINT)
|
||||
return SNMP_INTEGER(5);
|
||||
else
|
||||
break; /* Unknown, don't put anything */
|
||||
case OSPFv3IFADMINSTATUS:
|
||||
|
@ -1367,6 +1369,7 @@ static int ospf6TrapIfStateChange(struct ospf6_interface *oi, int next_state,
|
|||
|
||||
/* Terminal state or regression */
|
||||
if ((next_state != OSPF6_INTERFACE_POINTTOPOINT)
|
||||
&& (next_state != OSPF6_INTERFACE_POINTTOMULTIPOINT)
|
||||
&& (next_state != OSPF6_INTERFACE_DROTHER)
|
||||
&& (next_state != OSPF6_INTERFACE_BDR)
|
||||
&& (next_state != OSPF6_INTERFACE_DR) && (next_state >= prev_state))
|
||||
|
|
|
@ -83,8 +83,10 @@ clippy_scan += \
|
|||
ospf6d/ospf6_lsa.c \
|
||||
ospf6d/ospf6_gr_helper.c \
|
||||
ospf6d/ospf6_gr.c \
|
||||
ospf6d/ospf6_interface.c \
|
||||
ospf6d/ospf6_nssa.c \
|
||||
ospf6d/ospf6_route.c \
|
||||
ospf6d/ospf6_neighbor.c \
|
||||
# end
|
||||
|
||||
nodist_ospf6d_ospf6d_SOURCES = \
|
||||
|
|
|
@ -110,15 +110,18 @@ def test_wait_protocol_convergence():
|
|||
|
||||
def expect_neighbor_full(router, neighbor):
|
||||
"Wait until OSPFv3 neighborship is full"
|
||||
logger.info("waiting for OSPFv3 router '{}' neighborship with '{}'".format(router, neighbor))
|
||||
logger.info(
|
||||
"waiting for OSPFv3 router '{}' neighborship with '{}'".format(
|
||||
router, neighbor
|
||||
)
|
||||
)
|
||||
test_func = partial(
|
||||
topotest.router_json_cmp,
|
||||
tgen.gears[router],
|
||||
"show ipv6 ospf6 neighbor json",
|
||||
{"neighbors": [{"neighborId": neighbor, "state": "Full"}]},
|
||||
)
|
||||
_, result = topotest.run_and_expect(test_func, None,
|
||||
count=130, wait=1)
|
||||
_, result = topotest.run_and_expect(test_func, None, count=130, wait=1)
|
||||
assertmsg = '"{}" convergence failure'.format(router)
|
||||
assert result is None, assertmsg
|
||||
|
||||
|
@ -143,6 +146,7 @@ def test_wait_protocol_convergence():
|
|||
expect_neighbor_full("r8", "10.254.254.5")
|
||||
expect_neighbor_full("r9", "10.254.254.5")
|
||||
|
||||
|
||||
def test_ecmp_inter_area():
|
||||
"Test whether OSPFv3 ECMP nexthops are properly updated for inter-area routes after link down"
|
||||
tgen = get_topogen()
|
||||
|
@ -156,22 +160,28 @@ def test_ecmp_inter_area():
|
|||
|
||||
def expect_num_nexthops(router, expected_num_nexthops, count):
|
||||
"Wait until number of nexthops for routes matches expectation"
|
||||
logger.info("waiting for OSPFv3 router '{}' nexthops {}".format(router, expected_num_nexthops))
|
||||
logger.info(
|
||||
"waiting for OSPFv3 router '{}' nexthops {}".format(
|
||||
router, expected_num_nexthops
|
||||
)
|
||||
)
|
||||
test_func = partial(num_nexthops, router)
|
||||
_, result = topotest.run_and_expect(test_func, expected_num_nexthops,
|
||||
count=count, wait=3)
|
||||
assert result == expected_num_nexthops, \
|
||||
"'{}' wrong number of route nexthops".format(router)
|
||||
_, result = topotest.run_and_expect(
|
||||
test_func, expected_num_nexthops, count=count, wait=3
|
||||
)
|
||||
assert (
|
||||
result == expected_num_nexthops
|
||||
), "'{}' wrong number of route nexthops".format(router)
|
||||
|
||||
# Check nexthops pre link-down
|
||||
expect_num_nexthops("r1", [1, 1, 1, 3, 3, 3, 3, 3], 4)
|
||||
expect_num_nexthops("r1", [1, 1, 1, 3, 3, 3, 3, 3, 3, 3], 4)
|
||||
|
||||
logger.info("triggering R2-R4 link down")
|
||||
tgen.gears["r2"].run("ip link set r2-eth1 down")
|
||||
|
||||
#tgen.mininet_cli()
|
||||
# tgen.mininet_cli()
|
||||
# Check nexthops post link-down
|
||||
expect_num_nexthops("r1", [1, 1, 1, 2, 2, 2, 2, 2], 8)
|
||||
expect_num_nexthops("r1", [1, 1, 1, 2, 2, 2, 2, 2, 2, 2], 8)
|
||||
|
||||
|
||||
def teardown_module(_mod):
|
||||
|
|
137
tests/topotests/ospf6_point_to_multipoint/README.md
Normal file
137
tests/topotests/ospf6_point_to_multipoint/README.md
Normal file
|
@ -0,0 +1,137 @@
|
|||
# OSPFv3 (IPv6) Topology Test (point-to-multipoint)
|
||||
|
||||
## Topology
|
||||
-----\
|
||||
SW1 - Stub Net 1 SW2 - Stub Net 2 \
|
||||
fc00:1:1:1::/64 fc00:2:2:2::/64 \
|
||||
\___________________/ \___________________/ |
|
||||
| | |
|
||||
| | |
|
||||
| ::1 | ::2 |
|
||||
+---------+---------+ +---------+---------+ |
|
||||
| R1 | | R2 | |
|
||||
| FRRouting | | FRRouting | |
|
||||
| Rtr-ID: 10.0.0.1 | | Rtr-ID: 10.0.0.2 | |
|
||||
+---------+---------+ +---------+---------+ |
|
||||
| ::1 | ::2 \
|
||||
\______ ___________/ OSPFv3
|
||||
\ / Area 0.0.0.0
|
||||
\ / /
|
||||
~~~~~~~~~~~~~~~~~~ |
|
||||
~~ SW5 ~~ |
|
||||
~~ Switch ~~ |
|
||||
~~ fc00:A:A:A::/64 ~~ |
|
||||
~~~~~~~~~~~~~~~~~~ |
|
||||
| /---- |
|
||||
| ::3 | SW3 - Stub Net 3 |
|
||||
+---------+---------+ /-+ fc00:3:3:3::/64 |
|
||||
| R3 | / | /
|
||||
| FRRouting +--/ \---- /
|
||||
| Rtr-ID: 10.0.0.3 | ::3 ___________/
|
||||
+---------+---------+ \
|
||||
| ::3 \
|
||||
| \
|
||||
~~~~~~~~~~~~~~~~~~ |
|
||||
~~ SW6 ~~ |
|
||||
~~ Switch ~~ |
|
||||
~~ fc00:B:B:B::/64 ~~ \
|
||||
~~~~~~~~~~~~~~~~~~ OSPFv3
|
||||
| Area 0.0.0.1
|
||||
| ::4 /
|
||||
+---------+---------+ /---- |
|
||||
| R4 | | SW4 - Stub Net 4 |
|
||||
| FRRouting +------+ fc00:4:4:4::/64 |
|
||||
| Rtr-ID: 10.0.0.4 | ::4 | /
|
||||
+-------------------+ \---- /
|
||||
-----/
|
||||
|
||||
## FRR Configuration
|
||||
|
||||
Full config as used is in r1 / r2 / r3 / r4 / r5 subdirectories
|
||||
|
||||
Simplified `R1` config (R1 is similar)
|
||||
|
||||
hostname r1
|
||||
!
|
||||
interface r1-stubnet
|
||||
ipv6 address fc00:1:1:1::1/64
|
||||
ipv6 ospf6 passive
|
||||
ipv6 ospf6 area 0.0.0.0
|
||||
!
|
||||
interface r1-sw5
|
||||
ipv6 address fc00:a:a:a::1/64
|
||||
ipv6 ospf6 network point-to-multipoint
|
||||
ipv6 ospf6 area 0.0.0.0
|
||||
!
|
||||
router ospf6
|
||||
router-id 10.0.0.1
|
||||
log-adjacency-changes detail
|
||||
redistribute static
|
||||
!
|
||||
ipv6 route fc00:1111:1111:1111::/64 fc00:1:1:1::1234
|
||||
|
||||
Simplified `R3` config
|
||||
|
||||
hostname r3
|
||||
!
|
||||
interface r3-stubnet
|
||||
ipv6 address fc00:3:3:3::3/64
|
||||
ipv6 ospf6 passive
|
||||
ipv6 ospf6 area 0.0.0.0
|
||||
!
|
||||
interface r3-sw5
|
||||
ipv6 address fc00:a:a:a::3/64
|
||||
ipv6 ospf6 network point-to-multipoint
|
||||
ipv6 ospf6 area 0.0.0.0
|
||||
ipv6 ospf6 p2p-p2mp connected-prefixes include
|
||||
!
|
||||
interface r3-sw6
|
||||
ipv6 address fc00:b:b:b::3/64
|
||||
ipv6 ospf6 network point-to-multipoint
|
||||
ipv6 ospf6 area 0.0.0.1
|
||||
ipv6 ospf6 p2p-p2mp connected-prefixes include
|
||||
!
|
||||
router ospf6
|
||||
router-id 10.0.0.3
|
||||
log-adjacency-changes detail
|
||||
redistribute static
|
||||
!
|
||||
ipv6 route fc00:3333:3333:3333::/64 fc00:3:3:3::1234
|
||||
|
||||
## Tests executed
|
||||
|
||||
### Check if FRR is running
|
||||
|
||||
Test is executed by running
|
||||
|
||||
vtysh -c "show logging" | grep "Logging configuration for"
|
||||
|
||||
on each FRR router. This should return the logging information for all daemons registered
|
||||
to Zebra and the list of running daemons is compared to the daemons started for this test (`zebra` and `ospf6d`)
|
||||
|
||||
### Check if OSPFv3 to converge
|
||||
|
||||
OSPFv3 is expected to converge on each view within 60s total time. Convergence is verified by executing (on each node)
|
||||
|
||||
vtysh -c "show ipv6 ospf neigh"
|
||||
|
||||
and checking for "Full" neighbor status in the output. An additional 15 seconds after the full converge is waited for
|
||||
routes to populate before the following routing table checks are executed
|
||||
|
||||
### Check OSPFv3 Routing Tables
|
||||
|
||||
Routing table is verified by running
|
||||
|
||||
vtysh -c "show ipv6 route"
|
||||
|
||||
on each node and comparing the result to the stored example config (see `show_ipv6_route.ref` in r1 / r2 / r3 / r4 directories).
|
||||
Link-Local addresses are masked out before the compare.
|
||||
|
||||
### Check Linux Kernel Routing Table
|
||||
|
||||
Linux Kernel IPv6 Routing table is verified on each FRR node with
|
||||
|
||||
ip -6 route
|
||||
|
||||
Tables are compared with reference routing table (see `ip_6_address.ref` in r1 / r2 / r3 / r4 directories).
|
||||
Link-Local addresses are translated after getting collected on each node with interface name to make them consistent
|
|
@ -0,0 +1,14 @@
|
|||
fc00:1111:1111:1111::/64 nhid XXXX via fc00:1:1:1::1234 dev r1-stubnet proto XXXX metric 20 pref medium
|
||||
fc00:1:1:1::/64 dev r1-stubnet proto XXXX metric 256 pref medium
|
||||
fc00:2222:2222:2222::/64 nhid XXXX via fe80::__(r2-sw5)__ dev r1-sw5 proto XXXX metric 20 pref medium
|
||||
fc00:2:2:2::/64 nhid XXXX via fe80::__(r2-sw5)__ dev r1-sw5 proto XXXX metric 20 pref medium
|
||||
fc00:3333:3333:3333::/64 nhid XXXX via fe80::__(r3-sw5)__ dev r1-sw5 proto XXXX metric 20 pref medium
|
||||
fc00:3:3:3::/64 nhid XXXX via fe80::__(r3-sw5)__ dev r1-sw5 proto XXXX metric 20 pref medium
|
||||
fc00:4444:4444:4444::/64 nhid XXXX via fe80::__(r3-sw5)__ dev r1-sw5 proto XXXX metric 20 pref medium
|
||||
fc00:4:4:4::/64 nhid XXXX via fe80::__(r3-sw5)__ dev r1-sw5 proto XXXX metric 20 pref medium
|
||||
fc00:a:a:a::/64 dev r1-sw5 proto XXXX metric 256 pref medium
|
||||
fc00:a:a:a::2 nhid XXXX via fe80::__(r2-sw5)__ dev r1-sw5 proto XXXX metric 20 pref medium
|
||||
fc00:a:a:a::3 nhid XXXX via fe80::__(r3-sw5)__ dev r1-sw5 proto XXXX metric 20 pref medium
|
||||
fc00:b:b:b::/64 nhid XXXX via fe80::__(r3-sw5)__ dev r1-sw5 proto XXXX metric 20 pref medium
|
||||
fc00:b:b:b::3 nhid XXXX via fe80::__(r3-sw5)__ dev r1-sw5 proto XXXX metric 20 pref medium
|
||||
fc00:b:b:b::4 nhid XXXX via fe80::__(r3-sw5)__ dev r1-sw5 proto XXXX metric 20 pref medium
|
|
@ -0,0 +1,14 @@
|
|||
fc00:1111:1111:1111::/64 via fc00:1:1:1::1234 dev r1-stubnet proto XXXX metric 20 pref medium
|
||||
fc00:1:1:1::/64 dev r1-stubnet proto XXXX metric 256 pref medium
|
||||
fc00:2222:2222:2222::/64 via fe80::__(r2-sw5)__ dev r1-sw5 proto XXXX metric 20 pref medium
|
||||
fc00:2:2:2::/64 via fe80::__(r2-sw5)__ dev r1-sw5 proto XXXX metric 20 pref medium
|
||||
fc00:3333:3333:3333::/64 via fe80::__(r3-sw5)__ dev r1-sw5 proto XXXX metric 20 pref medium
|
||||
fc00:3:3:3::/64 via fe80::__(r3-sw5)__ dev r1-sw5 proto XXXX metric 20 pref medium
|
||||
fc00:4444:4444:4444::/64 via fe80::__(r3-sw5)__ dev r1-sw5 proto XXXX metric 20 pref medium
|
||||
fc00:4:4:4::/64 via fe80::__(r3-sw5)__ dev r1-sw5 proto XXXX metric 20 pref medium
|
||||
fc00:a:a:a::/64 dev r1-sw5 proto XXXX metric 256 pref medium
|
||||
fc00:a:a:a::2 via fe80::__(r2-sw5)__ dev r1-sw5 proto XXXX metric 20 pref medium
|
||||
fc00:a:a:a::3 via fe80::__(r3-sw5)__ dev r1-sw5 proto XXXX metric 20 pref medium
|
||||
fc00:b:b:b::/64 via fe80::__(r3-sw5)__ dev r1-sw5 proto XXXX metric 20 pref medium
|
||||
fc00:b:b:b::3 via fe80::__(r3-sw5)__ dev r1-sw5 proto XXXX metric 20 pref medium
|
||||
fc00:b:b:b::4 via fe80::__(r3-sw5)__ dev r1-sw5 proto XXXX metric 20 pref medium
|
30
tests/topotests/ospf6_point_to_multipoint/r1/ospf6d.conf
Normal file
30
tests/topotests/ospf6_point_to_multipoint/r1/ospf6d.conf
Normal file
|
@ -0,0 +1,30 @@
|
|||
hostname r1
|
||||
log file ospf6d.log
|
||||
!
|
||||
! debug ospf6 message all
|
||||
! debug ospf6 lsa unknown
|
||||
! debug ospf6 zebra
|
||||
! debug ospf6 interface
|
||||
! debug ospf6 neighbor
|
||||
! debug ospf6 route table
|
||||
! debug ospf6 flooding
|
||||
!
|
||||
interface r1-sw5
|
||||
ipv6 ospf6 network point-to-multipoint
|
||||
ipv6 ospf6 area 0.0.0.0
|
||||
ipv6 ospf6 hello-interval 2
|
||||
ipv6 ospf6 dead-interval 10
|
||||
ipv6 ospf6 p2p-p2mp connected-prefixes include
|
||||
!
|
||||
interface r1-stubnet
|
||||
ipv6 ospf6 passive
|
||||
ipv6 ospf6 area 0.0.0.0
|
||||
!
|
||||
router ospf6
|
||||
ospf6 router-id 10.0.0.1
|
||||
log-adjacency-changes detail
|
||||
redistribute static
|
||||
!
|
||||
line vty
|
||||
exec-timeout 0 0
|
||||
!
|
|
@ -0,0 +1,13 @@
|
|||
O fc00:1:1:1::/64 [110/10] is directly connected, r1-stubnet, weight 1, XX:XX:XX
|
||||
O>* fc00:2:2:2::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, weight 1, XX:XX:XX
|
||||
O>* fc00:3:3:3::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, weight 1, XX:XX:XX
|
||||
O>* fc00:4:4:4::/64 [110/30] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, weight 1, XX:XX:XX
|
||||
O fc00:a:a:a::/64 [110/10] is directly connected, r1-sw5, weight 1, XX:XX:XX
|
||||
O>* fc00:a:a:a::2/128 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, weight 1, XX:XX:XX
|
||||
O>* fc00:a:a:a::3/128 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, weight 1, XX:XX:XX
|
||||
O>* fc00:b:b:b::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, weight 1, XX:XX:XX
|
||||
O>* fc00:b:b:b::3/128 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, weight 1, XX:XX:XX
|
||||
O>* fc00:b:b:b::4/128 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, weight 1, XX:XX:XX
|
||||
O>* fc00:2222:2222:2222::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, weight 1, XX:XX:XX
|
||||
O>* fc00:3333:3333:3333::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, weight 1, XX:XX:XX
|
||||
O>* fc00:4444:4444:4444::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, weight 1, XX:XX:XX
|
20
tests/topotests/ospf6_point_to_multipoint/r1/zebra.conf
Normal file
20
tests/topotests/ospf6_point_to_multipoint/r1/zebra.conf
Normal file
|
@ -0,0 +1,20 @@
|
|||
!
|
||||
hostname r1
|
||||
log file zebra.log
|
||||
!
|
||||
! debug zebra events
|
||||
! debug zebra rib
|
||||
!
|
||||
interface r1-stubnet
|
||||
ipv6 address fc00:1:1:1::1/64
|
||||
!
|
||||
interface r1-sw5
|
||||
ipv6 address fc00:a:a:a::1/64
|
||||
!
|
||||
interface lo
|
||||
!
|
||||
ipv6 route fc00:1111:1111:1111::/64 fc00:1:1:1::1234
|
||||
!
|
||||
!
|
||||
line vty
|
||||
!
|
|
@ -0,0 +1,14 @@
|
|||
fc00:1111:1111:1111::/64 nhid XXXX via fe80::__(r1-sw5)__ dev r2-sw5 proto XXXX metric 20 pref medium
|
||||
fc00:1:1:1::/64 nhid XXXX via fe80::__(r1-sw5)__ dev r2-sw5 proto XXXX metric 20 pref medium
|
||||
fc00:2222:2222:2222::/64 nhid XXXX via fc00:2:2:2::1234 dev r2-stubnet proto XXXX metric 20 pref medium
|
||||
fc00:2:2:2::/64 dev r2-stubnet proto XXXX metric 256 pref medium
|
||||
fc00:3333:3333:3333::/64 nhid XXXX via fe80::__(r3-sw5)__ dev r2-sw5 proto XXXX metric 20 pref medium
|
||||
fc00:3:3:3::/64 nhid XXXX via fe80::__(r3-sw5)__ dev r2-sw5 proto XXXX metric 20 pref medium
|
||||
fc00:4444:4444:4444::/64 nhid XXXX via fe80::__(r3-sw5)__ dev r2-sw5 proto XXXX metric 20 pref medium
|
||||
fc00:4:4:4::/64 nhid XXXX via fe80::__(r3-sw5)__ dev r2-sw5 proto XXXX metric 20 pref medium
|
||||
fc00:a:a:a::/64 dev r2-sw5 proto XXXX metric 256 pref medium
|
||||
fc00:a:a:a::1 nhid XXXX via fe80::__(r1-sw5)__ dev r2-sw5 proto XXXX metric 20 pref medium
|
||||
fc00:a:a:a::3 nhid XXXX via fe80::__(r3-sw5)__ dev r2-sw5 proto XXXX metric 20 pref medium
|
||||
fc00:b:b:b::/64 nhid XXXX via fe80::__(r3-sw5)__ dev r2-sw5 proto XXXX metric 20 pref medium
|
||||
fc00:b:b:b::3 nhid XXXX via fe80::__(r3-sw5)__ dev r2-sw5 proto XXXX metric 20 pref medium
|
||||
fc00:b:b:b::4 nhid XXXX via fe80::__(r3-sw5)__ dev r2-sw5 proto XXXX metric 20 pref medium
|
|
@ -0,0 +1,14 @@
|
|||
fc00:1111:1111:1111::/64 via fe80::__(r1-sw5)__ dev r2-sw5 proto XXXX metric 20 pref medium
|
||||
fc00:1:1:1::/64 via fe80::__(r1-sw5)__ dev r2-sw5 proto XXXX metric 20 pref medium
|
||||
fc00:2222:2222:2222::/64 via fc00:2:2:2::1234 dev r2-stubnet proto XXXX metric 20 pref medium
|
||||
fc00:2:2:2::/64 dev r2-stubnet proto XXXX metric 256 pref medium
|
||||
fc00:3333:3333:3333::/64 via fe80::__(r3-sw5)__ dev r2-sw5 proto XXXX metric 20 pref medium
|
||||
fc00:3:3:3::/64 via fe80::__(r3-sw5)__ dev r2-sw5 proto XXXX metric 20 pref medium
|
||||
fc00:4444:4444:4444::/64 via fe80::__(r3-sw5)__ dev r2-sw5 proto XXXX metric 20 pref medium
|
||||
fc00:4:4:4::/64 via fe80::__(r3-sw5)__ dev r2-sw5 proto XXXX metric 20 pref medium
|
||||
fc00:a:a:a::/64 dev r2-sw5 proto XXXX metric 256 pref medium
|
||||
fc00:a:a:a::1 via fe80::__(r1-sw5)__ dev r2-sw5 proto XXXX metric 20 pref medium
|
||||
fc00:a:a:a::3 via fe80::__(r3-sw5)__ dev r2-sw5 proto XXXX metric 20 pref medium
|
||||
fc00:b:b:b::/64 via fe80::__(r3-sw5)__ dev r2-sw5 proto XXXX metric 20 pref medium
|
||||
fc00:b:b:b::3 via fe80::__(r3-sw5)__ dev r2-sw5 proto XXXX metric 20 pref medium
|
||||
fc00:b:b:b::4 via fe80::__(r3-sw5)__ dev r2-sw5 proto XXXX metric 20 pref medium
|
30
tests/topotests/ospf6_point_to_multipoint/r2/ospf6d.conf
Normal file
30
tests/topotests/ospf6_point_to_multipoint/r2/ospf6d.conf
Normal file
|
@ -0,0 +1,30 @@
|
|||
hostname r2
|
||||
log file ospf6d.log
|
||||
!
|
||||
! debug ospf6 message all
|
||||
! debug ospf6 lsa unknown
|
||||
! debug ospf6 zebra
|
||||
! debug ospf6 interface
|
||||
! debug ospf6 neighbor
|
||||
! debug ospf6 route table
|
||||
! debug ospf6 flooding
|
||||
!
|
||||
interface r2-sw5
|
||||
ipv6 ospf6 network point-to-multipoint
|
||||
ipv6 ospf6 area 0.0.0.0
|
||||
ipv6 ospf6 hello-interval 2
|
||||
ipv6 ospf6 dead-interval 10
|
||||
ipv6 ospf6 p2p-p2mp connected-prefixes include
|
||||
!
|
||||
interface r2-stubnet
|
||||
ipv6 ospf6 passive
|
||||
ipv6 ospf6 area 0.0.0.0
|
||||
!
|
||||
router ospf6
|
||||
ospf6 router-id 10.0.0.2
|
||||
log-adjacency-changes detail
|
||||
redistribute static
|
||||
!
|
||||
line vty
|
||||
exec-timeout 0 0
|
||||
!
|
|
@ -0,0 +1,13 @@
|
|||
O>* fc00:1:1:1::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, weight 1, XX:XX:XX
|
||||
O fc00:2:2:2::/64 [110/10] is directly connected, r2-stubnet, weight 1, XX:XX:XX
|
||||
O>* fc00:3:3:3::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, weight 1, XX:XX:XX
|
||||
O>* fc00:4:4:4::/64 [110/30] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, weight 1, XX:XX:XX
|
||||
O fc00:a:a:a::/64 [110/10] is directly connected, r2-sw5, weight 1, XX:XX:XX
|
||||
O>* fc00:a:a:a::1/128 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, weight 1, XX:XX:XX
|
||||
O>* fc00:a:a:a::3/128 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, weight 1, XX:XX:XX
|
||||
O>* fc00:b:b:b::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, weight 1, XX:XX:XX
|
||||
O>* fc00:b:b:b::3/128 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, weight 1, XX:XX:XX
|
||||
O>* fc00:b:b:b::4/128 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, weight 1, XX:XX:XX
|
||||
O>* fc00:1111:1111:1111::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, weight 1, XX:XX:XX
|
||||
O>* fc00:3333:3333:3333::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, weight 1, XX:XX:XX
|
||||
O>* fc00:4444:4444:4444::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, weight 1, XX:XX:XX
|
20
tests/topotests/ospf6_point_to_multipoint/r2/zebra.conf
Normal file
20
tests/topotests/ospf6_point_to_multipoint/r2/zebra.conf
Normal file
|
@ -0,0 +1,20 @@
|
|||
!
|
||||
hostname r2
|
||||
log file zebra.log
|
||||
!
|
||||
! debug zebra events
|
||||
! debug zebra rib
|
||||
!
|
||||
interface r2-stubnet
|
||||
ipv6 address fc00:2:2:2::2/64
|
||||
!
|
||||
interface r2-sw5
|
||||
ipv6 address fc00:a:a:a::2/64
|
||||
!
|
||||
interface lo
|
||||
!
|
||||
ipv6 route fc00:2222:2222:2222::/64 fc00:2:2:2::1234
|
||||
!
|
||||
!
|
||||
line vty
|
||||
!
|
|
@ -0,0 +1,13 @@
|
|||
fc00:1111:1111:1111::/64 nhid XXXX via fe80::__(r1-sw5)__ dev r3-sw5 proto XXXX metric 20 pref medium
|
||||
fc00:1:1:1::/64 nhid XXXX via fe80::__(r1-sw5)__ dev r3-sw5 proto XXXX metric 20 pref medium
|
||||
fc00:2222:2222:2222::/64 nhid XXXX via fe80::__(r2-sw5)__ dev r3-sw5 proto XXXX metric 20 pref medium
|
||||
fc00:2:2:2::/64 nhid XXXX via fe80::__(r2-sw5)__ dev r3-sw5 proto XXXX metric 20 pref medium
|
||||
fc00:3333:3333:3333::/64 nhid XXXX via fc00:3:3:3::1234 dev r3-stubnet proto XXXX metric 20 pref medium
|
||||
fc00:3:3:3::/64 dev r3-stubnet proto XXXX metric 256 pref medium
|
||||
fc00:4444:4444:4444::/64 nhid XXXX via fe80::__(r4-sw6)__ dev r3-sw6 proto XXXX metric 20 pref medium
|
||||
fc00:4:4:4::/64 nhid XXXX via fe80::__(r4-sw6)__ dev r3-sw6 proto XXXX metric 20 pref medium
|
||||
fc00:a:a:a::/64 dev r3-sw5 proto XXXX metric 256 pref medium
|
||||
fc00:a:a:a::1 nhid XXXX via fe80::__(r1-sw5)__ dev r3-sw5 proto XXXX metric 20 pref medium
|
||||
fc00:a:a:a::2 nhid XXXX via fe80::__(r2-sw5)__ dev r3-sw5 proto XXXX metric 20 pref medium
|
||||
fc00:b:b:b::/64 dev r3-sw6 proto XXXX metric 256 pref medium
|
||||
fc00:b:b:b::4 nhid XXXX via fe80::__(r4-sw6)__ dev r3-sw6 proto XXXX metric 20 pref medium
|
|
@ -0,0 +1,13 @@
|
|||
fc00:1111:1111:1111::/64 via fe80::__(r1-sw5)__ dev r3-sw5 proto XXXX metric 20 pref medium
|
||||
fc00:1:1:1::/64 via fe80::__(r1-sw5)__ dev r3-sw5 proto XXXX metric 20 pref medium
|
||||
fc00:2222:2222:2222::/64 via fe80::__(r2-sw5)__ dev r3-sw5 proto XXXX metric 20 pref medium
|
||||
fc00:2:2:2::/64 via fe80::__(r2-sw5)__ dev r3-sw5 proto XXXX metric 20 pref medium
|
||||
fc00:3333:3333:3333::/64 via fc00:3:3:3::1234 dev r3-stubnet proto XXXX metric 20 pref medium
|
||||
fc00:3:3:3::/64 dev r3-stubnet proto XXXX metric 256 pref medium
|
||||
fc00:4444:4444:4444::/64 via fe80::__(r4-sw6)__ dev r3-sw6 proto XXXX metric 20 pref medium
|
||||
fc00:4:4:4::/64 via fe80::__(r4-sw6)__ dev r3-sw6 proto XXXX metric 20 pref medium
|
||||
fc00:a:a:a::/64 dev r3-sw5 proto XXXX metric 256 pref medium
|
||||
fc00:a:a:a::1 via fe80::__(r1-sw5)__ dev r3-sw5 proto XXXX metric 20 pref medium
|
||||
fc00:a:a:a::2 via fe80::__(r2-sw5)__ dev r3-sw5 proto XXXX metric 20 pref medium
|
||||
fc00:b:b:b::/64 dev r3-sw6 proto XXXX metric 256 pref medium
|
||||
fc00:b:b:b::4 via fe80::__(r4-sw6)__ dev r3-sw6 proto XXXX metric 20 pref medium
|
37
tests/topotests/ospf6_point_to_multipoint/r3/ospf6d.conf
Normal file
37
tests/topotests/ospf6_point_to_multipoint/r3/ospf6d.conf
Normal file
|
@ -0,0 +1,37 @@
|
|||
hostname r3
|
||||
log file ospf6d.log
|
||||
!
|
||||
! debug ospf6 message all
|
||||
! debug ospf6 lsa unknown
|
||||
! debug ospf6 zebra
|
||||
! debug ospf6 interface
|
||||
! debug ospf6 neighbor
|
||||
! debug ospf6 route table
|
||||
! debug ospf6 flooding
|
||||
!
|
||||
interface r3-sw5
|
||||
ipv6 ospf6 network point-to-multipoint
|
||||
ipv6 ospf6 area 0.0.0.0
|
||||
ipv6 ospf6 hello-interval 2
|
||||
ipv6 ospf6 dead-interval 10
|
||||
ipv6 ospf6 p2p-p2mp connected-prefixes include
|
||||
!
|
||||
interface r3-sw6
|
||||
ipv6 ospf6 network point-to-multipoint
|
||||
ipv6 ospf6 area 0.0.0.1
|
||||
ipv6 ospf6 hello-interval 2
|
||||
ipv6 ospf6 dead-interval 10
|
||||
ipv6 ospf6 p2p-p2mp connected-prefixes include
|
||||
!
|
||||
interface r3-stubnet
|
||||
ipv6 ospf6 passive
|
||||
ipv6 ospf6 area 0.0.0.0
|
||||
!
|
||||
router ospf6
|
||||
ospf6 router-id 10.0.0.3
|
||||
log-adjacency-changes detail
|
||||
redistribute static
|
||||
!
|
||||
line vty
|
||||
exec-timeout 0 0
|
||||
!
|
|
@ -0,0 +1,12 @@
|
|||
O>* fc00:1:1:1::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw5, weight 1, XX:XX:XX
|
||||
O>* fc00:2:2:2::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw5, weight 1, XX:XX:XX
|
||||
O fc00:3:3:3::/64 [110/10] is directly connected, r3-stubnet, weight 1, XX:XX:XX
|
||||
O>* fc00:4:4:4::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw6, weight 1, XX:XX:XX
|
||||
O fc00:a:a:a::/64 [110/10] is directly connected, r3-sw5, weight 1, XX:XX:XX
|
||||
O>* fc00:a:a:a::1/128 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw5, weight 1, XX:XX:XX
|
||||
O>* fc00:a:a:a::2/128 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw5, weight 1, XX:XX:XX
|
||||
O fc00:b:b:b::/64 [110/10] is directly connected, r3-sw6, weight 1, XX:XX:XX
|
||||
O>* fc00:b:b:b::4/128 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw6, weight 1, XX:XX:XX
|
||||
O>* fc00:1111:1111:1111::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw5, weight 1, XX:XX:XX
|
||||
O>* fc00:2222:2222:2222::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw5, weight 1, XX:XX:XX
|
||||
O>* fc00:4444:4444:4444::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw6, weight 1, XX:XX:XX
|
23
tests/topotests/ospf6_point_to_multipoint/r3/zebra.conf
Normal file
23
tests/topotests/ospf6_point_to_multipoint/r3/zebra.conf
Normal file
|
@ -0,0 +1,23 @@
|
|||
!
|
||||
hostname r3
|
||||
log file zebra.log
|
||||
!
|
||||
! debug zebra events
|
||||
! debug zebra rib
|
||||
!
|
||||
interface r3-stubnet
|
||||
ipv6 address fc00:3:3:3::3/64
|
||||
!
|
||||
interface r3-sw5
|
||||
ipv6 address fc00:a:a:a::3/64
|
||||
!
|
||||
interface r3-sw6
|
||||
ipv6 address fc00:b:b:b::3/64
|
||||
!
|
||||
interface lo
|
||||
!
|
||||
ipv6 route fc00:3333:3333:3333::/64 fc00:3:3:3::1234
|
||||
!
|
||||
!
|
||||
line vty
|
||||
!
|
|
@ -0,0 +1,14 @@
|
|||
fc00:1111:1111:1111::/64 nhid XXXX via fe80::__(r3-sw6)__ dev r4-sw6 proto XXXX metric 20 pref medium
|
||||
fc00:1:1:1::/64 nhid XXXX via fe80::__(r3-sw6)__ dev r4-sw6 proto XXXX metric 20 pref medium
|
||||
fc00:2222:2222:2222::/64 nhid XXXX via fe80::__(r3-sw6)__ dev r4-sw6 proto XXXX metric 20 pref medium
|
||||
fc00:2:2:2::/64 nhid XXXX via fe80::__(r3-sw6)__ dev r4-sw6 proto XXXX metric 20 pref medium
|
||||
fc00:3333:3333:3333::/64 nhid XXXX via fe80::__(r3-sw6)__ dev r4-sw6 proto XXXX metric 20 pref medium
|
||||
fc00:3:3:3::/64 nhid XXXX via fe80::__(r3-sw6)__ dev r4-sw6 proto XXXX metric 20 pref medium
|
||||
fc00:4444:4444:4444::/64 nhid XXXX via fc00:4:4:4::1234 dev r4-stubnet proto XXXX metric 20 pref medium
|
||||
fc00:4:4:4::/64 dev r4-stubnet proto XXXX metric 256 pref medium
|
||||
fc00:a:a:a::/64 nhid XXXX via fe80::__(r3-sw6)__ dev r4-sw6 proto XXXX metric 20 pref medium
|
||||
fc00:a:a:a::1 nhid XXXX via fe80::__(r3-sw6)__ dev r4-sw6 proto XXXX metric 20 pref medium
|
||||
fc00:a:a:a::2 nhid XXXX via fe80::__(r3-sw6)__ dev r4-sw6 proto XXXX metric 20 pref medium
|
||||
fc00:a:a:a::3 nhid XXXX via fe80::__(r3-sw6)__ dev r4-sw6 proto XXXX metric 20 pref medium
|
||||
fc00:b:b:b::/64 dev r4-sw6 proto XXXX metric 256 pref medium
|
||||
fc00:b:b:b::3 nhid XXXX via fe80::__(r3-sw6)__ dev r4-sw6 proto XXXX metric 20 pref medium
|
|
@ -0,0 +1,14 @@
|
|||
fc00:1111:1111:1111::/64 via fe80::__(r3-sw6)__ dev r4-sw6 proto XXXX metric 20 pref medium
|
||||
fc00:1:1:1::/64 via fe80::__(r3-sw6)__ dev r4-sw6 proto XXXX metric 20 pref medium
|
||||
fc00:2222:2222:2222::/64 via fe80::__(r3-sw6)__ dev r4-sw6 proto XXXX metric 20 pref medium
|
||||
fc00:2:2:2::/64 via fe80::__(r3-sw6)__ dev r4-sw6 proto XXXX metric 20 pref medium
|
||||
fc00:3333:3333:3333::/64 via fe80::__(r3-sw6)__ dev r4-sw6 proto XXXX metric 20 pref medium
|
||||
fc00:3:3:3::/64 via fe80::__(r3-sw6)__ dev r4-sw6 proto XXXX metric 20 pref medium
|
||||
fc00:4444:4444:4444::/64 via fc00:4:4:4::1234 dev r4-stubnet proto XXXX metric 20 pref medium
|
||||
fc00:4:4:4::/64 dev r4-stubnet proto XXXX metric 256 pref medium
|
||||
fc00:a:a:a::/64 via fe80::__(r3-sw6)__ dev r4-sw6 proto XXXX metric 20 pref medium
|
||||
fc00:a:a:a::1 via fe80::__(r3-sw6)__ dev r4-sw6 proto XXXX metric 20 pref medium
|
||||
fc00:a:a:a::2 via fe80::__(r3-sw6)__ dev r4-sw6 proto XXXX metric 20 pref medium
|
||||
fc00:a:a:a::3 via fe80::__(r3-sw6)__ dev r4-sw6 proto XXXX metric 20 pref medium
|
||||
fc00:b:b:b::/64 dev r4-sw6 proto XXXX metric 256 pref medium
|
||||
fc00:b:b:b::3 via fe80::__(r3-sw6)__ dev r4-sw6 proto XXXX metric 20 pref medium
|
30
tests/topotests/ospf6_point_to_multipoint/r4/ospf6d.conf
Normal file
30
tests/topotests/ospf6_point_to_multipoint/r4/ospf6d.conf
Normal file
|
@ -0,0 +1,30 @@
|
|||
hostname r4
|
||||
log file ospf6d.log
|
||||
!
|
||||
! debug ospf6 message all
|
||||
! debug ospf6 lsa unknown
|
||||
! debug ospf6 zebra
|
||||
! debug ospf6 interface
|
||||
! debug ospf6 neighbor
|
||||
! debug ospf6 route table
|
||||
! debug ospf6 flooding
|
||||
!
|
||||
interface r4-sw6
|
||||
ipv6 ospf6 network point-to-multipoint
|
||||
ipv6 ospf6 area 0.0.0.1
|
||||
ipv6 ospf6 hello-interval 2
|
||||
ipv6 ospf6 dead-interval 10
|
||||
ipv6 ospf6 p2p-p2mp connected-prefixes include
|
||||
!
|
||||
interface r4-stubnet
|
||||
ipv6 ospf6 passive
|
||||
ipv6 ospf6 area 0.0.0.1
|
||||
!
|
||||
router ospf6
|
||||
ospf6 router-id 10.0.0.4
|
||||
log-adjacency-changes detail
|
||||
redistribute static
|
||||
!
|
||||
line vty
|
||||
exec-timeout 0 0
|
||||
!
|
|
@ -0,0 +1,13 @@
|
|||
O>* fc00:1:1:1::/64 [110/30] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6, weight 1, XX:XX:XX
|
||||
O>* fc00:2:2:2::/64 [110/30] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6, weight 1, XX:XX:XX
|
||||
O>* fc00:3:3:3::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6, weight 1, XX:XX:XX
|
||||
O fc00:4:4:4::/64 [110/10] is directly connected, r4-stubnet, weight 1, XX:XX:XX
|
||||
O>* fc00:a:a:a::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6, weight 1, XX:XX:XX
|
||||
O>* fc00:a:a:a::1/128 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6, weight 1, XX:XX:XX
|
||||
O>* fc00:a:a:a::2/128 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6, weight 1, XX:XX:XX
|
||||
O>* fc00:a:a:a::3/128 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6, weight 1, XX:XX:XX
|
||||
O fc00:b:b:b::/64 [110/10] is directly connected, r4-sw6, weight 1, XX:XX:XX
|
||||
O>* fc00:b:b:b::3/128 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6, weight 1, XX:XX:XX
|
||||
O>* fc00:1111:1111:1111::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6, weight 1, XX:XX:XX
|
||||
O>* fc00:2222:2222:2222::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6, weight 1, XX:XX:XX
|
||||
O>* fc00:3333:3333:3333::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6, weight 1, XX:XX:XX
|
20
tests/topotests/ospf6_point_to_multipoint/r4/zebra.conf
Normal file
20
tests/topotests/ospf6_point_to_multipoint/r4/zebra.conf
Normal file
|
@ -0,0 +1,20 @@
|
|||
!
|
||||
hostname r4
|
||||
log file zebra.log
|
||||
!
|
||||
! debug zebra events
|
||||
! debug zebra rib
|
||||
!
|
||||
interface r4-stubnet
|
||||
ipv6 address fc00:4:4:4::4/64
|
||||
!
|
||||
interface r4-sw6
|
||||
ipv6 address fc00:b:b:b::4/64
|
||||
!
|
||||
interface lo
|
||||
!
|
||||
ipv6 route fc00:4444:4444:4444::/64 fc00:4:4:4::1234
|
||||
!
|
||||
!
|
||||
line vty
|
||||
!
|
|
@ -0,0 +1,392 @@
|
|||
#!/usr/bin/env python
|
||||
# SPDX-License-Identifier: ISC
|
||||
|
||||
#
|
||||
# test_ospf6_point_to_multipoint.py
|
||||
# Part of NetDEF Topology Tests
|
||||
#
|
||||
# Copyright (c) 2023 by
|
||||
# Network Device Education Foundation, Inc. ("NetDEF")
|
||||
#
|
||||
|
||||
r"""
|
||||
test_ospf6_point_to_multipoint.py:
|
||||
|
||||
-----\
|
||||
SW1 - Stub Net 1 SW2 - Stub Net 2 \
|
||||
fc00:1:1:1::/64 fc00:2:2:2::/64 \
|
||||
\___________________/ \___________________/ |
|
||||
| | |
|
||||
| | |
|
||||
| ::1 | ::2 |
|
||||
+---------+---------+ +---------+---------+ |
|
||||
| R1 | | R2 | |
|
||||
| FRRouting | | FRRouting | |
|
||||
| Rtr-ID: 10.0.0.1 | | Rtr-ID: 10.0.0.2 | |
|
||||
+---------+---------+ +---------+---------+ |
|
||||
| ::1 | ::2 \
|
||||
\______ ___________/ OSPFv3
|
||||
\ / Area 0.0.0.0
|
||||
\ / /
|
||||
~~~~~~~~~~~~~~~~~~ |
|
||||
~~ SW5 ~~ |
|
||||
~~ Switch ~~ |
|
||||
~~ fc00:A:A:A::/64 ~~ |
|
||||
~~~~~~~~~~~~~~~~~~ |
|
||||
| /---- |
|
||||
| ::3 | SW3 - Stub Net 3 |
|
||||
+---------+---------+ /-+ fc00:3:3:3::/64 |
|
||||
| R3 | / | /
|
||||
| FRRouting +--/ \---- /
|
||||
| Rtr-ID: 10.0.0.3 | ::3 ___________/
|
||||
+---------+---------+ \
|
||||
| ::3 \
|
||||
| \
|
||||
~~~~~~~~~~~~~~~~~~ |
|
||||
~~ SW6 ~~ |
|
||||
~~ Switch ~~ |
|
||||
~~ fc00:B:B:B::/64 ~~ \
|
||||
~~~~~~~~~~~~~~~~~~ OSPFv3
|
||||
| Area 0.0.0.1
|
||||
| ::4 /
|
||||
+---------+---------+ /---- |
|
||||
| R4 | | SW4 - Stub Net 4 |
|
||||
| FRRouting +------+ fc00:4:4:4::/64 |
|
||||
| Rtr-ID: 10.0.0.4 | ::4 | /
|
||||
+-------------------+ \---- /
|
||||
-----/
|
||||
"""
|
||||
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import pytest
|
||||
|
||||
from functools import partial
|
||||
|
||||
|
||||
# Save the Current Working Directory to find configuration files later.
|
||||
CWD = os.path.dirname(os.path.realpath(__file__))
|
||||
sys.path.append(os.path.join(CWD, "../"))
|
||||
|
||||
# pylint: disable=C0413
|
||||
# Import topogen and topotest helpers
|
||||
from lib import topotest
|
||||
from lib.topogen import Topogen, TopoRouter, get_topogen
|
||||
from lib.topolog import logger
|
||||
|
||||
|
||||
pytestmark = [pytest.mark.ospfd]
|
||||
|
||||
|
||||
def build_topo(tgen):
|
||||
# Create 4 routers
|
||||
for routern in range(1, 5):
|
||||
tgen.add_router("r{}".format(routern))
|
||||
|
||||
#
|
||||
# Wire up the switches and routers
|
||||
# Note that we specify the link names so we match the config files
|
||||
#
|
||||
|
||||
# Create a empty network for router 1
|
||||
switch = tgen.add_switch("s1")
|
||||
switch.add_link(tgen.gears["r1"], nodeif="r1-stubnet")
|
||||
|
||||
# Create a empty network for router 2
|
||||
switch = tgen.add_switch("s2")
|
||||
switch.add_link(tgen.gears["r2"], nodeif="r2-stubnet")
|
||||
|
||||
# Create a empty network for router 3
|
||||
switch = tgen.add_switch("s3")
|
||||
switch.add_link(tgen.gears["r3"], nodeif="r3-stubnet")
|
||||
|
||||
# Create a empty network for router 4
|
||||
switch = tgen.add_switch("s4")
|
||||
switch.add_link(tgen.gears["r4"], nodeif="r4-stubnet")
|
||||
|
||||
# Interconnect routers 1, 2, and 3
|
||||
switch = tgen.add_switch("s5")
|
||||
switch.add_link(tgen.gears["r1"], nodeif="r1-sw5")
|
||||
switch.add_link(tgen.gears["r2"], nodeif="r2-sw5")
|
||||
switch.add_link(tgen.gears["r3"], nodeif="r3-sw5")
|
||||
|
||||
# Interconnect routers 3 and 4
|
||||
switch = tgen.add_switch("s6")
|
||||
switch.add_link(tgen.gears["r3"], nodeif="r3-sw6")
|
||||
switch.add_link(tgen.gears["r4"], nodeif="r4-sw6")
|
||||
|
||||
|
||||
#####################################################
|
||||
##
|
||||
## Tests starting
|
||||
##
|
||||
#####################################################
|
||||
|
||||
|
||||
def setup_module(mod):
|
||||
"Sets up the pytest environment"
|
||||
|
||||
tgen = Topogen(build_topo, mod.__name__)
|
||||
tgen.start_topology()
|
||||
|
||||
logger.info("** %s: Setup Topology" % mod.__name__)
|
||||
logger.info("******************************************")
|
||||
|
||||
# For debugging after starting net, but before starting FRR,
|
||||
# uncomment the next line
|
||||
# tgen.mininet_cli()
|
||||
|
||||
router_list = tgen.routers()
|
||||
for rname, router in router_list.items():
|
||||
router.load_config(
|
||||
TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
|
||||
)
|
||||
router.load_config(
|
||||
TopoRouter.RD_OSPF6, os.path.join(CWD, "{}/ospf6d.conf".format(rname))
|
||||
)
|
||||
|
||||
# Initialize all routers.
|
||||
tgen.start_router()
|
||||
|
||||
# For debugging after starting FRR daemons, uncomment the next line
|
||||
# tgen.mininet_cli()
|
||||
|
||||
|
||||
def teardown_module(mod):
|
||||
"Teardown the pytest environment"
|
||||
tgen = get_topogen()
|
||||
tgen.stop_topology()
|
||||
|
||||
|
||||
def test_wait_protocol_convergence():
|
||||
"Wait for OSPFv3 to converge"
|
||||
tgen = get_topogen()
|
||||
if tgen.routers_have_failure():
|
||||
pytest.skip(tgen.errors)
|
||||
|
||||
logger.info("waiting for protocols to converge")
|
||||
|
||||
def expect_neighbor_full(router, neighbor):
|
||||
"Wait until OSPFv3 convergence."
|
||||
logger.info("waiting OSPFv3 router '{}'".format(router))
|
||||
test_func = partial(
|
||||
topotest.router_json_cmp,
|
||||
tgen.gears[router],
|
||||
"show ipv6 ospf6 neighbor json",
|
||||
{"neighbors": [{"neighborId": neighbor, "state": "Full"}]},
|
||||
)
|
||||
_, result = topotest.run_and_expect(test_func, None, count=130, wait=1)
|
||||
assertmsg = '"{}" convergence failure'.format(router)
|
||||
assert result is None, assertmsg
|
||||
|
||||
expect_neighbor_full("r1", "10.0.0.2")
|
||||
expect_neighbor_full("r1", "10.0.0.3")
|
||||
|
||||
expect_neighbor_full("r2", "10.0.0.1")
|
||||
expect_neighbor_full("r2", "10.0.0.3")
|
||||
|
||||
expect_neighbor_full("r3", "10.0.0.1")
|
||||
expect_neighbor_full("r3", "10.0.0.2")
|
||||
expect_neighbor_full("r3", "10.0.0.4")
|
||||
|
||||
expect_neighbor_full("r4", "10.0.0.3")
|
||||
|
||||
|
||||
def compare_show_ipv6(rname, expected):
|
||||
"""
|
||||
Calls 'show ipv6 route' for router `rname` and compare the obtained
|
||||
result with the expected output.
|
||||
"""
|
||||
tgen = get_topogen()
|
||||
|
||||
# Use the vtysh output, with some masking to make comparison easy
|
||||
current = topotest.ip6_route_zebra(tgen.gears[rname])
|
||||
|
||||
# Use just the 'O'spf lines of the output
|
||||
linearr = []
|
||||
for line in current.splitlines():
|
||||
if re.match("^O", line):
|
||||
linearr.append(line)
|
||||
|
||||
current = "\n".join(linearr)
|
||||
|
||||
return topotest.difflines(
|
||||
topotest.normalize_text(current),
|
||||
topotest.normalize_text(expected),
|
||||
title1="Current output",
|
||||
title2="Expected output",
|
||||
)
|
||||
|
||||
|
||||
def test_ospfv3_routingTable():
|
||||
|
||||
tgen = get_topogen()
|
||||
if tgen.routers_have_failure():
|
||||
pytest.skip("skipped because of router(s) failure")
|
||||
|
||||
# For debugging, uncomment the next line
|
||||
# tgen.mininet_cli()
|
||||
|
||||
# Verify OSPFv3 Routing Table
|
||||
for router, rnode in tgen.routers().items():
|
||||
logger.info('Waiting for router "%s" convergence', router)
|
||||
|
||||
# Load expected results from the command
|
||||
reffile = os.path.join(CWD, "{}/show_ipv6_route.ref".format(router))
|
||||
expected = open(reffile).read()
|
||||
|
||||
# Run test function until we get an result. Wait at most 60 seconds.
|
||||
test_func = partial(compare_show_ipv6, router, expected)
|
||||
result, diff = topotest.run_and_expect(test_func, "", count=120, wait=0.5)
|
||||
assert result, "OSPFv3 did not converge on {}:\n{}".format(router, diff)
|
||||
|
||||
|
||||
def test_linux_ipv6_kernel_routingTable():
|
||||
|
||||
tgen = get_topogen()
|
||||
|
||||
if tgen.routers_have_failure():
|
||||
pytest.skip("skipped because of router(s) failure")
|
||||
|
||||
# Verify Linux Kernel Routing Table
|
||||
logger.info("Verifying Linux IPv6 Kernel Routing Table")
|
||||
|
||||
failures = 0
|
||||
|
||||
# Get a list of all current link-local addresses first as they change for
|
||||
# each run and we need to translate them
|
||||
linklocals = []
|
||||
for i in range(1, 5):
|
||||
linklocals += tgen.net["r{}".format(i)].get_ipv6_linklocal()
|
||||
|
||||
# Now compare the routing tables (after substituting link-local addresses)
|
||||
|
||||
for i in range(1, 5):
|
||||
# Actual output from router
|
||||
actual = tgen.gears["r{}".format(i)].run("ip -6 route").rstrip()
|
||||
if "nhid" in actual:
|
||||
refTableFile = os.path.join(CWD, "r{}/ip_6_address.nhg.ref".format(i))
|
||||
else:
|
||||
refTableFile = os.path.join(CWD, "r{}/ip_6_address.ref".format(i))
|
||||
|
||||
if os.path.isfile(refTableFile):
|
||||
expected = open(refTableFile).read().rstrip()
|
||||
# Fix newlines (make them all the same)
|
||||
expected = ("\n".join(expected.splitlines())).splitlines(1)
|
||||
|
||||
# Mask out Link-Local mac addresses
|
||||
for ll in linklocals:
|
||||
actual = actual.replace(ll[1], "fe80::__(%s)__" % ll[0])
|
||||
# Mask out protocol name or number
|
||||
actual = re.sub(r"[ ]+proto [0-9a-z]+ +", " proto XXXX ", actual)
|
||||
actual = re.sub(r"[ ]+nhid [0-9]+ +", " nhid XXXX ", actual)
|
||||
# Remove ff00::/8 routes (seen on some kernels - not from FRR)
|
||||
actual = re.sub(r"ff00::/8.*", "", actual)
|
||||
|
||||
# Strip empty lines
|
||||
actual = actual.lstrip()
|
||||
actual = actual.rstrip()
|
||||
actual = re.sub(r" +", " ", actual)
|
||||
|
||||
filtered_lines = []
|
||||
for line in sorted(actual.splitlines()):
|
||||
if line.startswith("fe80::/64 ") or line.startswith(
|
||||
"unreachable fe80::/64 "
|
||||
):
|
||||
continue
|
||||
filtered_lines.append(line)
|
||||
actual = "\n".join(filtered_lines).splitlines(1)
|
||||
|
||||
# Print Actual table
|
||||
# logger.info("Router r%s table" % i)
|
||||
# for line in actual:
|
||||
# logger.info(line.rstrip())
|
||||
|
||||
# Generate Diff
|
||||
diff = topotest.get_textdiff(
|
||||
actual,
|
||||
expected,
|
||||
title1="actual OSPFv3 IPv6 routing table",
|
||||
title2="expected OSPFv3 IPv6 routing table",
|
||||
)
|
||||
|
||||
# Empty string if it matches, otherwise diff contains unified diff
|
||||
if diff:
|
||||
sys.stderr.write(
|
||||
"r%s failed Linux IPv6 Kernel Routing Table Check:\n%s\n"
|
||||
% (i, diff)
|
||||
)
|
||||
failures += 1
|
||||
else:
|
||||
logger.info("r%s ok" % i)
|
||||
|
||||
assert failures == 0, (
|
||||
"Linux Kernel IPv6 Routing Table verification failed for router r%s:\n%s"
|
||||
% (i, diff)
|
||||
)
|
||||
else:
|
||||
logger.error("r{} failed - no nhid ref file: {}".format(i, refTableFile))
|
||||
|
||||
assert False, (
|
||||
"Linux Kernel IPv6 Routing Table verification failed for router r%s\n"
|
||||
% (i)
|
||||
)
|
||||
|
||||
|
||||
def test_shutdown_check_stderr():
|
||||
|
||||
tgen = get_topogen()
|
||||
|
||||
if tgen.routers_have_failure():
|
||||
pytest.skip("skipped because of router(s) failure")
|
||||
|
||||
if os.environ.get("TOPOTESTS_CHECK_STDERR") is None:
|
||||
logger.info(
|
||||
"SKIPPED final check on StdErr output: Disabled (TOPOTESTS_CHECK_STDERR undefined)\n"
|
||||
)
|
||||
pytest.skip("Skipping test for Stderr output")
|
||||
|
||||
net = tgen.net
|
||||
|
||||
logger.info("\n\n** Verifying unexpected STDERR output from daemons")
|
||||
logger.info("******************************************")
|
||||
|
||||
for i in range(1, 5):
|
||||
net["r%s" % i].stopRouter()
|
||||
log = net["r%s" % i].getStdErr("ospf6d")
|
||||
if log:
|
||||
logger.info("\nRouter r%s OSPF6d StdErr Log:\n%s" % (i, log))
|
||||
log = net["r%s" % i].getStdErr("zebra")
|
||||
if log:
|
||||
logger.info("\nRouter r%s Zebra StdErr Log:\n%s" % (i, log))
|
||||
|
||||
|
||||
def test_shutdown_check_memleak():
|
||||
"Run the memory leak test and report results."
|
||||
|
||||
if os.environ.get("TOPOTESTS_CHECK_MEMLEAK") is None:
|
||||
logger.info(
|
||||
"SKIPPED final check on Memory leaks: Disabled (TOPOTESTS_CHECK_MEMLEAK undefined)"
|
||||
)
|
||||
pytest.skip("Skipping test for memory leaks")
|
||||
|
||||
tgen = get_topogen()
|
||||
|
||||
net = tgen.net
|
||||
|
||||
for i in range(1, 5):
|
||||
net["r%s" % i].stopRouter()
|
||||
net["r%s" % i].report_memory_leaks(
|
||||
os.environ.get("TOPOTESTS_CHECK_MEMLEAK"), os.path.basename(__file__)
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
# To suppress tracebacks, either use the following pytest call or
|
||||
# add "--tb=no" to cli
|
||||
# retval = pytest.main(["-s", "--tb=no"])
|
||||
|
||||
retval = pytest.main(["-s"])
|
||||
sys.exit(retval)
|
Loading…
Reference in a new issue