mirror of
https://github.com/FRRouting/frr.git
synced 2025-04-30 13:37:17 +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.
|
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.
|
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
|
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. */
|
/* Connected address functions. */
|
||||||
extern struct connected *connected_new(void);
|
extern struct connected *connected_new(void);
|
||||||
extern void connected_free(struct connected **connected);
|
extern void connected_free(struct connected **connected);
|
||||||
extern void connected_add(struct interface *, struct connected *);
|
|
||||||
extern struct connected *
|
extern struct connected *
|
||||||
connected_add_by_prefix(struct interface *, struct prefix *, struct prefix *);
|
connected_add_by_prefix(struct interface *, struct prefix *, struct prefix *);
|
||||||
extern struct connected *connected_delete_by_prefix(struct interface *,
|
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 */
|
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 */
|
/* Interface structure */
|
||||||
struct ospf6_interface {
|
struct ospf6_interface {
|
||||||
/* IF info from zebra */
|
/* IF info from zebra */
|
||||||
|
@ -66,6 +85,20 @@ struct ospf6_interface {
|
||||||
uint8_t type;
|
uint8_t type;
|
||||||
bool type_cfg;
|
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 */
|
/* Router Priority */
|
||||||
uint8_t priority;
|
uint8_t priority;
|
||||||
|
|
||||||
|
@ -171,15 +204,16 @@ struct ospf6_interface {
|
||||||
DECLARE_QOBJ_TYPE(ospf6_interface);
|
DECLARE_QOBJ_TYPE(ospf6_interface);
|
||||||
|
|
||||||
/* interface state */
|
/* interface state */
|
||||||
#define OSPF6_INTERFACE_NONE 0
|
#define OSPF6_INTERFACE_NONE 0
|
||||||
#define OSPF6_INTERFACE_DOWN 1
|
#define OSPF6_INTERFACE_DOWN 1
|
||||||
#define OSPF6_INTERFACE_LOOPBACK 2
|
#define OSPF6_INTERFACE_LOOPBACK 2
|
||||||
#define OSPF6_INTERFACE_WAITING 3
|
#define OSPF6_INTERFACE_WAITING 3
|
||||||
#define OSPF6_INTERFACE_POINTTOPOINT 4
|
#define OSPF6_INTERFACE_POINTTOPOINT 4
|
||||||
#define OSPF6_INTERFACE_DROTHER 5
|
#define OSPF6_INTERFACE_POINTTOMULTIPOINT 5
|
||||||
#define OSPF6_INTERFACE_BDR 6
|
#define OSPF6_INTERFACE_DROTHER 6
|
||||||
#define OSPF6_INTERFACE_DR 7
|
#define OSPF6_INTERFACE_BDR 7
|
||||||
#define OSPF6_INTERFACE_MAX 8
|
#define OSPF6_INTERFACE_DR 8
|
||||||
|
#define OSPF6_INTERFACE_MAX 9
|
||||||
|
|
||||||
extern const char *const ospf6_interface_state_str[];
|
extern const char *const ospf6_interface_state_str[];
|
||||||
|
|
||||||
|
|
|
@ -321,13 +321,14 @@ void ospf6_router_lsa_originate(struct event *thread)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Point-to-Point interfaces */
|
/* 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)) {
|
for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, j, on)) {
|
||||||
if (on->state != OSPF6_NEIGHBOR_FULL)
|
if (on->state != OSPF6_NEIGHBOR_FULL)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
lsdesc->type = OSPF6_ROUTER_LSDESC_POINTTOPOINT;
|
lsdesc->type = OSPF6_ROUTER_LSDESC_POINTTOPOINT;
|
||||||
lsdesc->metric = htons(oi->cost);
|
lsdesc->metric = htons(ospf6_neighbor_cost(on));
|
||||||
lsdesc->interface_id =
|
lsdesc->interface_id =
|
||||||
htonl(oi->interface->ifindex);
|
htonl(oi->interface->ifindex);
|
||||||
lsdesc->neighbor_interface_id =
|
lsdesc->neighbor_interface_id =
|
||||||
|
@ -1068,6 +1069,7 @@ void ospf6_intra_prefix_lsa_originate_stub(struct event *thread)
|
||||||
|
|
||||||
if (oi->state != OSPF6_INTERFACE_LOOPBACK
|
if (oi->state != OSPF6_INTERFACE_LOOPBACK
|
||||||
&& oi->state != OSPF6_INTERFACE_POINTTOPOINT
|
&& oi->state != OSPF6_INTERFACE_POINTTOPOINT
|
||||||
|
&& oi->state != OSPF6_INTERFACE_POINTTOMULTIPOINT
|
||||||
&& full_count != 0) {
|
&& full_count != 0) {
|
||||||
if (IS_OSPF6_DEBUG_ORIGINATE(INTRA_PREFIX))
|
if (IS_OSPF6_DEBUG_ORIGINATE(INTRA_PREFIX))
|
||||||
zlog_debug(" Interface %s is not stub, ignore",
|
zlog_debug(" Interface %s is not stub, ignore",
|
||||||
|
|
|
@ -268,6 +268,18 @@ static struct ospf6_packet *ospf6_packet_new(size_t size)
|
||||||
return new;
|
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)
|
static void ospf6_packet_free(struct ospf6_packet *op)
|
||||||
{
|
{
|
||||||
if (op->s)
|
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
|
hello = (struct ospf6_hello *)((caddr_t)oh
|
||||||
+ sizeof(struct ospf6_header));
|
+ 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 */
|
/* HelloInterval check */
|
||||||
if (ntohs(hello->hello_interval) != oi->hello_interval) {
|
if (ntohs(hello->hello_interval) != oi->hello_interval) {
|
||||||
zlog_warn(
|
zlog_warn(
|
||||||
|
@ -479,7 +510,7 @@ static void ospf6_hello_recv(struct in6_addr *src, struct in6_addr *dst,
|
||||||
on->hello_in++;
|
on->hello_in++;
|
||||||
|
|
||||||
/* Always override neighbor's source address */
|
/* Always override neighbor's source address */
|
||||||
memcpy(&on->linklocal_addr, src, sizeof(struct in6_addr));
|
ospf6_neighbor_lladdr_set(on, src);
|
||||||
|
|
||||||
/* Neighbor ifindex check */
|
/* Neighbor ifindex check */
|
||||||
if (on->ifindex != (ifindex_t)ntohl(hello->interface_id)) {
|
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)
|
void ospf6_hello_send(struct event *thread)
|
||||||
{
|
{
|
||||||
struct ospf6_interface *oi;
|
struct ospf6_interface *oi;
|
||||||
struct ospf6_packet *op;
|
|
||||||
uint16_t length = OSPF6_HEADER_SIZE;
|
|
||||||
|
|
||||||
oi = (struct ospf6_interface *)EVENT_ARG(thread);
|
oi = (struct ospf6_interface *)EVENT_ARG(thread);
|
||||||
|
|
||||||
|
@ -2266,6 +2295,20 @@ void ospf6_hello_send(struct event *thread)
|
||||||
return;
|
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);
|
op = ospf6_packet_new(oi->ifmtu);
|
||||||
|
|
||||||
ospf6_make_header(OSPF6_MESSAGE_TYPE_HELLO, oi, op->s);
|
ospf6_make_header(OSPF6_MESSAGE_TYPE_HELLO, oi, op->s);
|
||||||
|
@ -2284,20 +2327,40 @@ void ospf6_hello_send(struct event *thread)
|
||||||
/* Set packet length. */
|
/* Set packet length. */
|
||||||
op->length = 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
|
opdup = ospf6_packet_dup(op);
|
||||||
* can't get delayed by things like long queues of LS Update packets
|
opdup->dst = on->linklocal_addr;
|
||||||
*/
|
ospf6_fill_hdr_checksum(oi, opdup);
|
||||||
ospf6_packet_add_top(oi, op);
|
ospf6_packet_add_top(oi, opdup);
|
||||||
|
anything = true;
|
||||||
|
}
|
||||||
|
|
||||||
/* set next thread */
|
ospf6_packet_free(op);
|
||||||
event_add_timer(master, ospf6_hello_send, oi, oi->hello_interval,
|
} else {
|
||||||
&oi->thread_send_hello);
|
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)
|
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_ALL 0x6 /* For debug option */
|
||||||
#define OSPF6_MESSAGE_TYPE_MAX 0x6 /* same as OSPF6_MESSAGE_TYPE_ALL */
|
#define OSPF6_MESSAGE_TYPE_MAX 0x6 /* same as OSPF6_MESSAGE_TYPE_ALL */
|
||||||
|
|
||||||
|
struct ospf6_interface;
|
||||||
|
|
||||||
struct ospf6_packet {
|
struct ospf6_packet {
|
||||||
struct ospf6_packet *next;
|
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_interface(struct event *thread);
|
||||||
extern void ospf6_lsack_send_neighbor(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 int config_write_ospf6_debug_message(struct vty *);
|
||||||
extern void install_element_ospf6_debug_message(void);
|
extern void install_element_ospf6_debug_message(void);
|
||||||
extern const char *ospf6_message_type(int type);
|
extern const char *ospf6_message_type(int type);
|
||||||
|
|
|
@ -34,6 +34,16 @@
|
||||||
#include "lib/json.h"
|
#include "lib/json.h"
|
||||||
|
|
||||||
DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_NEIGHBOR, "OSPF6 neighbor");
|
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,
|
DEFINE_HOOK(ospf6_neighbor_change,
|
||||||
(struct ospf6_neighbor * on, int state, int next_state),
|
(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;
|
unsigned char conf_debug_ospf6_neighbor = 0;
|
||||||
|
|
||||||
const char *const ospf6_neighbor_state_str[] = {
|
const char *const ospf6_neighbor_state_str[] = {
|
||||||
"None", "Down", "Attempt", "Init", "Twoway",
|
"None", "Down", "Attempt", "Init", "Twoway",
|
||||||
"ExStart", "ExChange", "Loading", "Full", NULL};
|
"ExStart", "ExChange", "Loading", "Full", NULL
|
||||||
|
};
|
||||||
|
|
||||||
const char *const ospf6_neighbor_event_str[] = {
|
const char *const ospf6_neighbor_event_str[] = {
|
||||||
"NoEvent", "HelloReceived", "2-WayReceived", "NegotiationDone",
|
"NoEvent", "HelloReceived", "2-WayReceived", "NegotiationDone",
|
||||||
"ExchangeDone", "LoadingDone", "AdjOK?", "SeqNumberMismatch",
|
"ExchangeDone", "LoadingDone", "AdjOK?", "SeqNumberMismatch",
|
||||||
"BadLSReq", "1-WayReceived", "InactivityTimer",
|
"BadLSReq", "1-WayReceived", "InactivityTimer",
|
||||||
};
|
};
|
||||||
|
|
||||||
int ospf6_neighbor_cmp(void *va, void *vb)
|
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));
|
on = XCALLOC(MTYPE_OSPF6_NEIGHBOR, sizeof(struct ospf6_neighbor));
|
||||||
inet_ntop(AF_INET, &router_id, buf, sizeof(buf));
|
inet_ntop(AF_INET, &router_id, buf, sizeof(buf));
|
||||||
snprintf(on->name, sizeof(on->name), "%s%%%s", buf,
|
snprintf(on->name, sizeof(on->name), "%s%%%s", buf, oi->interface->name);
|
||||||
oi->interface->name);
|
|
||||||
on->ospf6_if = oi;
|
on->ospf6_if = oi;
|
||||||
on->state = OSPF6_NEIGHBOR_DOWN;
|
on->state = OSPF6_NEIGHBOR_DOWN;
|
||||||
on->state_change = 0;
|
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)
|
void ospf6_neighbor_delete(struct ospf6_neighbor *on)
|
||||||
{
|
{
|
||||||
|
if (on->p2xp_cfg)
|
||||||
|
on->p2xp_cfg->active = NULL;
|
||||||
|
|
||||||
ospf6_neighbor_clear_ls_lists(on);
|
ospf6_neighbor_clear_ls_lists(on);
|
||||||
|
|
||||||
ospf6_lsdb_remove_all(on->dbdesc_list);
|
ospf6_lsdb_remove_all(on->dbdesc_list);
|
||||||
|
@ -182,6 +195,22 @@ void ospf6_neighbor_delete(struct ospf6_neighbor *on)
|
||||||
XFREE(MTYPE_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,
|
static void ospf6_neighbor_state_change(uint8_t next_state,
|
||||||
struct ospf6_neighbor *on, int event)
|
struct ospf6_neighbor *on, int event)
|
||||||
{
|
{
|
||||||
|
@ -198,31 +227,28 @@ static void ospf6_neighbor_state_change(uint8_t next_state,
|
||||||
|
|
||||||
/* log */
|
/* log */
|
||||||
if (IS_OSPF6_DEBUG_NEIGHBOR(STATE)) {
|
if (IS_OSPF6_DEBUG_NEIGHBOR(STATE)) {
|
||||||
zlog_debug(
|
zlog_debug("Neighbor state change %s (Router-ID: %pI4): [%s]->[%s] (%s)",
|
||||||
"Neighbor state change %s (Router-ID: %pI4): [%s]->[%s] (%s)",
|
on->name, &on->router_id,
|
||||||
on->name, &on->router_id,
|
ospf6_neighbor_state_str[prev_state],
|
||||||
ospf6_neighbor_state_str[prev_state],
|
ospf6_neighbor_state_str[next_state],
|
||||||
ospf6_neighbor_state_str[next_state],
|
ospf6_neighbor_event_string(event));
|
||||||
ospf6_neighbor_event_string(event));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Optionally notify about adjacency changes */
|
/* Optionally notify about adjacency changes */
|
||||||
if (CHECK_FLAG(on->ospf6_if->area->ospf6->config_flags,
|
if (CHECK_FLAG(on->ospf6_if->area->ospf6->config_flags,
|
||||||
OSPF6_LOG_ADJACENCY_CHANGES)
|
OSPF6_LOG_ADJACENCY_CHANGES) &&
|
||||||
&& (CHECK_FLAG(on->ospf6_if->area->ospf6->config_flags,
|
(CHECK_FLAG(on->ospf6_if->area->ospf6->config_flags,
|
||||||
OSPF6_LOG_ADJACENCY_DETAIL)
|
OSPF6_LOG_ADJACENCY_DETAIL) ||
|
||||||
|| (next_state == OSPF6_NEIGHBOR_FULL)
|
(next_state == OSPF6_NEIGHBOR_FULL) || (next_state < prev_state)))
|
||||||
|| (next_state < prev_state)))
|
zlog_notice("AdjChg: Nbr %pI4(%s) on %s: %s -> %s (%s)",
|
||||||
zlog_notice(
|
&on->router_id,
|
||||||
"AdjChg: Nbr %pI4(%s) on %s: %s -> %s (%s)",
|
vrf_id_to_name(on->ospf6_if->interface->vrf->vrf_id),
|
||||||
&on->router_id,
|
on->name, ospf6_neighbor_state_str[prev_state],
|
||||||
vrf_id_to_name(on->ospf6_if->interface->vrf->vrf_id),
|
ospf6_neighbor_state_str[next_state],
|
||||||
on->name, ospf6_neighbor_state_str[prev_state],
|
ospf6_neighbor_event_string(event));
|
||||||
ospf6_neighbor_state_str[next_state],
|
|
||||||
ospf6_neighbor_event_string(event));
|
|
||||||
|
|
||||||
if (prev_state == OSPF6_NEIGHBOR_FULL
|
if (prev_state == OSPF6_NEIGHBOR_FULL ||
|
||||||
|| next_state == OSPF6_NEIGHBOR_FULL) {
|
next_state == OSPF6_NEIGHBOR_FULL) {
|
||||||
if (!OSPF6_GR_IS_ACTIVE_HELPER(on)) {
|
if (!OSPF6_GR_IS_ACTIVE_HELPER(on)) {
|
||||||
OSPF6_ROUTER_LSA_SCHEDULE(on->ospf6_if->area);
|
OSPF6_ROUTER_LSA_SCHEDULE(on->ospf6_if->area);
|
||||||
if (on->ospf6_if->state == OSPF6_INTERFACE_DR) {
|
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;
|
on->ospf6_if->area->intra_prefix_originate = 1;
|
||||||
|
|
||||||
if (!OSPF6_GR_IS_ACTIVE_HELPER(on))
|
if (!OSPF6_GR_IS_ACTIVE_HELPER(on))
|
||||||
OSPF6_INTRA_PREFIX_LSA_SCHEDULE_STUB(
|
OSPF6_INTRA_PREFIX_LSA_SCHEDULE_STUB(on->ospf6_if->area);
|
||||||
on->ospf6_if->area);
|
|
||||||
|
|
||||||
if ((prev_state == OSPF6_NEIGHBOR_LOADING
|
if ((prev_state == OSPF6_NEIGHBOR_LOADING ||
|
||||||
|| prev_state == OSPF6_NEIGHBOR_EXCHANGE)
|
prev_state == OSPF6_NEIGHBOR_EXCHANGE) &&
|
||||||
&& next_state == OSPF6_NEIGHBOR_FULL) {
|
next_state == OSPF6_NEIGHBOR_FULL) {
|
||||||
OSPF6_AS_EXTERN_LSA_SCHEDULE(on->ospf6_if);
|
OSPF6_AS_EXTERN_LSA_SCHEDULE(on->ospf6_if);
|
||||||
on->ospf6_if->area->full_nbrs++;
|
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--;
|
on->ospf6_if->area->full_nbrs--;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((prev_state == OSPF6_NEIGHBOR_EXCHANGE
|
if ((prev_state == OSPF6_NEIGHBOR_EXCHANGE ||
|
||||||
|| prev_state == OSPF6_NEIGHBOR_LOADING)
|
prev_state == OSPF6_NEIGHBOR_LOADING) &&
|
||||||
&& (next_state != OSPF6_NEIGHBOR_EXCHANGE
|
(next_state != OSPF6_NEIGHBOR_EXCHANGE &&
|
||||||
&& next_state != OSPF6_NEIGHBOR_LOADING))
|
next_state != OSPF6_NEIGHBOR_LOADING))
|
||||||
ospf6_maxage_remove(on->ospf6_if->area->ospf6);
|
ospf6_maxage_remove(on->ospf6_if->area->ospf6);
|
||||||
|
|
||||||
hook_call(ospf6_neighbor_change, on, next_state, prev_state);
|
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 */
|
/* RFC2328 section 10.4 */
|
||||||
static int need_adjacency(struct ospf6_neighbor *on)
|
static int need_adjacency(struct ospf6_neighbor *on)
|
||||||
{
|
{
|
||||||
if (on->ospf6_if->state == OSPF6_INTERFACE_POINTTOPOINT
|
if (on->ospf6_if->state == OSPF6_INTERFACE_POINTTOPOINT ||
|
||||||
|| on->ospf6_if->state == OSPF6_INTERFACE_DR
|
on->ospf6_if->state == OSPF6_INTERFACE_POINTTOMULTIPOINT ||
|
||||||
|| on->ospf6_if->state == OSPF6_INTERFACE_BDR)
|
on->ospf6_if->state == OSPF6_INTERFACE_DR ||
|
||||||
|
on->ospf6_if->state == OSPF6_INTERFACE_BDR)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
if (on->ospf6_if->drouter == on->router_id
|
if (on->ospf6_if->drouter == on->router_id ||
|
||||||
|| on->ospf6_if->bdrouter == on->router_id)
|
on->ospf6_if->bdrouter == on->router_id)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -422,13 +448,12 @@ void exchange_done(struct event *thread)
|
||||||
/* Check loading state. */
|
/* Check loading state. */
|
||||||
void ospf6_check_nbr_loading(struct ospf6_neighbor *on)
|
void ospf6_check_nbr_loading(struct ospf6_neighbor *on)
|
||||||
{
|
{
|
||||||
|
|
||||||
/* RFC2328 Section 10.9: When the neighbor responds to these requests
|
/* RFC2328 Section 10.9: When the neighbor responds to these requests
|
||||||
with the proper Link State Update packet(s), the Link state request
|
with the proper Link State Update packet(s), the Link state request
|
||||||
list is truncated and a new Link State Request packet is sent.
|
list is truncated and a new Link State Request packet is sent.
|
||||||
*/
|
*/
|
||||||
if ((on->state == OSPF6_NEIGHBOR_LOADING)
|
if ((on->state == OSPF6_NEIGHBOR_LOADING) ||
|
||||||
|| (on->state == OSPF6_NEIGHBOR_EXCHANGE)) {
|
(on->state == OSPF6_NEIGHBOR_EXCHANGE)) {
|
||||||
if (on->request_list->count == 0)
|
if (on->request_list->count == 0)
|
||||||
event_add_event(master, loading_done, on, 0,
|
event_add_event(master, loading_done, on, 0,
|
||||||
&on->event_loading_done);
|
&on->event_loading_done);
|
||||||
|
@ -587,9 +612,8 @@ void inactivity_timer(struct event *thread)
|
||||||
on->drouter = on->prev_drouter = 0;
|
on->drouter = on->prev_drouter = 0;
|
||||||
on->bdrouter = on->prev_bdrouter = 0;
|
on->bdrouter = on->prev_bdrouter = 0;
|
||||||
|
|
||||||
ospf6_neighbor_state_change(
|
ospf6_neighbor_state_change(OSPF6_NEIGHBOR_DOWN, on,
|
||||||
OSPF6_NEIGHBOR_DOWN, on,
|
OSPF6_NEIGHBOR_EVENT_INACTIVITY_TIMER);
|
||||||
OSPF6_NEIGHBOR_EVENT_INACTIVITY_TIMER);
|
|
||||||
event_add_event(master, neighbor_change, on->ospf6_if, 0, NULL);
|
event_add_event(master, neighbor_change, on->ospf6_if, 0, NULL);
|
||||||
|
|
||||||
listnode_delete(on->ospf6_if->neighbor_list, on);
|
listnode_delete(on->ospf6_if->neighbor_list, on);
|
||||||
|
@ -597,9 +621,8 @@ void inactivity_timer(struct event *thread)
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (IS_DEBUG_OSPF6_GR)
|
if (IS_DEBUG_OSPF6_GR)
|
||||||
zlog_debug(
|
zlog_debug("%s, Acting as HELPER for this neighbour, So restart the dead timer.",
|
||||||
"%s, Acting as HELPER for this neighbour, So restart the dead timer.",
|
__PRETTY_FUNCTION__);
|
||||||
__PRETTY_FUNCTION__);
|
|
||||||
|
|
||||||
event_add_timer(master, inactivity_timer, on,
|
event_add_timer(master, inactivity_timer, on,
|
||||||
on->ospf6_if->dead_interval,
|
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 */
|
/* 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 */
|
/* show neighbor structure */
|
||||||
static void ospf6_neighbor_show(struct vty *vty, struct ospf6_neighbor *on,
|
static void ospf6_neighbor_show(struct vty *vty, struct ospf6_neighbor *on,
|
||||||
json_object *json_array, bool use_json)
|
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 */
|
/* Dead time */
|
||||||
h = m = s = 0;
|
h = m = s = 0;
|
||||||
if (on->inactivity_timer) {
|
if (on->inactivity_timer) {
|
||||||
s = monotime_until(&on->inactivity_timer->u.sands, NULL)
|
s = monotime_until(&on->inactivity_timer->u.sands, NULL) /
|
||||||
/ 1000000LL;
|
1000000LL;
|
||||||
h = s / 3600;
|
h = s / 3600;
|
||||||
s -= h * 3600;
|
s -= h * 3600;
|
||||||
m = s / 60;
|
m = s / 60;
|
||||||
|
@ -643,6 +882,8 @@ static void ospf6_neighbor_show(struct vty *vty, struct ospf6_neighbor *on,
|
||||||
/* Neighbor State */
|
/* Neighbor State */
|
||||||
if (on->ospf6_if->type == OSPF_IFTYPE_POINTOPOINT)
|
if (on->ospf6_if->type == OSPF_IFTYPE_POINTOPOINT)
|
||||||
snprintf(nstate, sizeof(nstate), "PointToPoint");
|
snprintf(nstate, sizeof(nstate), "PointToPoint");
|
||||||
|
else if (on->ospf6_if->type == OSPF_IFTYPE_POINTOMULTIPOINT)
|
||||||
|
snprintf(nstate, sizeof(nstate), "PtMultipoint");
|
||||||
else {
|
else {
|
||||||
if (on->router_id == on->drouter)
|
if (on->router_id == on->drouter)
|
||||||
snprintf(nstate, sizeof(nstate), "DR");
|
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, "duration", duration);
|
||||||
json_object_string_add(json_route, "interfaceName",
|
json_object_string_add(json_route, "interfaceName",
|
||||||
on->ospf6_if->interface->name);
|
on->ospf6_if->interface->name);
|
||||||
json_object_string_add(
|
json_object_string_add(json_route, "interfaceState",
|
||||||
json_route, "interfaceState",
|
ospf6_interface_state_str
|
||||||
ospf6_interface_state_str[on->ospf6_if->state]);
|
[on->ospf6_if->state]);
|
||||||
|
|
||||||
json_object_array_add(json_array, json_route);
|
json_object_array_add(json_array, json_route);
|
||||||
} else
|
} 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, "bdRouter", bdrouter);
|
||||||
json_object_string_add(json_route, "interfaceName",
|
json_object_string_add(json_route, "interfaceName",
|
||||||
on->ospf6_if->interface->name);
|
on->ospf6_if->interface->name);
|
||||||
json_object_string_add(
|
json_object_string_add(json_route, "interfaceState",
|
||||||
json_route, "interfaceState",
|
ospf6_interface_state_str
|
||||||
ospf6_interface_state_str[on->ospf6_if->state]);
|
[on->ospf6_if->state]);
|
||||||
|
|
||||||
json_object_array_add(json_array, json_route);
|
json_object_array_add(json_array, json_route);
|
||||||
} else
|
} else
|
||||||
|
@ -777,9 +1018,8 @@ static void ospf6_neighbor_show_detail(struct vty *vty,
|
||||||
(CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_IBIT)
|
(CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_IBIT)
|
||||||
? "Initial "
|
? "Initial "
|
||||||
: ""),
|
: ""),
|
||||||
(CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MBIT)
|
(CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MBIT) ? "More"
|
||||||
? "More"
|
: ""),
|
||||||
: ""),
|
|
||||||
(CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MSBIT)
|
(CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MSBIT)
|
||||||
? "Master"
|
? "Master"
|
||||||
: "Slave"));
|
: "Slave"));
|
||||||
|
@ -793,8 +1033,8 @@ static void ospf6_neighbor_show_detail(struct vty *vty,
|
||||||
json_object_int_add(json_neighbor, "summaryListCount",
|
json_object_int_add(json_neighbor, "summaryListCount",
|
||||||
on->summary_list->count);
|
on->summary_list->count);
|
||||||
for (ALL_LSDB(on->summary_list, lsa, lsanext))
|
for (ALL_LSDB(on->summary_list, lsa, lsanext))
|
||||||
json_object_array_add(
|
json_object_array_add(json_array,
|
||||||
json_array, json_object_new_string(lsa->name));
|
json_object_new_string(lsa->name));
|
||||||
json_object_object_add(json_neighbor, "summaryListLsa",
|
json_object_object_add(json_neighbor, "summaryListLsa",
|
||||||
json_array);
|
json_array);
|
||||||
|
|
||||||
|
@ -802,8 +1042,8 @@ static void ospf6_neighbor_show_detail(struct vty *vty,
|
||||||
json_object_int_add(json_neighbor, "requestListCount",
|
json_object_int_add(json_neighbor, "requestListCount",
|
||||||
on->request_list->count);
|
on->request_list->count);
|
||||||
for (ALL_LSDB(on->request_list, lsa, lsanext))
|
for (ALL_LSDB(on->request_list, lsa, lsanext))
|
||||||
json_object_array_add(
|
json_object_array_add(json_array,
|
||||||
json_array, json_object_new_string(lsa->name));
|
json_object_new_string(lsa->name));
|
||||||
json_object_object_add(json_neighbor, "requestListLsa",
|
json_object_object_add(json_neighbor, "requestListLsa",
|
||||||
json_array);
|
json_array);
|
||||||
|
|
||||||
|
@ -811,8 +1051,8 @@ static void ospf6_neighbor_show_detail(struct vty *vty,
|
||||||
json_object_int_add(json_neighbor, "reTransListCount",
|
json_object_int_add(json_neighbor, "reTransListCount",
|
||||||
on->retrans_list->count);
|
on->retrans_list->count);
|
||||||
for (ALL_LSDB(on->retrans_list, lsa, lsanext))
|
for (ALL_LSDB(on->retrans_list, lsa, lsanext))
|
||||||
json_object_array_add(
|
json_object_array_add(json_array,
|
||||||
json_array, json_object_new_string(lsa->name));
|
json_object_new_string(lsa->name));
|
||||||
json_object_object_add(json_neighbor, "reTransListLsa",
|
json_object_object_add(json_neighbor, "reTransListLsa",
|
||||||
json_array);
|
json_array);
|
||||||
|
|
||||||
|
@ -825,14 +1065,14 @@ static void ospf6_neighbor_show_detail(struct vty *vty,
|
||||||
on->dbdesc_list->count);
|
on->dbdesc_list->count);
|
||||||
json_object_string_add(json_neighbor, "pendingLsaDbDescTime",
|
json_object_string_add(json_neighbor, "pendingLsaDbDescTime",
|
||||||
duration);
|
duration);
|
||||||
json_object_string_add(
|
json_object_string_add(json_neighbor, "dbDescSendThread",
|
||||||
json_neighbor, "dbDescSendThread",
|
(event_is_scheduled(on->thread_send_dbdesc)
|
||||||
(event_is_scheduled(on->thread_send_dbdesc) ? "on"
|
? "on"
|
||||||
: "off"));
|
: "off"));
|
||||||
json_array = json_object_new_array();
|
json_array = json_object_new_array();
|
||||||
for (ALL_LSDB(on->dbdesc_list, lsa, lsanext))
|
for (ALL_LSDB(on->dbdesc_list, lsa, lsanext))
|
||||||
json_object_array_add(
|
json_object_array_add(json_array,
|
||||||
json_array, json_object_new_string(lsa->name));
|
json_object_new_string(lsa->name));
|
||||||
json_object_object_add(json_neighbor, "pendingLsaDbDesc",
|
json_object_object_add(json_neighbor, "pendingLsaDbDesc",
|
||||||
json_array);
|
json_array);
|
||||||
|
|
||||||
|
@ -844,35 +1084,35 @@ static void ospf6_neighbor_show_detail(struct vty *vty,
|
||||||
on->request_list->count);
|
on->request_list->count);
|
||||||
json_object_string_add(json_neighbor, "pendingLsaLsReqTime",
|
json_object_string_add(json_neighbor, "pendingLsaLsReqTime",
|
||||||
duration);
|
duration);
|
||||||
json_object_string_add(
|
json_object_string_add(json_neighbor, "lsReqSendThread",
|
||||||
json_neighbor, "lsReqSendThread",
|
(event_is_scheduled(on->thread_send_lsreq)
|
||||||
(event_is_scheduled(on->thread_send_lsreq) ? "on"
|
? "on"
|
||||||
: "off"));
|
: "off"));
|
||||||
json_array = json_object_new_array();
|
json_array = json_object_new_array();
|
||||||
for (ALL_LSDB(on->request_list, lsa, lsanext))
|
for (ALL_LSDB(on->request_list, lsa, lsanext))
|
||||||
json_object_array_add(
|
json_object_array_add(json_array,
|
||||||
json_array, json_object_new_string(lsa->name));
|
json_object_new_string(lsa->name));
|
||||||
json_object_object_add(json_neighbor, "pendingLsaLsReq",
|
json_object_object_add(json_neighbor, "pendingLsaLsReq",
|
||||||
json_array);
|
json_array);
|
||||||
|
|
||||||
|
|
||||||
timerclear(&res);
|
timerclear(&res);
|
||||||
if (event_is_scheduled(on->thread_send_lsupdate))
|
if (event_is_scheduled(on->thread_send_lsupdate))
|
||||||
timersub(&on->thread_send_lsupdate->u.sands, &now,
|
timersub(&on->thread_send_lsupdate->u.sands, &now, &res);
|
||||||
&res);
|
|
||||||
timerstring(&res, duration, sizeof(duration));
|
timerstring(&res, duration, sizeof(duration));
|
||||||
json_object_int_add(json_neighbor, "pendingLsaLsUpdateCount",
|
json_object_int_add(json_neighbor, "pendingLsaLsUpdateCount",
|
||||||
on->lsupdate_list->count);
|
on->lsupdate_list->count);
|
||||||
json_object_string_add(json_neighbor, "pendingLsaLsUpdateTime",
|
json_object_string_add(json_neighbor, "pendingLsaLsUpdateTime",
|
||||||
duration);
|
duration);
|
||||||
json_object_string_add(
|
json_object_string_add(json_neighbor, "lsUpdateSendThread",
|
||||||
json_neighbor, "lsUpdateSendThread",
|
(event_is_scheduled(
|
||||||
(event_is_scheduled(on->thread_send_lsupdate) ? "on"
|
on->thread_send_lsupdate)
|
||||||
: "off"));
|
? "on"
|
||||||
|
: "off"));
|
||||||
json_array = json_object_new_array();
|
json_array = json_object_new_array();
|
||||||
for (ALL_LSDB(on->lsupdate_list, lsa, lsanext))
|
for (ALL_LSDB(on->lsupdate_list, lsa, lsanext))
|
||||||
json_object_array_add(
|
json_object_array_add(json_array,
|
||||||
json_array, json_object_new_string(lsa->name));
|
json_object_new_string(lsa->name));
|
||||||
json_object_object_add(json_neighbor, "pendingLsaLsUpdate",
|
json_object_object_add(json_neighbor, "pendingLsaLsUpdate",
|
||||||
json_array);
|
json_array);
|
||||||
|
|
||||||
|
@ -884,14 +1124,14 @@ static void ospf6_neighbor_show_detail(struct vty *vty,
|
||||||
on->lsack_list->count);
|
on->lsack_list->count);
|
||||||
json_object_string_add(json_neighbor, "pendingLsaLsAckTime",
|
json_object_string_add(json_neighbor, "pendingLsaLsAckTime",
|
||||||
duration);
|
duration);
|
||||||
json_object_string_add(
|
json_object_string_add(json_neighbor, "lsAckSendThread",
|
||||||
json_neighbor, "lsAckSendThread",
|
(event_is_scheduled(on->thread_send_lsack)
|
||||||
(event_is_scheduled(on->thread_send_lsack) ? "on"
|
? "on"
|
||||||
: "off"));
|
: "off"));
|
||||||
json_array = json_object_new_array();
|
json_array = json_object_new_array();
|
||||||
for (ALL_LSDB(on->lsack_list, lsa, lsanext))
|
for (ALL_LSDB(on->lsack_list, lsa, lsanext))
|
||||||
json_object_array_add(
|
json_object_array_add(json_array,
|
||||||
json_array, json_object_new_string(lsa->name));
|
json_object_new_string(lsa->name));
|
||||||
json_object_object_add(json_neighbor, "pendingLsaLsAck",
|
json_object_object_add(json_neighbor, "pendingLsaLsAck",
|
||||||
json_array);
|
json_array);
|
||||||
|
|
||||||
|
@ -900,36 +1140,36 @@ static void ospf6_neighbor_show_detail(struct vty *vty,
|
||||||
if (on->auth_present == true) {
|
if (on->auth_present == true) {
|
||||||
json_object_string_add(json_neighbor, "authStatus",
|
json_object_string_add(json_neighbor, "authStatus",
|
||||||
"enabled");
|
"enabled");
|
||||||
json_object_int_add(
|
json_object_int_add(json_neighbor,
|
||||||
json_neighbor, "recvdHelloHigherSeqNo",
|
"recvdHelloHigherSeqNo",
|
||||||
on->seqnum_h[OSPF6_MESSAGE_TYPE_HELLO]);
|
on->seqnum_h[OSPF6_MESSAGE_TYPE_HELLO]);
|
||||||
json_object_int_add(
|
json_object_int_add(json_neighbor,
|
||||||
json_neighbor, "recvdHelloLowerSeqNo",
|
"recvdHelloLowerSeqNo",
|
||||||
on->seqnum_l[OSPF6_MESSAGE_TYPE_HELLO]);
|
on->seqnum_l[OSPF6_MESSAGE_TYPE_HELLO]);
|
||||||
json_object_int_add(
|
json_object_int_add(json_neighbor,
|
||||||
json_neighbor, "recvdDBDescHigherSeqNo",
|
"recvdDBDescHigherSeqNo",
|
||||||
on->seqnum_h[OSPF6_MESSAGE_TYPE_DBDESC]);
|
on->seqnum_h[OSPF6_MESSAGE_TYPE_DBDESC]);
|
||||||
json_object_int_add(
|
json_object_int_add(json_neighbor,
|
||||||
json_neighbor, "recvdDBDescLowerSeqNo",
|
"recvdDBDescLowerSeqNo",
|
||||||
on->seqnum_l[OSPF6_MESSAGE_TYPE_DBDESC]);
|
on->seqnum_l[OSPF6_MESSAGE_TYPE_DBDESC]);
|
||||||
json_object_int_add(
|
json_object_int_add(json_neighbor,
|
||||||
json_neighbor, "recvdLSReqHigherSeqNo",
|
"recvdLSReqHigherSeqNo",
|
||||||
on->seqnum_h[OSPF6_MESSAGE_TYPE_LSREQ]);
|
on->seqnum_h[OSPF6_MESSAGE_TYPE_LSREQ]);
|
||||||
json_object_int_add(
|
json_object_int_add(json_neighbor,
|
||||||
json_neighbor, "recvdLSReqLowerSeqNo",
|
"recvdLSReqLowerSeqNo",
|
||||||
on->seqnum_l[OSPF6_MESSAGE_TYPE_LSREQ]);
|
on->seqnum_l[OSPF6_MESSAGE_TYPE_LSREQ]);
|
||||||
json_object_int_add(
|
json_object_int_add(json_neighbor,
|
||||||
json_neighbor, "recvdLSUpdHigherSeqNo",
|
"recvdLSUpdHigherSeqNo",
|
||||||
on->seqnum_h[OSPF6_MESSAGE_TYPE_LSUPDATE]);
|
on->seqnum_h[OSPF6_MESSAGE_TYPE_LSUPDATE]);
|
||||||
json_object_int_add(
|
json_object_int_add(json_neighbor,
|
||||||
json_neighbor, "recvdLSUpdLowerSeqNo",
|
"recvdLSUpdLowerSeqNo",
|
||||||
on->seqnum_l[OSPF6_MESSAGE_TYPE_LSUPDATE]);
|
on->seqnum_l[OSPF6_MESSAGE_TYPE_LSUPDATE]);
|
||||||
json_object_int_add(
|
json_object_int_add(json_neighbor,
|
||||||
json_neighbor, "recvdLSAckHigherSeqNo",
|
"recvdLSAckHigherSeqNo",
|
||||||
on->seqnum_h[OSPF6_MESSAGE_TYPE_LSACK]);
|
on->seqnum_h[OSPF6_MESSAGE_TYPE_LSACK]);
|
||||||
json_object_int_add(
|
json_object_int_add(json_neighbor,
|
||||||
json_neighbor, "recvdLSAckLowerSeqNo",
|
"recvdLSAckLowerSeqNo",
|
||||||
on->seqnum_l[OSPF6_MESSAGE_TYPE_LSACK]);
|
on->seqnum_l[OSPF6_MESSAGE_TYPE_LSACK]);
|
||||||
} else
|
} else
|
||||||
json_object_string_add(json_neighbor, "authStatus",
|
json_object_string_add(json_neighbor, "authStatus",
|
||||||
"disabled");
|
"disabled");
|
||||||
|
@ -951,9 +1191,8 @@ static void ospf6_neighbor_show_detail(struct vty *vty,
|
||||||
(CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_IBIT)
|
(CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_IBIT)
|
||||||
? "Initial "
|
? "Initial "
|
||||||
: ""),
|
: ""),
|
||||||
(CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MBIT)
|
(CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MBIT) ? "More "
|
||||||
? "More "
|
: ""),
|
||||||
: ""),
|
|
||||||
(CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MSBIT)
|
(CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MSBIT)
|
||||||
? "Master"
|
? "Master"
|
||||||
: "Slave"),
|
: "Slave"),
|
||||||
|
@ -1000,8 +1239,7 @@ static void ospf6_neighbor_show_detail(struct vty *vty,
|
||||||
|
|
||||||
timerclear(&res);
|
timerclear(&res);
|
||||||
if (event_is_scheduled(on->thread_send_lsupdate))
|
if (event_is_scheduled(on->thread_send_lsupdate))
|
||||||
timersub(&on->thread_send_lsupdate->u.sands, &now,
|
timersub(&on->thread_send_lsupdate->u.sands, &now, &res);
|
||||||
&res);
|
|
||||||
timerstring(&res, duration, sizeof(duration));
|
timerstring(&res, duration, sizeof(duration));
|
||||||
vty_out(vty,
|
vty_out(vty,
|
||||||
" %d Pending LSAs for LSUpdate in Time %s [thread %s]\n",
|
" %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,
|
static int ospf6_neighbor_show_common(struct vty *vty, int argc,
|
||||||
struct cmd_token **argv,
|
struct cmd_token **argv,
|
||||||
struct ospf6 *ospf6, int idx_ipv4,
|
struct ospf6 *ospf6, int idx_ipv4, bool uj)
|
||||||
bool uj)
|
|
||||||
{
|
{
|
||||||
struct ospf6_neighbor *on;
|
struct ospf6_neighbor *on;
|
||||||
struct ospf6_interface *oi;
|
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_cmd);
|
||||||
install_element(VIEW_NODE, &show_ipv6_ospf6_neighbor_one_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,
|
DEFUN(debug_ospf6_neighbor, debug_ospf6_neighbor_cmd,
|
||||||
debug_ospf6_neighbor_cmd,
|
"debug ospf6 neighbor [<state|event>]",
|
||||||
"debug ospf6 neighbor [<state|event>]",
|
DEBUG_STR OSPF6_STR "Debug OSPFv3 Neighbor\n"
|
||||||
DEBUG_STR
|
"Debug OSPFv3 Neighbor State Change\n"
|
||||||
OSPF6_STR
|
"Debug OSPFv3 Neighbor Event\n")
|
||||||
"Debug OSPFv3 Neighbor\n"
|
|
||||||
"Debug OSPFv3 Neighbor State Change\n"
|
|
||||||
"Debug OSPFv3 Neighbor Event\n")
|
|
||||||
{
|
{
|
||||||
int idx_type = 3;
|
int idx_type = 3;
|
||||||
unsigned char level = 0;
|
unsigned char level = 0;
|
||||||
|
@ -1241,15 +1480,11 @@ DEFUN (debug_ospf6_neighbor,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
DEFUN (no_debug_ospf6_neighbor,
|
DEFUN(no_debug_ospf6_neighbor, no_debug_ospf6_neighbor_cmd,
|
||||||
no_debug_ospf6_neighbor_cmd,
|
"no debug ospf6 neighbor [<state|event>]",
|
||||||
"no debug ospf6 neighbor [<state|event>]",
|
NO_STR DEBUG_STR OSPF6_STR "Debug OSPFv3 Neighbor\n"
|
||||||
NO_STR
|
"Debug OSPFv3 Neighbor State Change\n"
|
||||||
DEBUG_STR
|
"Debug OSPFv3 Neighbor Event\n")
|
||||||
OSPF6_STR
|
|
||||||
"Debug OSPFv3 Neighbor\n"
|
|
||||||
"Debug OSPFv3 Neighbor State Change\n"
|
|
||||||
"Debug OSPFv3 Neighbor Event\n")
|
|
||||||
{
|
{
|
||||||
int idx_type = 4;
|
int idx_type = 4;
|
||||||
unsigned char level = 0;
|
unsigned char level = 0;
|
||||||
|
@ -1267,12 +1502,8 @@ DEFUN (no_debug_ospf6_neighbor,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
DEFUN (no_debug_ospf6,
|
DEFUN(no_debug_ospf6, no_debug_ospf6_cmd, "no debug ospf6",
|
||||||
no_debug_ospf6_cmd,
|
NO_STR DEBUG_STR OSPF6_STR)
|
||||||
"no debug ospf6",
|
|
||||||
NO_STR
|
|
||||||
DEBUG_STR
|
|
||||||
OSPF6_STR)
|
|
||||||
{
|
{
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
|
@ -1287,12 +1518,11 @@ DEFUN (no_debug_ospf6,
|
||||||
ospf6_lsa_debug_set_all(false);
|
ospf6_lsa_debug_set_all(false);
|
||||||
|
|
||||||
for (i = 0; i < 6; i++)
|
for (i = 0; i < 6; i++)
|
||||||
OSPF6_DEBUG_MESSAGE_OFF(i,
|
OSPF6_DEBUG_MESSAGE_OFF(i, OSPF6_DEBUG_NEIGHBOR_STATE |
|
||||||
OSPF6_DEBUG_NEIGHBOR_STATE
|
OSPF6_DEBUG_NEIGHBOR_EVENT);
|
||||||
| OSPF6_DEBUG_NEIGHBOR_EVENT);
|
|
||||||
|
|
||||||
OSPF6_DEBUG_NEIGHBOR_OFF(OSPF6_DEBUG_NEIGHBOR_STATE
|
OSPF6_DEBUG_NEIGHBOR_OFF(OSPF6_DEBUG_NEIGHBOR_STATE |
|
||||||
| OSPF6_DEBUG_NEIGHBOR_EVENT);
|
OSPF6_DEBUG_NEIGHBOR_EVENT);
|
||||||
OSPF6_DEBUG_ROUTE_OFF(OSPF6_DEBUG_ROUTE_TABLE);
|
OSPF6_DEBUG_ROUTE_OFF(OSPF6_DEBUG_ROUTE_TABLE);
|
||||||
OSPF6_DEBUG_ROUTE_OFF(OSPF6_DEBUG_ROUTE_INTRA);
|
OSPF6_DEBUG_ROUTE_OFF(OSPF6_DEBUG_ROUTE_INTRA);
|
||||||
OSPF6_DEBUG_ROUTE_OFF(OSPF6_DEBUG_ROUTE_INTER);
|
OSPF6_DEBUG_ROUTE_OFF(OSPF6_DEBUG_ROUTE_INTER);
|
||||||
|
@ -1316,6 +1546,25 @@ int config_write_ospf6_debug_neighbor(struct vty *vty)
|
||||||
return 0;
|
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)
|
void install_element_ospf6_debug_neighbor(void)
|
||||||
{
|
{
|
||||||
install_element(ENABLE_NODE, &debug_ospf6_neighbor_cmd);
|
install_element(ENABLE_NODE, &debug_ospf6_neighbor_cmd);
|
||||||
|
|
|
@ -6,8 +6,11 @@
|
||||||
#ifndef OSPF6_NEIGHBOR_H
|
#ifndef OSPF6_NEIGHBOR_H
|
||||||
#define OSPF6_NEIGHBOR_H
|
#define OSPF6_NEIGHBOR_H
|
||||||
|
|
||||||
|
#include "typesafe.h"
|
||||||
#include "hook.h"
|
#include "hook.h"
|
||||||
|
|
||||||
|
#include "ospf6_message.h"
|
||||||
|
|
||||||
/* Forward declaration(s). */
|
/* Forward declaration(s). */
|
||||||
struct ospf6_area;
|
struct ospf6_area;
|
||||||
|
|
||||||
|
@ -52,6 +55,8 @@ struct ospf6_helper_info {
|
||||||
uint32_t rejected_reason;
|
uint32_t rejected_reason;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ospf6_if_p2xp_neighcfg;
|
||||||
|
|
||||||
/* Neighbor structure */
|
/* Neighbor structure */
|
||||||
struct ospf6_neighbor {
|
struct ospf6_neighbor {
|
||||||
/* Neighbor Router ID String */
|
/* Neighbor Router ID String */
|
||||||
|
@ -60,6 +65,11 @@ struct ospf6_neighbor {
|
||||||
/* OSPFv3 Interface this neighbor belongs to */
|
/* OSPFv3 Interface this neighbor belongs to */
|
||||||
struct ospf6_interface *ospf6_if;
|
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 */
|
/* Neighbor state */
|
||||||
uint8_t state;
|
uint8_t state;
|
||||||
|
|
||||||
|
@ -190,6 +200,14 @@ struct ospf6_neighbor *ospf6_neighbor_create(uint32_t router_id,
|
||||||
struct ospf6_interface *oi);
|
struct ospf6_interface *oi);
|
||||||
void ospf6_neighbor_delete(struct ospf6_neighbor *on);
|
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 */
|
/* Neighbor event */
|
||||||
extern void hello_received(struct event *thread);
|
extern void hello_received(struct event *thread);
|
||||||
extern void twoway_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 void ospf6_neighbor_init(void);
|
||||||
extern int config_write_ospf6_debug_neighbor(struct vty *vty);
|
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);
|
extern void install_element_ospf6_debug_neighbor(void);
|
||||||
|
|
||||||
DECLARE_HOOK(ospf6_neighbor_change,
|
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)
|
if (ra->path.area_id != rb->path.area_id)
|
||||||
return (ntohl(ra->path.area_id) - ntohl(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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1126,6 +1126,8 @@ static uint8_t *ospfv3IfEntry(struct variable *v, oid *name, size_t *length,
|
||||||
return SNMP_INTEGER(1);
|
return SNMP_INTEGER(1);
|
||||||
else if (oi->type == OSPF_IFTYPE_POINTOPOINT)
|
else if (oi->type == OSPF_IFTYPE_POINTOPOINT)
|
||||||
return SNMP_INTEGER(3);
|
return SNMP_INTEGER(3);
|
||||||
|
else if (oi->type == OSPF_IFTYPE_POINTOMULTIPOINT)
|
||||||
|
return SNMP_INTEGER(5);
|
||||||
else
|
else
|
||||||
break; /* Unknown, don't put anything */
|
break; /* Unknown, don't put anything */
|
||||||
case OSPFv3IFADMINSTATUS:
|
case OSPFv3IFADMINSTATUS:
|
||||||
|
@ -1367,6 +1369,7 @@ static int ospf6TrapIfStateChange(struct ospf6_interface *oi, int next_state,
|
||||||
|
|
||||||
/* Terminal state or regression */
|
/* Terminal state or regression */
|
||||||
if ((next_state != OSPF6_INTERFACE_POINTTOPOINT)
|
if ((next_state != OSPF6_INTERFACE_POINTTOPOINT)
|
||||||
|
&& (next_state != OSPF6_INTERFACE_POINTTOMULTIPOINT)
|
||||||
&& (next_state != OSPF6_INTERFACE_DROTHER)
|
&& (next_state != OSPF6_INTERFACE_DROTHER)
|
||||||
&& (next_state != OSPF6_INTERFACE_BDR)
|
&& (next_state != OSPF6_INTERFACE_BDR)
|
||||||
&& (next_state != OSPF6_INTERFACE_DR) && (next_state >= prev_state))
|
&& (next_state != OSPF6_INTERFACE_DR) && (next_state >= prev_state))
|
||||||
|
|
|
@ -83,8 +83,10 @@ clippy_scan += \
|
||||||
ospf6d/ospf6_lsa.c \
|
ospf6d/ospf6_lsa.c \
|
||||||
ospf6d/ospf6_gr_helper.c \
|
ospf6d/ospf6_gr_helper.c \
|
||||||
ospf6d/ospf6_gr.c \
|
ospf6d/ospf6_gr.c \
|
||||||
|
ospf6d/ospf6_interface.c \
|
||||||
ospf6d/ospf6_nssa.c \
|
ospf6d/ospf6_nssa.c \
|
||||||
ospf6d/ospf6_route.c \
|
ospf6d/ospf6_route.c \
|
||||||
|
ospf6d/ospf6_neighbor.c \
|
||||||
# end
|
# end
|
||||||
|
|
||||||
nodist_ospf6d_ospf6d_SOURCES = \
|
nodist_ospf6d_ospf6d_SOURCES = \
|
||||||
|
|
|
@ -110,15 +110,18 @@ def test_wait_protocol_convergence():
|
||||||
|
|
||||||
def expect_neighbor_full(router, neighbor):
|
def expect_neighbor_full(router, neighbor):
|
||||||
"Wait until OSPFv3 neighborship is full"
|
"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(
|
test_func = partial(
|
||||||
topotest.router_json_cmp,
|
topotest.router_json_cmp,
|
||||||
tgen.gears[router],
|
tgen.gears[router],
|
||||||
"show ipv6 ospf6 neighbor json",
|
"show ipv6 ospf6 neighbor json",
|
||||||
{"neighbors": [{"neighborId": neighbor, "state": "Full"}]},
|
{"neighbors": [{"neighborId": neighbor, "state": "Full"}]},
|
||||||
)
|
)
|
||||||
_, result = topotest.run_and_expect(test_func, None,
|
_, result = topotest.run_and_expect(test_func, None, count=130, wait=1)
|
||||||
count=130, wait=1)
|
|
||||||
assertmsg = '"{}" convergence failure'.format(router)
|
assertmsg = '"{}" convergence failure'.format(router)
|
||||||
assert result is None, assertmsg
|
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("r8", "10.254.254.5")
|
||||||
expect_neighbor_full("r9", "10.254.254.5")
|
expect_neighbor_full("r9", "10.254.254.5")
|
||||||
|
|
||||||
|
|
||||||
def test_ecmp_inter_area():
|
def test_ecmp_inter_area():
|
||||||
"Test whether OSPFv3 ECMP nexthops are properly updated for inter-area routes after link down"
|
"Test whether OSPFv3 ECMP nexthops are properly updated for inter-area routes after link down"
|
||||||
tgen = get_topogen()
|
tgen = get_topogen()
|
||||||
|
@ -156,22 +160,28 @@ def test_ecmp_inter_area():
|
||||||
|
|
||||||
def expect_num_nexthops(router, expected_num_nexthops, count):
|
def expect_num_nexthops(router, expected_num_nexthops, count):
|
||||||
"Wait until number of nexthops for routes matches expectation"
|
"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)
|
test_func = partial(num_nexthops, router)
|
||||||
_, result = topotest.run_and_expect(test_func, expected_num_nexthops,
|
_, result = topotest.run_and_expect(
|
||||||
count=count, wait=3)
|
test_func, expected_num_nexthops, count=count, wait=3
|
||||||
assert result == expected_num_nexthops, \
|
)
|
||||||
"'{}' wrong number of route nexthops".format(router)
|
assert (
|
||||||
|
result == expected_num_nexthops
|
||||||
|
), "'{}' wrong number of route nexthops".format(router)
|
||||||
|
|
||||||
# Check nexthops pre link-down
|
# 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")
|
logger.info("triggering R2-R4 link down")
|
||||||
tgen.gears["r2"].run("ip link set r2-eth1 down")
|
tgen.gears["r2"].run("ip link set r2-eth1 down")
|
||||||
|
|
||||||
#tgen.mininet_cli()
|
# tgen.mininet_cli()
|
||||||
# Check nexthops post link-down
|
# 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):
|
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