summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/user/ospf6d.rst127
-rw-r--r--lib/if.h1
-rw-r--r--ospf6d/ospf6_interface.c855
-rw-r--r--ospf6d/ospf6_interface.h52
-rw-r--r--ospf6d/ospf6_intra.c6
-rw-r--r--ospf6d/ospf6_message.c91
-rw-r--r--ospf6d/ospf6_message.h5
-rw-r--r--ospf6d/ospf6_neighbor.c567
-rw-r--r--ospf6d/ospf6_neighbor.h20
-rw-r--r--ospf6d/ospf6_route.c4
-rw-r--r--ospf6d/ospf6_snmp.c3
-rw-r--r--ospf6d/subdir.am2
-rw-r--r--tests/topotests/ospf6_ecmp_inter_area/test_ospf6_ecmp_inter_area.py32
-rw-r--r--tests/topotests/ospf6_point_to_multipoint/README.md137
-rw-r--r--tests/topotests/ospf6_point_to_multipoint/r1/ip_6_address.nhg.ref14
-rw-r--r--tests/topotests/ospf6_point_to_multipoint/r1/ip_6_address.ref14
-rw-r--r--tests/topotests/ospf6_point_to_multipoint/r1/ospf6d.conf30
-rw-r--r--tests/topotests/ospf6_point_to_multipoint/r1/show_ipv6_route.ref13
-rw-r--r--tests/topotests/ospf6_point_to_multipoint/r1/zebra.conf20
-rw-r--r--tests/topotests/ospf6_point_to_multipoint/r2/ip_6_address.nhg.ref14
-rw-r--r--tests/topotests/ospf6_point_to_multipoint/r2/ip_6_address.ref14
-rw-r--r--tests/topotests/ospf6_point_to_multipoint/r2/ospf6d.conf30
-rw-r--r--tests/topotests/ospf6_point_to_multipoint/r2/show_ipv6_route.ref13
-rw-r--r--tests/topotests/ospf6_point_to_multipoint/r2/zebra.conf20
-rw-r--r--tests/topotests/ospf6_point_to_multipoint/r3/ip_6_address.nhg.ref13
-rw-r--r--tests/topotests/ospf6_point_to_multipoint/r3/ip_6_address.ref13
-rw-r--r--tests/topotests/ospf6_point_to_multipoint/r3/ospf6d.conf37
-rw-r--r--tests/topotests/ospf6_point_to_multipoint/r3/show_ipv6_route.ref12
-rw-r--r--tests/topotests/ospf6_point_to_multipoint/r3/zebra.conf23
-rw-r--r--tests/topotests/ospf6_point_to_multipoint/r4/ip_6_address.nhg.ref14
-rw-r--r--tests/topotests/ospf6_point_to_multipoint/r4/ip_6_address.ref14
-rw-r--r--tests/topotests/ospf6_point_to_multipoint/r4/ospf6d.conf30
-rw-r--r--tests/topotests/ospf6_point_to_multipoint/r4/show_ipv6_route.ref13
-rw-r--r--tests/topotests/ospf6_point_to_multipoint/r4/zebra.conf20
-rw-r--r--tests/topotests/ospf6_point_to_multipoint/test_ospf6_point_to_multipoint.py392
35 files changed, 2038 insertions, 627 deletions
diff --git a/doc/user/ospf6d.rst b/doc/user/ospf6d.rst
index 2f4c956ff..12b368d43 100644
--- a/doc/user/ospf6d.rst
+++ b/doc/user/ospf6d.rst
@@ -312,10 +312,135 @@ OSPF6 interface
Sets interface's Inf-Trans-Delay. Default value is 1.
-.. clicmd:: ipv6 ospf6 network (broadcast|point-to-point)
+.. clicmd:: ipv6 ospf6 network (broadcast|point-to-point|point-to-multipoint)
Set explicitly network type for specified interface.
+ The only functional difference between ``point-to-point`` (PtP) and
+ ``point-to-multipoint`` (PtMP) mode is the packet addressing for database
+ flooding and updates. PtP will use multicast packets while PtMP will
+ unicast them. Apart from this,
+ :clicmd:`ipv6 ospf6 p2p-p2mp connected-prefixes <include|exclude>` has a
+ different default for PtP and PtMP. There are no other differences, in
+ particular FRR does not impose a limit of one neighbor in PtP mode.
+
+ FRR does not support NBMA mode for IPv6 and likely never will, as NBMA is
+ considered deprecated for IPv6. Refer to `this IETF OSPF working group
+ discussion
+ <https://mailarchive.ietf.org/arch/msg/ospf/8GAbr4qSMMt5J7SvAcZQ1H7ARhk/>`_
+ for context.
+
+OSPF6 point-to-point and point-to-multipoint operation
+======================================================
+
+OSPFv3, by default, operates in broadcast mode where it elects a DR and BDR
+for each network segment. This can be changed to point-to-point (PtP) /
+point-to-multipoint (PtMP) mode by configuration. The actual physical
+interface characteristics do not matter for this setting, all interfaces can
+be configured for all modes. However, routers must be configured for the same
+mode to form adjacencies.
+
+The main advantages of PtP/PtMP mode are:
+
+- no DR/BDR election
+- adjacencies can be suppressed in a pairwise manner for any two routers, e.g.
+ to represent the underlying topology if it isn't a true full mesh
+- distinct costs can be set for each pair of routers and direction
+
+The main downside is less efficient flooding on networks with a large number
+of OSPFv3 routers.
+
+.. warning::
+
+ All options in this section should be considered "advanced" configuration
+ options. Inconsistent or nonsensical combinations can easily result in a
+ non-functional setup.
+
+.. clicmd:: ipv6 ospf6 p2p-p2mp disable-multicast-hello
+
+ Disables sending normal multicast hellos when in PtP/PtMP mode. Some
+ vendors do this automatically for PtMP mode while others have a separate
+ ``no-broadcast`` option matching this.
+
+ If this setting is used, you must issue
+ :clicmd:`ipv6 ospf6 neighbor X:X::X:X poll-interval (1-65535)` for each
+ neighbor to send unicast hello packets.
+
+.. clicmd:: ipv6 ospf6 p2p-p2mp config-neighbors-only
+
+ Only form adjacencies with neighbors that are explicitly configured with
+ the :clicmd:`ipv6 ospf6 neighbor X:X::X:X` command. Hellos from other
+ routers are ignored.
+
+ .. warning::
+
+ This setting is not intended to provide any security benefit. Do not
+ run OSPFv3 over untrusted links without additional security measures
+ (e.g. IPsec.)
+
+.. clicmd:: ipv6 ospf6 p2p-p2mp connected-prefixes <include|exclude>
+
+ For global/ULA prefixes configured on this interfaces, do (not) advertise
+ the full prefix to the area. Regardless of this setting, the router's own
+ address, as a /128 host route with the "LA" (Local Address) bit set, will
+ always be advertised.
+
+ The default is to include connected prefixes for PtP mode and exclude them
+ for PtMP mode. Since these prefixes will cover other router's addresses,
+ these addresses can become unreachable if the link is partitioned if the
+ other router does not advertise the address as a /128. However, conversely,
+ if all routers have this flag set, the overall prefix will not be advertised
+ anywhere. End hosts on this link will therefore be unreachable (and
+ blackholing best-practices for non-existing prefixes apply.) It may be
+ preferable to have only one router announce the connected prefix.
+
+ The Link LSA (which is not propagated into the area) always includes all
+ prefixes on the interface. This setting only affects the Router LSA that
+ is visible to all routers in the area.
+
+ .. note::
+
+ Before interacting with this setting, consider either not configuring
+ any global/ULA IPv6 address on the interface, or directly configuring a
+ /128 if needed. OSPFv3 relies exclusively on link-local addresses to do
+ its signaling and there is absolutely no reason to configure global/ULA
+ addresses as far as OSPFv3 is concerned.
+
+.. clicmd:: ipv6 ospf6 neighbor X:X::X:X
+
+ Explicitly configure a neighbor by its link-local address on this interface.
+ This statement has no effect other than allowing an adjacency when
+ :clicmd:`ipv6 ospf6 p2p-p2mp config-neighbors-only` is set. This command
+ does **not** cause unicast hellos to be sent.
+
+ Only link-local addresses can be used to establish explicit neighbors.
+ When using this command, you should probably assign static IPv6 link-local
+ addresses to all routers on this link. It would technically be possible to
+ use the neighbor's Router ID (IPv4 address) here to ease working with
+ changing link-local addresses but this is not planned as a feature at the
+ time of writing. Global/ULA IPv6 addresses cannot be supported here due to
+ the way OSPFv3 works.
+
+.. clicmd:: ipv6 ospf6 neighbor X:X::X:X poll-interval (1-65535)
+
+ Send unicast hellos to this neighbor at the specified interval (in seconds.)
+ The interval is only used while there is no adjacency with this neighbor.
+ As soon as an adjacency is formed, the interface's
+ :clicmd:`ipv6 ospf6 hello-interval HELLOINTERVAL` value is used.
+ (``hello-interval`` must be the same on all routers on this link.)
+
+ :rfc:`2328` recommends a "much larger" value than ``hello-interval`` for
+ this setting, but this is a legacy of ATM and X.25 networks and nowadays you
+ should probably just use the same value as for ``hello-interval``.
+
+.. clicmd:: ipv6 ospf6 neighbor X:X::X:X cost (1-65535)
+
+ Use a distinct cost for paths traversing this neighbor. The default is
+ to use the interface's cost value (which may be automatically calculated
+ based on link bandwidth.) Note that costs are directional in OSPF and the
+ reverse direction must be set on the other router.
+
+
OSPF6 route-map
===============
diff --git a/lib/if.h b/lib/if.h
index 7b4415da4..f93f0e70b 100644
--- a/lib/if.h
+++ b/lib/if.h
@@ -579,7 +579,6 @@ extern ifindex_t ifname2ifindex(const char *ifname, vrf_id_t vrf_id);
/* Connected address functions. */
extern struct connected *connected_new(void);
extern void connected_free(struct connected **connected);
-extern void connected_add(struct interface *, struct connected *);
extern struct connected *
connected_add_by_prefix(struct interface *, struct prefix *, struct prefix *);
extern struct connected *connected_delete_by_prefix(struct interface *,
diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c
index 2a6b81684..90185b09b 100644
--- a/ospf6d/ospf6_interface.c
+++ b/ospf6d/ospf6_interface.c
@@ -49,8 +49,9 @@ DEFINE_HOOK(ospf6_interface_change,
unsigned char conf_debug_ospf6_interface = 0;
const char *const ospf6_interface_state_str[] = {
- "None", "Down", "Loopback", "Waiting", "PointToPoint",
- "DROther", "BDR", "DR", NULL};
+ "None", "Down", "Loopback", "Waiting", "PointToPoint",
+ "PtMultipoint", "DROther", "BDR", "DR", NULL
+};
int ospf6_interface_neighbor_count(struct ospf6_interface *oi)
{
@@ -83,8 +84,7 @@ struct ospf6_interface *ospf6_interface_lookup_by_ifindex(ifindex_t ifindex,
}
/* schedule routing table recalculation */
-static void ospf6_interface_lsdb_hook(struct ospf6_lsa *lsa,
- unsigned int reason)
+static void ospf6_interface_lsdb_hook(struct ospf6_lsa *lsa, unsigned int reason)
{
struct ospf6_interface *oi;
@@ -227,9 +227,8 @@ struct ospf6_interface *ospf6_interface_create(struct interface *ifp)
iobuflen = ospf6_iobuf_size(ifp->mtu6);
if (oi->ifmtu > iobuflen) {
if (IS_OSPF6_DEBUG_INTERFACE)
- zlog_debug(
- "Interface %s: IfMtu is adjusted to I/O buffer size: %d.",
- ifp->name, iobuflen);
+ zlog_debug("Interface %s: IfMtu is adjusted to I/O buffer size: %d.",
+ ifp->name, iobuflen);
oi->ifmtu = iobuflen;
}
@@ -242,8 +241,8 @@ struct ospf6_interface *ospf6_interface_create(struct interface *ifp)
oi->lsdb->hook_remove = ospf6_interface_lsdb_hook_remove;
oi->lsdb_self = ospf6_lsdb_create(oi);
- oi->route_connected =
- OSPF6_ROUTE_TABLE_CREATE(INTERFACE, CONNECTED_ROUTES);
+ oi->route_connected = OSPF6_ROUTE_TABLE_CREATE(INTERFACE,
+ CONNECTED_ROUTES);
oi->route_connected->scope = oi;
/* link both */
@@ -380,23 +379,21 @@ void ospf6_interface_state_update(struct interface *ifp)
iobuflen = ospf6_iobuf_size(ifp->mtu6);
if (oi->ifmtu > iobuflen) {
if (IS_OSPF6_DEBUG_INTERFACE)
- zlog_debug(
- "Interface %s: IfMtu is adjusted to I/O buffer size: %d.",
- ifp->name, iobuflen);
+ zlog_debug("Interface %s: IfMtu is adjusted to I/O buffer size: %d.",
+ ifp->name, iobuflen);
oi->ifmtu = iobuflen;
}
} else if (oi->c_ifmtu > ifp->mtu6) {
oi->ifmtu = ifp->mtu6;
- zlog_warn(
- "Configured mtu %u on %s overridden by kernel %u",
- oi->c_ifmtu, ifp->name, ifp->mtu6);
+ zlog_warn("Configured mtu %u on %s overridden by kernel %u",
+ oi->c_ifmtu, ifp->name, ifp->mtu6);
} else
oi->ifmtu = oi->c_ifmtu;
}
- if (if_is_operative(ifp)
- && (ospf6_interface_get_linklocal_address(oi->interface)
- || if_is_loopback(oi->interface)))
+ if (if_is_operative(ifp) &&
+ (ospf6_interface_get_linklocal_address(oi->interface) ||
+ if_is_loopback(oi->interface)))
event_execute(master, interface_up, oi, 0, NULL);
else
event_execute(master, interface_down, oi, 0, NULL);
@@ -407,7 +404,6 @@ void ospf6_interface_state_update(struct interface *ifp)
void ospf6_interface_connected_route_update(struct interface *ifp)
{
struct ospf6_interface *oi;
- struct ospf6_route *route;
struct connected *c;
struct listnode *node, *nnode;
struct in6_addr nh_addr;
@@ -453,14 +449,43 @@ void ospf6_interface_connected_route_update(struct interface *ifp)
ret = prefix_list_apply(plist, (void *)c->address);
if (ret == PREFIX_DENY) {
if (IS_OSPF6_DEBUG_INTERFACE)
- zlog_debug(
- "%pFX on %s filtered by prefix-list %s ",
- c->address, oi->interface->name,
- oi->plist_name);
+ zlog_debug("%pFX on %s filtered by prefix-list %s ",
+ c->address,
+ oi->interface->name,
+ oi->plist_name);
continue;
}
}
+ if (oi->state == OSPF6_INTERFACE_LOOPBACK ||
+ oi->state == OSPF6_INTERFACE_POINTTOMULTIPOINT ||
+ oi->state == OSPF6_INTERFACE_POINTTOPOINT) {
+ struct ospf6_route *la_route;
+
+ la_route = ospf6_route_create(oi->area->ospf6);
+ la_route->prefix = *c->address;
+ la_route->prefix.prefixlen = 128;
+ la_route->prefix_options |= OSPF6_PREFIX_OPTION_LA;
+
+ la_route->type = OSPF6_DEST_TYPE_NETWORK;
+ la_route->path.area_id = oi->area->area_id;
+ la_route->path.type = OSPF6_PATH_TYPE_INTRA;
+ la_route->path.cost = 0;
+ inet_pton(AF_INET6, "::1", &nh_addr);
+ ospf6_route_add_nexthop(la_route, oi->interface->ifindex,
+ &nh_addr);
+ ospf6_route_add(la_route, oi->route_connected);
+ }
+
+ if (oi->state == OSPF6_INTERFACE_POINTTOMULTIPOINT &&
+ !oi->p2xp_connected_pfx_include)
+ continue;
+ if (oi->state == OSPF6_INTERFACE_POINTTOPOINT &&
+ oi->p2xp_connected_pfx_exclude)
+ continue;
+
+ struct ospf6_route *route;
+
route = ospf6_route_create(oi->area->ospf6);
memcpy(&route->prefix, c->address, sizeof(struct prefix));
apply_mask(&route->prefix);
@@ -469,8 +494,7 @@ void ospf6_interface_connected_route_update(struct interface *ifp)
route->path.type = OSPF6_PATH_TYPE_INTRA;
route->path.cost = oi->cost;
inet_pton(AF_INET6, "::1", &nh_addr);
- ospf6_route_add_nexthop(route, oi->interface->ifindex,
- &nh_addr);
+ ospf6_route_add_nexthop(route, oi->interface->ifindex, &nh_addr);
ospf6_route_add(route, oi->route_connected);
}
@@ -506,17 +530,17 @@ static int ospf6_interface_state_change(uint8_t next_state,
ospf6 = oi->area->ospf6;
- if ((prev_state == OSPF6_INTERFACE_DR
- || prev_state == OSPF6_INTERFACE_BDR)
- && (next_state != OSPF6_INTERFACE_DR
- && next_state != OSPF6_INTERFACE_BDR))
+ if ((prev_state == OSPF6_INTERFACE_DR ||
+ prev_state == OSPF6_INTERFACE_BDR) &&
+ (next_state != OSPF6_INTERFACE_DR &&
+ next_state != OSPF6_INTERFACE_BDR))
ospf6_sso(oi->interface->ifindex, &alldrouters6,
IPV6_LEAVE_GROUP, ospf6->fd);
- if ((prev_state != OSPF6_INTERFACE_DR
- && prev_state != OSPF6_INTERFACE_BDR)
- && (next_state == OSPF6_INTERFACE_DR
- || next_state == OSPF6_INTERFACE_BDR))
+ if ((prev_state != OSPF6_INTERFACE_DR &&
+ prev_state != OSPF6_INTERFACE_BDR) &&
+ (next_state == OSPF6_INTERFACE_DR ||
+ next_state == OSPF6_INTERFACE_BDR))
ospf6_sso(oi->interface->ifindex, &alldrouters6,
IPV6_JOIN_GROUP, ospf6->fd);
@@ -526,13 +550,17 @@ static int ospf6_interface_state_change(uint8_t next_state,
OSPF6_NETWORK_LSA_EXECUTE(oi);
OSPF6_INTRA_PREFIX_LSA_EXECUTE_TRANSIT(oi);
OSPF6_INTRA_PREFIX_LSA_SCHEDULE_STUB(oi->area);
- } else if (prev_state == OSPF6_INTERFACE_DR
- || next_state == OSPF6_INTERFACE_DR) {
+ } else if (prev_state == OSPF6_INTERFACE_DR ||
+ next_state == OSPF6_INTERFACE_DR) {
OSPF6_NETWORK_LSA_SCHEDULE(oi);
OSPF6_INTRA_PREFIX_LSA_SCHEDULE_TRANSIT(oi);
OSPF6_INTRA_PREFIX_LSA_SCHEDULE_STUB(oi->area);
}
+ if (next_state == OSPF6_INTERFACE_POINTTOPOINT ||
+ next_state == OSPF6_INTERFACE_POINTTOMULTIPOINT)
+ ospf6_if_p2xp_up(oi);
+
hook_call(ospf6_interface_change, oi, next_state, prev_state);
return 0;
@@ -547,8 +575,8 @@ static int ospf6_interface_state_change(uint8_t next_state,
static struct ospf6_neighbor *better_bdrouter(struct ospf6_neighbor *a,
struct ospf6_neighbor *b)
{
- if ((a == NULL || !IS_ELIGIBLE(a) || a->drouter == a->router_id)
- && (b == NULL || !IS_ELIGIBLE(b) || b->drouter == b->router_id))
+ if ((a == NULL || !IS_ELIGIBLE(a) || a->drouter == a->router_id) &&
+ (b == NULL || !IS_ELIGIBLE(b) || b->drouter == b->router_id))
return NULL;
else if (a == NULL || !IS_ELIGIBLE(a) || a->drouter == a->router_id)
return b;
@@ -577,8 +605,8 @@ static struct ospf6_neighbor *better_bdrouter(struct ospf6_neighbor *a,
static struct ospf6_neighbor *better_drouter(struct ospf6_neighbor *a,
struct ospf6_neighbor *b)
{
- if ((a == NULL || !IS_ELIGIBLE(a) || a->drouter != a->router_id)
- && (b == NULL || !IS_ELIGIBLE(b) || b->drouter != b->router_id))
+ if ((a == NULL || !IS_ELIGIBLE(a) || a->drouter != a->router_id) &&
+ (b == NULL || !IS_ELIGIBLE(b) || b->drouter != b->router_id))
return NULL;
else if (a == NULL || !IS_ELIGIBLE(a) || a->drouter != a->router_id)
return b;
@@ -641,10 +669,10 @@ uint8_t dr_election(struct ospf6_interface *oi)
drouter = bdrouter;
/* the router itself is newly/no longer DR/BDR (4) */
- if ((drouter == &myself && myself.drouter != myself.router_id)
- || (drouter != &myself && myself.drouter == myself.router_id)
- || (bdrouter == &myself && myself.bdrouter != myself.router_id)
- || (bdrouter != &myself && myself.bdrouter == myself.router_id)) {
+ if ((drouter == &myself && myself.drouter != myself.router_id) ||
+ (drouter != &myself && myself.drouter == myself.router_id) ||
+ (bdrouter == &myself && myself.bdrouter != myself.router_id) ||
+ (bdrouter != &myself && myself.bdrouter == myself.router_id)) {
myself.drouter = (drouter ? drouter->router_id : htonl(0));
myself.bdrouter = (bdrouter ? bdrouter->router_id : htonl(0));
@@ -718,8 +746,8 @@ static bool ifmaddr_check(ifindex_t ifindex, struct in6_addr *addr)
continue;
sdl = (struct sockaddr_dl *)ifma->ifma_name;
sin6 = (struct sockaddr_in6 *)ifma->ifma_addr;
- if (sdl->sdl_index == ifindex
- && memcmp(&sin6->sin6_addr, addr, IPV6_MAX_BYTELEN) == 0) {
+ if (sdl->sdl_index == ifindex &&
+ memcmp(&sin6->sin6_addr, addr, IPV6_MAX_BYTELEN) == 0) {
found = true;
break;
}
@@ -759,11 +787,10 @@ void interface_up(struct event *thread)
}
/* check interface has a link-local address */
- if (!(ospf6_interface_get_linklocal_address(oi->interface)
- || if_is_loopback(oi->interface))) {
- zlog_warn(
- "Interface %s has no link local address, can't execute [InterfaceUp]",
- oi->interface->name);
+ if (!(ospf6_interface_get_linklocal_address(oi->interface) ||
+ if_is_loopback(oi->interface))) {
+ zlog_warn("Interface %s has no link local address, can't execute [InterfaceUp]",
+ oi->interface->name);
return;
}
@@ -780,9 +807,8 @@ void interface_up(struct event *thread)
/* If no area assigned, return */
if (oi->area == NULL) {
- zlog_warn(
- "%s: Not scheduling Hello for %s as there is no area assigned yet",
- __func__, oi->interface->name);
+ zlog_warn("%s: Not scheduling Hello for %s as there is no area assigned yet",
+ __func__, oi->interface->name);
return;
}
@@ -807,9 +833,8 @@ void interface_up(struct event *thread)
* the interface actually left the group.
*/
if (ifmaddr_check(oi->interface->ifindex, &allspfrouters6)) {
- zlog_info(
- "Interface %s is still in all routers group, rescheduling for SSO",
- oi->interface->name);
+ zlog_info("Interface %s is still in all routers group, rescheduling for SSO",
+ oi->interface->name);
event_add_timer(master, interface_up, oi,
OSPF6_INTERFACE_SSO_RETRY_INT, &oi->thread_sso);
return;
@@ -820,12 +845,10 @@ void interface_up(struct event *thread)
/* Join AllSPFRouters */
if (ospf6_sso(oi->interface->ifindex, &allspfrouters6, IPV6_JOIN_GROUP,
- ospf6->fd)
- < 0) {
+ ospf6->fd) < 0) {
if (oi->sso_try_cnt++ < OSPF6_INTERFACE_SSO_RETRY_MAX) {
- zlog_info(
- "Scheduling %s for sso retry, trial count: %d",
- oi->interface->name, oi->sso_try_cnt);
+ zlog_info("Scheduling %s for sso retry, trial count: %d",
+ oi->interface->name, oi->sso_try_cnt);
event_add_timer(master, interface_up, oi,
OSPF6_INTERFACE_SSO_RETRY_INT,
&oi->thread_sso);
@@ -838,8 +861,8 @@ void interface_up(struct event *thread)
ospf6_interface_connected_route_update(oi->interface);
/* Schedule Hello */
- if (!CHECK_FLAG(oi->flag, OSPF6_INTERFACE_PASSIVE)
- && !if_is_loopback(oi->interface)) {
+ if (!CHECK_FLAG(oi->flag, OSPF6_INTERFACE_PASSIVE) &&
+ !if_is_loopback(oi->interface)) {
event_add_timer(master, ospf6_hello_send, oi, 0,
&oi->thread_send_hello);
}
@@ -849,6 +872,9 @@ void interface_up(struct event *thread)
ospf6_interface_state_change(OSPF6_INTERFACE_LOOPBACK, oi);
} else if (oi->type == OSPF_IFTYPE_POINTOPOINT) {
ospf6_interface_state_change(OSPF6_INTERFACE_POINTTOPOINT, oi);
+ } else if (oi->type == OSPF_IFTYPE_POINTOMULTIPOINT) {
+ ospf6_interface_state_change(OSPF6_INTERFACE_POINTTOMULTIPOINT,
+ oi);
} else if (oi->priority == 0)
ospf6_interface_state_change(OSPF6_INTERFACE_DROTHER, oi);
else {
@@ -899,9 +925,8 @@ void neighbor_change(struct event *thread)
zlog_debug("Interface Event %s: [NeighborChange]",
oi->interface->name);
- if (oi->state == OSPF6_INTERFACE_DROTHER
- || oi->state == OSPF6_INTERFACE_BDR
- || oi->state == OSPF6_INTERFACE_DR)
+ if (oi->state == OSPF6_INTERFACE_DROTHER ||
+ oi->state == OSPF6_INTERFACE_BDR || oi->state == OSPF6_INTERFACE_DR)
ospf6_interface_state_change(dr_election(oi), oi);
}
@@ -977,6 +1002,8 @@ static const char *ospf6_iftype_str(uint8_t iftype)
return "BROADCAST";
case OSPF_IFTYPE_POINTOPOINT:
return "POINTOPOINT";
+ case OSPF_IFTYPE_POINTOMULTIPOINT:
+ return "POINTOMULTIPOINT";
}
return "UNKNOWN";
}
@@ -1086,12 +1113,10 @@ static int ospf6_interface_show(struct vty *vty, struct interface *ifp,
if (use_json) {
if (oi->area) {
- json_object_boolean_true_add(json_obj,
- "attachedToArea");
+ json_object_boolean_true_add(json_obj, "attachedToArea");
json_object_int_add(json_obj, "instanceId",
oi->instance_id);
- json_object_int_add(json_obj, "interfaceMtu",
- oi->ifmtu);
+ json_object_int_add(json_obj, "interfaceMtu", oi->ifmtu);
json_object_int_add(json_obj, "autoDetect", ifp->mtu6);
json_object_string_add(json_obj, "mtuMismatchDetection",
oi->mtu_ignore ? "disabled"
@@ -1131,9 +1156,9 @@ static int ospf6_interface_show(struct vty *vty, struct interface *ifp,
oi->dead_interval);
json_object_int_add(json_obj, "timerIntervalsConfigRetransmit",
oi->rxmt_interval);
- json_object_boolean_add(
- json_obj, "timerPassiveIface",
- !!CHECK_FLAG(oi->flag, OSPF6_INTERFACE_PASSIVE));
+ json_object_boolean_add(json_obj, "timerPassiveIface",
+ !!CHECK_FLAG(oi->flag,
+ OSPF6_INTERFACE_PASSIVE));
} else {
vty_out(vty, " State %s, Transmit Delay %d sec, Priority %d\n",
ospf6_interface_state_str[oi->state], oi->transdelay,
@@ -1166,24 +1191,23 @@ static int ospf6_interface_show(struct vty *vty, struct interface *ifp,
if (use_json) {
timerclear(&res);
if (event_is_scheduled(oi->thread_send_lsupdate))
- timersub(&oi->thread_send_lsupdate->u.sands, &now,
- &res);
+ timersub(&oi->thread_send_lsupdate->u.sands, &now, &res);
timerstring(&res, duration, sizeof(duration));
json_object_int_add(json_obj, "pendingLsaLsUpdateCount",
oi->lsupdate_list->count);
json_object_string_add(json_obj, "pendingLsaLsUpdateTime",
duration);
- json_object_string_add(
- json_obj, "lsUpdateSendThread",
- (event_is_scheduled(oi->thread_send_lsupdate) ? "on"
- : "off"));
+ json_object_string_add(json_obj, "lsUpdateSendThread",
+ (event_is_scheduled(
+ oi->thread_send_lsupdate)
+ ? "on"
+ : "off"));
json_arr = json_object_new_array();
for (ALL_LSDB(oi->lsupdate_list, lsa, lsanext))
- json_object_array_add(
- json_arr, json_object_new_string(lsa->name));
- json_object_object_add(json_obj, "pendingLsaLsUpdate",
- json_arr);
+ json_object_array_add(json_arr,
+ json_object_new_string(lsa->name));
+ json_object_object_add(json_obj, "pendingLsaLsUpdate", json_arr);
timerclear(&res);
if (event_is_scheduled(oi->thread_send_lsack))
@@ -1194,15 +1218,15 @@ static int ospf6_interface_show(struct vty *vty, struct interface *ifp,
oi->lsack_list->count);
json_object_string_add(json_obj, "pendingLsaLsAckTime",
duration);
- json_object_string_add(
- json_obj, "lsAckSendThread",
- (event_is_scheduled(oi->thread_send_lsack) ? "on"
- : "off"));
+ json_object_string_add(json_obj, "lsAckSendThread",
+ (event_is_scheduled(oi->thread_send_lsack)
+ ? "on"
+ : "off"));
json_arr = json_object_new_array();
for (ALL_LSDB(oi->lsack_list, lsa, lsanext))
- json_object_array_add(
- json_arr, json_object_new_string(lsa->name));
+ json_object_array_add(json_arr,
+ json_object_new_string(lsa->name));
json_object_object_add(json_obj, "pendingLsaLsAck", json_arr);
if (oi->gr.hello_delay.interval != 0)
@@ -1211,8 +1235,7 @@ static int ospf6_interface_show(struct vty *vty, struct interface *ifp,
} else {
timerclear(&res);
if (event_is_scheduled(oi->thread_send_lsupdate))
- timersub(&oi->thread_send_lsupdate->u.sands, &now,
- &res);
+ timersub(&oi->thread_send_lsupdate->u.sands, &now, &res);
timerstring(&res, duration, sizeof(duration));
vty_out(vty,
" %d Pending LSAs for LSUpdate in Time %s [thread %s]\n",
@@ -1244,9 +1267,8 @@ static int ospf6_interface_show(struct vty *vty, struct interface *ifp,
if (use_json) {
struct json_object *json_bfd = json_object_new_object();
- json_object_int_add(
- json_bfd, "detectMultiplier",
- oi->bfd_config.detection_multiplier);
+ json_object_int_add(json_bfd, "detectMultiplier",
+ oi->bfd_config.detection_multiplier);
json_object_int_add(json_bfd, "rxMinInterval",
oi->bfd_config.min_rx);
json_object_int_add(json_bfd, "txMinInterval",
@@ -1269,8 +1291,7 @@ static int ospf6_interface_show(struct vty *vty, struct interface *ifp,
OSPF6_AUTH_TRAILER_KEYCHAIN)) {
json_object_string_add(json_auth, "authType",
"keychain");
- json_object_string_add(json_auth,
- "keychainName",
+ json_object_string_add(json_auth, "keychainName",
oi->at_data.keychain);
} else if (CHECK_FLAG(oi->at_data.flags,
OSPF6_AUTH_TRAILER_MANUAL_KEY))
@@ -1332,7 +1353,6 @@ static int show_ospf6_interface_common(struct vty *vty, vrf_id_t vrf_id,
int idx_ifname, int intf_idx,
int json_idx, bool uj)
{
-
struct vrf *vrf = vrf_lookup_by_id(vrf_id);
struct interface *ifp;
json_object *json;
@@ -1462,18 +1482,15 @@ static int ospf6_interface_show_traffic(struct vty *vty,
json_object_int_add(json_interface, "lsReqTx",
oi->ls_req_out);
json_object_int_add(json_interface,
- "lsUpdateRx",
- oi->ls_upd_in);
- json_object_int_add(json_interface,
- "lsUpdateTx",
+ "lsUpdateRx", oi->ls_upd_in);
+ json_object_int_add(json_interface, "lsUpdateTx",
oi->ls_upd_out);
json_object_int_add(json_interface, "lsAckRx",
oi->ls_ack_in);
json_object_int_add(json_interface, "lsAckTx",
oi->ls_ack_out);
- json_object_object_add(json,
- oi->interface->name,
+ json_object_object_add(json, oi->interface->name,
json_interface);
} else
vty_out(vty,
@@ -1659,8 +1676,8 @@ DEFUN(show_ipv6_ospf6_interface_ifname_prefix,
}
oi = ifp->info;
- if (oi == NULL
- || CHECK_FLAG(oi->flag, OSPF6_INTERFACE_DISABLE)) {
+ if (oi == NULL ||
+ CHECK_FLAG(oi->flag, OSPF6_INTERFACE_DISABLE)) {
vty_out(vty,
"Interface %s not attached to area\n",
argv[idx_ifname]->arg);
@@ -1687,8 +1704,7 @@ DEFUN(show_ipv6_ospf6_interface_prefix, show_ipv6_ospf6_interface_prefix_cmd,
|<X:X::X:X|X:X::X:X/M> [<match|detail>]\
>] [json]",
SHOW_STR IP6_STR OSPF6_STR VRF_CMD_HELP_STR
- "All VRFs\n" INTERFACE_STR
- "Display connected prefixes to advertise\n"
+ "All VRFs\n" INTERFACE_STR "Display connected prefixes to advertise\n"
"Display details of the prefixes\n" OSPF6_ROUTE_ADDRESS_STR
OSPF6_ROUTE_PREFIX_STR OSPF6_ROUTE_MATCH_STR
"Display details of the prefixes\n" JSON_STR)
@@ -1713,9 +1729,9 @@ DEFUN(show_ipv6_ospf6_interface_prefix, show_ipv6_ospf6_interface_prefix_cmd,
vrf = vrf_lookup_by_id(ospf6->vrf_id);
FOR_ALL_INTERFACES (vrf, ifp) {
oi = (struct ospf6_interface *)ifp->info;
- if (oi == NULL
- || CHECK_FLAG(oi->flag,
- OSPF6_INTERFACE_DISABLE))
+ if (oi == NULL ||
+ CHECK_FLAG(oi->flag,
+ OSPF6_INTERFACE_DISABLE))
continue;
ospf6_route_table_show(vty, idx_prefix, argc,
@@ -1790,14 +1806,11 @@ void ospf6_interface_stop(struct ospf6_interface *oi)
}
/* interface variable set command */
-DEFUN (ipv6_ospf6_area,
- ipv6_ospf6_area_cmd,
- "ipv6 ospf6 area <A.B.C.D|(0-4294967295)>",
- IP6_STR
- OSPF6_STR
- "Specify the OSPF6 area ID\n"
- "OSPF6 area ID in IPv4 address notation\n"
- "OSPF6 area ID in decimal notation\n")
+DEFUN(ipv6_ospf6_area, ipv6_ospf6_area_cmd,
+ "ipv6 ospf6 area <A.B.C.D|(0-4294967295)>",
+ IP6_STR OSPF6_STR "Specify the OSPF6 area ID\n"
+ "OSPF6 area ID in IPv4 address notation\n"
+ "OSPF6 area ID in decimal notation\n")
{
VTY_DECLVAR_CONTEXT(interface, ifp);
struct ospf6_interface *oi;
@@ -1831,15 +1844,11 @@ DEFUN (ipv6_ospf6_area,
return CMD_SUCCESS;
}
-DEFUN (no_ipv6_ospf6_area,
- no_ipv6_ospf6_area_cmd,
- "no ipv6 ospf6 area [<A.B.C.D|(0-4294967295)>]",
- NO_STR
- IP6_STR
- OSPF6_STR
- "Specify the OSPF6 area ID\n"
- "OSPF6 area ID in IPv4 address notation\n"
- "OSPF6 area ID in decimal notation\n")
+DEFUN(no_ipv6_ospf6_area, no_ipv6_ospf6_area_cmd,
+ "no ipv6 ospf6 area [<A.B.C.D|(0-4294967295)>]",
+ NO_STR IP6_STR OSPF6_STR "Specify the OSPF6 area ID\n"
+ "OSPF6 area ID in IPv4 address notation\n"
+ "OSPF6 area ID in decimal notation\n")
{
VTY_DECLVAR_CONTEXT(interface, ifp);
struct ospf6_interface *oi;
@@ -1859,14 +1868,9 @@ DEFUN (no_ipv6_ospf6_area,
return CMD_SUCCESS;
}
-DEFUN (ipv6_ospf6_ifmtu,
- ipv6_ospf6_ifmtu_cmd,
- "ipv6 ospf6 ifmtu (1-65535)",
- IP6_STR
- OSPF6_STR
- "Interface MTU\n"
- "OSPFv3 Interface MTU\n"
- )
+DEFUN(ipv6_ospf6_ifmtu, ipv6_ospf6_ifmtu_cmd, "ipv6 ospf6 ifmtu (1-65535)",
+ IP6_STR OSPF6_STR "Interface MTU\n"
+ "OSPFv3 Interface MTU\n")
{
VTY_DECLVAR_CONTEXT(interface, ifp);
int idx_number = 3;
@@ -1915,15 +1919,10 @@ DEFUN (ipv6_ospf6_ifmtu,
return CMD_SUCCESS;
}
-DEFUN (no_ipv6_ospf6_ifmtu,
- no_ipv6_ospf6_ifmtu_cmd,
- "no ipv6 ospf6 ifmtu [(1-65535)]",
- NO_STR
- IP6_STR
- OSPF6_STR
- "Interface MTU\n"
- "OSPFv3 Interface MTU\n"
- )
+DEFUN(no_ipv6_ospf6_ifmtu, no_ipv6_ospf6_ifmtu_cmd,
+ "no ipv6 ospf6 ifmtu [(1-65535)]",
+ NO_STR IP6_STR OSPF6_STR "Interface MTU\n"
+ "OSPFv3 Interface MTU\n")
{
VTY_DECLVAR_CONTEXT(interface, ifp);
struct ospf6_interface *oi;
@@ -1961,13 +1960,9 @@ DEFUN (no_ipv6_ospf6_ifmtu,
return CMD_SUCCESS;
}
-DEFUN (ipv6_ospf6_cost,
- ipv6_ospf6_cost_cmd,
- "ipv6 ospf6 cost (1-65535)",
- IP6_STR
- OSPF6_STR
- "Interface cost\n"
- "Outgoing metric of this interface\n")
+DEFUN(ipv6_ospf6_cost, ipv6_ospf6_cost_cmd, "ipv6 ospf6 cost (1-65535)",
+ IP6_STR OSPF6_STR "Interface cost\n"
+ "Outgoing metric of this interface\n")
{
VTY_DECLVAR_CONTEXT(interface, ifp);
int idx_number = 3;
@@ -1998,14 +1993,10 @@ DEFUN (ipv6_ospf6_cost,
return CMD_SUCCESS;
}
-DEFUN (no_ipv6_ospf6_cost,
- no_ipv6_ospf6_cost_cmd,
- "no ipv6 ospf6 cost [(1-65535)]",
- NO_STR
- IP6_STR
- OSPF6_STR
- "Calculate interface cost from bandwidth\n"
- "Outgoing metric of this interface\n")
+DEFUN(no_ipv6_ospf6_cost, no_ipv6_ospf6_cost_cmd,
+ "no ipv6 ospf6 cost [(1-65535)]",
+ NO_STR IP6_STR OSPF6_STR "Calculate interface cost from bandwidth\n"
+ "Outgoing metric of this interface\n")
{
VTY_DECLVAR_CONTEXT(interface, ifp);
struct ospf6_interface *oi;
@@ -2023,12 +2014,11 @@ DEFUN (no_ipv6_ospf6_cost,
return CMD_SUCCESS;
}
-DEFUN (auto_cost_reference_bandwidth,
- auto_cost_reference_bandwidth_cmd,
- "auto-cost reference-bandwidth (1-4294967)",
- "Calculate OSPF interface cost according to bandwidth\n"
- "Use reference bandwidth method to assign OSPF cost\n"
- "The reference bandwidth in terms of Mbits per second\n")
+DEFUN(auto_cost_reference_bandwidth, auto_cost_reference_bandwidth_cmd,
+ "auto-cost reference-bandwidth (1-4294967)",
+ "Calculate OSPF interface cost according to bandwidth\n"
+ "Use reference bandwidth method to assign OSPF cost\n"
+ "The reference bandwidth in terms of Mbits per second\n")
{
VTY_DECLVAR_CONTEXT(ospf6, o);
int idx_number = 2;
@@ -2055,13 +2045,11 @@ DEFUN (auto_cost_reference_bandwidth,
return CMD_SUCCESS;
}
-DEFUN (no_auto_cost_reference_bandwidth,
- no_auto_cost_reference_bandwidth_cmd,
- "no auto-cost reference-bandwidth [(1-4294967)]",
- NO_STR
- "Calculate OSPF interface cost according to bandwidth\n"
- "Use reference bandwidth method to assign OSPF cost\n"
- "The reference bandwidth in terms of Mbits per second\n")
+DEFUN(no_auto_cost_reference_bandwidth, no_auto_cost_reference_bandwidth_cmd,
+ "no auto-cost reference-bandwidth [(1-4294967)]",
+ NO_STR "Calculate OSPF interface cost according to bandwidth\n"
+ "Use reference bandwidth method to assign OSPF cost\n"
+ "The reference bandwidth in terms of Mbits per second\n")
{
VTY_DECLVAR_CONTEXT(ospf6, o);
struct ospf6_area *oa;
@@ -2080,11 +2068,10 @@ DEFUN (no_auto_cost_reference_bandwidth,
}
-DEFUN (ospf6_write_multiplier,
- ospf6_write_multiplier_cmd,
- "write-multiplier (1-100)",
- "Write multiplier\n"
- "Maximum number of interface serviced per write\n")
+DEFUN(ospf6_write_multiplier, ospf6_write_multiplier_cmd,
+ "write-multiplier (1-100)",
+ "Write multiplier\n"
+ "Maximum number of interface serviced per write\n")
{
VTY_DECLVAR_CONTEXT(ospf6, o);
uint32_t write_oi_count;
@@ -2099,12 +2086,10 @@ DEFUN (ospf6_write_multiplier,
return CMD_SUCCESS;
}
-DEFUN (no_ospf6_write_multiplier,
- no_ospf6_write_multiplier_cmd,
- "no write-multiplier (1-100)",
- NO_STR
- "Write multiplier\n"
- "Maximum number of interface serviced per write\n")
+DEFUN(no_ospf6_write_multiplier, no_ospf6_write_multiplier_cmd,
+ "no write-multiplier (1-100)",
+ NO_STR "Write multiplier\n"
+ "Maximum number of interface serviced per write\n")
{
VTY_DECLVAR_CONTEXT(ospf6, o);
@@ -2112,13 +2097,9 @@ DEFUN (no_ospf6_write_multiplier,
return CMD_SUCCESS;
}
-DEFUN (ipv6_ospf6_hellointerval,
- ipv6_ospf6_hellointerval_cmd,
- "ipv6 ospf6 hello-interval (1-65535)",
- IP6_STR
- OSPF6_STR
- "Time between HELLO packets\n"
- SECONDS_STR)
+DEFUN(ipv6_ospf6_hellointerval, ipv6_ospf6_hellointerval_cmd,
+ "ipv6 ospf6 hello-interval (1-65535)",
+ IP6_STR OSPF6_STR "Time between HELLO packets\n" SECONDS_STR)
{
VTY_DECLVAR_CONTEXT(interface, ifp);
int idx_number = 3;
@@ -2146,23 +2127,15 @@ DEFUN (ipv6_ospf6_hellointerval,
return CMD_SUCCESS;
}
-ALIAS (ipv6_ospf6_hellointerval,
- no_ipv6_ospf6_hellointerval_cmd,
- "no ipv6 ospf6 hello-interval [(1-65535)]",
- NO_STR
- IP6_STR
- OSPF6_STR
- "Time between HELLO packets\n"
- SECONDS_STR)
+ALIAS(ipv6_ospf6_hellointerval, no_ipv6_ospf6_hellointerval_cmd,
+ "no ipv6 ospf6 hello-interval [(1-65535)]",
+ NO_STR IP6_STR OSPF6_STR "Time between HELLO packets\n" SECONDS_STR)
/* interface variable set command */
-DEFUN (ipv6_ospf6_deadinterval,
- ipv6_ospf6_deadinterval_cmd,
- "ipv6 ospf6 dead-interval (1-65535)",
- IP6_STR
- OSPF6_STR
- "Interval time after which a neighbor is declared down\n"
- SECONDS_STR)
+DEFUN(ipv6_ospf6_deadinterval, ipv6_ospf6_deadinterval_cmd,
+ "ipv6 ospf6 dead-interval (1-65535)",
+ IP6_STR OSPF6_STR
+ "Interval time after which a neighbor is declared down\n" SECONDS_STR)
{
VTY_DECLVAR_CONTEXT(interface, ifp);
int idx_number = 3;
@@ -2180,22 +2153,16 @@ DEFUN (ipv6_ospf6_deadinterval,
return CMD_SUCCESS;
}
-ALIAS (ipv6_ospf6_deadinterval,
- no_ipv6_ospf6_deadinterval_cmd,
- "no ipv6 ospf6 dead-interval [(1-65535)]",
- NO_STR
- IP6_STR
- OSPF6_STR
- "Interval time after which a neighbor is declared down\n"
- SECONDS_STR)
+ALIAS(ipv6_ospf6_deadinterval, no_ipv6_ospf6_deadinterval_cmd,
+ "no ipv6 ospf6 dead-interval [(1-65535)]",
+ NO_STR IP6_STR OSPF6_STR
+ "Interval time after which a neighbor is declared down\n" SECONDS_STR)
DEFPY(ipv6_ospf6_gr_hdelay, ipv6_ospf6_gr_hdelay_cmd,
"ipv6 ospf6 graceful-restart hello-delay (1-1800)",
- IP6_STR
- OSPF6_STR
- "Graceful Restart parameters\n"
- "Delay the sending of the first hello packets.\n"
- "Delay in seconds\n")
+ IP6_STR OSPF6_STR "Graceful Restart parameters\n"
+ "Delay the sending of the first hello packets.\n"
+ "Delay in seconds\n")
{
VTY_DECLVAR_CONTEXT(interface, ifp);
struct ospf6_interface *oi;
@@ -2212,12 +2179,9 @@ DEFPY(ipv6_ospf6_gr_hdelay, ipv6_ospf6_gr_hdelay_cmd,
DEFPY(no_ipv6_ospf6_gr_hdelay, no_ipv6_ospf6_gr_hdelay_cmd,
"no ipv6 ospf6 graceful-restart hello-delay [(1-1800)]",
- NO_STR
- IP6_STR
- OSPF6_STR
- "Graceful Restart parameters\n"
- "Delay the sending of the first hello packets.\n"
- "Delay in seconds\n")
+ NO_STR IP6_STR OSPF6_STR "Graceful Restart parameters\n"
+ "Delay the sending of the first hello packets.\n"
+ "Delay in seconds\n")
{
VTY_DECLVAR_CONTEXT(interface, ifp);
struct ospf6_interface *oi;
@@ -2234,13 +2198,9 @@ DEFPY(no_ipv6_ospf6_gr_hdelay, no_ipv6_ospf6_gr_hdelay_cmd,
}
/* interface variable set command */
-DEFUN (ipv6_ospf6_transmitdelay,
- ipv6_ospf6_transmitdelay_cmd,
- "ipv6 ospf6 transmit-delay (1-3600)",
- IP6_STR
- OSPF6_STR
- "Link state transmit delay\n"
- SECONDS_STR)
+DEFUN(ipv6_ospf6_transmitdelay, ipv6_ospf6_transmitdelay_cmd,
+ "ipv6 ospf6 transmit-delay (1-3600)",
+ IP6_STR OSPF6_STR "Link state transmit delay\n" SECONDS_STR)
{
VTY_DECLVAR_CONTEXT(interface, ifp);
int idx_number = 3;
@@ -2258,23 +2218,15 @@ DEFUN (ipv6_ospf6_transmitdelay,
return CMD_SUCCESS;
}
-ALIAS (ipv6_ospf6_transmitdelay,
- no_ipv6_ospf6_transmitdelay_cmd,
- "no ipv6 ospf6 transmit-delay [(1-3600)]",
- NO_STR
- IP6_STR
- OSPF6_STR
- "Link state transmit delay\n"
- SECONDS_STR)
+ALIAS(ipv6_ospf6_transmitdelay, no_ipv6_ospf6_transmitdelay_cmd,
+ "no ipv6 ospf6 transmit-delay [(1-3600)]",
+ NO_STR IP6_STR OSPF6_STR "Link state transmit delay\n" SECONDS_STR)
/* interface variable set command */
-DEFUN (ipv6_ospf6_retransmitinterval,
- ipv6_ospf6_retransmitinterval_cmd,
- "ipv6 ospf6 retransmit-interval (1-65535)",
- IP6_STR
- OSPF6_STR
- "Time between retransmitting lost link state advertisements\n"
- SECONDS_STR)
+DEFUN(ipv6_ospf6_retransmitinterval, ipv6_ospf6_retransmitinterval_cmd,
+ "ipv6 ospf6 retransmit-interval (1-65535)",
+ IP6_STR OSPF6_STR
+ "Time between retransmitting lost link state advertisements\n" SECONDS_STR)
{
VTY_DECLVAR_CONTEXT(interface, ifp);
int idx_number = 3;
@@ -2292,23 +2244,16 @@ DEFUN (ipv6_ospf6_retransmitinterval,
return CMD_SUCCESS;
}
-ALIAS (ipv6_ospf6_retransmitinterval,
- no_ipv6_ospf6_retransmitinterval_cmd,
- "no ipv6 ospf6 retransmit-interval [(1-65535)]",
- NO_STR
- IP6_STR
- OSPF6_STR
- "Time between retransmitting lost link state advertisements\n"
- SECONDS_STR)
+ALIAS(ipv6_ospf6_retransmitinterval, no_ipv6_ospf6_retransmitinterval_cmd,
+ "no ipv6 ospf6 retransmit-interval [(1-65535)]",
+ NO_STR IP6_STR OSPF6_STR
+ "Time between retransmitting lost link state advertisements\n" SECONDS_STR)
/* interface variable set command */
-DEFUN (ipv6_ospf6_priority,
- ipv6_ospf6_priority_cmd,
- "ipv6 ospf6 priority (0-255)",
- IP6_STR
- OSPF6_STR
- "Router priority\n"
- "Priority value\n")
+DEFUN(ipv6_ospf6_priority, ipv6_ospf6_priority_cmd,
+ "ipv6 ospf6 priority (0-255)",
+ IP6_STR OSPF6_STR "Router priority\n"
+ "Priority value\n")
{
VTY_DECLVAR_CONTEXT(interface, ifp);
int idx_number = 3;
@@ -2324,10 +2269,9 @@ DEFUN (ipv6_ospf6_priority,
? OSPF6_INTERFACE_PRIORITY
: strtoul(argv[idx_number]->arg, NULL, 10);
- if (oi->area
- && (oi->state == OSPF6_INTERFACE_DROTHER
- || oi->state == OSPF6_INTERFACE_BDR
- || oi->state == OSPF6_INTERFACE_DR)) {
+ if (oi->area && (oi->state == OSPF6_INTERFACE_DROTHER ||
+ oi->state == OSPF6_INTERFACE_BDR ||
+ oi->state == OSPF6_INTERFACE_DR)) {
if (ospf6_interface_state_change(dr_election(oi), oi) == -1)
OSPF6_LINK_LSA_SCHEDULE(oi);
}
@@ -2335,22 +2279,15 @@ DEFUN (ipv6_ospf6_priority,
return CMD_SUCCESS;
}
-ALIAS (ipv6_ospf6_priority,
- no_ipv6_ospf6_priority_cmd,
- "no ipv6 ospf6 priority [(0-255)]",
- NO_STR
- IP6_STR
- OSPF6_STR
- "Router priority\n"
- "Priority value\n")
+ALIAS(ipv6_ospf6_priority, no_ipv6_ospf6_priority_cmd,
+ "no ipv6 ospf6 priority [(0-255)]",
+ NO_STR IP6_STR OSPF6_STR "Router priority\n"
+ "Priority value\n")
-DEFUN (ipv6_ospf6_instance,
- ipv6_ospf6_instance_cmd,
- "ipv6 ospf6 instance-id (0-255)",
- IP6_STR
- OSPF6_STR
- "Instance ID for this interface\n"
- "Instance ID value\n")
+DEFUN(ipv6_ospf6_instance, ipv6_ospf6_instance_cmd,
+ "ipv6 ospf6 instance-id (0-255)",
+ IP6_STR OSPF6_STR "Instance ID for this interface\n"
+ "Instance ID value\n")
{
VTY_DECLVAR_CONTEXT(interface, ifp);
int idx_number = 3;
@@ -2368,22 +2305,14 @@ DEFUN (ipv6_ospf6_instance,
return CMD_SUCCESS;
}
-ALIAS (ipv6_ospf6_instance,
- no_ipv6_ospf6_instance_cmd,
- "no ipv6 ospf6 instance-id [(0-255)]",
- NO_STR
- IP6_STR
- OSPF6_STR
- "Instance ID for this interface\n"
- "Instance ID value\n")
+ALIAS(ipv6_ospf6_instance, no_ipv6_ospf6_instance_cmd,
+ "no ipv6 ospf6 instance-id [(0-255)]",
+ NO_STR IP6_STR OSPF6_STR "Instance ID for this interface\n"
+ "Instance ID value\n")
-DEFUN (ipv6_ospf6_passive,
- ipv6_ospf6_passive_cmd,
- "ipv6 ospf6 passive",
- IP6_STR
- OSPF6_STR
- "Passive interface; no adjacency will be formed on this interface\n"
- )
+DEFUN(ipv6_ospf6_passive, ipv6_ospf6_passive_cmd, "ipv6 ospf6 passive",
+ IP6_STR OSPF6_STR
+ "Passive interface; no adjacency will be formed on this interface\n")
{
VTY_DECLVAR_CONTEXT(interface, ifp);
struct ospf6_interface *oi;
@@ -2409,14 +2338,9 @@ DEFUN (ipv6_ospf6_passive,
return CMD_SUCCESS;
}
-DEFUN (no_ipv6_ospf6_passive,
- no_ipv6_ospf6_passive_cmd,
- "no ipv6 ospf6 passive",
- NO_STR
- IP6_STR
- OSPF6_STR
- "passive interface: No Adjacency will be formed on this I/F\n"
- )
+DEFUN(no_ipv6_ospf6_passive, no_ipv6_ospf6_passive_cmd, "no ipv6 ospf6 passive",
+ NO_STR IP6_STR OSPF6_STR
+ "passive interface: No Adjacency will be formed on this I/F\n")
{
VTY_DECLVAR_CONTEXT(interface, ifp);
struct ospf6_interface *oi;
@@ -2439,13 +2363,8 @@ DEFUN (no_ipv6_ospf6_passive,
return CMD_SUCCESS;
}
-DEFUN (ipv6_ospf6_mtu_ignore,
- ipv6_ospf6_mtu_ignore_cmd,
- "ipv6 ospf6 mtu-ignore",
- IP6_STR
- OSPF6_STR
- "Disable MTU mismatch detection on this interface\n"
- )
+DEFUN(ipv6_ospf6_mtu_ignore, ipv6_ospf6_mtu_ignore_cmd, "ipv6 ospf6 mtu-ignore",
+ IP6_STR OSPF6_STR "Disable MTU mismatch detection on this interface\n")
{
VTY_DECLVAR_CONTEXT(interface, ifp);
struct ospf6_interface *oi;
@@ -2461,14 +2380,10 @@ DEFUN (ipv6_ospf6_mtu_ignore,
return CMD_SUCCESS;
}
-DEFUN (no_ipv6_ospf6_mtu_ignore,
- no_ipv6_ospf6_mtu_ignore_cmd,
- "no ipv6 ospf6 mtu-ignore",
- NO_STR
- IP6_STR
- OSPF6_STR
- "Disable MTU mismatch detection on this interface\n"
- )
+DEFUN(no_ipv6_ospf6_mtu_ignore, no_ipv6_ospf6_mtu_ignore_cmd,
+ "no ipv6 ospf6 mtu-ignore",
+ NO_STR IP6_STR OSPF6_STR
+ "Disable MTU mismatch detection on this interface\n")
{
VTY_DECLVAR_CONTEXT(interface, ifp);
struct ospf6_interface *oi;
@@ -2484,15 +2399,11 @@ DEFUN (no_ipv6_ospf6_mtu_ignore,
return CMD_SUCCESS;
}
-DEFUN (ipv6_ospf6_advertise_prefix_list,
- ipv6_ospf6_advertise_prefix_list_cmd,
- "ipv6 ospf6 advertise prefix-list WORD",
- IP6_STR
- OSPF6_STR
- "Advertising options\n"
- "Filter prefix using prefix-list\n"
- "Prefix list name\n"
- )
+DEFUN(ipv6_ospf6_advertise_prefix_list, ipv6_ospf6_advertise_prefix_list_cmd,
+ "ipv6 ospf6 advertise prefix-list WORD",
+ IP6_STR OSPF6_STR "Advertising options\n"
+ "Filter prefix using prefix-list\n"
+ "Prefix list name\n")
{
VTY_DECLVAR_CONTEXT(interface, ifp);
int idx_word = 4;
@@ -2522,15 +2433,12 @@ DEFUN (ipv6_ospf6_advertise_prefix_list,
return CMD_SUCCESS;
}
-DEFUN (no_ipv6_ospf6_advertise_prefix_list,
- no_ipv6_ospf6_advertise_prefix_list_cmd,
- "no ipv6 ospf6 advertise prefix-list [WORD]",
- NO_STR
- IP6_STR
- OSPF6_STR
- "Advertising options\n"
- "Filter prefix using prefix-list\n"
- "Prefix list name\n")
+DEFUN(no_ipv6_ospf6_advertise_prefix_list,
+ no_ipv6_ospf6_advertise_prefix_list_cmd,
+ "no ipv6 ospf6 advertise prefix-list [WORD]",
+ NO_STR IP6_STR OSPF6_STR "Advertising options\n"
+ "Filter prefix using prefix-list\n"
+ "Prefix list name\n")
{
VTY_DECLVAR_CONTEXT(interface, ifp);
struct ospf6_interface *oi;
@@ -2558,15 +2466,12 @@ DEFUN (no_ipv6_ospf6_advertise_prefix_list,
return CMD_SUCCESS;
}
-DEFUN (ipv6_ospf6_network,
- ipv6_ospf6_network_cmd,
- "ipv6 ospf6 network <broadcast|point-to-point>",
- IP6_STR
- OSPF6_STR
- "Network type\n"
- "Specify OSPF6 broadcast network\n"
- "Specify OSPF6 point-to-point network\n"
- )
+DEFUN(ipv6_ospf6_network, ipv6_ospf6_network_cmd,
+ "ipv6 ospf6 network <broadcast|point-to-point|point-to-multipoint>",
+ IP6_STR OSPF6_STR "Network type\n"
+ "Specify OSPF6 broadcast network\n"
+ "Specify OSPF6 point-to-point network\n"
+ "Specify OSPF6 point-to-multipoint network\n")
{
VTY_DECLVAR_CONTEXT(interface, ifp);
int idx_network = 3;
@@ -2591,6 +2496,11 @@ DEFUN (ipv6_ospf6_network,
return CMD_SUCCESS;
}
oi->type = OSPF_IFTYPE_POINTOPOINT;
+ } else if (strncmp(argv[idx_network]->arg, "point-to-m", 10) == 0) {
+ if (oi->type == OSPF_IFTYPE_POINTOMULTIPOINT) {
+ return CMD_SUCCESS;
+ }
+ oi->type = OSPF_IFTYPE_POINTOMULTIPOINT;
}
/* Reset the interface */
@@ -2600,15 +2510,11 @@ DEFUN (ipv6_ospf6_network,
return CMD_SUCCESS;
}
-DEFUN (no_ipv6_ospf6_network,
- no_ipv6_ospf6_network_cmd,
- "no ipv6 ospf6 network [<broadcast|point-to-point>]",
- NO_STR
- IP6_STR
- OSPF6_STR
- "Set default network type\n"
- "Specify OSPF6 broadcast network\n"
- "Specify OSPF6 point-to-point network\n")
+DEFUN(no_ipv6_ospf6_network, no_ipv6_ospf6_network_cmd,
+ "no ipv6 ospf6 network [<broadcast|point-to-point>]",
+ NO_STR IP6_STR OSPF6_STR "Set default network type\n"
+ "Specify OSPF6 broadcast network\n"
+ "Specify OSPF6 point-to-point network\n")
{
VTY_DECLVAR_CONTEXT(interface, ifp);
struct ospf6_interface *oi;
@@ -2617,9 +2523,8 @@ DEFUN (no_ipv6_ospf6_network,
assert(ifp);
oi = (struct ospf6_interface *)ifp->info;
- if (oi == NULL) {
+ if (oi == NULL)
return CMD_SUCCESS;
- }
oi->type_cfg = false;
@@ -2636,6 +2541,95 @@ DEFUN (no_ipv6_ospf6_network,
return CMD_SUCCESS;
}
+DEFPY(ipv6_ospf6_p2xp_only_cfg_neigh, ipv6_ospf6_p2xp_only_cfg_neigh_cmd,
+ "[no] ipv6 ospf6 p2p-p2mp config-neighbors-only",
+ NO_STR IP6_STR OSPF6_STR
+ "Point-to-point and Point-to-Multipoint parameters\n"
+ "Only form adjacencies with explicitly configured neighbors\n")
+{
+ VTY_DECLVAR_CONTEXT(interface, ifp);
+ struct ospf6_interface *oi = ifp->info;
+
+ if (no) {
+ if (!oi)
+ return CMD_SUCCESS;
+
+ oi->p2xp_only_cfg_neigh = false;
+ return CMD_SUCCESS;
+ }
+
+ if (!oi)
+ oi = ospf6_interface_create(ifp);
+
+ oi->p2xp_only_cfg_neigh = true;
+ return CMD_SUCCESS;
+}
+
+DEFPY(ipv6_ospf6_p2xp_no_multicast_hello, ipv6_ospf6_p2xp_no_multicast_hello_cmd,
+ "[no] ipv6 ospf6 p2p-p2mp disable-multicast-hello",
+ NO_STR IP6_STR OSPF6_STR
+ "Point-to-point and Point-to-Multipoint parameters\n"
+ "Do not send multicast hellos\n")
+{
+ VTY_DECLVAR_CONTEXT(interface, ifp);
+ struct ospf6_interface *oi = ifp->info;
+
+ if (no) {
+ if (!oi)
+ return CMD_SUCCESS;
+
+ oi->p2xp_no_multicast_hello = false;
+ return CMD_SUCCESS;
+ }
+
+ if (!oi)
+ oi = ospf6_interface_create(ifp);
+
+ oi->p2xp_no_multicast_hello = true;
+ return CMD_SUCCESS;
+}
+
+DEFPY(ipv6_ospf6_p2xp_connected_pfx, ipv6_ospf6_p2xp_connected_pfx_cmd,
+ "[no] ipv6 ospf6 p2p-p2mp connected-prefixes <include$incl|exclude$excl>",
+ NO_STR IP6_STR OSPF6_STR
+ "Point-to-point and Point-to-Multipoint parameters\n"
+ "Adjust handling of directly connected prefixes\n"
+ "Advertise prefixes and own /128 (default for PtP)\n"
+ "Ignore, only advertise own /128 (default for PtMP)\n")
+{
+ VTY_DECLVAR_CONTEXT(interface, ifp);
+ struct ospf6_interface *oi = ifp->info;
+ bool old_incl, old_excl;
+
+ if (no && !oi)
+ return CMD_SUCCESS;
+
+ if (!oi)
+ oi = ospf6_interface_create(ifp);
+
+ old_incl = oi->p2xp_connected_pfx_include;
+ old_excl = oi->p2xp_connected_pfx_exclude;
+ oi->p2xp_connected_pfx_include = false;
+ oi->p2xp_connected_pfx_exclude = false;
+
+ if (incl && !no)
+ oi->p2xp_connected_pfx_include = true;
+ if (excl && !no)
+ oi->p2xp_connected_pfx_exclude = true;
+
+ if (oi->p2xp_connected_pfx_include != old_incl ||
+ oi->p2xp_connected_pfx_exclude != old_excl)
+ ospf6_interface_connected_route_update(ifp);
+ return CMD_SUCCESS;
+}
+
+ALIAS(ipv6_ospf6_p2xp_connected_pfx, no_ipv6_ospf6_p2xp_connected_pfx_cmd,
+ "no ipv6 ospf6 p2p-p2mp connected-prefixes",
+ NO_STR IP6_STR OSPF6_STR
+ "Point-to-point and Point-to-Multipoint parameters\n"
+ "Adjust handling of directly connected prefixes\n")
+
+
static int config_write_ospf6_interface(struct vty *vty, struct vrf *vrf)
{
struct ospf6_interface *oi;
@@ -2695,7 +2689,10 @@ static int config_write_ospf6_interface(struct vty *vty, struct vrf *vrf)
if (oi->mtu_ignore)
vty_out(vty, " ipv6 ospf6 mtu-ignore\n");
- if (oi->type_cfg && oi->type == OSPF_IFTYPE_POINTOPOINT)
+ if (oi->type_cfg && oi->type == OSPF_IFTYPE_POINTOMULTIPOINT)
+ vty_out(vty,
+ " ipv6 ospf6 network point-to-multipoint\n");
+ else if (oi->type_cfg && oi->type == OSPF_IFTYPE_POINTOPOINT)
vty_out(vty, " ipv6 ospf6 network point-to-point\n");
else if (oi->type_cfg && oi->type == OSPF_IFTYPE_BROADCAST)
vty_out(vty, " ipv6 ospf6 network broadcast\n");
@@ -2704,7 +2701,22 @@ static int config_write_ospf6_interface(struct vty *vty, struct vrf *vrf)
vty_out(vty,
" ipv6 ospf6 graceful-restart hello-delay %u\n",
oi->gr.hello_delay.interval);
+ if (oi->p2xp_only_cfg_neigh)
+ vty_out(vty,
+ " ipv6 ospf6 p2p-p2mp config-neighbors-only\n");
+ if (oi->p2xp_no_multicast_hello)
+ vty_out(vty,
+ " ipv6 ospf6 p2p-p2mp disable-multicast-hello\n");
+
+ if (oi->p2xp_connected_pfx_include)
+ vty_out(vty,
+ " ipv6 ospf6 p2p-p2mp connected-prefixes include\n");
+ else if (oi->p2xp_connected_pfx_exclude)
+ vty_out(vty,
+ " ipv6 ospf6 p2p-p2mp connected-prefixes exclude\n");
+
+ config_write_ospf6_p2xp_neighbor(vty, oi);
ospf6_bfd_write_config(vty, oi);
ospf6_auth_write_config(vty, &oi->at_data);
@@ -2742,10 +2754,10 @@ static int ospf6_ifp_create(struct interface *ifp)
static int ospf6_ifp_up(struct interface *ifp)
{
if (IS_OSPF6_DEBUG_ZEBRA(RECV))
- zlog_debug(
- "Zebra Interface state change: %s index %d flags %llx metric %d mtu %d bandwidth %d",
- ifp->name, ifp->ifindex, (unsigned long long)ifp->flags,
- ifp->metric, ifp->mtu6, ifp->bandwidth);
+ zlog_debug("Zebra Interface state change: %s index %d flags %llx metric %d mtu %d bandwidth %d",
+ ifp->name, ifp->ifindex,
+ (unsigned long long)ifp->flags, ifp->metric,
+ ifp->mtu6, ifp->bandwidth);
ospf6_interface_state_update(ifp);
@@ -2755,10 +2767,10 @@ static int ospf6_ifp_up(struct interface *ifp)
static int ospf6_ifp_down(struct interface *ifp)
{
if (IS_OSPF6_DEBUG_ZEBRA(RECV))
- zlog_debug(
- "Zebra Interface state change: %s index %d flags %llx metric %d mtu %d bandwidth %d",
- ifp->name, ifp->ifindex, (unsigned long long)ifp->flags,
- ifp->metric, ifp->mtu6, ifp->bandwidth);
+ zlog_debug("Zebra Interface state change: %s index %d flags %llx metric %d mtu %d bandwidth %d",
+ ifp->name, ifp->ifindex,
+ (unsigned long long)ifp->flags, ifp->metric,
+ ifp->mtu6, ifp->bandwidth);
ospf6_interface_state_update(ifp);
@@ -2785,13 +2797,12 @@ void ospf6_interface_init(void)
{
/* Install interface node. */
if_cmd_init(config_write_interface);
- if_zapi_callbacks(ospf6_ifp_create, ospf6_ifp_up,
- ospf6_ifp_down, ospf6_ifp_destroy);
+ if_zapi_callbacks(ospf6_ifp_create, ospf6_ifp_up, ospf6_ifp_down,
+ ospf6_ifp_destroy);
install_element(VIEW_NODE, &show_ipv6_ospf6_interface_prefix_cmd);
install_element(VIEW_NODE, &show_ipv6_ospf6_interface_ifname_cmd);
- install_element(VIEW_NODE,
- &show_ipv6_ospf6_interface_ifname_prefix_cmd);
+ install_element(VIEW_NODE, &show_ipv6_ospf6_interface_ifname_prefix_cmd);
install_element(VIEW_NODE, &show_ipv6_ospf6_interface_traffic_cmd);
install_element(INTERFACE_NODE, &ipv6_ospf6_area_cmd);
@@ -2829,6 +2840,11 @@ void ospf6_interface_init(void)
install_element(INTERFACE_NODE, &ipv6_ospf6_network_cmd);
install_element(INTERFACE_NODE, &no_ipv6_ospf6_network_cmd);
+ install_element(INTERFACE_NODE, &ipv6_ospf6_p2xp_only_cfg_neigh_cmd);
+ install_element(INTERFACE_NODE, &ipv6_ospf6_p2xp_no_multicast_hello_cmd);
+ install_element(INTERFACE_NODE, &ipv6_ospf6_p2xp_connected_pfx_cmd);
+ install_element(INTERFACE_NODE, &no_ipv6_ospf6_p2xp_connected_pfx_cmd);
+
/* reference bandwidth commands */
install_element(OSPF6_NODE, &auto_cost_reference_bandwidth_cmd);
install_element(OSPF6_NODE, &no_auto_cost_reference_bandwidth_cmd);
@@ -2859,16 +2875,9 @@ void ospf6_interface_clear(struct interface *ifp)
}
/* Clear interface */
-DEFUN (clear_ipv6_ospf6_interface,
- clear_ipv6_ospf6_interface_cmd,
- "clear ipv6 ospf6 [vrf NAME] interface [IFNAME]",
- CLEAR_STR
- IP6_STR
- OSPF6_STR
- VRF_CMD_HELP_STR
- INTERFACE_STR
- IFNAME_STR
- )
+DEFUN(clear_ipv6_ospf6_interface, clear_ipv6_ospf6_interface_cmd,
+ "clear ipv6 ospf6 [vrf NAME] interface [IFNAME]",
+ CLEAR_STR IP6_STR OSPF6_STR VRF_CMD_HELP_STR INTERFACE_STR IFNAME_STR)
{
struct vrf *vrf;
int idx_vrf = 3;
@@ -2909,26 +2918,16 @@ void install_element_ospf6_clear_interface(void)
install_element(ENABLE_NODE, &clear_ipv6_ospf6_interface_cmd);
}
-DEFUN (debug_ospf6_interface,
- debug_ospf6_interface_cmd,
- "debug ospf6 interface",
- DEBUG_STR
- OSPF6_STR
- "Debug OSPFv3 Interface\n"
- )
+DEFUN(debug_ospf6_interface, debug_ospf6_interface_cmd, "debug ospf6 interface",
+ DEBUG_STR OSPF6_STR "Debug OSPFv3 Interface\n")
{
OSPF6_DEBUG_INTERFACE_ON();
return CMD_SUCCESS;
}
-DEFUN (no_debug_ospf6_interface,
- no_debug_ospf6_interface_cmd,
- "no debug ospf6 interface",
- NO_STR
- DEBUG_STR
- OSPF6_STR
- "Debug OSPFv3 Interface\n"
- )
+DEFUN(no_debug_ospf6_interface, no_debug_ospf6_interface_cmd,
+ "no debug ospf6 interface",
+ NO_STR DEBUG_STR OSPF6_STR "Debug OSPFv3 Interface\n")
{
OSPF6_DEBUG_INTERFACE_OFF();
return CMD_SUCCESS;
@@ -2965,10 +2964,9 @@ void ospf6_auth_write_config(struct vty *vty, struct ospf6_auth_data *at_data)
DEFUN(ipv6_ospf6_intf_auth_trailer_keychain,
ipv6_ospf6_intf_auth_trailer_keychain_cmd,
"ipv6 ospf6 authentication keychain KEYCHAIN_NAME",
- IP6_STR OSPF6_STR
- "Enable authentication on this interface\n"
- "Keychain\n"
- "Keychain name\n")
+ IP6_STR OSPF6_STR "Enable authentication on this interface\n"
+ "Keychain\n"
+ "Keychain name\n")
{
VTY_DECLVAR_CONTEXT(interface, ifp);
int keychain_idx = 4;
@@ -2989,8 +2987,8 @@ DEFUN(ipv6_ospf6_intf_auth_trailer_keychain,
if (oi->at_data.keychain)
XFREE(MTYPE_OSPF6_AUTH_KEYCHAIN, oi->at_data.keychain);
- oi->at_data.keychain =
- XSTRDUP(MTYPE_OSPF6_AUTH_KEYCHAIN, argv[keychain_idx]->arg);
+ oi->at_data.keychain = XSTRDUP(MTYPE_OSPF6_AUTH_KEYCHAIN,
+ argv[keychain_idx]->arg);
return CMD_SUCCESS;
}
@@ -2998,10 +2996,9 @@ DEFUN(ipv6_ospf6_intf_auth_trailer_keychain,
DEFUN(no_ipv6_ospf6_intf_auth_trailer_keychain,
no_ipv6_ospf6_intf_auth_trailer_keychain_cmd,
"no ipv6 ospf6 authentication keychain [KEYCHAIN_NAME]",
- NO_STR IP6_STR OSPF6_STR
- "Enable authentication on this interface\n"
- "Keychain\n"
- "Keychain name\n")
+ NO_STR IP6_STR OSPF6_STR "Enable authentication on this interface\n"
+ "Keychain\n"
+ "Keychain name\n")
{
VTY_DECLVAR_CONTEXT(interface, ifp);
struct ospf6_interface *oi;
@@ -3027,18 +3024,17 @@ DEFUN(ipv6_ospf6_intf_auth_trailer_key, ipv6_ospf6_intf_auth_trailer_key_cmd,
"ipv6 ospf6 authentication key-id (1-65535) hash-algo "
"<md5|hmac-sha-1|hmac-sha-256|hmac-sha-384|hmac-sha-512> "
"key WORD",
- IP6_STR OSPF6_STR
- "Authentication\n"
- "Key ID\n"
- "Key ID value\n"
- "Cryptographic-algorithm\n"
- "Use MD5 algorithm\n"
- "Use HMAC-SHA-1 algorithm\n"
- "Use HMAC-SHA-256 algorithm\n"
- "Use HMAC-SHA-384 algorithm\n"
- "Use HMAC-SHA-512 algorithm\n"
- "Password\n"
- "Password string (key)\n")
+ IP6_STR OSPF6_STR "Authentication\n"
+ "Key ID\n"
+ "Key ID value\n"
+ "Cryptographic-algorithm\n"
+ "Use MD5 algorithm\n"
+ "Use HMAC-SHA-1 algorithm\n"
+ "Use HMAC-SHA-256 algorithm\n"
+ "Use HMAC-SHA-384 algorithm\n"
+ "Use HMAC-SHA-512 algorithm\n"
+ "Password\n"
+ "Password string (key)\n")
{
VTY_DECLVAR_CONTEXT(interface, ifp);
int key_id_idx = 4;
@@ -3072,8 +3068,8 @@ DEFUN(ipv6_ospf6_intf_auth_trailer_key, ipv6_ospf6_intf_auth_trailer_key_cmd,
oi->at_data.key_id = (uint16_t)strtol(argv[key_id_idx]->arg, NULL, 10);
if (oi->at_data.auth_key)
XFREE(MTYPE_OSPF6_AUTH_MANUAL_KEY, oi->at_data.auth_key);
- oi->at_data.auth_key =
- XSTRDUP(MTYPE_OSPF6_AUTH_MANUAL_KEY, argv[password_idx]->arg);
+ oi->at_data.auth_key = XSTRDUP(MTYPE_OSPF6_AUTH_MANUAL_KEY,
+ argv[password_idx]->arg);
return CMD_SUCCESS;
}
@@ -3083,18 +3079,17 @@ DEFUN(no_ipv6_ospf6_intf_auth_trailer_key,
"no ipv6 ospf6 authentication key-id [(1-65535) hash-algo "
"<md5|hmac-sha-1|hmac-sha-256|hmac-sha-384|hmac-sha-512> "
"key WORD]",
- NO_STR IP6_STR OSPF6_STR
- "Authentication\n"
- "Key ID\n"
- "Key ID value\n"
- "Cryptographic-algorithm\n"
- "Use MD5 algorithm\n"
- "Use HMAC-SHA-1 algorithm\n"
- "Use HMAC-SHA-256 algorithm\n"
- "Use HMAC-SHA-384 algorithm\n"
- "Use HMAC-SHA-512 algorithm\n"
- "Password\n"
- "Password string (key)\n")
+ NO_STR IP6_STR OSPF6_STR "Authentication\n"
+ "Key ID\n"
+ "Key ID value\n"
+ "Cryptographic-algorithm\n"
+ "Use MD5 algorithm\n"
+ "Use HMAC-SHA-1 algorithm\n"
+ "Use HMAC-SHA-256 algorithm\n"
+ "Use HMAC-SHA-384 algorithm\n"
+ "Use HMAC-SHA-512 algorithm\n"
+ "Password\n"
+ "Password string (key)\n")
{
VTY_DECLVAR_CONTEXT(interface, ifp);
struct ospf6_interface *oi;
diff --git a/ospf6d/ospf6_interface.h b/ospf6d/ospf6_interface.h
index 5942df0ab..2b42af390 100644
--- a/ospf6d/ospf6_interface.h
+++ b/ospf6d/ospf6_interface.h
@@ -34,6 +34,25 @@ struct ospf6_auth_data {
uint32_t rx_drop; /* Pkt drop due to auth fail while reading */
};
+PREDECL_RBTREE_UNIQ(ospf6_if_p2xp_neighcfgs);
+
+struct ospf6_if_p2xp_neighcfg {
+ struct ospf6_if_p2xp_neighcfgs_item item;
+
+ struct ospf6_interface *ospf6_if;
+ struct in6_addr addr;
+
+ bool cfg_cost : 1;
+
+ uint32_t cost;
+ uint16_t poll_interval;
+
+ /* NULL if down */
+ struct ospf6_neighbor *active;
+
+ struct event *t_unicast_hello;
+};
+
/* Interface structure */
struct ospf6_interface {
/* IF info from zebra */
@@ -66,6 +85,20 @@ struct ospf6_interface {
uint8_t type;
bool type_cfg;
+ /* P2P/P2MP behavior: */
+
+ /* disable hellos on standard multicast? */
+ bool p2xp_no_multicast_hello;
+ /* only allow explicitly configured neighbors? */
+ bool p2xp_only_cfg_neigh;
+ /* override mode default for advertising connected prefixes.
+ * both false by default (= do include for PtP, exclude for PtMP)
+ */
+ bool p2xp_connected_pfx_include;
+ bool p2xp_connected_pfx_exclude;
+
+ struct ospf6_if_p2xp_neighcfgs_head p2xp_neighs;
+
/* Router Priority */
uint8_t priority;
@@ -171,15 +204,16 @@ struct ospf6_interface {
DECLARE_QOBJ_TYPE(ospf6_interface);
/* interface state */
-#define OSPF6_INTERFACE_NONE 0
-#define OSPF6_INTERFACE_DOWN 1
-#define OSPF6_INTERFACE_LOOPBACK 2
-#define OSPF6_INTERFACE_WAITING 3
-#define OSPF6_INTERFACE_POINTTOPOINT 4
-#define OSPF6_INTERFACE_DROTHER 5
-#define OSPF6_INTERFACE_BDR 6
-#define OSPF6_INTERFACE_DR 7
-#define OSPF6_INTERFACE_MAX 8
+#define OSPF6_INTERFACE_NONE 0
+#define OSPF6_INTERFACE_DOWN 1
+#define OSPF6_INTERFACE_LOOPBACK 2
+#define OSPF6_INTERFACE_WAITING 3
+#define OSPF6_INTERFACE_POINTTOPOINT 4
+#define OSPF6_INTERFACE_POINTTOMULTIPOINT 5
+#define OSPF6_INTERFACE_DROTHER 6
+#define OSPF6_INTERFACE_BDR 7
+#define OSPF6_INTERFACE_DR 8
+#define OSPF6_INTERFACE_MAX 9
extern const char *const ospf6_interface_state_str[];
diff --git a/ospf6d/ospf6_intra.c b/ospf6d/ospf6_intra.c
index eb5514adf..cb036752e 100644
--- a/ospf6d/ospf6_intra.c
+++ b/ospf6d/ospf6_intra.c
@@ -321,13 +321,14 @@ void ospf6_router_lsa_originate(struct event *thread)
}
/* Point-to-Point interfaces */
- if (oi->type == OSPF_IFTYPE_POINTOPOINT) {
+ if (oi->type == OSPF_IFTYPE_POINTOPOINT
+ || oi->type == OSPF_IFTYPE_POINTOMULTIPOINT) {
for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, j, on)) {
if (on->state != OSPF6_NEIGHBOR_FULL)
continue;
lsdesc->type = OSPF6_ROUTER_LSDESC_POINTTOPOINT;
- lsdesc->metric = htons(oi->cost);
+ lsdesc->metric = htons(ospf6_neighbor_cost(on));
lsdesc->interface_id =
htonl(oi->interface->ifindex);
lsdesc->neighbor_interface_id =
@@ -1068,6 +1069,7 @@ void ospf6_intra_prefix_lsa_originate_stub(struct event *thread)
if (oi->state != OSPF6_INTERFACE_LOOPBACK
&& oi->state != OSPF6_INTERFACE_POINTTOPOINT
+ && oi->state != OSPF6_INTERFACE_POINTTOMULTIPOINT
&& full_count != 0) {
if (IS_OSPF6_DEBUG_ORIGINATE(INTRA_PREFIX))
zlog_debug(" Interface %s is not stub, ignore",
diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c
index 7fbe08d30..d13799c0e 100644
--- a/ospf6d/ospf6_message.c
+++ b/ospf6d/ospf6_message.c
@@ -268,6 +268,18 @@ static struct ospf6_packet *ospf6_packet_new(size_t size)
return new;
}
+static struct ospf6_packet *ospf6_packet_dup(struct ospf6_packet *old)
+{
+ struct ospf6_packet *new;
+
+ new = XCALLOC(MTYPE_OSPF6_PACKET, sizeof(struct ospf6_packet));
+ new->s = stream_dup(old->s);
+ new->dst = old->dst;
+ new->length = old->length;
+
+ return new;
+}
+
static void ospf6_packet_free(struct ospf6_packet *op)
{
if (op->s)
@@ -407,6 +419,25 @@ static void ospf6_hello_recv(struct in6_addr *src, struct in6_addr *dst,
hello = (struct ospf6_hello *)((caddr_t)oh
+ sizeof(struct ospf6_header));
+ if ((oi->state == OSPF6_INTERFACE_POINTTOPOINT
+ || oi->state == OSPF6_INTERFACE_POINTTOMULTIPOINT)
+ && oi->p2xp_only_cfg_neigh) {
+ /* NEVER, never, ever, do this on broadcast (or NBMA)!
+ * DR/BDR election requires everyone to talk to everyone else
+ * only for PtP/PtMP we can be selective in adjacencies!
+ */
+ struct ospf6_if_p2xp_neighcfg *p2xp_cfg;
+
+ p2xp_cfg = ospf6_if_p2xp_find(oi, src);
+ if (!p2xp_cfg) {
+ if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
+ zlog_debug(
+ "ignoring PtP/PtMP hello from %pI6, neighbor not configured",
+ src);
+ return;
+ }
+ }
+
/* HelloInterval check */
if (ntohs(hello->hello_interval) != oi->hello_interval) {
zlog_warn(
@@ -479,7 +510,7 @@ static void ospf6_hello_recv(struct in6_addr *src, struct in6_addr *dst,
on->hello_in++;
/* Always override neighbor's source address */
- memcpy(&on->linklocal_addr, src, sizeof(struct in6_addr));
+ ospf6_neighbor_lladdr_set(on, src);
/* Neighbor ifindex check */
if (on->ifindex != (ifindex_t)ntohl(hello->interface_id)) {
@@ -2239,8 +2270,6 @@ static void ospf6_write(struct event *thread)
void ospf6_hello_send(struct event *thread)
{
struct ospf6_interface *oi;
- struct ospf6_packet *op;
- uint16_t length = OSPF6_HEADER_SIZE;
oi = (struct ospf6_interface *)EVENT_ARG(thread);
@@ -2266,6 +2295,20 @@ void ospf6_hello_send(struct event *thread)
return;
}
+ event_add_timer(master, ospf6_hello_send, oi, oi->hello_interval,
+ &oi->thread_send_hello);
+
+ ospf6_hello_send_addr(oi, NULL);
+}
+
+/* used to send polls for PtP/PtMP too */
+void ospf6_hello_send_addr(struct ospf6_interface *oi,
+ const struct in6_addr *addr)
+{
+ struct ospf6_packet *op;
+ uint16_t length = OSPF6_HEADER_SIZE;
+ bool anything = false;
+
op = ospf6_packet_new(oi->ifmtu);
ospf6_make_header(OSPF6_MESSAGE_TYPE_HELLO, oi, op->s);
@@ -2284,20 +2327,40 @@ void ospf6_hello_send(struct event *thread)
/* Set packet length. */
op->length = length;
- op->dst = allspfrouters6;
-
- ospf6_fill_hdr_checksum(oi, op);
+ 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;
+
+ for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, node, on)) {
+ if (on->state < OSPF6_NEIGHBOR_INIT)
+ /* poll-interval for these */
+ continue;
+
+ opdup = ospf6_packet_dup(op);
+ opdup->dst = on->linklocal_addr;
+ ospf6_fill_hdr_checksum(oi, opdup);
+ ospf6_packet_add_top(oi, opdup);
+ anything = true;
+ }
- /* Add packet to the top of the interface output queue, so that they
- * can't get delayed by things like long queues of LS Update packets
- */
- ospf6_packet_add_top(oi, op);
+ ospf6_packet_free(op);
+ } else {
+ op->dst = addr ? *addr : allspfrouters6;
- /* set next thread */
- event_add_timer(master, ospf6_hello_send, oi, oi->hello_interval,
- &oi->thread_send_hello);
+ /* 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;
+ }
- OSPF6_MESSAGE_WRITE_ON(oi);
+ if (anything)
+ OSPF6_MESSAGE_WRITE_ON(oi);
}
static uint16_t ospf6_make_dbdesc(struct ospf6_neighbor *on, struct stream *s)
diff --git a/ospf6d/ospf6_message.h b/ospf6d/ospf6_message.h
index 2b25b0744..24340793f 100644
--- a/ospf6d/ospf6_message.h
+++ b/ospf6d/ospf6_message.h
@@ -50,6 +50,8 @@ extern unsigned char conf_debug_ospf6_message[];
#define OSPF6_MESSAGE_TYPE_ALL 0x6 /* For debug option */
#define OSPF6_MESSAGE_TYPE_MAX 0x6 /* same as OSPF6_MESSAGE_TYPE_ALL */
+struct ospf6_interface;
+
struct ospf6_packet {
struct ospf6_packet *next;
@@ -169,6 +171,9 @@ extern void ospf6_lsupdate_send_neighbor(struct event *thread);
extern void ospf6_lsack_send_interface(struct event *thread);
extern void ospf6_lsack_send_neighbor(struct event *thread);
+extern void ospf6_hello_send_addr(struct ospf6_interface *oi,
+ const struct in6_addr *addr);
+
extern int config_write_ospf6_debug_message(struct vty *);
extern void install_element_ospf6_debug_message(void);
extern const char *ospf6_message_type(int type);
diff --git a/ospf6d/ospf6_neighbor.c b/ospf6d/ospf6_neighbor.c
index e1aec06f8..47d01e72a 100644
--- a/ospf6d/ospf6_neighbor.c
+++ b/ospf6d/ospf6_neighbor.c
@@ -34,6 +34,16 @@
#include "lib/json.h"
DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_NEIGHBOR, "OSPF6 neighbor");
+DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_NEIGHBOR_P2XP_CFG,
+ "OSPF6 PtP/PtMP neighbor config");
+
+static int ospf6_if_p2xp_neighcfg_cmp(const struct ospf6_if_p2xp_neighcfg *a,
+ const struct ospf6_if_p2xp_neighcfg *b);
+
+DECLARE_RBTREE_UNIQ(ospf6_if_p2xp_neighcfgs, struct ospf6_if_p2xp_neighcfg,
+ item, ospf6_if_p2xp_neighcfg_cmp);
+
+static void p2xp_neigh_refresh(struct ospf6_neighbor *on, uint32_t prev_cost);
DEFINE_HOOK(ospf6_neighbor_change,
(struct ospf6_neighbor * on, int state, int next_state),
@@ -42,13 +52,14 @@ DEFINE_HOOK(ospf6_neighbor_change,
unsigned char conf_debug_ospf6_neighbor = 0;
const char *const ospf6_neighbor_state_str[] = {
- "None", "Down", "Attempt", "Init", "Twoway",
- "ExStart", "ExChange", "Loading", "Full", NULL};
+ "None", "Down", "Attempt", "Init", "Twoway",
+ "ExStart", "ExChange", "Loading", "Full", NULL
+};
const char *const ospf6_neighbor_event_str[] = {
- "NoEvent", "HelloReceived", "2-WayReceived", "NegotiationDone",
- "ExchangeDone", "LoadingDone", "AdjOK?", "SeqNumberMismatch",
- "BadLSReq", "1-WayReceived", "InactivityTimer",
+ "NoEvent", "HelloReceived", "2-WayReceived", "NegotiationDone",
+ "ExchangeDone", "LoadingDone", "AdjOK?", "SeqNumberMismatch",
+ "BadLSReq", "1-WayReceived", "InactivityTimer",
};
int ospf6_neighbor_cmp(void *va, void *vb)
@@ -119,8 +130,7 @@ struct ospf6_neighbor *ospf6_neighbor_create(uint32_t router_id,
on = XCALLOC(MTYPE_OSPF6_NEIGHBOR, sizeof(struct ospf6_neighbor));
inet_ntop(AF_INET, &router_id, buf, sizeof(buf));
- snprintf(on->name, sizeof(on->name), "%s%%%s", buf,
- oi->interface->name);
+ snprintf(on->name, sizeof(on->name), "%s%%%s", buf, oi->interface->name);
on->ospf6_if = oi;
on->state = OSPF6_NEIGHBOR_DOWN;
on->state_change = 0;
@@ -150,6 +160,9 @@ struct ospf6_neighbor *ospf6_neighbor_create(uint32_t router_id,
void ospf6_neighbor_delete(struct ospf6_neighbor *on)
{
+ if (on->p2xp_cfg)
+ on->p2xp_cfg->active = NULL;
+
ospf6_neighbor_clear_ls_lists(on);
ospf6_lsdb_remove_all(on->dbdesc_list);
@@ -182,6 +195,22 @@ void ospf6_neighbor_delete(struct ospf6_neighbor *on)
XFREE(MTYPE_OSPF6_NEIGHBOR, on);
}
+void ospf6_neighbor_lladdr_set(struct ospf6_neighbor *on,
+ const struct in6_addr *addr)
+{
+ if (IPV6_ADDR_SAME(addr, &on->linklocal_addr))
+ return;
+
+ memcpy(&on->linklocal_addr, addr, sizeof(struct in6_addr));
+
+ if (on->ospf6_if->type == OSPF_IFTYPE_POINTOPOINT ||
+ on->ospf6_if->type == OSPF_IFTYPE_POINTOMULTIPOINT) {
+ uint32_t prev_cost = ospf6_neighbor_cost(on);
+
+ p2xp_neigh_refresh(on, prev_cost);
+ }
+}
+
static void ospf6_neighbor_state_change(uint8_t next_state,
struct ospf6_neighbor *on, int event)
{
@@ -198,31 +227,28 @@ static void ospf6_neighbor_state_change(uint8_t next_state,
/* log */
if (IS_OSPF6_DEBUG_NEIGHBOR(STATE)) {
- zlog_debug(
- "Neighbor state change %s (Router-ID: %pI4): [%s]->[%s] (%s)",
- on->name, &on->router_id,
- ospf6_neighbor_state_str[prev_state],
- ospf6_neighbor_state_str[next_state],
- ospf6_neighbor_event_string(event));
+ zlog_debug("Neighbor state change %s (Router-ID: %pI4): [%s]->[%s] (%s)",
+ on->name, &on->router_id,
+ ospf6_neighbor_state_str[prev_state],
+ ospf6_neighbor_state_str[next_state],
+ ospf6_neighbor_event_string(event));
}
/* Optionally notify about adjacency changes */
if (CHECK_FLAG(on->ospf6_if->area->ospf6->config_flags,
- OSPF6_LOG_ADJACENCY_CHANGES)
- && (CHECK_FLAG(on->ospf6_if->area->ospf6->config_flags,
- OSPF6_LOG_ADJACENCY_DETAIL)
- || (next_state == OSPF6_NEIGHBOR_FULL)
- || (next_state < prev_state)))
- zlog_notice(
- "AdjChg: Nbr %pI4(%s) on %s: %s -> %s (%s)",
- &on->router_id,
- vrf_id_to_name(on->ospf6_if->interface->vrf->vrf_id),
- on->name, ospf6_neighbor_state_str[prev_state],
- ospf6_neighbor_state_str[next_state],
- ospf6_neighbor_event_string(event));
-
- if (prev_state == OSPF6_NEIGHBOR_FULL
- || next_state == OSPF6_NEIGHBOR_FULL) {
+ OSPF6_LOG_ADJACENCY_CHANGES) &&
+ (CHECK_FLAG(on->ospf6_if->area->ospf6->config_flags,
+ OSPF6_LOG_ADJACENCY_DETAIL) ||
+ (next_state == OSPF6_NEIGHBOR_FULL) || (next_state < prev_state)))
+ zlog_notice("AdjChg: Nbr %pI4(%s) on %s: %s -> %s (%s)",
+ &on->router_id,
+ vrf_id_to_name(on->ospf6_if->interface->vrf->vrf_id),
+ on->name, ospf6_neighbor_state_str[prev_state],
+ ospf6_neighbor_state_str[next_state],
+ ospf6_neighbor_event_string(event));
+
+ if (prev_state == OSPF6_NEIGHBOR_FULL ||
+ next_state == OSPF6_NEIGHBOR_FULL) {
if (!OSPF6_GR_IS_ACTIVE_HELPER(on)) {
OSPF6_ROUTER_LSA_SCHEDULE(on->ospf6_if->area);
if (on->ospf6_if->state == OSPF6_INTERFACE_DR) {
@@ -235,12 +261,11 @@ static void ospf6_neighbor_state_change(uint8_t next_state,
on->ospf6_if->area->intra_prefix_originate = 1;
if (!OSPF6_GR_IS_ACTIVE_HELPER(on))
- OSPF6_INTRA_PREFIX_LSA_SCHEDULE_STUB(
- on->ospf6_if->area);
+ OSPF6_INTRA_PREFIX_LSA_SCHEDULE_STUB(on->ospf6_if->area);
- if ((prev_state == OSPF6_NEIGHBOR_LOADING
- || prev_state == OSPF6_NEIGHBOR_EXCHANGE)
- && next_state == OSPF6_NEIGHBOR_FULL) {
+ if ((prev_state == OSPF6_NEIGHBOR_LOADING ||
+ prev_state == OSPF6_NEIGHBOR_EXCHANGE) &&
+ next_state == OSPF6_NEIGHBOR_FULL) {
OSPF6_AS_EXTERN_LSA_SCHEDULE(on->ospf6_if);
on->ospf6_if->area->full_nbrs++;
}
@@ -249,10 +274,10 @@ static void ospf6_neighbor_state_change(uint8_t next_state,
on->ospf6_if->area->full_nbrs--;
}
- if ((prev_state == OSPF6_NEIGHBOR_EXCHANGE
- || prev_state == OSPF6_NEIGHBOR_LOADING)
- && (next_state != OSPF6_NEIGHBOR_EXCHANGE
- && next_state != OSPF6_NEIGHBOR_LOADING))
+ if ((prev_state == OSPF6_NEIGHBOR_EXCHANGE ||
+ prev_state == OSPF6_NEIGHBOR_LOADING) &&
+ (next_state != OSPF6_NEIGHBOR_EXCHANGE &&
+ next_state != OSPF6_NEIGHBOR_LOADING))
ospf6_maxage_remove(on->ospf6_if->area->ospf6);
hook_call(ospf6_neighbor_change, on, next_state, prev_state);
@@ -262,13 +287,14 @@ static void ospf6_neighbor_state_change(uint8_t next_state,
/* RFC2328 section 10.4 */
static int need_adjacency(struct ospf6_neighbor *on)
{
- if (on->ospf6_if->state == OSPF6_INTERFACE_POINTTOPOINT
- || on->ospf6_if->state == OSPF6_INTERFACE_DR
- || on->ospf6_if->state == OSPF6_INTERFACE_BDR)
+ if (on->ospf6_if->state == OSPF6_INTERFACE_POINTTOPOINT ||
+ on->ospf6_if->state == OSPF6_INTERFACE_POINTTOMULTIPOINT ||
+ on->ospf6_if->state == OSPF6_INTERFACE_DR ||
+ on->ospf6_if->state == OSPF6_INTERFACE_BDR)
return 1;
- if (on->ospf6_if->drouter == on->router_id
- || on->ospf6_if->bdrouter == on->router_id)
+ if (on->ospf6_if->drouter == on->router_id ||
+ on->ospf6_if->bdrouter == on->router_id)
return 1;
return 0;
@@ -422,13 +448,12 @@ void exchange_done(struct event *thread)
/* Check loading state. */
void ospf6_check_nbr_loading(struct ospf6_neighbor *on)
{
-
/* RFC2328 Section 10.9: When the neighbor responds to these requests
with the proper Link State Update packet(s), the Link state request
list is truncated and a new Link State Request packet is sent.
*/
- if ((on->state == OSPF6_NEIGHBOR_LOADING)
- || (on->state == OSPF6_NEIGHBOR_EXCHANGE)) {
+ if ((on->state == OSPF6_NEIGHBOR_LOADING) ||
+ (on->state == OSPF6_NEIGHBOR_EXCHANGE)) {
if (on->request_list->count == 0)
event_add_event(master, loading_done, on, 0,
&on->event_loading_done);
@@ -587,9 +612,8 @@ void inactivity_timer(struct event *thread)
on->drouter = on->prev_drouter = 0;
on->bdrouter = on->prev_bdrouter = 0;
- ospf6_neighbor_state_change(
- OSPF6_NEIGHBOR_DOWN, on,
- OSPF6_NEIGHBOR_EVENT_INACTIVITY_TIMER);
+ ospf6_neighbor_state_change(OSPF6_NEIGHBOR_DOWN, on,
+ OSPF6_NEIGHBOR_EVENT_INACTIVITY_TIMER);
event_add_event(master, neighbor_change, on->ospf6_if, 0, NULL);
listnode_delete(on->ospf6_if->neighbor_list, on);
@@ -597,9 +621,8 @@ void inactivity_timer(struct event *thread)
} else {
if (IS_DEBUG_OSPF6_GR)
- zlog_debug(
- "%s, Acting as HELPER for this neighbour, So restart the dead timer.",
- __PRETTY_FUNCTION__);
+ zlog_debug("%s, Acting as HELPER for this neighbour, So restart the dead timer.",
+ __PRETTY_FUNCTION__);
event_add_timer(master, inactivity_timer, on,
on->ospf6_if->dead_interval,
@@ -607,8 +630,224 @@ void inactivity_timer(struct event *thread)
}
}
+/* P2P/P2MP stuff */
+
+uint32_t ospf6_neighbor_cost(struct ospf6_neighbor *on)
+{
+ if (on->p2xp_cfg && on->p2xp_cfg->cfg_cost)
+ return on->p2xp_cfg->cost;
+ return on->ospf6_if->cost;
+}
+
+static int ospf6_if_p2xp_neighcfg_cmp(const struct ospf6_if_p2xp_neighcfg *a,
+ const struct ospf6_if_p2xp_neighcfg *b)
+{
+ return IPV6_ADDR_CMP(&a->addr, &b->addr);
+}
+
+struct ospf6_if_p2xp_neighcfg *ospf6_if_p2xp_find(struct ospf6_interface *oi,
+ const struct in6_addr *addr)
+{
+ struct ospf6_if_p2xp_neighcfg ref;
+
+ if (!oi)
+ return NULL;
+
+ ref.addr = *addr;
+ return ospf6_if_p2xp_neighcfgs_find(&oi->p2xp_neighs, &ref);
+}
+
+static struct ospf6_if_p2xp_neighcfg *
+ospf6_if_p2xp_get(struct ospf6_interface *oi, const struct in6_addr *addr)
+{
+ struct ospf6_if_p2xp_neighcfg ref, *ret;
+
+ if (!oi)
+ return NULL;
+
+ ref.addr = *addr;
+ ret = ospf6_if_p2xp_neighcfgs_find(&oi->p2xp_neighs, &ref);
+ if (!ret) {
+ ret = XCALLOC(MTYPE_OSPF6_NEIGHBOR_P2XP_CFG, sizeof(*ret));
+ ret->addr = *addr;
+ ret->ospf6_if = oi;
+
+ ospf6_if_p2xp_neighcfgs_add(&oi->p2xp_neighs, ret);
+ }
+
+ return ret;
+}
+
+static void ospf6_if_p2xp_destroy(struct ospf6_if_p2xp_neighcfg *p2xp_cfg)
+{
+ EVENT_OFF(p2xp_cfg->t_unicast_hello);
+ ospf6_if_p2xp_neighcfgs_del(&p2xp_cfg->ospf6_if->p2xp_neighs, p2xp_cfg);
+
+ XFREE(MTYPE_OSPF6_NEIGHBOR_P2XP_CFG, p2xp_cfg);
+}
+
+static void p2xp_neigh_refresh(struct ospf6_neighbor *on, uint32_t prev_cost)
+{
+ if (on->p2xp_cfg)
+ on->p2xp_cfg->active = NULL;
+ on->p2xp_cfg = ospf6_if_p2xp_find(on->ospf6_if, &on->linklocal_addr);
+ if (on->p2xp_cfg)
+ on->p2xp_cfg->active = on;
+
+ if (ospf6_neighbor_cost(on) != prev_cost)
+ OSPF6_ROUTER_LSA_SCHEDULE(on->ospf6_if->area);
+}
/* vty functions */
+
+#ifndef VTYSH_EXTRACT_PL
+#include "ospf6d/ospf6_neighbor_clippy.c"
+#endif
+
+DEFPY(ipv6_ospf6_p2xp_neigh, ipv6_ospf6_p2xp_neigh_cmd,
+ "[no] ipv6 ospf6 neighbor X:X::X:X",
+ NO_STR IP6_STR OSPF6_STR "Configure static neighbor\n"
+ "Neighbor link-local address\n")
+{
+ VTY_DECLVAR_CONTEXT(interface, ifp);
+ struct ospf6_interface *oi = ifp->info;
+ struct ospf6_if_p2xp_neighcfg *p2xp_cfg;
+
+ if (!oi) {
+ if (no)
+ return CMD_SUCCESS;
+ oi = ospf6_interface_create(ifp);
+ }
+
+ if (no) {
+ struct ospf6_neighbor *on;
+ uint32_t prev_cost = 0;
+
+ p2xp_cfg = ospf6_if_p2xp_find(oi, &neighbor);
+ if (!p2xp_cfg)
+ return CMD_SUCCESS;
+
+ on = p2xp_cfg->active;
+ if (on)
+ prev_cost = ospf6_neighbor_cost(on);
+
+ p2xp_cfg->active = NULL;
+ ospf6_if_p2xp_destroy(p2xp_cfg);
+
+ if (on) {
+ on->p2xp_cfg = NULL;
+ p2xp_neigh_refresh(on, prev_cost);
+ }
+ return CMD_SUCCESS;
+ }
+
+ p2xp_cfg = ospf6_if_p2xp_get(oi, &neighbor);
+ return CMD_SUCCESS;
+}
+
+DEFPY(ipv6_ospf6_p2xp_neigh_cost, ipv6_ospf6_p2xp_neigh_cost_cmd,
+ "[no] ipv6 ospf6 neighbor X:X::X:X cost (1-65535)",
+ NO_STR IP6_STR OSPF6_STR "Configure static neighbor\n"
+ "Neighbor link-local address\n"
+ "Outgoing metric for this neighbor\n"
+ "Outgoing metric for this neighbor\n")
+{
+ VTY_DECLVAR_CONTEXT(interface, ifp);
+ struct ospf6_interface *oi = ifp->info;
+ struct ospf6_if_p2xp_neighcfg *p2xp_cfg;
+ uint32_t prev_cost;
+
+ if (!oi) {
+ if (no)
+ return CMD_SUCCESS;
+ oi = ospf6_interface_create(ifp);
+ }
+
+ p2xp_cfg = ospf6_if_p2xp_get(oi, &neighbor);
+
+ if (p2xp_cfg->active)
+ prev_cost = ospf6_neighbor_cost(p2xp_cfg->active);
+
+ if (no) {
+ p2xp_cfg->cfg_cost = false;
+ p2xp_cfg->cost = 0;
+ } else {
+ p2xp_cfg->cfg_cost = true;
+ p2xp_cfg->cost = cost;
+ }
+
+ if (p2xp_cfg->active)
+ p2xp_neigh_refresh(p2xp_cfg->active, prev_cost);
+ return CMD_SUCCESS;
+}
+
+static void p2xp_unicast_hello_send(struct event *event);
+
+static void p2xp_unicast_hello_sched(struct ospf6_if_p2xp_neighcfg *p2xp_cfg)
+{
+ if (!p2xp_cfg->poll_interval ||
+ (p2xp_cfg->ospf6_if->state != OSPF6_INTERFACE_POINTTOMULTIPOINT &&
+ p2xp_cfg->ospf6_if->state != OSPF6_INTERFACE_POINTTOPOINT))
+ /* state check covers DOWN state too */
+ EVENT_OFF(p2xp_cfg->t_unicast_hello);
+ else
+ event_add_timer(master, p2xp_unicast_hello_send, p2xp_cfg,
+ p2xp_cfg->poll_interval,
+ &p2xp_cfg->t_unicast_hello);
+}
+
+void ospf6_if_p2xp_up(struct ospf6_interface *oi)
+{
+ struct ospf6_if_p2xp_neighcfg *p2xp_cfg;
+
+ frr_each (ospf6_if_p2xp_neighcfgs, &oi->p2xp_neighs, p2xp_cfg)
+ p2xp_unicast_hello_sched(p2xp_cfg);
+}
+
+static void p2xp_unicast_hello_send(struct event *event)
+{
+ struct ospf6_if_p2xp_neighcfg *p2xp_cfg = EVENT_ARG(event);
+ struct ospf6_interface *oi = p2xp_cfg->ospf6_if;
+
+ if (oi->state != OSPF6_INTERFACE_POINTTOPOINT &&
+ oi->state != OSPF6_INTERFACE_POINTTOMULTIPOINT)
+ return;
+
+ p2xp_unicast_hello_sched(p2xp_cfg);
+
+ if (p2xp_cfg->active && p2xp_cfg->active->state >= OSPF6_NEIGHBOR_INIT)
+ return;
+
+ ospf6_hello_send_addr(oi, &p2xp_cfg->addr);
+}
+
+DEFPY(ipv6_ospf6_p2xp_neigh_poll_interval,
+ ipv6_ospf6_p2xp_neigh_poll_interval_cmd,
+ "[no] ipv6 ospf6 neighbor X:X::X:X poll-interval (1-65535)",
+ NO_STR IP6_STR OSPF6_STR "Configure static neighbor\n"
+ "Neighbor link-local address\n"
+ "Send unicast hellos to neighbor when down\n"
+ "Unicast hello interval when down (seconds)\n")
+{
+ VTY_DECLVAR_CONTEXT(interface, ifp);
+ struct ospf6_interface *oi = ifp->info;
+ struct ospf6_if_p2xp_neighcfg *p2xp_cfg;
+
+ if (!oi) {
+ if (no)
+ return CMD_SUCCESS;
+ oi = ospf6_interface_create(ifp);
+ }
+ if (no)
+ poll_interval = 0;
+
+ p2xp_cfg = ospf6_if_p2xp_get(oi, &neighbor);
+ p2xp_cfg->poll_interval = poll_interval;
+
+ p2xp_unicast_hello_sched(p2xp_cfg);
+ return CMD_SUCCESS;
+}
+
/* show neighbor structure */
static void ospf6_neighbor_show(struct vty *vty, struct ospf6_neighbor *on,
json_object *json_array, bool use_json)
@@ -631,8 +870,8 @@ static void ospf6_neighbor_show(struct vty *vty, struct ospf6_neighbor *on,
/* Dead time */
h = m = s = 0;
if (on->inactivity_timer) {
- s = monotime_until(&on->inactivity_timer->u.sands, NULL)
- / 1000000LL;
+ s = monotime_until(&on->inactivity_timer->u.sands, NULL) /
+ 1000000LL;
h = s / 3600;
s -= h * 3600;
m = s / 60;
@@ -643,6 +882,8 @@ static void ospf6_neighbor_show(struct vty *vty, struct ospf6_neighbor *on,
/* Neighbor State */
if (on->ospf6_if->type == OSPF_IFTYPE_POINTOPOINT)
snprintf(nstate, sizeof(nstate), "PointToPoint");
+ else if (on->ospf6_if->type == OSPF_IFTYPE_POINTOMULTIPOINT)
+ snprintf(nstate, sizeof(nstate), "PtMultipoint");
else {
if (on->router_id == on->drouter)
snprintf(nstate, sizeof(nstate), "DR");
@@ -673,9 +914,9 @@ static void ospf6_neighbor_show(struct vty *vty, struct ospf6_neighbor *on,
json_object_string_add(json_route, "duration", duration);
json_object_string_add(json_route, "interfaceName",
on->ospf6_if->interface->name);
- json_object_string_add(
- json_route, "interfaceState",
- ospf6_interface_state_str[on->ospf6_if->state]);
+ json_object_string_add(json_route, "interfaceState",
+ ospf6_interface_state_str
+ [on->ospf6_if->state]);
json_object_array_add(json_array, json_route);
} else
@@ -720,9 +961,9 @@ static void ospf6_neighbor_show_drchoice(struct vty *vty,
json_object_string_add(json_route, "bdRouter", bdrouter);
json_object_string_add(json_route, "interfaceName",
on->ospf6_if->interface->name);
- json_object_string_add(
- json_route, "interfaceState",
- ospf6_interface_state_str[on->ospf6_if->state]);
+ json_object_string_add(json_route, "interfaceState",
+ ospf6_interface_state_str
+ [on->ospf6_if->state]);
json_object_array_add(json_array, json_route);
} else
@@ -777,9 +1018,8 @@ static void ospf6_neighbor_show_detail(struct vty *vty,
(CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_IBIT)
? "Initial "
: ""),
- (CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MBIT)
- ? "More"
- : ""),
+ (CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MBIT) ? "More"
+ : ""),
(CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MSBIT)
? "Master"
: "Slave"));
@@ -793,8 +1033,8 @@ static void ospf6_neighbor_show_detail(struct vty *vty,
json_object_int_add(json_neighbor, "summaryListCount",
on->summary_list->count);
for (ALL_LSDB(on->summary_list, lsa, lsanext))
- json_object_array_add(
- json_array, json_object_new_string(lsa->name));
+ json_object_array_add(json_array,
+ json_object_new_string(lsa->name));
json_object_object_add(json_neighbor, "summaryListLsa",
json_array);
@@ -802,8 +1042,8 @@ static void ospf6_neighbor_show_detail(struct vty *vty,
json_object_int_add(json_neighbor, "requestListCount",
on->request_list->count);
for (ALL_LSDB(on->request_list, lsa, lsanext))
- json_object_array_add(
- json_array, json_object_new_string(lsa->name));
+ json_object_array_add(json_array,
+ json_object_new_string(lsa->name));
json_object_object_add(json_neighbor, "requestListLsa",
json_array);
@@ -811,8 +1051,8 @@ static void ospf6_neighbor_show_detail(struct vty *vty,
json_object_int_add(json_neighbor, "reTransListCount",
on->retrans_list->count);
for (ALL_LSDB(on->retrans_list, lsa, lsanext))
- json_object_array_add(
- json_array, json_object_new_string(lsa->name));
+ json_object_array_add(json_array,
+ json_object_new_string(lsa->name));
json_object_object_add(json_neighbor, "reTransListLsa",
json_array);
@@ -825,14 +1065,14 @@ static void ospf6_neighbor_show_detail(struct vty *vty,
on->dbdesc_list->count);
json_object_string_add(json_neighbor, "pendingLsaDbDescTime",
duration);
- json_object_string_add(
- json_neighbor, "dbDescSendThread",
- (event_is_scheduled(on->thread_send_dbdesc) ? "on"
- : "off"));
+ json_object_string_add(json_neighbor, "dbDescSendThread",
+ (event_is_scheduled(on->thread_send_dbdesc)
+ ? "on"
+ : "off"));
json_array = json_object_new_array();
for (ALL_LSDB(on->dbdesc_list, lsa, lsanext))
- json_object_array_add(
- json_array, json_object_new_string(lsa->name));
+ json_object_array_add(json_array,
+ json_object_new_string(lsa->name));
json_object_object_add(json_neighbor, "pendingLsaDbDesc",
json_array);
@@ -844,35 +1084,35 @@ static void ospf6_neighbor_show_detail(struct vty *vty,
on->request_list->count);
json_object_string_add(json_neighbor, "pendingLsaLsReqTime",
duration);
- json_object_string_add(
- json_neighbor, "lsReqSendThread",
- (event_is_scheduled(on->thread_send_lsreq) ? "on"
- : "off"));
+ json_object_string_add(json_neighbor, "lsReqSendThread",
+ (event_is_scheduled(on->thread_send_lsreq)
+ ? "on"
+ : "off"));
json_array = json_object_new_array();
for (ALL_LSDB(on->request_list, lsa, lsanext))
- json_object_array_add(
- json_array, json_object_new_string(lsa->name));
+ json_object_array_add(json_array,
+ json_object_new_string(lsa->name));
json_object_object_add(json_neighbor, "pendingLsaLsReq",
json_array);
timerclear(&res);
if (event_is_scheduled(on->thread_send_lsupdate))
- timersub(&on->thread_send_lsupdate->u.sands, &now,
- &res);
+ timersub(&on->thread_send_lsupdate->u.sands, &now, &res);
timerstring(&res, duration, sizeof(duration));
json_object_int_add(json_neighbor, "pendingLsaLsUpdateCount",
on->lsupdate_list->count);
json_object_string_add(json_neighbor, "pendingLsaLsUpdateTime",
duration);
- json_object_string_add(
- json_neighbor, "lsUpdateSendThread",
- (event_is_scheduled(on->thread_send_lsupdate) ? "on"
- : "off"));
+ json_object_string_add(json_neighbor, "lsUpdateSendThread",
+ (event_is_scheduled(
+ on->thread_send_lsupdate)
+ ? "on"
+ : "off"));
json_array = json_object_new_array();
for (ALL_LSDB(on->lsupdate_list, lsa, lsanext))
- json_object_array_add(
- json_array, json_object_new_string(lsa->name));
+ json_object_array_add(json_array,
+ json_object_new_string(lsa->name));
json_object_object_add(json_neighbor, "pendingLsaLsUpdate",
json_array);
@@ -884,14 +1124,14 @@ static void ospf6_neighbor_show_detail(struct vty *vty,
on->lsack_list->count);
json_object_string_add(json_neighbor, "pendingLsaLsAckTime",
duration);
- json_object_string_add(
- json_neighbor, "lsAckSendThread",
- (event_is_scheduled(on->thread_send_lsack) ? "on"
- : "off"));
+ json_object_string_add(json_neighbor, "lsAckSendThread",
+ (event_is_scheduled(on->thread_send_lsack)
+ ? "on"
+ : "off"));
json_array = json_object_new_array();
for (ALL_LSDB(on->lsack_list, lsa, lsanext))
- json_object_array_add(
- json_array, json_object_new_string(lsa->name));
+ json_object_array_add(json_array,
+ json_object_new_string(lsa->name));
json_object_object_add(json_neighbor, "pendingLsaLsAck",
json_array);
@@ -900,36 +1140,36 @@ static void ospf6_neighbor_show_detail(struct vty *vty,
if (on->auth_present == true) {
json_object_string_add(json_neighbor, "authStatus",
"enabled");
- json_object_int_add(
- json_neighbor, "recvdHelloHigherSeqNo",
- on->seqnum_h[OSPF6_MESSAGE_TYPE_HELLO]);
- json_object_int_add(
- json_neighbor, "recvdHelloLowerSeqNo",
- on->seqnum_l[OSPF6_MESSAGE_TYPE_HELLO]);
- json_object_int_add(
- json_neighbor, "recvdDBDescHigherSeqNo",
- on->seqnum_h[OSPF6_MESSAGE_TYPE_DBDESC]);
- json_object_int_add(
- json_neighbor, "recvdDBDescLowerSeqNo",
- on->seqnum_l[OSPF6_MESSAGE_TYPE_DBDESC]);
- json_object_int_add(
- json_neighbor, "recvdLSReqHigherSeqNo",
- on->seqnum_h[OSPF6_MESSAGE_TYPE_LSREQ]);
- json_object_int_add(
- json_neighbor, "recvdLSReqLowerSeqNo",
- on->seqnum_l[OSPF6_MESSAGE_TYPE_LSREQ]);
- json_object_int_add(
- json_neighbor, "recvdLSUpdHigherSeqNo",
- on->seqnum_h[OSPF6_MESSAGE_TYPE_LSUPDATE]);
- json_object_int_add(
- json_neighbor, "recvdLSUpdLowerSeqNo",
- on->seqnum_l[OSPF6_MESSAGE_TYPE_LSUPDATE]);
- json_object_int_add(
- json_neighbor, "recvdLSAckHigherSeqNo",
- on->seqnum_h[OSPF6_MESSAGE_TYPE_LSACK]);
- json_object_int_add(
- json_neighbor, "recvdLSAckLowerSeqNo",
- on->seqnum_l[OSPF6_MESSAGE_TYPE_LSACK]);
+ json_object_int_add(json_neighbor,
+ "recvdHelloHigherSeqNo",
+ on->seqnum_h[OSPF6_MESSAGE_TYPE_HELLO]);
+ json_object_int_add(json_neighbor,
+ "recvdHelloLowerSeqNo",
+ on->seqnum_l[OSPF6_MESSAGE_TYPE_HELLO]);
+ json_object_int_add(json_neighbor,
+ "recvdDBDescHigherSeqNo",
+ on->seqnum_h[OSPF6_MESSAGE_TYPE_DBDESC]);
+ json_object_int_add(json_neighbor,
+ "recvdDBDescLowerSeqNo",
+ on->seqnum_l[OSPF6_MESSAGE_TYPE_DBDESC]);
+ json_object_int_add(json_neighbor,
+ "recvdLSReqHigherSeqNo",
+ on->seqnum_h[OSPF6_MESSAGE_TYPE_LSREQ]);
+ json_object_int_add(json_neighbor,
+ "recvdLSReqLowerSeqNo",
+ on->seqnum_l[OSPF6_MESSAGE_TYPE_LSREQ]);
+ json_object_int_add(json_neighbor,
+ "recvdLSUpdHigherSeqNo",
+ on->seqnum_h[OSPF6_MESSAGE_TYPE_LSUPDATE]);
+ json_object_int_add(json_neighbor,
+ "recvdLSUpdLowerSeqNo",
+ on->seqnum_l[OSPF6_MESSAGE_TYPE_LSUPDATE]);
+ json_object_int_add(json_neighbor,
+ "recvdLSAckHigherSeqNo",
+ on->seqnum_h[OSPF6_MESSAGE_TYPE_LSACK]);
+ json_object_int_add(json_neighbor,
+ "recvdLSAckLowerSeqNo",
+ on->seqnum_l[OSPF6_MESSAGE_TYPE_LSACK]);
} else
json_object_string_add(json_neighbor, "authStatus",
"disabled");
@@ -951,9 +1191,8 @@ static void ospf6_neighbor_show_detail(struct vty *vty,
(CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_IBIT)
? "Initial "
: ""),
- (CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MBIT)
- ? "More "
- : ""),
+ (CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MBIT) ? "More "
+ : ""),
(CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MSBIT)
? "Master"
: "Slave"),
@@ -1000,8 +1239,7 @@ static void ospf6_neighbor_show_detail(struct vty *vty,
timerclear(&res);
if (event_is_scheduled(on->thread_send_lsupdate))
- timersub(&on->thread_send_lsupdate->u.sands, &now,
- &res);
+ timersub(&on->thread_send_lsupdate->u.sands, &now, &res);
timerstring(&res, duration, sizeof(duration));
vty_out(vty,
" %d Pending LSAs for LSUpdate in Time %s [thread %s]\n",
@@ -1141,8 +1379,7 @@ DEFUN(show_ipv6_ospf6_neighbor, show_ipv6_ospf6_neighbor_cmd,
static int ospf6_neighbor_show_common(struct vty *vty, int argc,
struct cmd_token **argv,
- struct ospf6 *ospf6, int idx_ipv4,
- bool uj)
+ struct ospf6 *ospf6, int idx_ipv4, bool uj)
{
struct ospf6_neighbor *on;
struct ospf6_interface *oi;
@@ -1214,16 +1451,18 @@ void ospf6_neighbor_init(void)
{
install_element(VIEW_NODE, &show_ipv6_ospf6_neighbor_cmd);
install_element(VIEW_NODE, &show_ipv6_ospf6_neighbor_one_cmd);
+
+ install_element(INTERFACE_NODE, &ipv6_ospf6_p2xp_neigh_cmd);
+ install_element(INTERFACE_NODE, &ipv6_ospf6_p2xp_neigh_cost_cmd);
+ install_element(INTERFACE_NODE,
+ &ipv6_ospf6_p2xp_neigh_poll_interval_cmd);
}
-DEFUN (debug_ospf6_neighbor,
- debug_ospf6_neighbor_cmd,
- "debug ospf6 neighbor [<state|event>]",
- DEBUG_STR
- OSPF6_STR
- "Debug OSPFv3 Neighbor\n"
- "Debug OSPFv3 Neighbor State Change\n"
- "Debug OSPFv3 Neighbor Event\n")
+DEFUN(debug_ospf6_neighbor, debug_ospf6_neighbor_cmd,
+ "debug ospf6 neighbor [<state|event>]",
+ DEBUG_STR OSPF6_STR "Debug OSPFv3 Neighbor\n"
+ "Debug OSPFv3 Neighbor State Change\n"
+ "Debug OSPFv3 Neighbor Event\n")
{
int idx_type = 3;
unsigned char level = 0;
@@ -1241,15 +1480,11 @@ DEFUN (debug_ospf6_neighbor,
}
-DEFUN (no_debug_ospf6_neighbor,
- no_debug_ospf6_neighbor_cmd,
- "no debug ospf6 neighbor [<state|event>]",
- NO_STR
- DEBUG_STR
- OSPF6_STR
- "Debug OSPFv3 Neighbor\n"
- "Debug OSPFv3 Neighbor State Change\n"
- "Debug OSPFv3 Neighbor Event\n")
+DEFUN(no_debug_ospf6_neighbor, no_debug_ospf6_neighbor_cmd,
+ "no debug ospf6 neighbor [<state|event>]",
+ NO_STR DEBUG_STR OSPF6_STR "Debug OSPFv3 Neighbor\n"
+ "Debug OSPFv3 Neighbor State Change\n"
+ "Debug OSPFv3 Neighbor Event\n")
{
int idx_type = 4;
unsigned char level = 0;
@@ -1267,12 +1502,8 @@ DEFUN (no_debug_ospf6_neighbor,
}
-DEFUN (no_debug_ospf6,
- no_debug_ospf6_cmd,
- "no debug ospf6",
- NO_STR
- DEBUG_STR
- OSPF6_STR)
+DEFUN(no_debug_ospf6, no_debug_ospf6_cmd, "no debug ospf6",
+ NO_STR DEBUG_STR OSPF6_STR)
{
unsigned int i;
@@ -1287,12 +1518,11 @@ DEFUN (no_debug_ospf6,
ospf6_lsa_debug_set_all(false);
for (i = 0; i < 6; i++)
- OSPF6_DEBUG_MESSAGE_OFF(i,
- OSPF6_DEBUG_NEIGHBOR_STATE
- | OSPF6_DEBUG_NEIGHBOR_EVENT);
+ OSPF6_DEBUG_MESSAGE_OFF(i, OSPF6_DEBUG_NEIGHBOR_STATE |
+ OSPF6_DEBUG_NEIGHBOR_EVENT);
- OSPF6_DEBUG_NEIGHBOR_OFF(OSPF6_DEBUG_NEIGHBOR_STATE
- | OSPF6_DEBUG_NEIGHBOR_EVENT);
+ OSPF6_DEBUG_NEIGHBOR_OFF(OSPF6_DEBUG_NEIGHBOR_STATE |
+ OSPF6_DEBUG_NEIGHBOR_EVENT);
OSPF6_DEBUG_ROUTE_OFF(OSPF6_DEBUG_ROUTE_TABLE);
OSPF6_DEBUG_ROUTE_OFF(OSPF6_DEBUG_ROUTE_INTRA);
OSPF6_DEBUG_ROUTE_OFF(OSPF6_DEBUG_ROUTE_INTER);
@@ -1316,6 +1546,25 @@ int config_write_ospf6_debug_neighbor(struct vty *vty)
return 0;
}
+int config_write_ospf6_p2xp_neighbor(struct vty *vty, struct ospf6_interface *oi)
+{
+ struct ospf6_if_p2xp_neighcfg *p2xp_cfg;
+
+ frr_each (ospf6_if_p2xp_neighcfgs, &oi->p2xp_neighs, p2xp_cfg) {
+ vty_out(vty, " ipv6 ospf6 neighbor %pI6\n", &p2xp_cfg->addr);
+
+ if (p2xp_cfg->poll_interval)
+ vty_out(vty,
+ " ipv6 ospf6 neighbor %pI6 poll-interval %u\n",
+ &p2xp_cfg->addr, p2xp_cfg->poll_interval);
+
+ if (p2xp_cfg->cfg_cost)
+ vty_out(vty, " ipv6 ospf6 neighbor %pI6 cost %u\n",
+ &p2xp_cfg->addr, p2xp_cfg->cost);
+ }
+ return 0;
+}
+
void install_element_ospf6_debug_neighbor(void)
{
install_element(ENABLE_NODE, &debug_ospf6_neighbor_cmd);
diff --git a/ospf6d/ospf6_neighbor.h b/ospf6d/ospf6_neighbor.h
index 226f4c132..60a76215b 100644
--- a/ospf6d/ospf6_neighbor.h
+++ b/ospf6d/ospf6_neighbor.h
@@ -6,8 +6,11 @@
#ifndef OSPF6_NEIGHBOR_H
#define OSPF6_NEIGHBOR_H
+#include "typesafe.h"
#include "hook.h"
+#include "ospf6_message.h"
+
/* Forward declaration(s). */
struct ospf6_area;
@@ -52,6 +55,8 @@ struct ospf6_helper_info {
uint32_t rejected_reason;
};
+struct ospf6_if_p2xp_neighcfg;
+
/* Neighbor structure */
struct ospf6_neighbor {
/* Neighbor Router ID String */
@@ -60,6 +65,11 @@ struct ospf6_neighbor {
/* OSPFv3 Interface this neighbor belongs to */
struct ospf6_interface *ospf6_if;
+ /* P2P/P2MP config for this neighbor.
+ * can be NULL if not explicitly configured!
+ */
+ struct ospf6_if_p2xp_neighcfg *p2xp_cfg;
+
/* Neighbor state */
uint8_t state;
@@ -190,6 +200,14 @@ struct ospf6_neighbor *ospf6_neighbor_create(uint32_t router_id,
struct ospf6_interface *oi);
void ospf6_neighbor_delete(struct ospf6_neighbor *on);
+void ospf6_neighbor_lladdr_set(struct ospf6_neighbor *on,
+ const struct in6_addr *addr);
+struct ospf6_if_p2xp_neighcfg *ospf6_if_p2xp_find(struct ospf6_interface *oi,
+ const struct in6_addr *addr);
+void ospf6_if_p2xp_up(struct ospf6_interface *oi);
+
+uint32_t ospf6_neighbor_cost(struct ospf6_neighbor *on);
+
/* Neighbor event */
extern void hello_received(struct event *thread);
extern void twoway_received(struct event *thread);
@@ -205,6 +223,8 @@ extern void ospf6_check_nbr_loading(struct ospf6_neighbor *on);
extern void ospf6_neighbor_init(void);
extern int config_write_ospf6_debug_neighbor(struct vty *vty);
+extern int config_write_ospf6_p2xp_neighbor(struct vty *vty,
+ struct ospf6_interface *oi);
extern void install_element_ospf6_debug_neighbor(void);
DECLARE_HOOK(ospf6_neighbor_change,
diff --git a/ospf6d/ospf6_route.c b/ospf6d/ospf6_route.c
index ca026dc97..10a1208e9 100644
--- a/ospf6d/ospf6_route.c
+++ b/ospf6d/ospf6_route.c
@@ -540,6 +540,10 @@ int ospf6_route_cmp(struct ospf6_route *ra, struct ospf6_route *rb)
if (ra->path.area_id != rb->path.area_id)
return (ntohl(ra->path.area_id) - ntohl(rb->path.area_id));
+ if ((ra->prefix_options & OSPF6_PREFIX_OPTION_LA)
+ != (rb->prefix_options & OSPF6_PREFIX_OPTION_LA))
+ return ra->prefix_options & OSPF6_PREFIX_OPTION_LA ? -1 : 1;
+
return 0;
}
diff --git a/ospf6d/ospf6_snmp.c b/ospf6d/ospf6_snmp.c
index 671291312..17cdcdae8 100644
--- a/ospf6d/ospf6_snmp.c
+++ b/ospf6d/ospf6_snmp.c
@@ -1126,6 +1126,8 @@ static uint8_t *ospfv3IfEntry(struct variable *v, oid *name, size_t *length,
return SNMP_INTEGER(1);
else if (oi->type == OSPF_IFTYPE_POINTOPOINT)
return SNMP_INTEGER(3);
+ else if (oi->type == OSPF_IFTYPE_POINTOMULTIPOINT)
+ return SNMP_INTEGER(5);
else
break; /* Unknown, don't put anything */
case OSPFv3IFADMINSTATUS:
@@ -1367,6 +1369,7 @@ static int ospf6TrapIfStateChange(struct ospf6_interface *oi, int next_state,
/* Terminal state or regression */
if ((next_state != OSPF6_INTERFACE_POINTTOPOINT)
+ && (next_state != OSPF6_INTERFACE_POINTTOMULTIPOINT)
&& (next_state != OSPF6_INTERFACE_DROTHER)
&& (next_state != OSPF6_INTERFACE_BDR)
&& (next_state != OSPF6_INTERFACE_DR) && (next_state >= prev_state))
diff --git a/ospf6d/subdir.am b/ospf6d/subdir.am
index f6d27c84c..5f89af950 100644
--- a/ospf6d/subdir.am
+++ b/ospf6d/subdir.am
@@ -83,8 +83,10 @@ clippy_scan += \
ospf6d/ospf6_lsa.c \
ospf6d/ospf6_gr_helper.c \
ospf6d/ospf6_gr.c \
+ ospf6d/ospf6_interface.c \
ospf6d/ospf6_nssa.c \
ospf6d/ospf6_route.c \
+ ospf6d/ospf6_neighbor.c \
# end
nodist_ospf6d_ospf6d_SOURCES = \
diff --git a/tests/topotests/ospf6_ecmp_inter_area/test_ospf6_ecmp_inter_area.py b/tests/topotests/ospf6_ecmp_inter_area/test_ospf6_ecmp_inter_area.py
index ec15ff9b1..2eaccb834 100644
--- a/tests/topotests/ospf6_ecmp_inter_area/test_ospf6_ecmp_inter_area.py
+++ b/tests/topotests/ospf6_ecmp_inter_area/test_ospf6_ecmp_inter_area.py
@@ -110,15 +110,18 @@ def test_wait_protocol_convergence():
def expect_neighbor_full(router, neighbor):
"Wait until OSPFv3 neighborship is full"
- logger.info("waiting for OSPFv3 router '{}' neighborship with '{}'".format(router, neighbor))
+ logger.info(
+ "waiting for OSPFv3 router '{}' neighborship with '{}'".format(
+ router, neighbor
+ )
+ )
test_func = partial(
topotest.router_json_cmp,
tgen.gears[router],
"show ipv6 ospf6 neighbor json",
{"neighbors": [{"neighborId": neighbor, "state": "Full"}]},
)
- _, result = topotest.run_and_expect(test_func, None,
- count=130, wait=1)
+ _, result = topotest.run_and_expect(test_func, None, count=130, wait=1)
assertmsg = '"{}" convergence failure'.format(router)
assert result is None, assertmsg
@@ -143,6 +146,7 @@ def test_wait_protocol_convergence():
expect_neighbor_full("r8", "10.254.254.5")
expect_neighbor_full("r9", "10.254.254.5")
+
def test_ecmp_inter_area():
"Test whether OSPFv3 ECMP nexthops are properly updated for inter-area routes after link down"
tgen = get_topogen()
@@ -156,22 +160,28 @@ def test_ecmp_inter_area():
def expect_num_nexthops(router, expected_num_nexthops, count):
"Wait until number of nexthops for routes matches expectation"
- logger.info("waiting for OSPFv3 router '{}' nexthops {}".format(router, expected_num_nexthops))
+ logger.info(
+ "waiting for OSPFv3 router '{}' nexthops {}".format(
+ router, expected_num_nexthops
+ )
+ )
test_func = partial(num_nexthops, router)
- _, result = topotest.run_and_expect(test_func, expected_num_nexthops,
- count=count, wait=3)
- assert result == expected_num_nexthops, \
- "'{}' wrong number of route nexthops".format(router)
+ _, result = topotest.run_and_expect(
+ test_func, expected_num_nexthops, count=count, wait=3
+ )
+ assert (
+ result == expected_num_nexthops
+ ), "'{}' wrong number of route nexthops".format(router)
# Check nexthops pre link-down
- expect_num_nexthops("r1", [1, 1, 1, 3, 3, 3, 3, 3], 4)
+ expect_num_nexthops("r1", [1, 1, 1, 3, 3, 3, 3, 3, 3, 3], 4)
logger.info("triggering R2-R4 link down")
tgen.gears["r2"].run("ip link set r2-eth1 down")
- #tgen.mininet_cli()
+ # tgen.mininet_cli()
# Check nexthops post link-down
- expect_num_nexthops("r1", [1, 1, 1, 2, 2, 2, 2, 2], 8)
+ expect_num_nexthops("r1", [1, 1, 1, 2, 2, 2, 2, 2, 2, 2], 8)
def teardown_module(_mod):
diff --git a/tests/topotests/ospf6_point_to_multipoint/README.md b/tests/topotests/ospf6_point_to_multipoint/README.md
new file mode 100644
index 000000000..59c9837ae
--- /dev/null
+++ b/tests/topotests/ospf6_point_to_multipoint/README.md
@@ -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
diff --git a/tests/topotests/ospf6_point_to_multipoint/r1/ip_6_address.nhg.ref b/tests/topotests/ospf6_point_to_multipoint/r1/ip_6_address.nhg.ref
new file mode 100644
index 000000000..203f2def5
--- /dev/null
+++ b/tests/topotests/ospf6_point_to_multipoint/r1/ip_6_address.nhg.ref
@@ -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
diff --git a/tests/topotests/ospf6_point_to_multipoint/r1/ip_6_address.ref b/tests/topotests/ospf6_point_to_multipoint/r1/ip_6_address.ref
new file mode 100644
index 000000000..b77c99674
--- /dev/null
+++ b/tests/topotests/ospf6_point_to_multipoint/r1/ip_6_address.ref
@@ -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
diff --git a/tests/topotests/ospf6_point_to_multipoint/r1/ospf6d.conf b/tests/topotests/ospf6_point_to_multipoint/r1/ospf6d.conf
new file mode 100644
index 000000000..79a9dcae1
--- /dev/null
+++ b/tests/topotests/ospf6_point_to_multipoint/r1/ospf6d.conf
@@ -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
+!
diff --git a/tests/topotests/ospf6_point_to_multipoint/r1/show_ipv6_route.ref b/tests/topotests/ospf6_point_to_multipoint/r1/show_ipv6_route.ref
new file mode 100644
index 000000000..911b3e40d
--- /dev/null
+++ b/tests/topotests/ospf6_point_to_multipoint/r1/show_ipv6_route.ref
@@ -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
diff --git a/tests/topotests/ospf6_point_to_multipoint/r1/zebra.conf b/tests/topotests/ospf6_point_to_multipoint/r1/zebra.conf
new file mode 100644
index 000000000..3a7db9f25
--- /dev/null
+++ b/tests/topotests/ospf6_point_to_multipoint/r1/zebra.conf
@@ -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
+!
diff --git a/tests/topotests/ospf6_point_to_multipoint/r2/ip_6_address.nhg.ref b/tests/topotests/ospf6_point_to_multipoint/r2/ip_6_address.nhg.ref
new file mode 100644
index 000000000..d4534b10b
--- /dev/null
+++ b/tests/topotests/ospf6_point_to_multipoint/r2/ip_6_address.nhg.ref
@@ -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
diff --git a/tests/topotests/ospf6_point_to_multipoint/r2/ip_6_address.ref b/tests/topotests/ospf6_point_to_multipoint/r2/ip_6_address.ref
new file mode 100644
index 000000000..330b696c3
--- /dev/null
+++ b/tests/topotests/ospf6_point_to_multipoint/r2/ip_6_address.ref
@@ -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
diff --git a/tests/topotests/ospf6_point_to_multipoint/r2/ospf6d.conf b/tests/topotests/ospf6_point_to_multipoint/r2/ospf6d.conf
new file mode 100644
index 000000000..751d8d84e
--- /dev/null
+++ b/tests/topotests/ospf6_point_to_multipoint/r2/ospf6d.conf
@@ -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
+!
diff --git a/tests/topotests/ospf6_point_to_multipoint/r2/show_ipv6_route.ref b/tests/topotests/ospf6_point_to_multipoint/r2/show_ipv6_route.ref
new file mode 100644
index 000000000..2eff0291a
--- /dev/null
+++ b/tests/topotests/ospf6_point_to_multipoint/r2/show_ipv6_route.ref
@@ -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
diff --git a/tests/topotests/ospf6_point_to_multipoint/r2/zebra.conf b/tests/topotests/ospf6_point_to_multipoint/r2/zebra.conf
new file mode 100644
index 000000000..5571dc979
--- /dev/null
+++ b/tests/topotests/ospf6_point_to_multipoint/r2/zebra.conf
@@ -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
+!
diff --git a/tests/topotests/ospf6_point_to_multipoint/r3/ip_6_address.nhg.ref b/tests/topotests/ospf6_point_to_multipoint/r3/ip_6_address.nhg.ref
new file mode 100644
index 000000000..903c1d962
--- /dev/null
+++ b/tests/topotests/ospf6_point_to_multipoint/r3/ip_6_address.nhg.ref
@@ -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
diff --git a/tests/topotests/ospf6_point_to_multipoint/r3/ip_6_address.ref b/tests/topotests/ospf6_point_to_multipoint/r3/ip_6_address.ref
new file mode 100644
index 000000000..3dbcf36b4
--- /dev/null
+++ b/tests/topotests/ospf6_point_to_multipoint/r3/ip_6_address.ref
@@ -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
diff --git a/tests/topotests/ospf6_point_to_multipoint/r3/ospf6d.conf b/tests/topotests/ospf6_point_to_multipoint/r3/ospf6d.conf
new file mode 100644
index 000000000..74e8ddf00
--- /dev/null
+++ b/tests/topotests/ospf6_point_to_multipoint/r3/ospf6d.conf
@@ -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
+!
diff --git a/tests/topotests/ospf6_point_to_multipoint/r3/show_ipv6_route.ref b/tests/topotests/ospf6_point_to_multipoint/r3/show_ipv6_route.ref
new file mode 100644
index 000000000..df949e64e
--- /dev/null
+++ b/tests/topotests/ospf6_point_to_multipoint/r3/show_ipv6_route.ref
@@ -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
diff --git a/tests/topotests/ospf6_point_to_multipoint/r3/zebra.conf b/tests/topotests/ospf6_point_to_multipoint/r3/zebra.conf
new file mode 100644
index 000000000..3cc5626bd
--- /dev/null
+++ b/tests/topotests/ospf6_point_to_multipoint/r3/zebra.conf
@@ -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
+!
diff --git a/tests/topotests/ospf6_point_to_multipoint/r4/ip_6_address.nhg.ref b/tests/topotests/ospf6_point_to_multipoint/r4/ip_6_address.nhg.ref
new file mode 100644
index 000000000..ca1e2f0d7
--- /dev/null
+++ b/tests/topotests/ospf6_point_to_multipoint/r4/ip_6_address.nhg.ref
@@ -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
diff --git a/tests/topotests/ospf6_point_to_multipoint/r4/ip_6_address.ref b/tests/topotests/ospf6_point_to_multipoint/r4/ip_6_address.ref
new file mode 100644
index 000000000..4f4e72fc2
--- /dev/null
+++ b/tests/topotests/ospf6_point_to_multipoint/r4/ip_6_address.ref
@@ -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
diff --git a/tests/topotests/ospf6_point_to_multipoint/r4/ospf6d.conf b/tests/topotests/ospf6_point_to_multipoint/r4/ospf6d.conf
new file mode 100644
index 000000000..25b8551dd
--- /dev/null
+++ b/tests/topotests/ospf6_point_to_multipoint/r4/ospf6d.conf
@@ -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
+!
diff --git a/tests/topotests/ospf6_point_to_multipoint/r4/show_ipv6_route.ref b/tests/topotests/ospf6_point_to_multipoint/r4/show_ipv6_route.ref
new file mode 100644
index 000000000..f377ca3a8
--- /dev/null
+++ b/tests/topotests/ospf6_point_to_multipoint/r4/show_ipv6_route.ref
@@ -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
diff --git a/tests/topotests/ospf6_point_to_multipoint/r4/zebra.conf b/tests/topotests/ospf6_point_to_multipoint/r4/zebra.conf
new file mode 100644
index 000000000..20e27cea4
--- /dev/null
+++ b/tests/topotests/ospf6_point_to_multipoint/r4/zebra.conf
@@ -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
+!
diff --git a/tests/topotests/ospf6_point_to_multipoint/test_ospf6_point_to_multipoint.py b/tests/topotests/ospf6_point_to_multipoint/test_ospf6_point_to_multipoint.py
new file mode 100644
index 000000000..142acf1eb
--- /dev/null
+++ b/tests/topotests/ospf6_point_to_multipoint/test_ospf6_point_to_multipoint.py
@@ -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)