diff --git a/doc/user/ospf6d.rst b/doc/user/ospf6d.rst index 2f4c956ffd90..12b368d431a2 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 ` 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 + `_ + 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 + + 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 7b4415da45d4..f93f0e70b87a 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 a20ddf6c1096..0db42cbd23ec 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; @@ -217,9 +217,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; } @@ -232,8 +231,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 */ @@ -370,23 +369,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); @@ -397,7 +394,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; @@ -443,14 +439,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); @@ -459,8 +484,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); } @@ -496,17 +520,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); @@ -516,13 +540,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; @@ -537,8 +565,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; @@ -567,8 +595,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; @@ -631,10 +659,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)); @@ -708,8 +736,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; } @@ -749,11 +777,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; } @@ -770,9 +797,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; } @@ -797,9 +823,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; @@ -810,12 +835,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); @@ -828,8 +851,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); } @@ -839,6 +862,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 { @@ -889,9 +915,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); } @@ -967,6 +992,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"; } @@ -1076,12 +1103,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" @@ -1121,9 +1146,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, @@ -1156,24 +1181,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)) @@ -1184,15 +1208,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) @@ -1201,8 +1225,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", @@ -1234,9 +1257,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", @@ -1259,8 +1281,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)) @@ -1322,7 +1343,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; @@ -1452,18 +1472,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, @@ -1649,8 +1666,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); @@ -1677,8 +1694,7 @@ DEFUN(show_ipv6_ospf6_interface_prefix, show_ipv6_ospf6_interface_prefix_cmd, | []\ >] [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) @@ -1703,9 +1719,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, @@ -1780,14 +1796,11 @@ void ospf6_interface_stop(struct ospf6_interface *oi) } /* interface variable set command */ -DEFUN (ipv6_ospf6_area, - ipv6_ospf6_area_cmd, - "ipv6 ospf6 area ", - 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 ", + 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; @@ -1821,15 +1834,11 @@ DEFUN (ipv6_ospf6_area, return CMD_SUCCESS; } -DEFUN (no_ipv6_ospf6_area, - no_ipv6_ospf6_area_cmd, - "no ipv6 ospf6 area []", - 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 []", + 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; @@ -1849,14 +1858,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; @@ -1905,15 +1909,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; @@ -1951,13 +1950,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; @@ -1988,14 +1983,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; @@ -2013,12 +2004,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; @@ -2045,13 +2035,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; @@ -2070,11 +2058,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; @@ -2089,12 +2076,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); @@ -2102,13 +2087,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; @@ -2136,23 +2117,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; @@ -2170,22 +2143,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; @@ -2202,12 +2169,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; @@ -2224,13 +2188,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; @@ -2248,23 +2208,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; @@ -2282,23 +2234,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; @@ -2314,10 +2259,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); } @@ -2325,22 +2269,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; @@ -2358,22 +2295,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; @@ -2399,14 +2328,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; @@ -2429,13 +2353,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; @@ -2451,14 +2370,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; @@ -2474,15 +2389,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; @@ -2512,15 +2423,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; @@ -2548,15 +2456,12 @@ DEFUN (no_ipv6_ospf6_advertise_prefix_list, return CMD_SUCCESS; } -DEFUN (ipv6_ospf6_network, - ipv6_ospf6_network_cmd, - "ipv6 ospf6 network ", - 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 ", + 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; @@ -2581,6 +2486,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 */ @@ -2590,15 +2500,11 @@ DEFUN (ipv6_ospf6_network, return CMD_SUCCESS; } -DEFUN (no_ipv6_ospf6_network, - no_ipv6_ospf6_network_cmd, - "no ipv6 ospf6 network []", - 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 []", + 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; @@ -2607,9 +2513,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; @@ -2626,6 +2531,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 ", + 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; @@ -2685,7 +2679,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"); @@ -2694,7 +2691,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); @@ -2732,10 +2744,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); @@ -2745,10 +2757,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); @@ -2775,13 +2787,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); @@ -2819,6 +2830,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); @@ -2849,16 +2865,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; @@ -2899,26 +2908,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; @@ -2955,10 +2954,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; @@ -2979,8 +2977,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; } @@ -2988,10 +2986,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; @@ -3017,18 +3014,17 @@ DEFUN(ipv6_ospf6_intf_auth_trailer_key, ipv6_ospf6_intf_auth_trailer_key_cmd, "ipv6 ospf6 authentication key-id (1-65535) hash-algo " " " "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; @@ -3062,8 +3058,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; } @@ -3073,18 +3069,17 @@ DEFUN(no_ipv6_ospf6_intf_auth_trailer_key, "no ipv6 ospf6 authentication key-id [(1-65535) hash-algo " " " "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 5942df0ab5df..2b42af390a0c 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 eb5514adfb3f..cb036752e8a3 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 07da9a5ec124..c7d35344a0c0 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 2b25b074457b..24340793fffb 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 e1aec06f8e8b..47d01e72a259 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 []", - 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 []", + 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 []", - 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 []", + 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 226f4c1322b9..60a76215b7d9 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 443032933d0f..cf3f5c909d58 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 f88667bfd077..e42ca3b6093d 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 f6d27c84cd5f..5f89af950890 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 ec15ff9b1a37..2eaccb8348d0 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 expect_neighbor_full(router, neighbor): 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 num_nexthops(router): 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 000000000000..59c9837aea97 --- /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 000000000000..203f2def5e9e --- /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 000000000000..b77c99674000 --- /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 000000000000..79a9dcae116b --- /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 000000000000..911b3e40d68c --- /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 000000000000..3a7db9f25e36 --- /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 000000000000..d4534b10bb6d --- /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 000000000000..330b696c3a18 --- /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 000000000000..751d8d84e7db --- /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 000000000000..2eff0291ad97 --- /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 000000000000..5571dc979c70 --- /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 000000000000..903c1d962fb8 --- /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 000000000000..3dbcf36b4806 --- /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 000000000000..74e8ddf00f7c --- /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 000000000000..df949e64ea11 --- /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 000000000000..3cc5626bd7e5 --- /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 000000000000..ca1e2f0d7866 --- /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 000000000000..4f4e72fc27be --- /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 000000000000..25b8551dd792 --- /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 000000000000..f377ca3a8882 --- /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 000000000000..20e27cea46ae --- /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 000000000000..142acf1eb47d --- /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)