continue;
}
- if(i + 1 > alen) {
+ if(i + 1 >= alen) {
flog_err(EC_BABEL_PACKET, "Received truncated attributes.");
return;
}
len = a[i + 1];
- if(i + len > alen) {
+ if(i + len + 2 > alen) {
flog_err(EC_BABEL_PACKET, "Received truncated attributes.");
return;
}
int type, len, i = 0, ret = 0;
while(i < alen) {
- type = a[0];
+ type = a[i];
if(type == SUBTLV_PAD1) {
i++;
continue;
}
- if(i + 1 > alen) {
+ if(i + 1 >= alen) {
flog_err(EC_BABEL_PACKET,
"Received truncated sub-TLV on Hello message.");
return -1;
}
len = a[i + 1];
- if(i + len > alen) {
+ if(i + len + 2 > alen) {
flog_err(EC_BABEL_PACKET,
"Received truncated sub-TLV on Hello message.");
return -1;
int type, len, i = 0, ret = 0;
while(i < alen) {
- type = a[0];
+ type = a[i];
if(type == SUBTLV_PAD1) {
i++;
continue;
}
- if(i + 1 > alen) {
+ if(i + 1 >= alen) {
flog_err(EC_BABEL_PACKET,
"Received truncated sub-TLV on IHU message.");
return -1;
}
len = a[i + 1];
- if(i + len > alen) {
+ if(i + len + 2 > alen) {
flog_err(EC_BABEL_PACKET,
"Received truncated sub-TLV on IHU message.");
return -1;
i++;
continue;
}
- if(i + 1 > bodylen) {
+ if(i + 2 > bodylen) {
debugf(BABEL_DEBUG_COMMON,"Received truncated message.");
return 1;
}
len = message[1];
- if(i + len > bodylen) {
+ if(i + len + 2 > bodylen) {
debugf(BABEL_DEBUG_COMMON,"Received truncated message.");
return 1;
}
}
/* Sanity check: peer and local address must match IP types. */
- if (bpc->bpc_local.sa_sin.sin_family != 0
+ if (bpc->bpc_local.sa_sin.sin_family != AF_UNSPEC
&& (bpc->bpc_local.sa_sin.sin_family
!= bpc->bpc_peer.sa_sin.sin_family)) {
zlog_warn("ptm-read: peer family doesn't match local type");
if (ret == RMAP_DENYMATCH) {
if (bgp_debug_update(NULL, p, subgrp->update_group, 0))
zlog_debug(
- "%s [Update:SEND] %pFX is filtered by route-map",
- peer->host, p);
+ "%s [Update:SEND] %pFX is filtered by route-map '%s'",
+ peer->host, p,
+ ROUTE_MAP_OUT_NAME(filter));
- bgp_attr_flush(attr);
+ bgp_attr_flush(&dummy_attr);
return false;
}
}
return 0;
/* MPLS carries UN address in next hop */
rfapiNexthop2Prefix(attr, p);
- if (p->family != 0)
+ if (p->family != AF_UNSPEC)
return 0;
return ENOENT;
return 0;
default:
if (p)
- p->family = 0;
+ p->family = AF_UNSPEC;
#ifdef DEBUG_ENCAP_MONITOR
vnc_zlog_debug_verbose(
"%s: bpi->extra->vnc.import.un_family is 0, no UN addr",
bpi1->extra->vnc.import.un.addr6;
break;
default:
- pfx_un1.family = 0;
+ pfx_un1.family = AF_UNSPEC;
break;
}
}
bpi2->extra->vnc.import.un.addr6;
break;
default:
- pfx_un2.family = 0;
+ pfx_un2.family = AF_UNSPEC;
break;
}
}
}
- if (pfx_un1.family == 0 || pfx_un2.family == 0)
+ if (pfx_un1.family == AF_UNSPEC || pfx_un2.family == AF_UNSPEC)
return 0;
if (pfx_un1.family != pfx_un2.family)
struct prefix p;
/* MPLS carries UN address in next hop */
rfapiNexthop2Prefix(bpi->attr, &p);
- if (p.family != 0) {
+ if (p.family != AF_UNSPEC) {
rfapiQprefix2Raddr(&p, &new->un_address);
have_vnc_tunnel_un = 1;
}
default:
zlog_warn("%s: invalid encap nexthop length: %d", __func__,
encap_bpi->attr->mp_nexthop_len);
- vpn_bpi->extra->vnc.import.un_family = 0;
+ vpn_bpi->extra->vnc.import.un_family = AF_UNSPEC;
break;
}
}
__func__);
return 1;
}
- vpn_bpi->extra->vnc.import.un_family = 0;
+ vpn_bpi->extra->vnc.import.un_family = AF_UNSPEC;
memset(&vpn_bpi->extra->vnc.import.un, 0,
sizeof(vpn_bpi->extra->vnc.import.un));
if (CHECK_FLAG(vpn_bpi->flags, BGP_PATH_VALID)) {
/* Not a big deal, just means VPN route got here first */
vnc_zlog_debug_verbose("%s: no encap route for vn addr %pFX",
__func__, &vn_prefix);
- info_new->extra->vnc.import.un_family = 0;
+ info_new->extra->vnc.import.un_family = AF_UNSPEC;
}
if (rn) {
&& RFAPI_HOST_PREFIX(&rk.aux_prefix)) {
/* mark as "none" if nhp->prefix is 0/32 or
* 0/128 */
- rk.aux_prefix.family = 0;
+ rk.aux_prefix.family = AF_UNSPEC;
}
}
--- /dev/null
+Path Computation Algorithms
+===========================
+
+Introduction
+------------
+
+Both RSVP-TE and Segment Routing Flex Algo need to compute end to end path
+with other constraints as the standard IGP metric. Based on Shortest Path First
+(SPF) algorithms, a new class of Constrained SPF (CSPF) is provided by the FRR
+library.
+
+Supported constraints are as follow:
+- Standard IGP metric (here, CSPF provides the same result as a normal SPF)
+- Traffic Engineering (TE) IGP metric
+- Delay from the IGP Extended Metrics
+- Bandwidth for a given Class of Service (CoS) for bandwidth reservation
+
+Algorithm
+---------
+
+The CSPF algorithm is based on a Priority Queue which store the on-going
+possible path sorted by their respective weights. This weight corresponds
+to the cost of the cuurent path from the source up to the current node.
+
+The algorithm is as followed:
+
+```
+ cost = MAX_COST;
+ Priority_Queue.empty();
+ Visited_Node.empty();
+ Processed_Path.empty();
+ src = new_path(source_address);
+ src.cost = 0;
+ dst = new_destinatio(destination_address);
+ dst.cost = MAX_COST;
+ Processed_Path.add(src);
+ Processed_Path.add(dst);
+ while (Priority_Queue.count != 0) {
+ current_path = Priority_Queue.pop();
+ current_node = next_path.destination;
+ Visited_Node.add(current_node);
+ for (current_node.edges: edge) {
+ if (prune_edge(current_path, edge)
+ continue;
+ if (relax(current_path) && cost > current_path.cost) {
+ optim_path = current_path;
+ cost = current_path.cost;
+ }
+ }
+ }
+
+ prune_edge(path, edge) {
+ // check that path + edge meet constraints e.g.
+ if (current_path.cost + edge.cost > constrained_cost)
+ return false;
+ else
+ return true;
+ }
+
+ relax_edge(current_path, edge) {
+ next_node = edge.destination;
+ if (Visited_Node.get(next_node))
+ return false;
+ next_path = Processed_Path.get(edge.destination);
+ if (!next_path) {
+ next_path = new path(edge.destination);
+ Processed_Path.add(next_path);
+ }
+ total_cost = current_path.cost + edge.cost;
+ if (total_cost < next_path.cost) {
+ next_path = current_path;
+ next_path.add_edge(edge);
+ next_path.cost = total_cost;
+ Priority_Queue.add(next_path);
+ }
+ return (next_path.destination == destination);
+ }
+
+```
+
+Definition
+----------
+
+.. c:struct:: constraints
+
+This is the constraints structure that contains:
+
+- cost: the total cost that the path must respect
+- ctype: type of constraints:
+
+ - CSPF_METRIC for standard metric
+ - CSPF_TE_METRIC for TE metric
+ - CSPF_DELAY for delay metric
+
+- bw: bandwidth that the path must respect
+- cos: Class of Service (COS) for the bandwidth
+- family: AF_INET or AF_INET6
+- type: RSVP_TE, SR_TE or SRV6_TE
+
+.. c:struct:: c_path
+
+This is the Constraint Path structure that contains:
+
+- edges: List of Edges that compose the path
+- status: FAILED, IN_PROGRESS, SUCCESS, NO_SOURCE, NO_DESTINATION, SAME_SRC_DST
+- weight: the cost from source to the destination of the path
+- dst: key of the destination vertex
+
+.. c:struct:: cspf
+
+This is the main structure for path computation. Even if it is public, you
+don't need to set manually the internal field of the structure. Instead, use
+the following functions:
+
+.. c:function:: struct cspf *cspf_new(void);
+
+Function to create an empty cspf for future call of path computation
+
+.. c:function:: struct cspf *cspf_init(struct cspf *algo, const struct ls_vertex *src, const struct ls_vertex *dst, struct constraints *csts);
+
+This function initialize the cspf with source and destination vertex and
+constraints and return pointer to the cspf structure. If input cspf structure
+is NULL, a new cspf structure is allocated and initialize.
+
+.. c:function:: struct cspf *cspf_init_v4(struct cspf *algo, struct ls_ted *ted, const struct in_addr src, const struct in_addr dst, struct constraints *csts);
+
+Same as cspf_init, but here, source and destination vertex are extract from
+the TED data base based on respective IPv4 source and destination addresses.
+
+.. c:function:: struct cspf *cspf_init_v6(struct cspf *algo, struct ls_ted *ted, const struct in6_addr src, const struct in6_addr dst, struct constraints *csts);
+
+Same as cspf_init_v4 but with IPv6 source and destination addresses.
+
+.. c:function:: void cspf_clean(struct cspf *algo);
+
+Clean internal structure of cspf in order to reuse it for another path
+computation.
+
+.. c:function:: void cspf_del(struct cspf *algo);
+
+Delete cspf structure. A call to cspf_clean() function is perform prior to
+free allocated memeory.
+
+.. c:function:: struct c_path *compute_p2p_path(struct ls_ted *ted, struct cspf *algo);
+
+Compute point to point path from the ted and cspf.
+The function always return a constraints path. The status of the path gives
+indication about the success or failure of the algorithm. If cspf structure has
+not been initialize with a call to `cspf_init() or cspf_init_XX()`, the
+algorithm returns a constraints path with status set to FAILED.
+Note that a call to `cspf_clean()` is performed at the end of this function,
+thus it is mandatory to initialize the cspf structure again prior to call again
+the path computation algorithm.
+
+
+Usage
+-----
+
+Of course, CSPF algorithm needs a network topology that contains the
+various metrics. Link State provides such Traffic Engineering Database.
+
+To perform a Path Computation with given constraints, proceed as follow:
+
+.. code-block:: c
+ struct cspf *algo;
+ struct ls_ted *ted;
+ struct in_addr src;
+ struct in_addr dst;
+ struct constraints csts;
+ struct c_path *path;
+
+ // Create a new CSPF structure
+ algo = cspf_new();
+
+ // Initialize constraints
+ csts.cost = 100;
+ csts.ctype = CSPF_TE_METRIC;
+ csts.family = AF_INET;
+ csts.type = SR_TE;
+ csts.bw = 1000000;
+ csts.cos = 3;
+
+ // Then, initialise th CSPF with source, destination and constraints
+ cspf_init_v4(algo, ted, src, dst, &csts);
+
+ // Finally, got the Computed Path;
+ path = compute_p2p_path(ted, algo);
+
+ if (path.status == SUCCESS)
+ zlog_info("Got a valid constraints path");
+ else
+ zlog_info("Unable to compute constraints path. Got %d status", path->status);
+
+
+If you would compute another path, you must call `cspf_init()` prior to
+`compute_p2p_path()` to change source, destination and/or constraints.
.. clicmd:: show ip pim assert
Display information about asserts in the PIM system for S,G mroutes.
+ This command does not show S,G Channel states that in a NOINFO state.
.. clicmd:: show ip pim assert-internal
.. clicmd:: sharp import-te
- Import Traffic Engineering Database produce by OSPF or IS-IS.
+ Import Traffic Engineering Database produced by OSPF or IS-IS.
.. clicmd:: show sharp ted [verbose|json]
Show imported Traffic Engineering Data Base
+.. clicmd:: show sharp cspf source <A.B.C.D|X:X:X:X> destination <A.B.C.D|X:X:X:X> <metric|te-metric|delay> (0-16777215) [rsv-bw (0-7) BANDWIDTH]
+
+ Show the result of a call to the Constraint Shortest Path First (CSPF)
+ algorithm that allows to compute a path between a source and a
+ destination under various constraints. Standard Metric, TE Metric, Delay
+ and Bandwidth are supported constraints. Prior to use this function, it is
+ necessary to import a Traffic Engineering Database with `sharp import-te`
+ command (see above).
+
.. clicmd:: sharp install seg6-routes [vrf NAME] <A.B.C.D|X:X::X:X> nexthop-seg6 X:X::X:X encap X:X::X:X (1-1000000)
This command installs a route for SRv6 Transit behavior (on Linux it is
SEG6_LOCAL_IIF,
SEG6_LOCAL_OIF,
SEG6_LOCAL_BPF,
+ SEG6_LOCAL_VRFTABLE,
__SEG6_LOCAL_MAX,
};
#define SEG6_LOCAL_MAX (__SEG6_LOCAL_MAX - 1)
return LSP_ITER_CONTINUE;
attr->metric = metric;
+ SET_FLAG(attr->flags, LS_ATTR_METRIC);
/* Get corresponding Edge from Link State Data Base */
edge = get_edge(args->ted, attr);
type = stream_getc(s);
length = stream_getc(s);
+
+ if (length > STREAM_READABLE(s) || length > subtlv_len - 2) {
+ sbuf_push(
+ log, indent,
+ "WARNING: Router Capability subTLV length too large compared to expected size\n");
+ stream_forward_getp(s, STREAM_READABLE(s));
+
+ return 0;
+ }
+
switch (type) {
case ISIS_SUBTLV_SID_LABEL_RANGE:
/* Check that SRGB is correctly formated */
if (length < SUBTLV_RANGE_LABEL_SIZE
|| length > SUBTLV_RANGE_INDEX_SIZE) {
stream_forward_getp(s, length);
- continue;
+ break;
}
/* Only one SRGB is supported. Skip subsequent one */
if (rcap->srgb.range_size != 0) {
stream_forward_getp(s, length);
- continue;
+ break;
}
rcap->srgb.flags = stream_getc(s);
rcap->srgb.range_size = stream_get3(s);
/* Skip Type and get Length of SID Label */
stream_getc(s);
size = stream_getc(s);
- if (size == ISIS_SUBTLV_SID_LABEL_SIZE)
+
+ if (size == ISIS_SUBTLV_SID_LABEL_SIZE
+ && length != SUBTLV_RANGE_LABEL_SIZE) {
+ stream_forward_getp(s, length - 6);
+ break;
+ }
+
+ if (size == ISIS_SUBTLV_SID_INDEX_SIZE
+ && length != SUBTLV_RANGE_INDEX_SIZE) {
+ stream_forward_getp(s, length - 6);
+ break;
+ }
+
+ if (size == ISIS_SUBTLV_SID_LABEL_SIZE) {
rcap->srgb.lower_bound = stream_get3(s);
- else
+ } else if (size == ISIS_SUBTLV_SID_INDEX_SIZE) {
rcap->srgb.lower_bound = stream_getl(s);
+ } else {
+ stream_forward_getp(s, length - 6);
+ break;
+ }
/* SRGB sanity checks. */
if (rcap->srgb.range_size == 0
/* Only one range is supported. Skip subsequent one */
size = length - (size + SUBTLV_SR_BLOCK_SIZE);
if (size > 0)
- stream_forward_getp(s, length);
+ stream_forward_getp(s, size);
+
break;
case ISIS_SUBTLV_ALGORITHM:
+ if (length == 0)
+ break;
/* Only 2 algorithms are supported: SPF & Strict SPF */
stream_get(&rcap->algo, s,
length > SR_ALGORITHM_COUNT
if (length < SUBTLV_RANGE_LABEL_SIZE
|| length > SUBTLV_RANGE_INDEX_SIZE) {
stream_forward_getp(s, length);
- continue;
+ break;
}
/* RFC 8667 section #3.3: Only one SRLB is authorized */
if (rcap->srlb.range_size != 0) {
stream_forward_getp(s, length);
- continue;
+ break;
}
/* Ignore Flags which are not defined */
stream_getc(s);
/* Skip Type and get Length of SID Label */
stream_getc(s);
size = stream_getc(s);
- if (size == ISIS_SUBTLV_SID_LABEL_SIZE)
+
+ if (size == ISIS_SUBTLV_SID_LABEL_SIZE
+ && length != SUBTLV_RANGE_LABEL_SIZE) {
+ stream_forward_getp(s, length - 6);
+ break;
+ }
+
+ if (size == ISIS_SUBTLV_SID_INDEX_SIZE
+ && length != SUBTLV_RANGE_INDEX_SIZE) {
+ stream_forward_getp(s, length - 6);
+ break;
+ }
+
+ if (size == ISIS_SUBTLV_SID_LABEL_SIZE) {
rcap->srlb.lower_bound = stream_get3(s);
- else
+ } else if (size == ISIS_SUBTLV_SID_INDEX_SIZE) {
rcap->srlb.lower_bound = stream_getl(s);
+ } else {
+ stream_forward_getp(s, length - 6);
+ break;
+ }
/* SRLB sanity checks. */
if (rcap->srlb.range_size == 0
/* Only one range is supported. Skip subsequent one */
size = length - (size + SUBTLV_SR_BLOCK_SIZE);
if (size > 0)
- stream_forward_getp(s, length);
+ stream_forward_getp(s, size);
+
break;
case ISIS_SUBTLV_NODE_MSD:
/* Check that MSD is correctly formated */
if (length < MSD_TLV_SIZE) {
stream_forward_getp(s, length);
- continue;
+ break;
}
msd_type = stream_getc(s);
rcap->msd = stream_getc(s);
/* RFC 8667 sections #2 & #3 */
ISIS_SUBTLV_SID_LABEL_SIZE = 3,
+ ISIS_SUBTLV_SID_INDEX_SIZE = 4,
ISIS_SUBTLV_SID_LABEL_RANGE_SIZE = 9,
ISIS_SUBTLV_ALGORITHM_SIZE = 4,
ISIS_SUBTLV_ADJ_SID_SIZE = 5,
--- /dev/null
+/*
+ * Constraints Shortest Path First algorithms - cspf.c
+ *
+ * Author: Olivier Dugeon <olivier.dugeon@orange.com>
+ *
+ * Copyright (C) 2022 Orange http://www.orange.com
+ *
+ * This file is part of Free Range Routing (FRR).
+ *
+ * FRR is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * FRR is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <zebra.h>
+
+#include "if.h"
+#include "linklist.h"
+#include "log.h"
+#include "hash.h"
+#include "memory.h"
+#include "prefix.h"
+#include "table.h"
+#include "stream.h"
+#include "printfrr.h"
+#include "link_state.h"
+#include "cspf.h"
+
+/* Link State Memory allocation */
+DEFINE_MTYPE_STATIC(LIB, PCA, "Path Computation Algorithms");
+
+/**
+ * Create new Constrained Path. Memory is dynamically allocated.
+ *
+ * @param key Vertex key of the destination of this path
+ *
+ * @return Pointer to a new Constrained Path structure
+ */
+static struct c_path *cpath_new(uint64_t key)
+{
+ struct c_path *path;
+
+ /* Sanity Check */
+ if (key == 0)
+ return NULL;
+
+ path = XCALLOC(MTYPE_PCA, sizeof(struct c_path));
+ path->dst = key;
+ path->status = IN_PROGRESS;
+ path->edges = list_new();
+ path->weight = MAX_COST;
+
+ return path;
+}
+
+/**
+ * Copy src Constrained Path into dst Constrained Path. A new Constrained Path
+ * structure is dynamically allocated if dst is NULL. If src is NULL, the
+ * function return the dst disregarding if it is NULL or not.
+ *
+ * @param dest Destination Constrained Path structure
+ * @param src Source Constrained Path structure
+ *
+ * @return Pointer to the destination Constrained Path structure
+ */
+static struct c_path *cpath_copy(struct c_path *dest, const struct c_path *src)
+{
+ struct c_path *new_path;
+
+ if (!src)
+ return dest;
+
+ if (!dest) {
+ new_path = XCALLOC(MTYPE_PCA, sizeof(struct c_path));
+ } else {
+ new_path = dest;
+ if (dest->edges)
+ list_delete(&new_path->edges);
+ }
+
+ new_path->dst = src->dst;
+ new_path->weight = src->weight;
+ new_path->edges = list_dup(src->edges);
+ new_path->status = src->status;
+
+ return new_path;
+}
+
+/**
+ * Delete Constrained Path structure. Previous allocated memory is freed.
+ *
+ * @param path Constrained Path structure to be deleted
+ */
+static void cpath_del(struct c_path *path)
+{
+ if (!path)
+ return;
+
+ if (path->edges)
+ list_delete(&path->edges);
+
+ XFREE(MTYPE_PCA, path);
+ path = NULL;
+}
+
+/**
+ * Replace the list of edges in the next Constrained Path by the list of edges
+ * in the current Constrained Path.
+ *
+ * @param next_path next Constrained Path structure
+ * @param cur_path current Constrained Path structure
+ */
+static void cpath_replace(struct c_path *next_path, struct c_path *cur_path)
+{
+
+ if (next_path->edges)
+ list_delete(&next_path->edges);
+
+ next_path->edges = list_dup(cur_path->edges);
+}
+
+/**
+ * Create a new Visited Node structure from the provided Vertex. Structure is
+ * dynamically allocated.
+ *
+ * @param vertex Vertex structure
+ *
+ * @return Pointer to the new Visited Node structure
+ */
+static struct v_node *vnode_new(struct ls_vertex *vertex)
+{
+ struct v_node *vnode;
+
+ if (!vertex)
+ return NULL;
+
+ vnode = XCALLOC(MTYPE_PCA, sizeof(struct v_node));
+ vnode->vertex = vertex;
+ vnode->key = vertex->key;
+
+ return vnode;
+}
+
+/**
+ * Delete Visited Node structure. Previous allocated memory is freed.
+ *
+ * @param vnode Visited Node structure to be deleted
+ */
+static void vnode_del(struct v_node *vnode)
+{
+ if (!vnode)
+ return;
+
+ XFREE(MTYPE_PCA, vnode);
+ vnode = NULL;
+}
+
+/**
+ * Search Vertex in TED by IPv4 address. The function search vertex by browsing
+ * the subnets table. It allows to find not only vertex by router ID, but also
+ * vertex by interface IPv4 address.
+ *
+ * @param ted Traffic Engineering Database
+ * @param ipv4 IPv4 address
+ *
+ * @return Vertex if found, NULL otherwise
+ */
+static struct ls_vertex *get_vertex_by_ipv4(struct ls_ted *ted,
+ struct in_addr ipv4)
+{
+ struct ls_subnet *subnet;
+ struct prefix p;
+
+ p.family = AF_INET;
+ p.u.prefix4 = ipv4;
+
+ frr_each (subnets, &ted->subnets, subnet) {
+ if (subnet->key.family != AF_INET)
+ continue;
+ p.prefixlen = subnet->key.prefixlen;
+ if (prefix_same(&subnet->key, &p))
+ return subnet->vertex;
+ }
+
+ return NULL;
+}
+
+/**
+ * Search Vertex in TED by IPv6 address. The function search vertex by browsing
+ * the subnets table. It allows to find not only vertex by router ID, but also
+ * vertex by interface IPv6 address.
+ *
+ * @param ted Traffic Engineering Database
+ * @param ipv6 IPv6 address
+ *
+ * @return Vertex if found, NULL otherwise
+ */
+static struct ls_vertex *get_vertex_by_ipv6(struct ls_ted *ted,
+ struct in6_addr ipv6)
+{
+ struct ls_subnet *subnet;
+ struct prefix p;
+
+ p.family = AF_INET6;
+ p.u.prefix6 = ipv6;
+
+ frr_each (subnets, &ted->subnets, subnet) {
+ if (subnet->key.family != AF_INET6)
+ continue;
+ p.prefixlen = subnet->key.prefixlen;
+ if (prefix_cmp(&subnet->key, &p) == 0)
+ return subnet->vertex;
+ }
+
+ return NULL;
+}
+
+struct cspf *cspf_new(void)
+{
+ struct cspf *algo;
+
+ /* Allocate New CSPF structure */
+ algo = XCALLOC(MTYPE_PCA, sizeof(struct cspf));
+
+ /* Initialize RB-Trees */
+ processed_init(&algo->processed);
+ visited_init(&algo->visited);
+ pqueue_init(&algo->pqueue);
+
+ algo->path = NULL;
+ algo->pdst = NULL;
+
+ return algo;
+}
+
+struct cspf *cspf_init(struct cspf *algo, const struct ls_vertex *src,
+ const struct ls_vertex *dst, struct constraints *csts)
+{
+ struct cspf *new_algo;
+ struct c_path *psrc;
+
+ if (!csts)
+ return NULL;
+
+ if (!algo)
+ new_algo = cspf_new();
+ else
+ new_algo = algo;
+
+ /* Initialize Processed Path and Priority Queue with Src & Dst */
+ if (src) {
+ psrc = cpath_new(src->key);
+ psrc->weight = 0;
+ processed_add(&new_algo->processed, psrc);
+ pqueue_add(&new_algo->pqueue, psrc);
+ new_algo->path = psrc;
+ }
+ if (dst) {
+ new_algo->pdst = cpath_new(dst->key);
+ processed_add(&new_algo->processed, new_algo->pdst);
+ }
+
+ memcpy(&new_algo->csts, csts, sizeof(struct constraints));
+
+ return new_algo;
+}
+
+struct cspf *cspf_init_v4(struct cspf *algo, struct ls_ted *ted,
+ const struct in_addr src, const struct in_addr dst,
+ struct constraints *csts)
+{
+ struct ls_vertex *vsrc;
+ struct ls_vertex *vdst;
+ struct cspf *new_algo;
+
+ /* Sanity Check */
+ if (!ted)
+ return algo;
+
+ if (!algo)
+ new_algo = cspf_new();
+ else
+ new_algo = algo;
+
+ /* Got Source and Destination Vertex from TED */
+ vsrc = get_vertex_by_ipv4(ted, src);
+ vdst = get_vertex_by_ipv4(ted, dst);
+ csts->family = AF_INET;
+
+ return cspf_init(new_algo, vsrc, vdst, csts);
+}
+
+struct cspf *cspf_init_v6(struct cspf *algo, struct ls_ted *ted,
+ const struct in6_addr src, const struct in6_addr dst,
+ struct constraints *csts)
+{
+ struct ls_vertex *vsrc;
+ struct ls_vertex *vdst;
+ struct cspf *new_algo;
+
+ /* Sanity Check */
+ if (!ted)
+ return algo;
+
+ if (!algo)
+ new_algo = cspf_new();
+ else
+ new_algo = algo;
+
+ /* Got Source and Destination Vertex from TED */
+ vsrc = get_vertex_by_ipv6(ted, src);
+ vdst = get_vertex_by_ipv6(ted, dst);
+ csts->family = AF_INET6;
+
+ return cspf_init(new_algo, vsrc, vdst, csts);
+}
+
+void cspf_clean(struct cspf *algo)
+{
+ struct c_path *path;
+ struct v_node *vnode;
+
+ if (!algo)
+ return;
+
+ /* Normally, Priority Queue is empty. Clean it in case of. */
+ if (pqueue_count(&algo->pqueue)) {
+ frr_each_safe (pqueue, &algo->pqueue, path) {
+ pqueue_del(&algo->pqueue, path);
+ }
+ }
+
+ /* Empty Processed Path tree and associated Path */
+ if (processed_count(&algo->processed)) {
+ frr_each_safe (processed, &algo->processed, path) {
+ processed_del(&algo->processed, path);
+ cpath_del(path);
+ }
+ }
+
+ /* Empty visited Vertex tree and associated Node */
+ if (visited_count(&algo->visited)) {
+ frr_each_safe (visited, &algo->visited, vnode) {
+ visited_del(&algo->visited, vnode);
+ vnode_del(vnode);
+ }
+ }
+
+ memset(&algo->csts, 0, sizeof(struct constraints));
+ algo->path = NULL;
+ algo->pdst = NULL;
+}
+
+void cspf_del(struct cspf *algo)
+{
+ if (!algo)
+ return;
+
+ /* Empty Priority Queue and Processes Path */
+ cspf_clean(algo);
+
+ /* Then, reset Priority Queue, Processed Path and Visited RB-Tree */
+ pqueue_fini(&algo->pqueue);
+ processed_fini(&algo->processed);
+ visited_fini(&algo->visited);
+
+ XFREE(MTYPE_PCA, algo);
+ algo = NULL;
+}
+
+/**
+ * Prune Edge if constraints are not met by testing Edge Attributes against
+ * given constraints and cumulative cost of the given constrained path.
+ *
+ * @param path On-going Computed Path with cumulative cost constraints
+ * @param edge Edge to be validate against Constraints
+ * @param csts Constraints for this path
+ *
+ * @return True if Edge should be prune, false if Edge is valid
+ */
+static bool prune_edge(const struct c_path *path, const struct ls_edge *edge,
+ const struct constraints *csts)
+{
+ struct ls_vertex *dst;
+ struct ls_attributes *attr;
+
+ /* Check that Path, Edge and Constraints are valid */
+ if (!path || !edge || !csts)
+ return true;
+
+ /* Check that Edge has a valid destination */
+ if (!edge->destination)
+ return true;
+ dst = edge->destination;
+
+ /* Check that Edge has valid attributes */
+ if (!edge->attributes)
+ return true;
+ attr = edge->attributes;
+
+ /* Check that Edge belongs to the requested Address Family and type */
+ if (csts->family == AF_INET) {
+ if (IPV4_NET0(attr->standard.local.s_addr))
+ return true;
+ if (csts->type == SR_TE)
+ if (!CHECK_FLAG(attr->flags, LS_ATTR_ADJ_SID) ||
+ !CHECK_FLAG(dst->node->flags, LS_NODE_SR))
+ return true;
+ }
+ if (csts->family == AF_INET6) {
+ if (IN6_IS_ADDR_UNSPECIFIED(&attr->standard.local6))
+ return true;
+ if (csts->type == SR_TE)
+ if (!CHECK_FLAG(attr->flags, LS_ATTR_ADJ_SID6) ||
+ !CHECK_FLAG(dst->node->flags, LS_NODE_SR))
+ return true;
+ }
+
+ /*
+ * Check that total cost, up to this edge, respects the initial
+ * constraints
+ */
+ switch (csts->ctype) {
+ case CSPF_METRIC:
+ if (!CHECK_FLAG(attr->flags, LS_ATTR_METRIC))
+ return true;
+ if ((attr->metric + path->weight) > csts->cost)
+ return true;
+ break;
+
+ case CSPF_TE_METRIC:
+ if (!CHECK_FLAG(attr->flags, LS_ATTR_TE_METRIC))
+ return true;
+ if ((attr->standard.te_metric + path->weight) > csts->cost)
+ return true;
+ break;
+
+ case CSPF_DELAY:
+ if (!CHECK_FLAG(attr->flags, LS_ATTR_DELAY))
+ return true;
+ if ((attr->extended.delay + path->weight) > csts->cost)
+ return true;
+ break;
+ }
+
+ /* If specified, check that Edge meet Bandwidth constraint */
+ if (csts->bw > 0.0) {
+ if (attr->standard.max_bw < csts->bw ||
+ attr->standard.max_rsv_bw < csts->bw ||
+ attr->standard.unrsv_bw[csts->cos] < csts->bw)
+ return true;
+ }
+
+ /* All is fine. We can consider this Edge valid, so not to be prune */
+ return false;
+}
+
+/**
+ * Relax constraints of the current path up to the destination vertex of the
+ * provided Edge. This function progress in the network topology by validating
+ * the next vertex on the computed path. If Vertex has not already been visited,
+ * list of edges of the current path is augmented with this edge if the new cost
+ * is lower than prior path up to this vertex. Current path is re-inserted in
+ * the Priority Queue with its new cost i.e. current cost + edge cost.
+ *
+ * @param algo CSPF structure
+ * @param edge Next Edge to be added to the current computed path
+ *
+ * @return True if current path reach destination, false otherwise
+ */
+static bool relax_constraints(struct cspf *algo, struct ls_edge *edge)
+{
+
+ struct c_path pkey = {};
+ struct c_path *next_path;
+ struct v_node vnode = {};
+ uint32_t total_cost = MAX_COST;
+
+ /* Verify that we have a current computed path */
+ if (!algo->path)
+ return false;
+
+ /* Verify if we have not visited the next Vertex to avoid loop */
+ vnode.key = edge->destination->key;
+ if (visited_member(&algo->visited, &vnode)) {
+ return false;
+ }
+
+ /*
+ * Get Next Computed Path from next vertex key
+ * or create a new one if it has not yet computed.
+ */
+ pkey.dst = edge->destination->key;
+ next_path = processed_find(&algo->processed, &pkey);
+ if (!next_path) {
+ next_path = cpath_new(pkey.dst);
+ processed_add(&algo->processed, next_path);
+ }
+
+ /*
+ * Add or update the Computed Path in the Priority Queue if total cost
+ * is lower than cost associated to this next Vertex. This could occurs
+ * if we process a Vertex that as not yet been visited in the Graph
+ * or if we found a shortest path up to this Vertex.
+ */
+ switch (algo->csts.ctype) {
+ case CSPF_METRIC:
+ total_cost = edge->attributes->metric + algo->path->weight;
+ break;
+ case CSPF_TE_METRIC:
+ total_cost = edge->attributes->standard.te_metric +
+ algo->path->weight;
+ break;
+ case CSPF_DELAY:
+ total_cost =
+ edge->attributes->extended.delay + algo->path->weight;
+ break;
+ default:
+ break;
+ }
+ if (total_cost < next_path->weight) {
+ /*
+ * It is not possible to directly update the q_path in the
+ * Priority Queue. Indeed, if we modify the path weight, the
+ * Priority Queue must be re-ordered. So, we need fist to remove
+ * the q_path if it is present in the Priority Queue, then,
+ * update the Path, in particular the Weight, and finally
+ * (re-)insert it in the Priority Queue.
+ */
+ struct c_path *path;
+ frr_each_safe (pqueue, &algo->pqueue, path) {
+ if (path->dst == pkey.dst) {
+ pqueue_del(&algo->pqueue, path);
+ break;
+ }
+ }
+ next_path->weight = total_cost;
+ cpath_replace(next_path, algo->path);
+ listnode_add(next_path->edges, edge);
+ pqueue_add(&algo->pqueue, next_path);
+ }
+
+ /* Return True if we reach the destination */
+ return (next_path->dst == algo->pdst->dst);
+}
+
+struct c_path *compute_p2p_path(struct cspf *algo, struct ls_ted *ted)
+{
+ struct listnode *node;
+ struct ls_vertex *vertex;
+ struct ls_edge *edge;
+ struct c_path *optim_path;
+ struct v_node *vnode;
+ uint32_t cur_cost;
+
+ optim_path = cpath_new(0xFFFFFFFFFFFFFFFF);
+ optim_path->status = FAILED;
+
+ /* Check that all is correctly initialized */
+ if (!algo)
+ return optim_path;
+
+ if (!algo->csts.ctype)
+ return optim_path;
+
+ if (!algo->pdst) {
+ optim_path->status = NO_DESTINATION;
+ return optim_path;
+ }
+
+ if (!algo->path) {
+ optim_path->status = NO_SOURCE;
+ return optim_path;
+ }
+
+ if (algo->pdst->dst == algo->path->dst) {
+ optim_path->status = SAME_SRC_DST;
+ return optim_path;
+ }
+
+ optim_path->dst = algo->pdst->dst;
+ optim_path->status = IN_PROGRESS;
+
+ /*
+ * Process all Connected Vertex until priority queue becomes empty.
+ * Connected Vertices are added into the priority queue when
+ * processing the next Connected Vertex: see relax_constraints()
+ */
+ cur_cost = MAX_COST;
+ while (pqueue_count(&algo->pqueue) != 0) {
+ /* Got shortest current Path from the Priority Queue */
+ algo->path = pqueue_pop(&algo->pqueue);
+
+ /* Add destination Vertex of this path to the visited RB Tree */
+ vertex = ls_find_vertex_by_key(ted, algo->path->dst);
+ if (!vertex)
+ continue;
+ vnode = vnode_new(vertex);
+ visited_add(&algo->visited, vnode);
+
+ /* Process all outgoing links from this Vertex */
+ for (ALL_LIST_ELEMENTS_RO(vertex->outgoing_edges, node, edge)) {
+ /*
+ * Skip Connected Edges that must be prune i.e.
+ * Edges that not satisfy the given constraints,
+ * in particular the Bandwidth, TE Metric and Delay.
+ */
+ if (prune_edge(algo->path, edge, &algo->csts))
+ continue;
+
+ /*
+ * Relax constraints and check if we got a shorter
+ * candidate path
+ */
+ if (relax_constraints(algo, edge) &&
+ algo->pdst->weight < cur_cost) {
+ cur_cost = algo->pdst->weight;
+ cpath_copy(optim_path, algo->pdst);
+ optim_path->status = SUCCESS;
+ }
+ }
+ }
+
+ /*
+ * The priority queue is empty => all the possible (vertex, path)
+ * elements have been explored. The optim_path contains the optimal
+ * path if it exists. Otherwise an empty path with status failed is
+ * returned.
+ */
+ if (optim_path->status == IN_PROGRESS ||
+ listcount(optim_path->edges) == 0)
+ optim_path->status = FAILED;
+ cspf_clean(algo);
+
+ return optim_path;
+}
--- /dev/null
+/*
+ * Constraints Shortest Path First algorithms definition - cspf.h
+ *
+ * Author: Olivier Dugeon <olivier.dugeon@orange.com>
+ *
+ * Copyright (C) 2022 Orange http://www.orange.com
+ *
+ * This file is part of Free Range Routing (FRR).
+ *
+ * FRR is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * FRR is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _FRR_CSPF_H_
+#define _FRR_CSPF_H_
+
+#include "typesafe.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * This file defines the different structure used for Path Computation with
+ * various constrained. Up to now, standard metric, TE metric, delay and
+ * bandwidth constraints are supported.
+ * All proposed algorithms used the same principle:
+ * - A pruning function that keeps only links that meet constraints
+ * - A priority Queue that keeps the shortest on-going computed path
+ * - A main loop over all vertices to find the shortest path
+ */
+
+#define MAX_COST 0xFFFFFFFF
+
+/* Status of the path */
+enum path_status {
+ FAILED = 0,
+ NO_SOURCE,
+ NO_DESTINATION,
+ SAME_SRC_DST,
+ IN_PROGRESS,
+ SUCCESS
+};
+enum path_type {RSVP_TE = 1, SR_TE, SRV6_TE};
+enum metric_type {CSPF_METRIC = 1, CSPF_TE_METRIC, CSPF_DELAY};
+
+/* Constrained metrics structure */
+struct constraints {
+ uint32_t cost; /* total cost (metric) of the path */
+ enum metric_type ctype; /* Metric Type: standard, TE or Delay */
+ float bw; /* bandwidth of the path */
+ uint8_t cos; /* Class of Service of the path */
+ enum path_type type; /* RSVP-TE or SR-TE path */
+ uint8_t family; /* AF_INET or AF_INET6 address family */
+};
+
+/* Priority Queue for Constrained Path Computation */
+PREDECL_RBTREE_NONUNIQ(pqueue);
+
+/* Processed Path for Constrained Path Computation */
+PREDECL_RBTREE_UNIQ(processed);
+
+/* Constrained Path structure */
+struct c_path {
+ struct pqueue_item q_itm; /* entry in the Priority Queue */
+ uint32_t weight; /* Weight to sort path in Priority Queue */
+ struct processed_item p_itm; /* entry in the Processed RB Tree */
+ uint64_t dst; /* Destination vertex key of this path */
+ struct list *edges; /* List of Edges that compose this path */
+ enum path_status status; /* status of the computed path */
+};
+
+macro_inline int q_cmp(const struct c_path *p1, const struct c_path *p2)
+{
+ return numcmp(p1->weight, p2->weight);
+}
+DECLARE_RBTREE_NONUNIQ(pqueue, struct c_path, q_itm, q_cmp);
+
+macro_inline int p_cmp(const struct c_path *p1, const struct c_path *p2)
+{
+ return numcmp(p1->dst, p2->dst);
+}
+DECLARE_RBTREE_UNIQ(processed, struct c_path, p_itm, p_cmp);
+
+/* List of visited node */
+PREDECL_RBTREE_UNIQ(visited);
+struct v_node {
+ struct visited_item item; /* entry in the Processed RB Tree */
+ uint64_t key;
+ struct ls_vertex *vertex;
+};
+
+macro_inline int v_cmp(const struct v_node *p1, const struct v_node *p2)
+{
+ return numcmp(p1->key, p2->key);
+}
+DECLARE_RBTREE_UNIQ(visited, struct v_node, item, v_cmp);
+
+/* Path Computation algorithms structure */
+struct cspf {
+ struct pqueue_head pqueue; /* Priority Queue */
+ struct processed_head processed; /* Paths that have been processed */
+ struct visited_head visited; /* Vertices that have been visited */
+ struct constraints csts; /* Constraints of the path */
+ struct c_path *path; /* Current Computed Path */
+ struct c_path *pdst; /* Computed Path to the destination */
+};
+
+/**
+ * Create a new CSPF structure. Memory is dynamically allocated.
+ *
+ * @return pointer to the new cspf structure
+ */
+extern struct cspf *cspf_new(void);
+
+/**
+ * Initialize CSPF structure prior to compute a constrained path. If CSPF
+ * structure is NULL, a new CSPF is dynamically allocated prior to the
+ * configuration itself.
+ *
+ * @param algo CSPF structure, may be null if a new CSPF must be created
+ * @param src Source vertex of the requested path
+ * @param dst Destination vertex of the requested path
+ * @param csts Constraints of the requested path
+ *
+ * @return pointer to the initialized CSPF structure
+ */
+extern struct cspf *cspf_init(struct cspf *algo, const struct ls_vertex *src,
+ const struct ls_vertex *dst,
+ struct constraints *csts);
+
+/**
+ * Initialize CSPF structure prior to compute a constrained path. If CSPF
+ * structure is NULL, a new CSPF is dynamically allocated prior to the
+ * configuration itself. This function starts by searching source and
+ * destination vertices from the IPv4 addresses in the provided TED.
+ *
+ * @param algo CSPF structure, may be null if a new CSPF must be created
+ * @param ted Traffic Engineering Database
+ * @param src Source IPv4 address of the requested path
+ * @param dst Destination IPv4 address of the requested path
+ * @param csts Constraints of the requested path
+ *
+ * @return pointer to the initialized CSPF structure
+ */
+extern struct cspf *cspf_init_v4(struct cspf *algo, struct ls_ted *ted,
+ const struct in_addr src,
+ const struct in_addr dst,
+ struct constraints *csts);
+
+/**
+ * Initialize CSPF structure prior to compute a constrained path. If CSPF
+ * structure is NULL, a new CSPF is dynamically allocated prior to the
+ * configuration itself. This function starts by searching source and
+ * destination vertices from the IPv6 addresses in the provided TED.
+ *
+ * @param algo CSPF structure, may be null if a new CSPF must be created
+ * @param ted Traffic Engineering Database
+ * @param src Source IPv6 address of the requested path
+ * @param dst Destination IPv6 address of the requested path
+ * @param csts Constraints of the requested path
+ *
+ * @return pointer to the initialized CSPF structure
+ */
+extern struct cspf *cspf_init_v6(struct cspf *algo, struct ls_ted *ted,
+ const struct in6_addr src,
+ const struct in6_addr dst,
+ struct constraints *csts);
+
+/**
+ * Clean CSPF structure. Reset all internal list and priority queue for latter
+ * initialization of the CSPF structure and new path computation.
+ *
+ * @param algo CSPF structure
+ */
+extern void cspf_clean(struct cspf *algo);
+
+/**
+ * Delete CSPF structure, internal list and priority queue.
+ *
+ * @param algo CSPF structure
+ */
+extern void cspf_del(struct cspf *algo);
+
+/**
+ * Compute point-to-point constrained path. cspf_init() function must be call
+ * prior to call this function.
+ *
+ * @param algo CSPF structure
+ * @param ted Traffic Engineering Database
+ *
+ * @return Constrained Path with status to indicate computation success
+ */
+extern struct c_path *compute_p2p_path(struct cspf *algo, struct ls_ted *ted);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _FRR_CSPF_H_ */
f = nb_running_get_entry(args->dnode, NULL, true);
fz = &f->u.zfilter;
- fz->prefix.family = 0;
+ fz->prefix.family = AF_UNSPEC;
acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_DELETED);
struct if_link_params *iflp =
XCALLOC(MTYPE_IF_LINK_PARAMS, sizeof(struct if_link_params));
- /* Set TE metric equal to standard metric */
- iflp->te_metric = ifp->metric;
-
/* Compute default bandwidth based on interface */
iflp->default_bw =
((ifp->bandwidth ? ifp->bandwidth : DEFAULT_BANDWIDTH)
iflp->unrsv_bw[i] = iflp->default_bw;
/* Update Link parameters status */
- iflp->lp_status =
- LP_TE_METRIC | LP_MAX_BW | LP_MAX_RSV_BW | LP_UNRSV_BW;
+ iflp->lp_status = LP_MAX_BW | LP_MAX_RSV_BW | LP_UNRSV_BW;
+
+ /* Set TE metric equal to standard metric only if it is set */
+ if (ifp->metric != 0) {
+ iflp->te_metric = ifp->metric;
+ iflp->lp_status |= LP_TE_METRIC;
+ }
/* Finally attach newly created Link Parameters */
ifp->link_params = iflp;
lib/command_lex.l \
lib/command_match.c \
lib/command_parse.y \
+ lib/cspf.c \
lib/csv.c \
lib/debug.c \
lib/defaults.c \
lib/command_graph.h \
lib/command_match.h \
lib/compiler.h \
+ lib/cspf.h \
lib/csv.h \
lib/db.h \
lib/debug.h \
id.s_addr = p->prefix.s_addr | (~mask.s_addr);
lsa = ospf_lsdb_lookup_by_id(ospf->lsdb, OSPF_AS_EXTERNAL_LSA, id,
ospf->router_id);
- if (lsa)
+ if (lsa) {
+ if (p->prefixlen == IPV4_MAX_BITLEN) {
+ al = (struct as_external_lsa *)lsa->data;
+
+ if (mask.s_addr != al->mask.s_addr)
+ return NULL;
+ }
return lsa;
+ }
lsa = ospf_lsdb_lookup_by_id(ospf->lsdb, OSPF_AS_EXTERNAL_LSA,
p->prefix, ospf->router_id);
#include "ospfd/ospf_abr.h"
#include "ospfd/ospf_errors.h"
+static struct ospf_lsa *ospf_handle_summarylsa_lsId_chg(struct ospf *ospf,
+ struct prefix_ipv4 *p,
+ uint8_t type,
+ uint32_t metric,
+ struct in_addr old_id);
+static struct ospf_lsa *
+ospf_summary_lsa_prepare_and_flood(struct prefix_ipv4 *p, uint32_t metric,
+ struct ospf_area *area, struct in_addr id);
+static struct ospf_lsa *ospf_summary_lsa_refresh(struct ospf *ospf,
+ struct ospf_lsa *lsa);
+static struct ospf_lsa *
+ospf_asbr_summary_lsa_prepare_and_flood(struct prefix_ipv4 *p, uint32_t metric,
+ struct ospf_area *area,
+ struct in_addr id);
+static struct ospf_lsa *ospf_summary_asbr_lsa_refresh(struct ospf *ospf,
+ struct ospf_lsa *lsa);
+static struct ospf_lsa *ospf_handle_exnl_lsa_lsId_chg(struct ospf *ospf,
+ struct external_info *ei,
+ struct in_addr id);
+static struct ospf_lsa *
+ospf_exnl_lsa_prepare_and_flood(struct ospf *ospf, struct external_info *ei,
+ struct in_addr id);
+
uint32_t get_metric(uint8_t *metric)
{
uint32_t m;
}
/* Originate Summary-LSA. */
-struct ospf_lsa *ospf_summary_lsa_originate(struct prefix_ipv4 *p,
- uint32_t metric,
- struct ospf_area *area)
+static struct ospf_lsa *
+ospf_summary_lsa_prepare_and_flood(struct prefix_ipv4 *p, uint32_t metric,
+ struct ospf_area *area, struct in_addr id)
{
struct ospf_lsa *new;
- struct in_addr id;
-
- if (area->ospf->gr_info.restart_in_progress) {
- if (IS_DEBUG_OSPF(lsa, LSA_GENERATE))
- zlog_debug(
- "LSA[Type%d]: Graceful Restart in progress, don't originate",
- OSPF_SUMMARY_LSA);
- return NULL;
- }
-
- id = ospf_lsa_unique_id(area->ospf, area->lsdb, OSPF_SUMMARY_LSA, p);
-
- if (id.s_addr == 0xffffffff) {
- /* Maybe Link State ID not available. */
- if (IS_DEBUG_OSPF(lsa, LSA_GENERATE))
- zlog_debug(
- "LSA[Type%d]: Link ID not available, can't originate",
- OSPF_SUMMARY_LSA);
- return NULL;
- }
/* Create new summary-LSA instance. */
if (!(new = ospf_summary_lsa_new(area, (struct prefix *)p, metric, id)))
return new;
}
+static struct ospf_lsa *ospf_handle_summarylsa_lsId_chg(struct ospf *ospf,
+ struct prefix_ipv4 *p,
+ uint8_t type,
+ uint32_t metric,
+ struct in_addr old_id)
+{
+ struct ospf_lsa *lsa = NULL;
+ struct ospf_lsa *new = NULL;
+ struct summary_lsa *sl = NULL;
+ struct ospf_area *old_area = NULL;
+ struct prefix_ipv4 old_prefix;
+ uint32_t old_metric;
+ struct in_addr mask;
+ uint32_t metric_val;
+ char *metric_buf;
+
+ lsa = ospf_lsdb_lookup_by_id(ospf->lsdb, type, p->prefix,
+ ospf->router_id);
+
+ if (!lsa) {
+ flog_warn(EC_OSPF_LSA_NULL, "(%s): LSA not found", __func__);
+ return NULL;
+ }
+
+ sl = (struct summary_lsa *)lsa->data;
+
+ old_area = lsa->area;
+ old_metric = GET_METRIC(sl->metric);
+ old_prefix.prefix = sl->header.id;
+ old_prefix.prefixlen = ip_masklen(sl->mask);
+ old_prefix.family = AF_INET;
+
+
+ /* change the mask */
+ masklen2ip(p->prefixlen, &mask);
+ sl->mask.s_addr = mask.s_addr;
+
+ /* Copy the metric*/
+ metric_val = htonl(metric);
+ metric_buf = (char *)&metric_val;
+ memcpy(sl->metric, metric_buf, sizeof(metric_val));
+
+ if (type == OSPF_SUMMARY_LSA) {
+ /*Refresh the LSA with new LSA*/
+ ospf_summary_lsa_refresh(ospf, lsa);
+
+ new = ospf_summary_lsa_prepare_and_flood(
+ &old_prefix, old_metric, old_area, old_id);
+ } else {
+ /*Refresh the LSA with new LSA*/
+ ospf_summary_asbr_lsa_refresh(ospf, lsa);
+
+ new = ospf_asbr_summary_lsa_prepare_and_flood(
+ &old_prefix, old_metric, old_area, old_id);
+ }
+
+ return new;
+}
+
+/* Originate Summary-LSA. */
+struct ospf_lsa *ospf_summary_lsa_originate(struct prefix_ipv4 *p,
+ uint32_t metric,
+ struct ospf_area *area)
+{
+ struct in_addr id;
+ enum lsid_status status;
+ struct ospf_lsa *new = NULL;
+
+ status = ospf_lsa_unique_id(area->ospf, area->lsdb, OSPF_SUMMARY_LSA, p,
+ &id);
+
+ if (status == LSID_CHANGE) {
+ if (IS_DEBUG_OSPF(lsa, LSA_GENERATE))
+ zlog_debug("Link ID has to be changed.");
+
+ new = ospf_handle_summarylsa_lsId_chg(
+ area->ospf, p, OSPF_SUMMARY_LSA, metric, id);
+ return new;
+ } else if (status == LSID_NOT_AVAILABLE) {
+ /* Link State ID not available. */
+ if (IS_DEBUG_OSPF(lsa, LSA_GENERATE))
+ zlog_debug(
+ "LSA[Type5]: Link ID not available, can't originate");
+
+ return NULL;
+ }
+
+ new = ospf_summary_lsa_prepare_and_flood(p, metric, area, id);
+ return new;
+}
+
static struct ospf_lsa *ospf_summary_lsa_refresh(struct ospf *ospf,
struct ospf_lsa *lsa)
{
}
/* Originate summary-ASBR-LSA. */
-struct ospf_lsa *ospf_summary_asbr_lsa_originate(struct prefix_ipv4 *p,
- uint32_t metric,
- struct ospf_area *area)
+static struct ospf_lsa *
+ospf_asbr_summary_lsa_prepare_and_flood(struct prefix_ipv4 *p, uint32_t metric,
+ struct ospf_area *area,
+ struct in_addr id)
{
struct ospf_lsa *new;
- struct in_addr id;
-
- if (area->ospf->gr_info.restart_in_progress) {
- if (IS_DEBUG_OSPF(lsa, LSA_GENERATE))
- zlog_debug(
- "LSA[Type%d]: Graceful Restart in progress, don't originate",
- OSPF_ASBR_SUMMARY_LSA);
- return NULL;
- }
-
- id = ospf_lsa_unique_id(area->ospf, area->lsdb, OSPF_ASBR_SUMMARY_LSA,
- p);
-
- if (id.s_addr == 0xffffffff) {
- /* Maybe Link State ID not available. */
- if (IS_DEBUG_OSPF(lsa, LSA_GENERATE))
- zlog_debug(
- "LSA[Type%d]: Link ID not available, can't originate",
- OSPF_ASBR_SUMMARY_LSA);
- return NULL;
- }
/* Create new summary-LSA instance. */
new = ospf_summary_asbr_lsa_new(area, (struct prefix *)p, metric, id);
return new;
}
+struct ospf_lsa *ospf_summary_asbr_lsa_originate(struct prefix_ipv4 *p,
+ uint32_t metric,
+ struct ospf_area *area)
+{
+ struct ospf_lsa *new;
+ struct in_addr id;
+ enum lsid_status status;
+
+ status = ospf_lsa_unique_id(area->ospf, area->lsdb,
+ OSPF_ASBR_SUMMARY_LSA, p, &id);
+
+ if (status == LSID_CHANGE) {
+ if (IS_DEBUG_OSPF(lsa, LSA_GENERATE))
+ zlog_debug("Link ID has to be changed.");
+
+ new = ospf_handle_summarylsa_lsId_chg(
+ area->ospf, p, OSPF_ASBR_SUMMARY_LSA, metric, id);
+ return new;
+ } else if (status == LSID_NOT_AVAILABLE) {
+ /* Link State ID not available. */
+ if (IS_DEBUG_OSPF(lsa, LSA_GENERATE))
+ zlog_debug(
+ "LSA[Type5]: Link ID not available, can't originate");
+
+ return NULL;
+ }
+
+ new = ospf_asbr_summary_lsa_prepare_and_flood(p, metric, area, id);
+ return new;
+}
+
static struct ospf_lsa *ospf_summary_asbr_lsa_refresh(struct ospf *ospf,
struct ospf_lsa *lsa)
{
}
/* Create new external-LSA. */
-static struct ospf_lsa *ospf_external_lsa_new(struct ospf *ospf,
- struct external_info *ei,
- struct in_addr *old_id)
+static struct ospf_lsa *
+ospf_exnl_lsa_prepare_and_flood(struct ospf *ospf, struct external_info *ei,
+ struct in_addr id)
{
struct stream *s;
struct lsa_header *lsah;
struct ospf_lsa *new;
- struct in_addr id;
int length;
- if (ei == NULL) {
- if (IS_DEBUG_OSPF(lsa, LSA_GENERATE))
- zlog_debug(
- "LSA[Type5]: External info is NULL, can't originate");
- return NULL;
- }
-
- if (IS_DEBUG_OSPF(lsa, LSA_GENERATE))
- zlog_debug("LSA[Type5]: Originate AS-external-LSA instance");
-
- /* If old Link State ID is specified, refresh LSA with same ID. */
- if (old_id)
- id = *old_id;
- /* Get Link State with unique ID. */
- else {
- id = ospf_lsa_unique_id(ospf, ospf->lsdb, OSPF_AS_EXTERNAL_LSA,
- &ei->p);
- if (id.s_addr == 0xffffffff) {
- /* Maybe Link State ID not available. */
- if (IS_DEBUG_OSPF(lsa, LSA_GENERATE))
- zlog_debug(
- "LSA[Type5]: Link ID not available, can't originate");
- return NULL;
- }
- }
-
/* Create new stream for LSA. */
s = stream_new(OSPF_MAX_LSA_SIZE);
lsah = (struct lsa_header *)STREAM_DATA(s);
return new;
}
+static struct ospf_lsa *ospf_handle_exnl_lsa_lsId_chg(struct ospf *ospf,
+ struct external_info *ei,
+ struct in_addr id)
+{
+ struct ospf_lsa *lsa;
+ struct as_external_lsa *al;
+ struct in_addr mask;
+ struct ospf_lsa *new;
+ struct external_info ei_summary;
+ struct external_info *ei_old;
+
+ lsa = ospf_lsdb_lookup_by_id(ospf->lsdb, OSPF_AS_EXTERNAL_LSA,
+ ei->p.prefix, ospf->router_id);
+
+ if (!lsa) {
+ flog_warn(EC_OSPF_LSA_NULL, "(%s): LSA not found", __func__);
+ return NULL;
+ }
+
+ ei_old = ospf_external_info_check(ospf, lsa);
+
+ al = (struct as_external_lsa *)lsa->data;
+
+ if (!ei_old) {
+ /* eii_old pointer of LSA is NULL, this
+ * must be external aggregate route.
+ */
+ ei_summary.p.family = AF_INET;
+ ei_summary.p.prefix = al->header.id;
+ ei_summary.p.prefixlen = ip_masklen(al->mask);
+ ei_summary.tag = (unsigned long)ntohl(al->e[0].route_tag);
+ ei_old = &ei_summary;
+ }
+
+ /* change the mask */
+ masklen2ip(ei->p.prefixlen, &mask);
+ al->mask.s_addr = mask.s_addr;
+
+ /*Refresh the LSA with new LSA*/
+ ospf_external_lsa_refresh(ospf, lsa, ei, LSA_REFRESH_FORCE, 0);
+
+ /*Originate the old LSA with changed LSID*/
+ new = ospf_exnl_lsa_prepare_and_flood(ospf, ei_old, id);
+
+ return new;
+}
+
+static struct ospf_lsa *ospf_external_lsa_new(struct ospf *ospf,
+ struct external_info *ei,
+ struct in_addr *old_id)
+{
+ struct ospf_lsa *new;
+ struct in_addr id;
+ enum lsid_status status;
+
+ if (ei == NULL) {
+ if (IS_DEBUG_OSPF(lsa, LSA_GENERATE))
+ zlog_debug(
+ "LSA[Type5]: External info is NULL, can't originate");
+ return NULL;
+ }
+
+ if (IS_DEBUG_OSPF(lsa, LSA_GENERATE))
+ zlog_debug("LSA[Type5]: Originate AS-external-LSA instance");
+
+ /* If old Link State ID is specified, refresh LSA with same ID. */
+ if (old_id)
+ id = *old_id;
+ /* Get Link State with unique ID. */
+ else {
+ status = ospf_lsa_unique_id(ospf, ospf->lsdb,
+ OSPF_AS_EXTERNAL_LSA, &ei->p, &id);
+
+ if (status == LSID_CHANGE) {
+ if (IS_DEBUG_OSPF(lsa, LSA_GENERATE))
+ zlog_debug("Link ID has to be changed.");
+
+ new = ospf_handle_exnl_lsa_lsId_chg(ospf, ei, id);
+ return new;
+ } else if (status == LSID_NOT_AVAILABLE) {
+ /* Link State ID not available. */
+ if (IS_DEBUG_OSPF(lsa, LSA_GENERATE))
+ zlog_debug(
+ "LSA[Type5]: Link ID not available, can't originate");
+ return NULL;
+ }
+ }
+
+ new = ospf_exnl_lsa_prepare_and_flood(ospf, ei, id);
+
+ return new;
+}
+
/* As Type-7 */
static void ospf_install_flood_nssa(struct ospf *ospf, struct ospf_lsa *lsa,
struct external_info *ei)
struct prefix lsa_prefix;
memset(&lsa_prefix, 0, sizeof(struct prefix));
- lsa_prefix.family = 0;
+ lsa_prefix.family = AF_UNSPEC;
lsa_prefix.prefixlen = sizeof(lsa_prefix.u.ptr) * CHAR_BIT;
lsa_prefix.u.ptr = (uintptr_t)lsa;
}
memset(&lsa_prefix, 0, sizeof(struct prefix));
- lsa_prefix.family = 0;
+ lsa_prefix.family = AF_UNSPEC;
lsa_prefix.prefixlen = sizeof(lsa_prefix.u.ptr) * CHAR_BIT;
lsa_prefix.u.ptr = (uintptr_t)lsa;
}
/* Get unique Link State ID. */
-struct in_addr ospf_lsa_unique_id(struct ospf *ospf, struct ospf_lsdb *lsdb,
- uint8_t type, struct prefix_ipv4 *p)
+enum lsid_status ospf_lsa_unique_id(struct ospf *ospf, struct ospf_lsdb *lsdb,
+ uint8_t type, struct prefix_ipv4 *p,
+ struct in_addr *id)
{
struct ospf_lsa *lsa;
- struct in_addr mask, id;
+ struct in_addr mask;
- id = p->prefix;
+ *id = p->prefix;
/* Check existence of LSA instance. */
- lsa = ospf_lsdb_lookup_by_id(lsdb, type, id, ospf->router_id);
+ lsa = ospf_lsdb_lookup_by_id(lsdb, type, *id, ospf->router_id);
if (lsa) {
struct as_external_lsa *al =
(struct as_external_lsa *)lsa->data;
+ /* Ref rfc2328,Appendex E.1
+ * If router already originated the external lsa with lsid
+ * as the current prefix, and the masklens are same then
+ * terminate the LSID algorithem.
+ */
if (ip_masklen(al->mask) == p->prefixlen) {
if (IS_DEBUG_OSPF(lsa, LSA_GENERATE))
zlog_debug(
- "ospf_lsa_unique_id(): Can't get Link State ID for %pFX",
- p);
+ "%s: Can't get Link State ID for %pFX",
+ __func__, p);
/* id.s_addr = 0; */
- id.s_addr = 0xffffffff;
- return id;
- }
- /* Masklen differs, then apply wildcard mask to Link State ID.
- */
- else {
+ id->s_addr = 0xffffffff;
+ return LSID_NOT_AVAILABLE;
+ } else if (ip_masklen(al->mask) < p->prefixlen) {
+ /* Ref rfc2328,Appendex E.2
+ * the current prefix masklen is greater than the
+ * existing LSA, then generate the Link state ID,
+ * by setting all host bits in prefix addressa and
+ * originate.
+ *
+ * Eg: 1st Route : 10.0.0.0/16 - LSID:10.0.0.0
+ * 2nd Route : 10.0.0.0/24 - LSID:10.0.0.255
+ */
masklen2ip(p->prefixlen, &mask);
- id.s_addr = p->prefix.s_addr | (~mask.s_addr);
- lsa = ospf_lsdb_lookup_by_id(ospf->lsdb, type, id,
+ id->s_addr = p->prefix.s_addr | (~mask.s_addr);
+ lsa = ospf_lsdb_lookup_by_id(ospf->lsdb, type, *id,
ospf->router_id);
if (lsa) {
if (IS_DEBUG_OSPF(lsa, LSA_GENERATE))
zlog_debug(
- "ospf_lsa_unique_id(): Can't get Link State ID for %pFX",
- p);
- /* id.s_addr = 0; */
- id.s_addr = 0xffffffff;
- return id;
+ "%s: Can't get Link State ID for %pFX",
+ __func__, p);
+ id->s_addr = 0xffffffff;
+ return LSID_NOT_AVAILABLE;
+ }
+ } else {
+ /* Ref rfc2328,Appendex E.3
+ * the current prefix masklen is lesser than the
+ * existing LSA,then the originated LSA has to be
+ * refreshed by modifying masklen, cost and tag.
+ * Originate the old route info with new LSID by
+ * setting the host bits in prefix address.
+ *
+ * Eg: 1st Route : 10.0.0.0/24 - LSID:10.0.0.0
+ * 2nd Route : 10.0.0.0/16 - ?
+ * Since 2nd route mask len is less than firstone
+ * LSID has to be changed.
+ * 1st route LSID:10.0.0.255
+ * 2nd route LSID:10.0.0.0
+ */
+ id->s_addr = lsa->data->id.s_addr | (~al->mask.s_addr);
+ lsa = ospf_lsdb_lookup_by_id(ospf->lsdb, type, *id,
+ ospf->router_id);
+ if (lsa && (ip_masklen(al->mask) != IPV4_MAX_BITLEN)) {
+ if (IS_DEBUG_OSPF(lsa, LSA_GENERATE))
+ zlog_debug(
+ "%s: Can't get Link State ID for %pFX",
+ __func__, p);
+ id->s_addr = 0xffffffff;
+ return LSID_NOT_AVAILABLE;
}
+ return LSID_CHANGE;
}
}
- return id;
+ return LSID_AVAILABLE;
}
} e[1];
};
+enum lsid_status { LSID_AVAILABLE = 0, LSID_CHANGE, LSID_NOT_AVAILABLE };
+
#include "ospfd/ospf_opaque.h"
/* Macros. */
struct ospf_lsa *,
struct external_info *, int,
bool aggr);
-extern struct in_addr ospf_lsa_unique_id(struct ospf *, struct ospf_lsdb *,
- uint8_t, struct prefix_ipv4 *);
+extern enum lsid_status ospf_lsa_unique_id(struct ospf *ospf,
+ struct ospf_lsdb *lsdb,
+ uint8_t type, struct prefix_ipv4 *p,
+ struct in_addr *addr);
extern void ospf_schedule_lsa_flood_area(struct ospf_area *, struct ospf_lsa *);
extern void ospf_schedule_lsa_flush_area(struct ospf_area *, struct ospf_lsa *);
void ls_prefix_set(struct prefix_ls *lp, struct ospf_lsa *lsa)
{
if (lp && lsa && lsa->data) {
- lp->family = 0;
+ lp->family = AF_UNSPEC;
lp->prefixlen = 64;
lp->id = lsa->data->id;
lp->adv_router = lsa->data->adv_router;
table = lsdb->type[type].db;
memset(&lp, 0, sizeof(struct prefix_ls));
- lp.family = 0;
+ lp.family = AF_UNSPEC;
lp.prefixlen = 64;
lp.id = id;
lp.adv_router = adv_router;
table = lsdb->type[type].db;
memset(&lp, 0, sizeof(struct prefix_ls));
- lp.family = 0;
+ lp.family = AF_UNSPEC;
lp.prefixlen = 64;
lp.id = id;
lp.adv_router = adv_router;
struct route_node *rn;
memset(&lp, 0, sizeof(struct prefix_ls));
- lp.family = 0;
+ lp.family = AF_UNSPEC;
lp.prefixlen = 64;
lp.id = vl_data->vl_area_id;
lp.adv_router = vl_data->vl_peer;
struct route_node *rn;
memset(&lp, 0, sizeof(struct prefix_ls));
- lp.family = 0;
+ lp.family = AF_UNSPEC;
lp.prefixlen = 64;
lp.id = vl_data->vl_area_id;
lp.adv_router = vl_data->vl_peer;
struct ospf_vl_data *vl_data;
memset(&lp, 0, sizeof(struct prefix_ls));
- lp.family = 0;
+ lp.family = AF_UNSPEC;
lp.prefixlen = 64;
lp.id = *area_id;
lp.adv_router = *neighbor;
struct ospf_vl_data *vl_data;
memset(&lp, 0, sizeof(struct prefix_ls));
- lp.family = 0;
+ lp.family = AF_UNSPEC;
lp.prefixlen = 64;
lp.id = *area_id;
lp.adv_router = *neighbor;
struct in_addr *id, struct in_addr *adv_router)
{
memset(lp, 0, sizeof(struct prefix_ls));
- lp->family = 0;
+ lp->family = AF_UNSPEC;
if (id == NULL)
lp->prefixlen = 0;
else if (adv_router == NULL) {
uint32_t bsr_prio)
{
if (bsr.s_addr != pim->global_scope.current_bsr.s_addr) {
- if (pim->global_scope.current_bsr.s_addr)
- pim_nht_bsr_del(pim, pim->global_scope.current_bsr);
+ pim_nht_bsr_del(pim, pim->global_scope.current_bsr);
pim_nht_bsr_add(pim, bsr);
pim->global_scope.current_bsr = bsr;
struct rp_info *rp_info;
bool upstream_updated = false;
- if (pim->global_scope.current_bsr.s_addr)
- pim_nht_bsr_del(pim, pim->global_scope.current_bsr);
+ pim_nht_bsr_del(pim, pim->global_scope.current_bsr);
/* Reset scope zone data */
pim->global_scope.accept_nofwd_bsm = false;
continue;
RB_FOREACH (ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) {
+ if (ch->ifassert_state == PIM_IFASSERT_NOINFO)
+ continue;
+
pim_show_assert_helper(vty, pim_ifp, ch, now);
} /* scan interface channels */
}
struct pim_nexthop_cache *pnc = NULL;
struct pim_nexthop_cache lookup;
+ /*
+ * Nothing to do here if the address to unregister
+ * is 0.0.0.0 as that the BSR has not been registered
+ * for tracking yet.
+ */
+ if (addr.s_addr == INADDR_ANY)
+ return;
+
lookup.rpf.rpf_addr.family = AF_INET;
lookup.rpf.rpf_addr.prefixlen = IPV4_MAX_BITLEN;
lookup.rpf.rpf_addr.u.prefix4 = addr;
#include "vrf.h"
#include "zclient.h"
#include "nexthop_group.h"
+#include "linklist.h"
#include "link_state.h"
+#include "cspf.h"
#include "sharpd/sharp_globals.h"
#include "sharpd/sharp_zebra.h"
End_X$seg6l_endx X:X::X:X$seg6l_endx_nh6|\
End_T$seg6l_endt (1-4294967295)$seg6l_endt_table|\
End_DX4$seg6l_enddx4 A.B.C.D$seg6l_enddx4_nh4|\
- End_DT6$seg6l_enddt6 (1-4294967295)$seg6l_enddt6_table>\
+ End_DT6$seg6l_enddt6 (1-4294967295)$seg6l_enddt6_table|\
+ End_DT4$seg6l_enddt4 (1-4294967295)$seg6l_enddt4_table>\
(1-1000000)$routes [repeat (2-1000)$rpt]",
"Sharp routing Protocol\n"
"install some routes\n"
"V4 Nexthop address to use\n"
"SRv6 End.DT6 function to use\n"
"Redirect table id to use\n"
+ "SRv6 End.DT4 function to use\n"
+ "Redirect table id to use\n"
"How many to create\n"
"Should we repeat this command\n"
"How many times to repeat this command\n")
} else if (seg6l_enddt6) {
action = ZEBRA_SEG6_LOCAL_ACTION_END_DT6;
ctx.table = seg6l_enddt6_table;
+ } else if (seg6l_enddt4) {
+ action = ZEBRA_SEG6_LOCAL_ACTION_END_DT4;
+ ctx.table = seg6l_enddt4_table;
} else {
action = ZEBRA_SEG6_LOCAL_ACTION_END;
}
return CMD_SUCCESS;
}
+DEFPY (show_sharp_cspf,
+ show_sharp_cspf_cmd,
+ "show sharp cspf source <A.B.C.D$src4|X:X::X:X$src6> \
+ destination <A.B.C.D$dst4|X:X::X:X$dst6> \
+ <metric|te-metric|delay> (0-16777215)$cost \
+ [rsv-bw (0-7)$cos BANDWIDTH$bw]",
+ SHOW_STR
+ SHARP_STR
+ "Constraint Shortest Path First path computation\n"
+ "Source of the path\n"
+ "IPv4 Source address in dot decimal A.B.C.D\n"
+ "IPv6 Source address as X:X:X:X\n"
+ "Destination of the path\n"
+ "IPv4 Destination address in dot decimal A.B.C.D\n"
+ "IPv6 Destination address as X:X:X:X\n"
+ "Maximum Metric\n"
+ "Maximum TE Metric\n"
+ "Maxim Delay\n"
+ "Value of Maximum cost\n"
+ "Reserved Bandwidth of this path\n"
+ "Class of Service or Priority level\n"
+ "Bytes/second (IEEE floating point format)\n")
+{
+
+ struct cspf *algo;
+ struct constraints csts;
+ struct c_path *path;
+ struct listnode *node;
+ struct ls_edge *edge;
+ int idx;
+
+ if (sg.ted == NULL) {
+ vty_out(vty, "MPLS-TE import is not enabled\n");
+ return CMD_WARNING;
+ }
+
+ if ((src4.s_addr != INADDR_ANY && dst4.s_addr == INADDR_ANY) ||
+ (src4.s_addr == INADDR_ANY && dst4.s_addr != INADDR_ANY)) {
+ vty_out(vty, "Don't mix IPv4 and IPv6 addresses\n");
+ return CMD_WARNING;
+ }
+
+ idx = 6;
+ memset(&csts, 0, sizeof(struct constraints));
+ if (argv_find(argv, argc, "metric", &idx)) {
+ csts.ctype = CSPF_METRIC;
+ csts.cost = cost;
+ }
+ idx = 6;
+ if (argv_find(argv, argc, "te-metric", &idx)) {
+ csts.ctype = CSPF_TE_METRIC;
+ csts.cost = cost;
+ }
+ idx = 6;
+ if (argv_find(argv, argc, "delay", &idx)) {
+ csts.ctype = CSPF_DELAY;
+ csts.cost = cost;
+ }
+ if (argc > 9) {
+ if (sscanf(bw, "%g", &csts.bw) != 1) {
+ vty_out(vty, "Bandwidth constraints: fscanf: %s\n",
+ safe_strerror(errno));
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+ csts.cos = cos;
+ }
+
+ /* Initialize and call point-to-point Path computation */
+ if (src4.s_addr != INADDR_ANY)
+ algo = cspf_init_v4(NULL, sg.ted, src4, dst4, &csts);
+ else
+ algo = cspf_init_v6(NULL, sg.ted, src6, dst6, &csts);
+ path = compute_p2p_path(algo, sg.ted);
+ cspf_del(algo);
+
+ if (!path) {
+ vty_out(vty, "Path computation failed without error\n");
+ return CMD_SUCCESS;
+ }
+ if (path->status != SUCCESS) {
+ vty_out(vty, "Path computation failed: %d\n", path->status);
+ return CMD_SUCCESS;
+ }
+
+ vty_out(vty, "Path computation success\n");
+ vty_out(vty, "\tCost: %d\n", path->weight);
+ vty_out(vty, "\tEdges:");
+ for (ALL_LIST_ELEMENTS_RO(path->edges, node, edge)) {
+ if (src4.s_addr != INADDR_ANY)
+ vty_out(vty, " %pI4",
+ &edge->attributes->standard.remote);
+ else
+ vty_out(vty, " %pI6",
+ &edge->attributes->standard.remote6);
+ }
+ vty_out(vty, "\n");
+
+ return CMD_SUCCESS;
+}
+
void sharp_vty_init(void)
{
install_element(ENABLE_NODE, &install_routes_data_dump_cmd);
install_element(ENABLE_NODE, &show_debugging_sharpd_cmd);
install_element(ENABLE_NODE, &show_sharp_ted_cmd);
+ install_element(ENABLE_NODE, &show_sharp_cspf_cmd);
install_element(ENABLE_NODE, &sharp_srv6_manager_get_locator_chunk_cmd);
install_element(ENABLE_NODE,
if (info.type == LINK_STATE_UPDATE) {
lse = ls_stream2ted(sg.ted, s, false);
- if (lse)
+ if (lse) {
zlog_debug(" |- Got %s %s from Link State Database",
status2txt[lse->status],
type2txt[lse->type]);
+ lse->status = SYNC;
+ }
else
zlog_debug(
"%s: Error to convert Stream into Link State",
--- /dev/null
+frr defaults traditional
+!
+hostname ce1
+password zebra
+!
+log stdout notifications
+log commands
+log file bgpd.log
--- /dev/null
+{
+ "0.0.0.0/0": [
+ {
+ "prefix": "0.0.0.0/0",
+ "protocol": "static",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 1,
+ "metric": 0,
+ "installed": true,
+ "table": 254,
+ "internalStatus": 16,
+ "internalFlags": 73,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "ip": "192.168.1.1",
+ "afi": "ipv4",
+ "interfaceName": "eth0",
+ "active": true,
+ "weight": 1
+ }
+ ]
+ }
+ ],
+ "192.168.1.0/24": [
+ {
+ "prefix": "192.168.1.0/24",
+ "protocol": "connected",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 0,
+ "metric": 0,
+ "installed": true,
+ "table": 254,
+ "internalStatus": 16,
+ "internalFlags": 8,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "eth0",
+ "active": true
+ }
+ ]
+ }
+ ]
+}
--- /dev/null
+log file zebra.log
+!
+hostname ce1
+!
+interface eth0
+ ip address 192.168.1.2/24
+!
+ip forwarding
+ipv6 forwarding
+!
+ip route 0.0.0.0/0 192.168.1.1
+!
+line vty
+!
--- /dev/null
+frr defaults traditional
+!
+hostname ce2
+password zebra
+!
+log stdout notifications
+log commands
+log file bgpd.log
--- /dev/null
+{
+ "0.0.0.0/0": [
+ {
+ "prefix": "0.0.0.0/0",
+ "protocol": "static",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 1,
+ "metric": 0,
+ "installed": true,
+ "table": 254,
+ "internalStatus": 16,
+ "internalFlags": 73,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "ip": "192.168.2.1",
+ "afi": "ipv4",
+ "interfaceName": "eth0",
+ "active": true,
+ "weight": 1
+ }
+ ]
+ }
+ ],
+ "192.168.2.0/24": [
+ {
+ "prefix": "192.168.2.0/24",
+ "protocol": "connected",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 0,
+ "metric": 0,
+ "installed": true,
+ "table": 254,
+ "internalStatus": 16,
+ "internalFlags": 8,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "eth0",
+ "active": true
+ }
+ ]
+ }
+ ]
+}
--- /dev/null
+log file zebra.log
+!
+hostname ce2
+!
+interface eth0
+ ip address 192.168.2.2/24
+!
+ip forwarding
+ipv6 forwarding
+!
+ip route 0.0.0.0/0 192.168.2.1
+!
+line vty
+!
--- /dev/null
+frr defaults traditional
+!
+hostname ce3
+password zebra
+!
+log stdout notifications
+log commands
+log file bgpd.log
--- /dev/null
+{
+ "0.0.0.0/0": [
+ {
+ "prefix": "0.0.0.0/0",
+ "protocol": "static",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 1,
+ "metric": 0,
+ "installed": true,
+ "table": 254,
+ "internalStatus": 16,
+ "internalFlags": 73,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "ip": "192.168.3.1",
+ "afi": "ipv4",
+ "interfaceName": "eth0",
+ "active": true,
+ "weight": 1
+ }
+ ]
+ }
+ ],
+ "192.168.3.0/24": [
+ {
+ "prefix": "192.168.3.0/24",
+ "protocol": "connected",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 0,
+ "metric": 0,
+ "installed": true,
+ "table": 254,
+ "internalStatus": 16,
+ "internalFlags": 8,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "eth0",
+ "active": true
+ }
+ ]
+ }
+ ]
+}
--- /dev/null
+log file zebra.log
+!
+hostname ce3
+!
+interface eth0
+ ip address 192.168.3.2/24
+!
+ip forwarding
+ipv6 forwarding
+!
+ip route 0.0.0.0/0 192.168.3.1
+!
+line vty
+!
--- /dev/null
+frr defaults traditional
+!
+hostname ce4
+password zebra
+!
+log stdout notifications
+log commands
+log file bgpd.log
--- /dev/null
+{
+ "0.0.0.0/0": [
+ {
+ "prefix": "0.0.0.0/0",
+ "protocol": "static",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 1,
+ "metric": 0,
+ "installed": true,
+ "table": 254,
+ "internalStatus": 16,
+ "internalFlags": 73,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "ip": "192.168.4.1",
+ "afi": "ipv4",
+ "interfaceName": "eth0",
+ "active": true,
+ "weight": 1
+ }
+ ]
+ }
+ ],
+ "192.168.4.0/24": [
+ {
+ "prefix": "192.168.4.0/24",
+ "protocol": "connected",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 0,
+ "metric": 0,
+ "installed": true,
+ "table": 254,
+ "internalStatus": 16,
+ "internalFlags": 8,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "eth0",
+ "active": true
+ }
+ ]
+ }
+ ]
+}
--- /dev/null
+log file zebra.log
+!
+hostname ce4
+!
+interface eth0
+ ip address 192.168.4.2/24
+!
+ip forwarding
+ipv6 forwarding
+!
+ip route 0.0.0.0/0 192.168.4.1
+!
+line vty
+!
--- /dev/null
+frr defaults traditional
+!
+hostname ce5
+password zebra
+!
+log stdout notifications
+log commands
+log file bgpd.log
--- /dev/null
+{
+ "0.0.0.0/0": [
+ {
+ "prefix": "0.0.0.0/0",
+ "protocol": "static",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 1,
+ "metric": 0,
+ "installed": true,
+ "table": 254,
+ "internalStatus": 16,
+ "internalFlags": 73,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "ip": "192.168.5.1",
+ "afi": "ipv4",
+ "interfaceName": "eth0",
+ "active": true,
+ "weight": 1
+ }
+ ]
+ }
+ ],
+ "192.168.5.0/24": [
+ {
+ "prefix": "192.168.5.0/24",
+ "protocol": "connected",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 0,
+ "metric": 0,
+ "installed": true,
+ "table": 254,
+ "internalStatus": 16,
+ "internalFlags": 8,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "eth0",
+ "active": true
+ }
+ ]
+ }
+ ]
+}
--- /dev/null
+log file zebra.log
+!
+hostname ce5
+!
+interface eth0
+ ip address 192.168.5.2/24
+!
+ip forwarding
+ipv6 forwarding
+!
+ip route 0.0.0.0/0 192.168.5.1
+!
+line vty
+!
--- /dev/null
+frr defaults traditional
+!
+hostname ce6
+password zebra
+!
+log stdout notifications
+log commands
+log file bgpd.log
--- /dev/null
+{
+ "0.0.0.0/0": [
+ {
+ "prefix": "0.0.0.0/0",
+ "protocol": "static",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 1,
+ "metric": 0,
+ "installed": true,
+ "table": 254,
+ "internalStatus": 16,
+ "internalFlags": 73,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "ip": "192.168.6.1",
+ "afi": "ipv4",
+ "interfaceName": "eth0",
+ "active": true,
+ "weight": 1
+ }
+ ]
+ }
+ ],
+ "192.168.6.0/24": [
+ {
+ "prefix": "192.168.6.0/24",
+ "protocol": "connected",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 0,
+ "metric": 0,
+ "installed": true,
+ "table": 254,
+ "internalStatus": 16,
+ "internalFlags": 8,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "eth0",
+ "active": true
+ }
+ ]
+ }
+ ]
+}
--- /dev/null
+log file zebra.log
+!
+hostname ce6
+!
+interface eth0
+ ip address 192.168.6.2/24
+!
+ip forwarding
+ipv6 forwarding
+!
+ip route 0.0.0.0/0 192.168.6.1
+!
+line vty
+!
--- /dev/null
+frr defaults traditional
+!
+hostname r1
+password zebra
+!
+log stdout notifications
+log monitor notifications
+log commands
+!
+!debug bgp neighbor-events
+!debug bgp zebra
+!debug bgp vnc verbose
+!debug bgp update-groups
+!debug bgp updates in
+!debug bgp updates out
+!debug bgp vpn label
+!debug bgp vpn leak-from-vrf
+!debug bgp vpn leak-to-vrf
+!debug bgp vpn rmap-event
+!
+router bgp 1
+ bgp router-id 1.1.1.1
+ no bgp ebgp-requires-policy
+ no bgp default ipv4-unicast
+ neighbor 2001::2 remote-as 2
+ neighbor 2001::2 timers 3 10
+ neighbor 2001::2 timers connect 1
+ neighbor 2001::2 capability extended-nexthop
+ !
+ address-family ipv4 vpn
+ neighbor 2001::2 activate
+ exit-address-family
+ !
+ segment-routing srv6
+ locator loc1
+ !
+!
+router bgp 1 vrf vrf10
+ bgp router-id 1.1.1.1
+ no bgp ebgp-requires-policy
+ !
+ address-family ipv4 unicast
+ sid vpn export auto
+ nexthop vpn export 2001::1
+ rd vpn export 1:10
+ rt vpn both 99:99
+ import vpn
+ export vpn
+ redistribute connected
+ !
+ exit-address-family
+!
+router bgp 1 vrf vrf20
+ bgp router-id 1.1.1.1
+ no bgp ebgp-requires-policy
+ !
+ address-family ipv4 unicast
+ sid vpn export auto
+ nexthop vpn export 2001::1
+ rd vpn export 1:20
+ rt vpn both 88:88
+ import vpn
+ export vpn
+ redistribute connected
+ exit-address-family
+!
--- /dev/null
+{
+ "vrfId": 0,
+ "vrfName": "default",
+ "tableVersion": 2,
+ "routerId": "1.1.1.1",
+ "defaultLocPrf": 100,
+ "localAS": 1,
+ "routes": {
+ "routeDistinguishers": {
+ "1:10": {
+ "192.168.1.0/24": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "192.168.1.0",
+ "prefixLen": 24,
+ "network": "192.168.1.0/24",
+ "metric": 0,
+ "weight": 32768,
+ "peerId": "(unspec)",
+ "path": "",
+ "origin": "incomplete",
+ "nhVrfName": "vrf10",
+ "nexthops": [
+ {
+ "ip": "2001::1",
+ "hostname": "r1",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "192.168.3.0/24": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "192.168.3.0",
+ "prefixLen": 24,
+ "network": "192.168.3.0/24",
+ "metric": 0,
+ "weight": 32768,
+ "peerId": "(unspec)",
+ "path": "",
+ "origin": "incomplete",
+ "nhVrfName": "vrf10",
+ "nexthops": [
+ {
+ "ip": "2001::1",
+ "hostname": "r1",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ },
+ "1:20": {
+ "192.168.5.0/24": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "192.168.5.0",
+ "prefixLen": 24,
+ "network": "192.168.5.0/24",
+ "metric": 0,
+ "weight": 32768,
+ "peerId": "(unspec)",
+ "path": "",
+ "origin": "incomplete",
+ "nhVrfName": "vrf20",
+ "nexthops": [
+ {
+ "ip": "2001::1",
+ "hostname": "r1",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ },
+ "2:10": {
+ "192.168.2.0/24": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "192.168.2.0",
+ "prefixLen": 24,
+ "network": "192.168.2.0/24",
+ "metric": 0,
+ "weight": 0,
+ "peerId": "2001::2",
+ "path": "2",
+ "origin": "incomplete",
+ "nexthops": [
+ {
+ "ip": "2001::2",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ },
+ "2:20": {
+ "192.168.4.0/24": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "192.168.4.0",
+ "prefixLen": 24,
+ "network": "192.168.4.0/24",
+ "metric": 0,
+ "weight": 0,
+ "peerId": "2001::2",
+ "path": "2",
+ "origin": "incomplete",
+ "nexthops": [
+ {
+ "ip": "2001::2",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "192.168.6.0/24": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "192.168.6.0",
+ "prefixLen": 24,
+ "network": "192.168.6.0/24",
+ "metric": 0,
+ "weight": 0,
+ "peerId": "2001::2",
+ "path": "2",
+ "origin": "incomplete",
+ "nexthops": [
+ {
+ "ip": "2001::2",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }
+}
--- /dev/null
+{
+ "192.168.1.0/24": [
+ {
+ "prefix": "192.168.1.0/24",
+ "protocol": "connected",
+ "vrfName": "vrf10",
+ "selected": true,
+ "destSelected": true,
+ "distance": 0,
+ "metric": 0,
+ "installed": true,
+ "table": 10,
+ "internalStatus": 16,
+ "internalFlags": 8,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "eth1",
+ "active": true
+ }
+ ]
+ }
+ ],
+ "192.168.2.0/24": [
+ {
+ "prefix": "192.168.2.0/24",
+ "protocol": "bgp",
+ "vrfName": "vrf10",
+ "selected": true,
+ "destSelected": true,
+ "distance": 20,
+ "metric": 0,
+ "installed": true,
+ "table": 10,
+ "internalStatus": 16,
+ "internalFlags": 8,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "afi": "ipv6",
+ "interfaceName": "eth0",
+ "vrf": "default",
+ "active": true,
+ "weight": 1,
+ "seg6": {
+ "segs": "2001:db8:2:2:100::"
+ }
+ }
+ ],
+ "asPath": "2"
+ }
+ ],
+ "192.168.3.0/24": [
+ {
+ "prefix": "192.168.3.0/24",
+ "protocol": "connected",
+ "vrfName": "vrf10",
+ "selected": true,
+ "destSelected": true,
+ "distance": 0,
+ "metric": 0,
+ "installed": true,
+ "table": 10,
+ "internalStatus": 16,
+ "internalFlags": 8,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "eth2",
+ "active": true
+ }
+ ]
+ }
+ ]
+}
--- /dev/null
+{
+ "192.168.4.0/24": [
+ {
+ "prefix": "192.168.4.0/24",
+ "protocol": "bgp",
+ "vrfName": "vrf20",
+ "selected": true,
+ "destSelected": true,
+ "distance": 20,
+ "metric": 0,
+ "installed": true,
+ "table": 20,
+ "internalStatus": 16,
+ "internalFlags": 8,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "afi": "ipv6",
+ "interfaceName": "eth0",
+ "vrf": "default",
+ "active": true,
+ "weight": 1,
+ "seg6": {
+ "segs": "2001:db8:2:2:200::"
+ }
+ }
+ ],
+ "asPath": "2"
+ }
+ ],
+ "192.168.5.0/24": [
+ {
+ "prefix": "192.168.5.0/24",
+ "protocol": "connected",
+ "vrfName": "vrf20",
+ "selected": true,
+ "destSelected": true,
+ "distance": 0,
+ "metric": 0,
+ "installed": true,
+ "table": 20,
+ "internalStatus": 16,
+ "internalFlags": 8,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "eth3",
+ "active": true
+ }
+ ]
+ }
+ ],
+ "192.168.6.0/24": [
+ {
+ "prefix": "192.168.6.0/24",
+ "protocol": "bgp",
+ "vrfName": "vrf20",
+ "selected": true,
+ "destSelected": true,
+ "distance": 20,
+ "metric": 0,
+ "installed": true,
+ "table": 20,
+ "internalStatus": 16,
+ "internalFlags": 8,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "afi": "ipv6",
+ "interfaceName": "eth0",
+ "vrf": "default",
+ "active": true,
+ "weight": 1,
+ "seg6": {
+ "segs": "2001:db8:2:2:200::"
+ }
+ }
+ ],
+ "asPath": "2"
+ }
+ ]
+}
--- /dev/null
+log file zebra.log
+!
+hostname r1
+password zebra
+!
+log stdout notifications
+log monitor notifications
+log commands
+!
+debug zebra packet
+debug zebra dplane
+debug zebra kernel
+!
+interface eth0
+ ipv6 address 2001::1/64
+!
+interface eth1 vrf vrf10
+ ip address 192.168.1.1/24
+ ipv6 address 2001:1::1/64
+!
+interface eth2 vrf vrf10
+ ip address 192.168.3.1/24
+!
+interface eth3 vrf vrf20
+ ip address 192.168.5.1/24
+!
+segment-routing
+ srv6
+ locators
+ locator loc1
+ prefix 2001:db8:1:1::/64
+ !
+ !
+!
+ip forwarding
+ipv6 forwarding
+!
+ipv6 route 2001:db8:2:2::/64 2001::2
+!
+line vty
+!
--- /dev/null
+frr defaults traditional
+!
+hostname r2
+password zebra
+!
+log stdout notifications
+log monitor notifications
+log commands
+!
+!debug bgp neighbor-events
+!debug bgp zebra
+!debug bgp vnc verbose
+!debug bgp update-groups
+!debug bgp updates in
+!debug bgp updates out
+!debug bgp updates
+!debug bgp vpn label
+!debug bgp vpn leak-from-vrf
+!debug bgp vpn leak-to-vrf
+!debug bgp vpn rmap-event
+!
+router bgp 2
+ bgp router-id 2.2.2.2
+ no bgp ebgp-requires-policy
+ no bgp default ipv4-unicast
+ neighbor 2001::1 remote-as 1
+ neighbor 2001::1 timers 3 10
+ neighbor 2001::1 timers connect 1
+ neighbor 2001::1 capability extended-nexthop
+ !
+ address-family ipv4 vpn
+ neighbor 2001::1 activate
+ exit-address-family
+ !
+ segment-routing srv6
+ locator loc1
+ !
+!
+router bgp 2 vrf vrf10
+ bgp router-id 2.2.2.2
+ no bgp ebgp-requires-policy
+ !
+ address-family ipv4 unicast
+ sid vpn export auto
+ nexthop vpn export 2001::2
+ rd vpn export 2:10
+ rt vpn both 99:99
+ import vpn
+ export vpn
+ redistribute connected
+ exit-address-family
+!
+router bgp 2 vrf vrf20
+ bgp router-id 2.2.2.2
+ no bgp ebgp-requires-policy
+ !
+ address-family ipv4 unicast
+ sid vpn export auto
+ nexthop vpn export 2001::2
+ rd vpn export 2:20
+ rt vpn both 88:88
+ import vpn
+ export vpn
+ redistribute connected
+ exit-address-family
+!
--- /dev/null
+{
+ "vrfId": 0,
+ "vrfName": "default",
+ "tableVersion": 2,
+ "routerId": "2.2.2.2",
+ "defaultLocPrf": 100,
+ "localAS": 2,
+ "routes": {
+ "routeDistinguishers": {
+ "1:10": {
+ "192.168.1.0/24": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "192.168.1.0",
+ "prefixLen": 24,
+ "network": "192.168.1.0/24",
+ "metric": 0,
+ "weight": 0,
+ "peerId": "2001::1",
+ "path": "1",
+ "origin": "incomplete",
+ "nexthops": [
+ {
+ "ip": "2001::1",
+ "hostname": "r1",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "192.168.3.0/24": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "192.168.3.0",
+ "prefixLen": 24,
+ "network": "192.168.3.0/24",
+ "metric": 0,
+ "weight": 0,
+ "peerId": "2001::1",
+ "path": "1",
+ "origin": "incomplete",
+ "nexthops": [
+ {
+ "ip": "2001::1",
+ "hostname": "r1",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ },
+ "1:20": {
+ "192.168.5.0/24": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "192.168.5.0",
+ "prefixLen": 24,
+ "network": "192.168.5.0/24",
+ "metric": 0,
+ "weight": 0,
+ "peerId": "2001::1",
+ "path": "1",
+ "origin": "incomplete",
+ "nexthops": [
+ {
+ "ip": "2001::1",
+ "hostname": "r1",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ },
+ "2:10": {
+ "192.168.2.0/24": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "192.168.2.0",
+ "prefixLen": 24,
+ "network": "192.168.2.0/24",
+ "metric": 0,
+ "weight": 32768,
+ "peerId": "(unspec)",
+ "path": "",
+ "origin": "incomplete",
+ "nhVrfName": "vrf10",
+ "nexthops": [
+ {
+ "ip": "2001::2",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ },
+ "2:20": {
+ "192.168.4.0/24": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "192.168.4.0",
+ "prefixLen": 24,
+ "network": "192.168.4.0/24",
+ "metric": 0,
+ "weight": 32768,
+ "peerId": "(unspec)",
+ "path": "",
+ "origin": "incomplete",
+ "nhVrfName": "vrf20",
+ "nexthops": [
+ {
+ "ip": "2001::2",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "192.168.6.0/24": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "192.168.6.0",
+ "prefixLen": 24,
+ "network": "192.168.6.0/24",
+ "metric": 0,
+ "weight": 32768,
+ "peerId": "(unspec)",
+ "path": "",
+ "origin": "incomplete",
+ "nhVrfName": "vrf20",
+ "nexthops": [
+ {
+ "ip": "2001::2",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }
+}
--- /dev/null
+{
+ "192.168.1.0/24": [
+ {
+ "prefix": "192.168.1.0/24",
+ "protocol": "bgp",
+ "vrfName": "vrf10",
+ "selected": true,
+ "destSelected": true,
+ "distance": 20,
+ "metric": 0,
+ "installed": true,
+ "table": 10,
+ "internalStatus": 16,
+ "internalFlags": 8,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "afi": "ipv6",
+ "interfaceName": "eth0",
+ "vrf": "default",
+ "active": true,
+ "weight": 1,
+ "seg6": {
+ "segs": "2001:db8:1:1:100::"
+ }
+ }
+ ],
+ "asPath": "1"
+ }
+ ],
+ "192.168.2.0/24": [
+ {
+ "prefix": "192.168.2.0/24",
+ "protocol": "connected",
+ "vrfName": "vrf10",
+ "selected": true,
+ "destSelected": true,
+ "distance": 0,
+ "metric": 0,
+ "installed": true,
+ "table": 10,
+ "internalStatus": 16,
+ "internalFlags": 8,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "eth1",
+ "active": true
+ }
+ ]
+ }
+ ],
+ "192.168.3.0/24": [
+ {
+ "prefix": "192.168.3.0/24",
+ "protocol": "bgp",
+ "vrfName": "vrf10",
+ "selected": true,
+ "destSelected": true,
+ "distance": 20,
+ "metric": 0,
+ "installed": true,
+ "table": 10,
+ "internalStatus": 16,
+ "internalFlags": 8,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "afi": "ipv6",
+ "interfaceName": "eth0",
+ "vrf": "default",
+ "active": true,
+ "weight": 1,
+ "seg6": {
+ "segs": "2001:db8:1:1:100::"
+ }
+ }
+ ],
+ "asPath": "1"
+ }
+ ]
+}
--- /dev/null
+{
+ "192.168.4.0/24": [
+ {
+ "prefix": "192.168.4.0/24",
+ "protocol": "connected",
+ "vrfName": "vrf20",
+ "selected": true,
+ "destSelected": true,
+ "distance": 0,
+ "metric": 0,
+ "installed": true,
+ "table": 20,
+ "internalStatus": 16,
+ "internalFlags": 8,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "eth2",
+ "active": true
+ }
+ ]
+ }
+ ],
+ "192.168.5.0/24": [
+ {
+ "prefix": "192.168.5.0/24",
+ "protocol": "bgp",
+ "vrfName": "vrf20",
+ "selected": true,
+ "destSelected": true,
+ "distance": 20,
+ "metric": 0,
+ "installed": true,
+ "table": 20,
+ "internalStatus": 16,
+ "internalFlags": 8,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "afi": "ipv6",
+ "interfaceName": "eth0",
+ "vrf": "default",
+ "active": true,
+ "weight": 1,
+ "seg6": {
+ "segs": "2001:db8:1:1:200::"
+ }
+ }
+ ],
+ "asPath": "1"
+ }
+ ],
+ "192.168.6.0/24": [
+ {
+ "prefix": "192.168.6.0/24",
+ "protocol": "connected",
+ "vrfName": "vrf20",
+ "selected": true,
+ "destSelected": true,
+ "distance": 0,
+ "metric": 0,
+ "installed": true,
+ "table": 20,
+ "internalStatus": 16,
+ "internalFlags": 8,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "eth3",
+ "active": true
+ }
+ ]
+ }
+ ]
+}
--- /dev/null
+log file zebra.log
+!
+hostname r2
+password zebra
+!
+log stdout notifications
+log monitor notifications
+log commands
+!
+debug zebra packet
+debug zebra dplane
+debug zebra kernel
+!
+interface eth0
+ ipv6 address 2001::2/64
+!
+interface eth1 vrf vrf10
+ ip address 192.168.2.1/24
+!
+interface eth2 vrf vrf20
+ ip address 192.168.4.1/24
+!
+interface eth3 vrf vrf20
+ ip address 192.168.6.1/24
+!
+segment-routing
+ srv6
+ locators
+ locator loc1
+ prefix 2001:db8:2:2::/64
+ !
+ !
+!
+ip forwarding
+ipv6 forwarding
+!
+ipv6 route 2001:db8:1:1::/64 2001::1
+!
+line vty
+!
--- /dev/null
+#!/usr/bin/env python
+
+#
+# Part of NetDEF Topology Tests
+#
+# Copyright (c) 2018, LabN Consulting, L.L.C.
+# Authored by Lou Berger <lberger@labn.net>
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+import os
+import re
+import sys
+import json
+import functools
+import pytest
+
+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
+from lib.common_config import required_linux_kernel_version
+
+pytestmark = [pytest.mark.bgpd]
+
+
+def build_topo(tgen):
+ tgen.add_router("r1")
+ tgen.add_router("r2")
+ tgen.add_router("ce1")
+ tgen.add_router("ce2")
+ tgen.add_router("ce3")
+ tgen.add_router("ce4")
+ tgen.add_router("ce5")
+ tgen.add_router("ce6")
+
+ tgen.add_link(tgen.gears["r1"], tgen.gears["r2"], "eth0", "eth0")
+ tgen.add_link(tgen.gears["ce1"], tgen.gears["r1"], "eth0", "eth1")
+ tgen.add_link(tgen.gears["ce2"], tgen.gears["r2"], "eth0", "eth1")
+ tgen.add_link(tgen.gears["ce3"], tgen.gears["r1"], "eth0", "eth2")
+ tgen.add_link(tgen.gears["ce4"], tgen.gears["r2"], "eth0", "eth2")
+ tgen.add_link(tgen.gears["ce5"], tgen.gears["r1"], "eth0", "eth3")
+ tgen.add_link(tgen.gears["ce6"], tgen.gears["r2"], "eth0", "eth3")
+
+
+def setup_module(mod):
+ result = required_linux_kernel_version("5.15")
+ if result is not True:
+ pytest.skip("Kernel requirements are not met")
+
+ tgen = Topogen(build_topo, mod.__name__)
+ tgen.start_topology()
+ for rname, router in tgen.routers().items():
+ router.run("/bin/bash {}/{}/setup.sh".format(CWD, rname))
+ router.load_config(TopoRouter.RD_ZEBRA,
+ os.path.join(CWD, '{}/zebra.conf'.format(rname)))
+ router.load_config(TopoRouter.RD_BGP,
+ os.path.join(CWD, '{}/bgpd.conf'.format(rname)))
+
+ tgen.gears["r1"].run("sysctl net.vrf.strict_mode=1")
+ tgen.gears["r1"].run("ip link add vrf10 type vrf table 10")
+ tgen.gears["r1"].run("ip link set vrf10 up")
+ tgen.gears["r1"].run("ip link add vrf20 type vrf table 20")
+ tgen.gears["r1"].run("ip link set vrf20 up")
+ tgen.gears["r1"].run("ip link set eth1 master vrf10")
+ tgen.gears["r1"].run("ip link set eth2 master vrf10")
+ tgen.gears["r1"].run("ip link set eth3 master vrf20")
+
+ tgen.gears["r2"].run("sysctl net.vrf.strict_mode=1")
+ tgen.gears["r2"].run("ip link add vrf10 type vrf table 10")
+ tgen.gears["r2"].run("ip link set vrf10 up")
+ tgen.gears["r2"].run("ip link add vrf20 type vrf table 20")
+ tgen.gears["r2"].run("ip link set vrf20 up")
+ tgen.gears["r2"].run("ip link set eth1 master vrf10")
+ tgen.gears["r2"].run("ip link set eth2 master vrf20")
+ tgen.gears["r2"].run("ip link set eth3 master vrf20")
+ tgen.start_router()
+
+
+def teardown_module(mod):
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+
+def open_json_file(filename):
+ try:
+ with open(filename, "r") as f:
+ return json.load(f)
+ except IOError:
+ assert False, "Could not read file {}".format(filename)
+
+
+def check_ping(name, dest_addr, expect_connected):
+ def _check(name, dest_addr, match):
+ tgen = get_topogen()
+ output = tgen.gears[name].run("ping {} -c 1 -w 1".format(dest_addr))
+ logger.info(output)
+ assert match in output, "ping fail"
+
+ match = "{} packet loss".format("0%" if expect_connected else "100%")
+ logger.info("[+] check {} {} {}".format(name, dest_addr, match))
+ tgen = get_topogen()
+ func = functools.partial(_check, name, dest_addr, match)
+ success, result = topotest.run_and_expect(func, None, count=10, wait=0.5)
+ assert result is None, "Failed"
+
+
+def check_rib(name, cmd, expected_file):
+ def _check(name, dest_addr, match):
+ logger.info("polling")
+ tgen = get_topogen()
+ router = tgen.gears[name]
+ output = json.loads(router.vtysh_cmd(cmd))
+ expected = open_json_file("{}/{}".format(CWD, expected_file))
+ return topotest.json_cmp(output, expected)
+
+ logger.info("[+] check {} \"{}\" {}".format(name, cmd, expected_file))
+ tgen = get_topogen()
+ func = functools.partial(_check, name, cmd, expected_file)
+ success, result = topotest.run_and_expect(func, None, count=10, wait=0.5)
+ assert result is None, "Failed"
+
+
+def test_rib():
+ check_rib("r1", "show bgp ipv4 vpn json", "r1/vpnv4_rib.json")
+ check_rib("r2", "show bgp ipv4 vpn json", "r2/vpnv4_rib.json")
+ check_rib("r1", "show ip route vrf vrf10 json", "r1/vrf10_rib.json")
+ check_rib("r1", "show ip route vrf vrf20 json", "r1/vrf20_rib.json")
+ check_rib("r2", "show ip route vrf vrf10 json", "r2/vrf10_rib.json")
+ check_rib("r2", "show ip route vrf vrf20 json", "r2/vrf20_rib.json")
+ check_rib("ce1", "show ip route json", "ce1/ip_rib.json")
+ check_rib("ce2", "show ip route json", "ce2/ip_rib.json")
+ check_rib("ce3", "show ip route json", "ce3/ip_rib.json")
+ check_rib("ce4", "show ip route json", "ce4/ip_rib.json")
+ check_rib("ce5", "show ip route json", "ce5/ip_rib.json")
+ check_rib("ce6", "show ip route json", "ce6/ip_rib.json")
+
+
+def test_ping():
+ check_ping("ce1", "192.168.2.2", " 0% packet loss")
+ check_ping("ce1", "192.168.3.2", " 0% packet loss")
+ check_ping("ce1", "192.168.4.2", " 100% packet loss")
+ check_ping("ce1", "192.168.5.2", " 100% packet loss")
+ check_ping("ce1", "192.168.6.2", " 100% packet loss")
+ check_ping("ce4", "192.168.1.2", " 100% packet loss")
+ check_ping("ce4", "192.168.2.2", " 100% packet loss")
+ check_ping("ce4", "192.168.3.2", " 100% packet loss")
+ check_ping("ce4", "192.168.5.2", " 0% packet loss")
+ check_ping("ce4", "192.168.6.2", " 0% packet loss")
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
--- /dev/null
+!
+hostname r1
+!
+interface lo
+ ip router isis TE
+ ipv6 router isis TE
+ isis circuit-type level-2-only
+ isis passive
+!
+interface r1-eth0
+ ip router isis TE
+ isis circuit-type level-2-only
+ isis network point-to-point
+ isis hello-multiplier 3
+!
+interface r1-eth1
+ ip router isis TE
+ ipv6 router isis TE
+ isis circuit-type level-2-only
+ isis network point-to-point
+ isis hello-multiplier 3
+!
+router isis TE
+ net 49.0000.0000.0000.0001.00
+ is-type level-2-only
+ topology ipv6-unicast
+ lsp-timers gen-interval 2 refresh-interval 10 max-lifetime 350
+ mpls-te on
+ mpls-te router-address 10.0.255.1
+ mpls-te router-address ipv6 2001:db8::1
+ mpls-te export
+!
+
--- /dev/null
+!
+import-te
+!
--- /dev/null
+!
+hostname r1
+!
+interface lo
+ ip address 10.0.255.1/32
+ ipv6 address 2001:db8::1/128
+!
+interface r1-eth0
+ ip address 10.0.0.1/24
+ link-params
+ metric 20
+ delay 10000
+ ava-bw 1.25e+08
+ enable
+ exit-link-params
+!
+interface r1-eth1
+ ip address 10.0.1.1/24
+ ipv6 address 2001:db8:1::1:1/64
+ link-params
+ metric 10
+ delay 20000
+ enable
+ exit-link-params
+!
+ip forwarding
+!
--- /dev/null
+!
+hostname r2
+!
+! debug isis te-events
+!
+interface lo
+ ip router isis TE
+ ipv6 router isis TE
+ isis circuit-type level-2-only
+ isis passive
+!
+interface r2-eth0
+ ip router isis TE
+ isis circuit-type level-2-only
+ isis network point-to-point
+ isis hello-multiplier 3
+!
+interface r2-eth1
+ ip router isis TE
+ ipv6 router isis TE
+ isis circuit-type level-2-only
+ isis network point-to-point
+ isis hello-multiplier 3
+!
+interface r2-eth2
+ ip router isis TE
+ ipv6 router isis TE
+ isis circuit-type level-2-only
+ isis network point-to-point
+ isis hello-multiplier 3
+!
+interface r2-eth3
+ ip router isis TE
+ isis circuit-type level-2-only
+ isis network point-to-point
+ isis hello-multiplier 3
+!
+router isis TE
+ net 49.0000.0000.0000.0002.00
+ is-type level-2-only
+ topology ipv6-unicast
+ lsp-timers gen-interval 2 refresh-interval 10 max-lifetime 350
+ mpls-te on
+ mpls-te router-address 10.0.255.2
+ mpls-te router-address ipv6 2001:db8::2
+!
--- /dev/null
+!
+hostname r2
+!
+interface lo
+ ip address 10.0.255.2/32
+ ipv6 address 2001:db8::2/128
+!
+interface r2-eth0
+ ip address 10.0.0.2/24
+ link-params
+ metric 20
+ delay 10000
+ enable
+ exit-link-params
+!
+interface r2-eth1
+ ip address 10.0.1.2/24
+ ipv6 address 2001:db8:1::1:2/64
+ link-params
+ metric 10
+ delay 20000
+ enable
+ exit-link-params
+!
+interface r2-eth2
+ ip address 10.0.3.2/24
+ ipv6 address 2001:db8:3::3:2/64
+ link-params
+ metric 40
+ delay 40000
+ enable
+ exit-link-params
+!
+interface r2-eth3
+ ip address 10.0.4.2/24
+ ipv6 address 2001:db8:4::4:2/64
+ link-params
+ metric 25
+ delay 25000
+ use-bw 1.25e+8
+ enable
+ exit-link-params
+!
+ip forwarding
+!
--- /dev/null
+!
+hostname r3
+!
+! debug isis te-events
+!
+interface lo
+ ip router isis TE
+ ipv6 router isis TE
+ isis circuit-type level-2-only
+ isis passive
+!
+interface r3-eth0
+ ip router isis TE
+ ipv6 router isis TE
+ isis circuit-type level-2-only
+ isis network point-to-point
+ isis hello-multiplier 3
+!
+interface r3-eth1
+ ipv6 router isis TE
+ isis circuit-type level-2-only
+ isis network point-to-point
+ isis hello-multiplier 3
+!
+!
+router isis TE
+ net 49.0000.0000.0000.0003.00
+ is-type level-2-only
+ topology ipv6-unicast
+ lsp-timers gen-interval 2 refresh-interval 10 max-lifetime 350
+ mpls-te on
+ mpls-te router-address 10.0.255.3
+ mpls-te router-address ipv6 2001:db8::3
+!
--- /dev/null
+!
+hostname r3
+!
+interface lo
+ ip address 10.0.255.3/32
+ ipv6 address 2001:db8::3/128
+!
+interface r3-eth0
+ ip address 10.0.3.3/24
+ ipv6 address 2001:db8:3::3:3/64
+ link-params
+ metric 25
+ delay 25000
+ enable
+ admin-grp 0x20
+ exit-link-params
+!
+interface r3-eth1
+ ipv6 address 2001:db8:5::4:3/64
+ link-params
+ enable
+ metric 10
+ delay 10000
+ exit-link-params
+!
+ip forwarding
+!
--- /dev/null
+!
+hostname r4
+!
+! debug isis te-events
+! debug isis sr-events
+! debug isis lsp-gen
+!
+interface lo
+ ip router isis TE
+ ipv6 router isis TE
+ isis circuit-type level-2-only
+ isis passive
+!
+interface r4-eth0
+ ip router isis TE
+ isis circuit-type level-2-only
+ isis network point-to-point
+ isis hello-multiplier 3
+!
+interface r4-eth1
+ ipv6 router isis TE
+ isis circuit-type level-2-only
+ isis network point-to-point
+ isis hello-multiplier 3
+!
+!
+router isis TE
+ net 49.0000.0000.0000.0004.00
+ is-type level-2-only
+ topology ipv6-unicast
+ lsp-timers gen-interval 2 refresh-interval 10 max-lifetime 350
+ mpls-te on
+ mpls-te router-address 10.0.255.4
+ mpls-te router-address ipv6 2001:db8::4
+ segment-routing on
+ segment-routing global-block 10000 19999 local-block 5000 5999
+ segment-routing node-msd 12
+ segment-routing prefix 10.0.255.4/32 index 400 no-php-flag
+ segment-routing prefix 2001:db8:ffff::4/128 index 1400 no-php-flag
+!
--- /dev/null
+!
+hostname r4
+!
+interface lo
+ ip address 10.0.255.4/32
+ ipv6 address 2001:db8::4/128
+!
+interface r4-eth0
+ ip address 10.0.4.4/24
+ ipv6 address 2001:db8:4::2:4/64
+ link-params
+ metric 40
+ delay 40000
+ enable
+ exit-link-params
+!
+interface r4-eth1
+ ipv6 address 2001:db8:5::3:4/64
+ link-params
+ metric 10
+ delay 10000
+ enable
+ exit-link-params
+!
+ip forwarding
+!
--- /dev/null
+Path computation failed: 2
--- /dev/null
+Path computation failed: 3
--- /dev/null
+Path computation failed: 1
--- /dev/null
+Path computation failed: 0
--- /dev/null
+Path computation success
+ Cost: 35000
+ Edges: 10.0.0.2 10.0.4.4
--- /dev/null
+Path computation success
+ Cost: 20
+ Edges: 10.0.0.2 10.0.4.4
--- /dev/null
+Path computation success
+ Cost: 35
+ Edges: 10.0.1.2 10.0.4.4
--- /dev/null
+Path computation success
+ Cost: 70000
+ Edges: 2001:db8:1::1:2 2001:db8:3::3:3 2001:db8:5::3:4
--- /dev/null
+Path computation success
+ Cost: 30
+ Edges: 2001:db8:1::1:2 2001:db8:3::3:3 2001:db8:5::3:4
--- /dev/null
+Path computation success
+ Cost: 60
+ Edges: 2001:db8:1::1:2 2001:db8:3::3:3 2001:db8:5::3:4
--- /dev/null
+{
+ "ted":{
+ "name":"Sharp",
+ "key":1,
+ "verticesCount":4,
+ "edgesCount":14,
+ "subnetsCount":22,
+ "vertices":[
+ {
+ "vertex-id":1,
+ "status":"Sync",
+ "origin":"ISIS_L2",
+ "name":"r1",
+ "router-id":"10.0.255.1",
+ "router-id-v6":"2001:db8::1"
+ },
+ {
+ "vertex-id":2,
+ "status":"Sync",
+ "origin":"ISIS_L2",
+ "name":"r2",
+ "router-id":"10.0.255.2",
+ "router-id-v6":"2001:db8::2"
+ },
+ {
+ "vertex-id":3,
+ "status":"Sync",
+ "origin":"ISIS_L2",
+ "name":"r3",
+ "router-id":"10.0.255.3",
+ "router-id-v6":"2001:db8::3"
+ },
+ {
+ "vertex-id":4,
+ "status":"Sync",
+ "origin":"ISIS_L2",
+ "name":"r4",
+ "router-id":"10.0.255.4",
+ "router-id-v6":"2001:db8::4",
+ "segment-routing":{
+ "srgb-size":10000,
+ "srgb-lower":10000,
+ "algorithms":[
+ {
+ "0":"SPF"
+ }
+ ],
+ "srlb-size":1000,
+ "srlb-lower":5000,
+ "msd":12
+ }
+ }
+ ],
+ "edges":[
+ {
+ "edge-id":65537,
+ "status":"Sync",
+ "origin":"ISIS_L2",
+ "advertised-router":"0000.0000.0001",
+ "local-vertex-id":1,
+ "remote-vertex-id":2,
+ "metric":10,
+ "edge-attributes":{
+ "te-metric":10,
+ "local-address-v6":"2001:db8:1::1:1",
+ "remote-address-v6":"2001:db8:1::1:2",
+ "max-link-bandwidth":176258176.0,
+ "max-resv-link-bandwidth":176258176.0,
+ "unreserved-bandwidth":[
+ {
+ "class-type-0":176258176.0
+ },
+ {
+ "class-type-1":176258176.0
+ },
+ {
+ "class-type-2":176258176.0
+ },
+ {
+ "class-type-3":176258176.0
+ },
+ {
+ "class-type-4":176258176.0
+ },
+ {
+ "class-type-5":176258176.0
+ },
+ {
+ "class-type-6":176258176.0
+ },
+ {
+ "class-type-7":176258176.0
+ }
+ ],
+ "delay":20000
+ }
+ },
+ {
+ "edge-id":65538,
+ "status":"Sync",
+ "origin":"ISIS_L2",
+ "advertised-router":"0000.0000.0002",
+ "local-vertex-id":2,
+ "remote-vertex-id":1,
+ "metric":10,
+ "edge-attributes":{
+ "te-metric":10,
+ "local-address-v6":"2001:db8:1::1:2",
+ "remote-address-v6":"2001:db8:1::1:1",
+ "max-link-bandwidth":176258176.0,
+ "max-resv-link-bandwidth":176258176.0,
+ "unreserved-bandwidth":[
+ {
+ "class-type-0":176258176.0
+ },
+ {
+ "class-type-1":176258176.0
+ },
+ {
+ "class-type-2":176258176.0
+ },
+ {
+ "class-type-3":176258176.0
+ },
+ {
+ "class-type-4":176258176.0
+ },
+ {
+ "class-type-5":176258176.0
+ },
+ {
+ "class-type-6":176258176.0
+ },
+ {
+ "class-type-7":176258176.0
+ }
+ ],
+ "delay":20000
+ }
+ },
+ {
+ "edge-id":196610,
+ "status":"Sync",
+ "origin":"ISIS_L2",
+ "advertised-router":"0000.0000.0002",
+ "local-vertex-id":2,
+ "remote-vertex-id":3,
+ "metric":10,
+ "edge-attributes":{
+ "te-metric":40,
+ "local-address-v6":"2001:db8:3::3:2",
+ "remote-address-v6":"2001:db8:3::3:3",
+ "max-link-bandwidth":176258176.0,
+ "max-resv-link-bandwidth":176258176.0,
+ "unreserved-bandwidth":[
+ {
+ "class-type-0":176258176.0
+ },
+ {
+ "class-type-1":176258176.0
+ },
+ {
+ "class-type-2":176258176.0
+ },
+ {
+ "class-type-3":176258176.0
+ },
+ {
+ "class-type-4":176258176.0
+ },
+ {
+ "class-type-5":176258176.0
+ },
+ {
+ "class-type-6":176258176.0
+ },
+ {
+ "class-type-7":176258176.0
+ }
+ ],
+ "delay":40000
+ }
+ },
+ {
+ "edge-id":196611,
+ "status":"Sync",
+ "origin":"ISIS_L2",
+ "advertised-router":"0000.0000.0003",
+ "local-vertex-id":3,
+ "remote-vertex-id":2,
+ "metric":10,
+ "edge-attributes":{
+ "te-metric":25,
+ "admin-group":32,
+ "local-address-v6":"2001:db8:3::3:3",
+ "remote-address-v6":"2001:db8:3::3:2",
+ "max-link-bandwidth":176258176.0,
+ "max-resv-link-bandwidth":176258176.0,
+ "unreserved-bandwidth":[
+ {
+ "class-type-0":176258176.0
+ },
+ {
+ "class-type-1":176258176.0
+ },
+ {
+ "class-type-2":176258176.0
+ },
+ {
+ "class-type-3":176258176.0
+ },
+ {
+ "class-type-4":176258176.0
+ },
+ {
+ "class-type-5":176258176.0
+ },
+ {
+ "class-type-6":176258176.0
+ },
+ {
+ "class-type-7":176258176.0
+ }
+ ],
+ "delay":25000
+ }
+ },
+ {
+ "edge-id":196612,
+ "status":"Sync",
+ "origin":"ISIS_L2",
+ "advertised-router":"0000.0000.0004",
+ "local-vertex-id":4,
+ "remote-vertex-id":3,
+ "metric":10,
+ "edge-attributes":{
+ "te-metric":10,
+ "local-address-v6":"2001:db8:5::3:4",
+ "remote-address-v6":"2001:db8:5::4:3",
+ "max-link-bandwidth":176258176.0,
+ "max-resv-link-bandwidth":176258176.0,
+ "unreserved-bandwidth":[
+ {
+ "class-type-0":176258176.0
+ },
+ {
+ "class-type-1":176258176.0
+ },
+ {
+ "class-type-2":176258176.0
+ },
+ {
+ "class-type-3":176258176.0
+ },
+ {
+ "class-type-4":176258176.0
+ },
+ {
+ "class-type-5":176258176.0
+ },
+ {
+ "class-type-6":176258176.0
+ },
+ {
+ "class-type-7":176258176.0
+ }
+ ],
+ "delay":10000
+ },
+ "segment-routing":[
+ {
+ "adj-sid":5001,
+ "flags":"0xb0",
+ "weight":0
+ }
+ ]
+ },
+ {
+ "edge-id":262147,
+ "status":"Sync",
+ "origin":"ISIS_L2",
+ "advertised-router":"0000.0000.0003",
+ "local-vertex-id":3,
+ "remote-vertex-id":4,
+ "metric":10,
+ "edge-attributes":{
+ "te-metric":10,
+ "local-address-v6":"2001:db8:5::4:3",
+ "remote-address-v6":"2001:db8:5::3:4",
+ "max-link-bandwidth":176258176.0,
+ "max-resv-link-bandwidth":176258176.0,
+ "unreserved-bandwidth":[
+ {
+ "class-type-0":176258176.0
+ },
+ {
+ "class-type-1":176258176.0
+ },
+ {
+ "class-type-2":176258176.0
+ },
+ {
+ "class-type-3":176258176.0
+ },
+ {
+ "class-type-4":176258176.0
+ },
+ {
+ "class-type-5":176258176.0
+ },
+ {
+ "class-type-6":176258176.0
+ },
+ {
+ "class-type-7":176258176.0
+ }
+ ],
+ "delay":10000
+ }
+ },
+ {
+ "edge-id":167772161,
+ "status":"Sync",
+ "origin":"ISIS_L2",
+ "advertised-router":"0000.0000.0001",
+ "local-vertex-id":1,
+ "remote-vertex-id":2,
+ "metric":10,
+ "edge-attributes":{
+ "te-metric":20,
+ "local-address":"10.0.0.1",
+ "remote-address":"10.0.0.2",
+ "max-link-bandwidth":176258176.0,
+ "max-resv-link-bandwidth":176258176.0,
+ "unreserved-bandwidth":[
+ {
+ "class-type-0":176258176.0
+ },
+ {
+ "class-type-1":176258176.0
+ },
+ {
+ "class-type-2":176258176.0
+ },
+ {
+ "class-type-3":176258176.0
+ },
+ {
+ "class-type-4":176258176.0
+ },
+ {
+ "class-type-5":176258176.0
+ },
+ {
+ "class-type-6":176258176.0
+ },
+ {
+ "class-type-7":176258176.0
+ }
+ ],
+ "delay":10000,
+ "available-bandwidth":125000000.0
+ }
+ },
+ {
+ "edge-id":167772162,
+ "status":"Sync",
+ "origin":"ISIS_L2",
+ "advertised-router":"0000.0000.0002",
+ "local-vertex-id":2,
+ "remote-vertex-id":1,
+ "metric":10,
+ "edge-attributes":{
+ "te-metric":20,
+ "local-address":"10.0.0.2",
+ "remote-address":"10.0.0.1",
+ "max-link-bandwidth":176258176.0,
+ "max-resv-link-bandwidth":176258176.0,
+ "unreserved-bandwidth":[
+ {
+ "class-type-0":176258176.0
+ },
+ {
+ "class-type-1":176258176.0
+ },
+ {
+ "class-type-2":176258176.0
+ },
+ {
+ "class-type-3":176258176.0
+ },
+ {
+ "class-type-4":176258176.0
+ },
+ {
+ "class-type-5":176258176.0
+ },
+ {
+ "class-type-6":176258176.0
+ },
+ {
+ "class-type-7":176258176.0
+ }
+ ],
+ "delay":10000
+ }
+ },
+ {
+ "edge-id":167772417,
+ "status":"Sync",
+ "origin":"ISIS_L2",
+ "advertised-router":"0000.0000.0001",
+ "local-vertex-id":1,
+ "remote-vertex-id":2,
+ "metric":10,
+ "edge-attributes":{
+ "te-metric":10,
+ "local-address":"10.0.1.1",
+ "remote-address":"10.0.1.2",
+ "max-link-bandwidth":176258176.0,
+ "max-resv-link-bandwidth":176258176.0,
+ "unreserved-bandwidth":[
+ {
+ "class-type-0":176258176.0
+ },
+ {
+ "class-type-1":176258176.0
+ },
+ {
+ "class-type-2":176258176.0
+ },
+ {
+ "class-type-3":176258176.0
+ },
+ {
+ "class-type-4":176258176.0
+ },
+ {
+ "class-type-5":176258176.0
+ },
+ {
+ "class-type-6":176258176.0
+ },
+ {
+ "class-type-7":176258176.0
+ }
+ ],
+ "delay":20000
+ }
+ },
+ {
+ "edge-id":167772418,
+ "status":"Sync",
+ "origin":"ISIS_L2",
+ "advertised-router":"0000.0000.0002",
+ "local-vertex-id":2,
+ "remote-vertex-id":1,
+ "metric":10,
+ "edge-attributes":{
+ "te-metric":10,
+ "local-address":"10.0.1.2",
+ "remote-address":"10.0.1.1",
+ "max-link-bandwidth":176258176.0,
+ "max-resv-link-bandwidth":176258176.0,
+ "unreserved-bandwidth":[
+ {
+ "class-type-0":176258176.0
+ },
+ {
+ "class-type-1":176258176.0
+ },
+ {
+ "class-type-2":176258176.0
+ },
+ {
+ "class-type-3":176258176.0
+ },
+ {
+ "class-type-4":176258176.0
+ },
+ {
+ "class-type-5":176258176.0
+ },
+ {
+ "class-type-6":176258176.0
+ },
+ {
+ "class-type-7":176258176.0
+ }
+ ],
+ "delay":20000
+ }
+ },
+ {
+ "edge-id":167772930,
+ "status":"Sync",
+ "origin":"ISIS_L2",
+ "advertised-router":"0000.0000.0002",
+ "local-vertex-id":2,
+ "remote-vertex-id":3,
+ "metric":10,
+ "edge-attributes":{
+ "te-metric":40,
+ "local-address":"10.0.3.2",
+ "remote-address":"10.0.3.3",
+ "max-link-bandwidth":176258176.0,
+ "max-resv-link-bandwidth":176258176.0,
+ "unreserved-bandwidth":[
+ {
+ "class-type-0":176258176.0
+ },
+ {
+ "class-type-1":176258176.0
+ },
+ {
+ "class-type-2":176258176.0
+ },
+ {
+ "class-type-3":176258176.0
+ },
+ {
+ "class-type-4":176258176.0
+ },
+ {
+ "class-type-5":176258176.0
+ },
+ {
+ "class-type-6":176258176.0
+ },
+ {
+ "class-type-7":176258176.0
+ }
+ ],
+ "delay":40000
+ }
+ },
+ {
+ "edge-id":167772931,
+ "status":"Sync",
+ "origin":"ISIS_L2",
+ "advertised-router":"0000.0000.0003",
+ "local-vertex-id":3,
+ "remote-vertex-id":2,
+ "metric":10,
+ "edge-attributes":{
+ "te-metric":25,
+ "admin-group":32,
+ "local-address":"10.0.3.3",
+ "remote-address":"10.0.3.2",
+ "max-link-bandwidth":176258176.0,
+ "max-resv-link-bandwidth":176258176.0,
+ "unreserved-bandwidth":[
+ {
+ "class-type-0":176258176.0
+ },
+ {
+ "class-type-1":176258176.0
+ },
+ {
+ "class-type-2":176258176.0
+ },
+ {
+ "class-type-3":176258176.0
+ },
+ {
+ "class-type-4":176258176.0
+ },
+ {
+ "class-type-5":176258176.0
+ },
+ {
+ "class-type-6":176258176.0
+ },
+ {
+ "class-type-7":176258176.0
+ }
+ ],
+ "delay":25000
+ }
+ },
+ {
+ "edge-id":167773186,
+ "status":"Sync",
+ "origin":"ISIS_L2",
+ "advertised-router":"0000.0000.0002",
+ "local-vertex-id":2,
+ "remote-vertex-id":4,
+ "metric":10,
+ "edge-attributes":{
+ "te-metric":25,
+ "local-address":"10.0.4.2",
+ "remote-address":"10.0.4.4",
+ "max-link-bandwidth":176258176.0,
+ "max-resv-link-bandwidth":176258176.0,
+ "unreserved-bandwidth":[
+ {
+ "class-type-0":176258176.0
+ },
+ {
+ "class-type-1":176258176.0
+ },
+ {
+ "class-type-2":176258176.0
+ },
+ {
+ "class-type-3":176258176.0
+ },
+ {
+ "class-type-4":176258176.0
+ },
+ {
+ "class-type-5":176258176.0
+ },
+ {
+ "class-type-6":176258176.0
+ },
+ {
+ "class-type-7":176258176.0
+ }
+ ],
+ "delay":25000,
+ "utilized-bandwidth":125000000.0
+ }
+ },
+ {
+ "edge-id":167773188,
+ "status":"Sync",
+ "origin":"ISIS_L2",
+ "advertised-router":"0000.0000.0004",
+ "local-vertex-id":4,
+ "remote-vertex-id":2,
+ "metric":10,
+ "edge-attributes":{
+ "te-metric":40,
+ "local-address":"10.0.4.4",
+ "remote-address":"10.0.4.2",
+ "max-link-bandwidth":176258176.0,
+ "max-resv-link-bandwidth":176258176.0,
+ "unreserved-bandwidth":[
+ {
+ "class-type-0":176258176.0
+ },
+ {
+ "class-type-1":176258176.0
+ },
+ {
+ "class-type-2":176258176.0
+ },
+ {
+ "class-type-3":176258176.0
+ },
+ {
+ "class-type-4":176258176.0
+ },
+ {
+ "class-type-5":176258176.0
+ },
+ {
+ "class-type-6":176258176.0
+ },
+ {
+ "class-type-7":176258176.0
+ }
+ ],
+ "delay":40000
+ },
+ "segment-routing":[
+ {
+ "adj-sid":5000,
+ "flags":"0x30",
+ "weight":0
+ }
+ ]
+ }
+ ],
+ "subnets":[
+ {
+ "subnet-id":"10.0.0.1/24",
+ "status":"Sync",
+ "origin":"ISIS_L2",
+ "advertised-router":"0000.0000.0001",
+ "vertex-id":1,
+ "metric":10
+ },
+ {
+ "subnet-id":"10.0.0.2/24",
+ "status":"Sync",
+ "origin":"ISIS_L2",
+ "advertised-router":"0000.0000.0002",
+ "vertex-id":2,
+ "metric":10
+ },
+ {
+ "subnet-id":"10.0.1.1/24",
+ "status":"Sync",
+ "origin":"ISIS_L2",
+ "advertised-router":"0000.0000.0001",
+ "vertex-id":1,
+ "metric":10
+ },
+ {
+ "subnet-id":"10.0.1.2/24",
+ "status":"Sync",
+ "origin":"ISIS_L2",
+ "advertised-router":"0000.0000.0002",
+ "vertex-id":2,
+ "metric":10
+ },
+ {
+ "subnet-id":"10.0.3.2/24",
+ "status":"Sync",
+ "origin":"ISIS_L2",
+ "advertised-router":"0000.0000.0002",
+ "vertex-id":2,
+ "metric":10
+ },
+ {
+ "subnet-id":"10.0.3.3/24",
+ "status":"Sync",
+ "origin":"ISIS_L2",
+ "advertised-router":"0000.0000.0003",
+ "vertex-id":3,
+ "metric":10
+ },
+ {
+ "subnet-id":"10.0.4.2/24",
+ "status":"Sync",
+ "origin":"ISIS_L2",
+ "advertised-router":"0000.0000.0002",
+ "vertex-id":2,
+ "metric":10
+ },
+ {
+ "subnet-id":"10.0.4.4/24",
+ "status":"Sync",
+ "origin":"ISIS_L2",
+ "advertised-router":"0000.0000.0004",
+ "vertex-id":4,
+ "metric":10
+ },
+ {
+ "subnet-id":"10.0.255.1/32",
+ "status":"Sync",
+ "origin":"ISIS_L2",
+ "advertised-router":"0000.0000.0001",
+ "vertex-id":1,
+ "metric":10
+ },
+ {
+ "subnet-id":"10.0.255.2/32",
+ "status":"Sync",
+ "origin":"ISIS_L2",
+ "advertised-router":"0000.0000.0002",
+ "vertex-id":2,
+ "metric":10
+ },
+ {
+ "subnet-id":"10.0.255.3/32",
+ "status":"Sync",
+ "origin":"ISIS_L2",
+ "advertised-router":"0000.0000.0003",
+ "vertex-id":3,
+ "metric":10
+ },
+ {
+ "subnet-id":"10.0.255.4/32",
+ "status":"Sync",
+ "origin":"ISIS_L2",
+ "advertised-router":"0000.0000.0004",
+ "vertex-id":4,
+ "metric":10,
+ "segment-routing":{
+ "pref-sid":400,
+ "algo":0,
+ "flags":"0x60"
+ }
+ },
+ {
+ "subnet-id":"2001:db8:1::1:1/64",
+ "status":"Sync",
+ "origin":"ISIS_L2",
+ "advertised-router":"0000.0000.0001",
+ "vertex-id":1,
+ "metric":10
+ },
+ {
+ "subnet-id":"2001:db8:1::1:2/64",
+ "status":"Sync",
+ "origin":"ISIS_L2",
+ "advertised-router":"0000.0000.0002",
+ "vertex-id":2,
+ "metric":10
+ },
+ {
+ "subnet-id":"2001:db8:3::3:2/64",
+ "status":"Sync",
+ "origin":"ISIS_L2",
+ "advertised-router":"0000.0000.0002",
+ "vertex-id":2,
+ "metric":10
+ },
+ {
+ "subnet-id":"2001:db8:3::3:3/64",
+ "status":"Sync",
+ "origin":"ISIS_L2",
+ "advertised-router":"0000.0000.0003",
+ "vertex-id":3,
+ "metric":10
+ },
+ {
+ "subnet-id":"2001:db8:5::3:4/64",
+ "status":"Sync",
+ "origin":"ISIS_L2",
+ "advertised-router":"0000.0000.0004",
+ "vertex-id":4,
+ "metric":10
+ },
+ {
+ "subnet-id":"2001:db8:5::4:3/64",
+ "status":"Sync",
+ "origin":"ISIS_L2",
+ "advertised-router":"0000.0000.0003",
+ "vertex-id":3,
+ "metric":10
+ },
+ {
+ "subnet-id":"2001:db8::1/128",
+ "status":"Sync",
+ "origin":"ISIS_L2",
+ "advertised-router":"0000.0000.0001",
+ "vertex-id":1,
+ "metric":10
+ },
+ {
+ "subnet-id":"2001:db8::2/128",
+ "status":"Sync",
+ "origin":"ISIS_L2",
+ "advertised-router":"0000.0000.0002",
+ "vertex-id":2,
+ "metric":10
+ },
+ {
+ "subnet-id":"2001:db8::3/128",
+ "status":"Sync",
+ "origin":"ISIS_L2",
+ "advertised-router":"0000.0000.0003",
+ "vertex-id":3,
+ "metric":10
+ },
+ {
+ "subnet-id":"2001:db8::4/128",
+ "status":"Sync",
+ "origin":"ISIS_L2",
+ "advertised-router":"0000.0000.0004",
+ "vertex-id":4,
+ "metric":10
+ }
+ ]
+ }
+}
--- /dev/null
+#!/usr/bin/env python
+
+#
+# test_cspf_topo1.py
+# Part of NetDEF Topology Tests
+#
+# Copyright (c) 2022 by Orange
+# Author: Olivier Dugeon <olivier.dugeon@orange.com>
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+test_cspf_topo1.py: Test the FRR Constraint Shortest Path First algorithm.
+
+ +------------+
+ | |
+ | R1 |
+ | 10.0.225.1 |
+ | |
+ +------------+
+ r1-eth0| |r1-eth1
+ | |
+ 10.0.0.0/24| |10.0.1.0/24
+ | |2001:db8:1:/64
+ | |
+ r2-eth0| |r2-eth1
+ +------------+ +------------+
+ | | | |
+ | R2 |r2-eth2 r3-eth0| R3 |
+ | 10.0.255.2 +------------------+ 10.0.255.3 |
+ | | 10.0.3.0/24 | |
+ +------------+ 2001:db8:3:/64 +------+-----+
+ r2-eth3| r3-eth1|
+ | |
+ 10.0.4.0/24| |
+ | |
+ | |
+ r4-eth0| 2001:db8:5:/64|
+ +------------+ |
+ | | |
+ | R4 |r4-eth1 |
+ | 10.0.255.4 +-------------------------+
+ | |
+ +------------+
+
+"""
+
+import os
+import sys
+import json
+from functools import partial
+
+# Save the Current Working Directory to find configuration files.
+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
+
+# and Finally pytest
+import pytest
+
+pytestmark = [pytest.mark.isisd]
+
+
+def build_topo(tgen):
+ "Build function"
+
+ # Create 4 routers
+ for routern in range(1, 5):
+ tgen.add_router("r{}".format(routern))
+
+ # Interconect router 1 and 2 with 2 links
+ switch = tgen.add_switch("s1")
+ switch.add_link(tgen.gears["r1"])
+ switch.add_link(tgen.gears["r2"])
+ switch = tgen.add_switch("s2")
+ switch.add_link(tgen.gears["r1"])
+ switch.add_link(tgen.gears["r2"])
+
+ # Interconect router 3 and 2
+ switch = tgen.add_switch("s3")
+ switch.add_link(tgen.gears["r3"])
+ switch.add_link(tgen.gears["r2"])
+
+ # Interconect router 4 and 2
+ switch = tgen.add_switch("s4")
+ switch.add_link(tgen.gears["r4"])
+ switch.add_link(tgen.gears["r2"])
+
+ # Interconnect router 3 and 4
+ switch = tgen.add_switch("s5")
+ switch.add_link(tgen.gears["r3"])
+ switch.add_link(tgen.gears["r4"])
+
+
+def setup_module(mod):
+ "Sets up the pytest environment"
+
+ logger.info("\n\n---- Starting CSPF tests ----\n")
+
+ tgen = Topogen(build_topo, mod.__name__)
+ tgen.start_topology()
+
+ 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_ISIS, os.path.join(CWD, "{}/isisd.conf".format(rname))
+ )
+ if rname == "r1":
+ router.load_config(
+ TopoRouter.RD_SHARP, os.path.join(CWD, "{}/sharpd.conf".format("r1"))
+ )
+
+ # Initialize all routers.
+ tgen.start_router()
+
+
+def teardown_module():
+ "Teardown the pytest environment"
+
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+ logger.info("\n\n---- CSPF tests End ----\n")
+
+
+def compare_ted_json_output(tgen, rname, fileref):
+ "Compare TED JSON output"
+
+ logger.info('Comparing router "%s" TED output', rname)
+
+ filename = "{}/reference/{}".format(CWD, fileref)
+ expected = json.loads(open(filename).read())
+ command = "show sharp ted json"
+
+ # Run test function until we get an result. Wait at most 60 seconds.
+ test_func = partial(topotest.router_json_cmp, tgen.gears[rname], command, expected)
+ _, diff = topotest.run_and_expect(test_func, None, count=60, wait=2)
+ assertmsg = '"{}" TED JSON output mismatches the expected result'.format(rname)
+ assert diff is None, assertmsg
+
+
+def compare_cspf_output(tgen, rname, fileref, src, dst, cost, bw=""):
+ "Compare CSPF output"
+
+ logger.info('Comparing router "%s" CSPF output', rname)
+
+ filename = "{}/reference/{}".format(CWD, fileref)
+ expected = open(filename).read()
+ command = "show sharp cspf source {} destination {} {} {}".format(src, dst, cost, bw)
+
+ # Run test function until we get an result. Wait at most 60 seconds.
+ test_func = partial(topotest.router_output_cmp, tgen.gears[rname], command, expected)
+ result, diff = topotest.run_and_expect(test_func, "", count=2, wait=2)
+ assert result, "CSPF output mismatches the expected result on {}:\n{}".format(rname, diff)
+
+
+def setup_testcase(msg):
+ "Setup test case"
+
+ logger.info(msg)
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ return tgen
+
+
+# Note that all routers must discover the same Network Topology, so the same TED.
+
+
+def test_step1():
+ "Step1: Check initial topology"
+
+ tgen = setup_testcase("Step1: test initial IS-IS TE Data Base import")
+ tgen.net["r1"].cmd('vtysh -c "sharp import-te"')
+
+ compare_ted_json_output(tgen, "r1", "sharp-ted.json")
+
+
+def test_step2():
+ "Step2: Test CSPF from r1 to r4 for IPv4 with various metric"
+
+ tgen = setup_testcase("Step2: CSPF(r1, r4, IPv4)")
+
+ compare_cspf_output(tgen, "r1", "cspf-ipv4-metric.txt", "10.0.0.1", "10.0.255.4", "metric 50")
+ compare_cspf_output(tgen, "r1", "cspf-ipv4-te-metric.txt", "10.0.255.1", "10.0.4.4", "te-metric 50")
+ compare_cspf_output(tgen, "r1", "cspf-ipv4-delay.txt", "10.0.255.1", "10.0.255.4", "delay 50000")
+ compare_cspf_output(tgen, "r1", "cspf-ipv4-delay.txt", "10.0.255.1", "10.0.255.4", "delay 50000", "rsv 7 100000000")
+
+
+def test_step3():
+ "Step3: Test CSPF from r1 to r4 for IPv6 with various metric"
+
+ tgen = setup_testcase("Step2: CSPF(r1, r4, IPv6)")
+
+ compare_cspf_output(tgen, "r1", "cspf-ipv6-metric.txt", "2001:db8:1::1:1", "2001:db8::4", "metric 50")
+ compare_cspf_output(tgen, "r1", "cspf-ipv6-te-metric.txt", "2001:db8::1", "2001:db8:5::3:4", "te-metric 80")
+ compare_cspf_output(tgen, "r1", "cspf-ipv6-delay.txt", "2001:db8::1", "2001:db8::4", "delay 80000")
+ compare_cspf_output(tgen, "r1", "cspf-ipv6-delay.txt", "2001:db8::1", "2001:db8::4", "delay 80000", "rsv 7 100000000")
+
+
+def test_step4():
+ "Step4: Test CSPF from r1 to r4 with no possible path"
+
+ tgen = setup_testcase("Step2: CSPF(r1, r4, failure)")
+
+ compare_cspf_output(tgen, "r1", "cspf-failed.txt", "10.0.255.1", "10.0.255.4", "metric 10")
+ compare_cspf_output(tgen, "r1", "cspf-failed.txt", "2001:db8::1", "2001:db8::4", "te-metric 50")
+ compare_cspf_output(tgen, "r1", "cspf-failed.txt", "10.0.255.1", "10.0.255.4", "delay 5000")
+ compare_cspf_output(tgen, "r1", "cspf-failed.txt", "2001:db8::1", "2001:db8::4", "delay 80000", "rsv 7 1000000000")
+ compare_cspf_output(tgen, "r1", "cspf-failed-src.txt", "10.0.0.3", "10.0.255.4", "metric 10")
+ compare_cspf_output(tgen, "r1", "cspf-failed-dst.txt", "10.0.0.1", "10.0.4.40", "metric 10")
+ compare_cspf_output(tgen, "r1", "cspf-failed-same.txt", "10.0.0.1", "10.0.0.1", "metric 10")
+
+
+def test_memory_leak():
+ "Run the memory leak test and report results."
+
+ tgen = get_topogen()
+ if not tgen.is_memleak_enabled():
+ pytest.skip("Memory leak test/report is disabled")
+
+ tgen.report_memory_leaks()
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
"remote-vertex-id":2,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"local-address-v6":"2001:db8:1::1:1",
"remote-address-v6":"2001:db8:1::1:2",
"max-link-bandwidth":176258176.0,
"remote-vertex-id":1,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"local-address-v6":"2001:db8:1::1:2",
"remote-address-v6":"2001:db8:1::1:1",
"max-link-bandwidth":176258176.0,
"remote-vertex-id":3,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"local-address-v6":"2001:db8:3::3:2",
"remote-address-v6":"2001:db8:3::3:3",
"max-link-bandwidth":176258176.0,
"remote-vertex-id":2,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"admin-group":32,
"local-address-v6":"2001:db8:3::3:3",
"remote-address-v6":"2001:db8:3::3:2",
"remote-vertex-id":3,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"local-address-v6":"2001:db8:5::3:4",
"remote-address-v6":"2001:db8:5::4:3",
"max-link-bandwidth":176258176.0,
"remote-vertex-id":1,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"local-address":"10.0.0.2",
"remote-address":"10.0.0.1",
"max-link-bandwidth":176258176.0,
"remote-vertex-id":2,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"local-address":"10.0.1.1",
"remote-address":"10.0.1.2",
"max-link-bandwidth":176258176.0,
"remote-vertex-id":1,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"local-address":"10.0.1.2",
"remote-address":"10.0.1.1",
"max-link-bandwidth":176258176.0,
"remote-vertex-id":3,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"local-address":"10.0.3.2",
"remote-address":"10.0.3.3",
"max-link-bandwidth":176258176.0,
"remote-vertex-id":2,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"admin-group":32,
"local-address":"10.0.3.3",
"remote-address":"10.0.3.2",
"remote-vertex-id":2,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"local-address":"10.0.4.4",
"remote-address":"10.0.4.2",
"max-link-bandwidth":176258176.0,
"remote-vertex-id":3,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"local-address-v6":"2001:db8:3::3:2",
"remote-address-v6":"2001:db8:3::3:3",
"max-link-bandwidth":176258176.0,
"remote-vertex-id":2,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"admin-group":32,
"local-address-v6":"2001:db8:3::3:3",
"remote-address-v6":"2001:db8:3::3:2",
"remote-vertex-id":3,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"local-address-v6":"2001:db8:5::3:4",
"remote-address-v6":"2001:db8:5::4:3",
"max-link-bandwidth":176258176.0,
"remote-vertex-id":1,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"local-address":"10.0.0.2",
"remote-address":"10.0.0.1",
"max-link-bandwidth":176258176.0,
"remote-vertex-id":3,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"local-address":"10.0.3.2",
"remote-address":"10.0.3.3",
"max-link-bandwidth":176258176.0,
"remote-vertex-id":2,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"admin-group":32,
"local-address":"10.0.3.3",
"remote-address":"10.0.3.2",
"remote-vertex-id":2,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"local-address":"10.0.4.4",
"remote-address":"10.0.4.2",
"max-link-bandwidth":176258176.0,
"remote-vertex-id":1,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"local-address-v6":"2001:db8::2",
"max-link-bandwidth":176258176.0,
"max-resv-link-bandwidth":176258176.0,
"remote-vertex-id":3,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"local-address-v6":"2001:db8:3::3:2",
"remote-address-v6":"2001:db8:3::3:3",
"max-link-bandwidth":176258176.0,
"remote-vertex-id":2,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"admin-group":32,
"local-address-v6":"2001:db8:3::3:3",
"remote-address-v6":"2001:db8:3::3:2",
"remote-vertex-id":3,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"local-address-v6":"2001:db8:5::3:4",
"remote-address-v6":"2001:db8:5::4:3",
"max-link-bandwidth":176258176.0,
"remote-vertex-id":1,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"local-address":"10.0.0.2",
"remote-address":"10.0.0.1",
"max-link-bandwidth":176258176.0,
"remote-vertex-id":3,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"local-address":"10.0.3.2",
"remote-address":"10.0.3.3",
"max-link-bandwidth":176258176.0,
"remote-vertex-id":2,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"admin-group":32,
"local-address":"10.0.3.3",
"remote-address":"10.0.3.2",
"remote-vertex-id":2,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"local-address":"10.0.4.4",
"remote-address":"10.0.4.2",
"max-link-bandwidth":176258176.0,
"remote-vertex-id":1,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"local-address-v6":"2001:db8::2",
"max-link-bandwidth":176258176.0,
"max-resv-link-bandwidth":176258176.0,
"remote-vertex-id":3,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"local-address-v6":"2001:db8:3::3:2",
"remote-address-v6":"2001:db8:3::3:3",
"max-link-bandwidth":176258176.0,
"remote-vertex-id":2,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"admin-group":32,
"local-address-v6":"2001:db8:3::3:3",
"remote-address-v6":"2001:db8:3::3:2",
"remote-vertex-id":3,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"local-address-v6":"2001:db8:5::3:4",
"remote-address-v6":"2001:db8:5::4:3",
"max-link-bandwidth":176258176.0,
"remote-vertex-id":1,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"local-address":"10.0.0.2",
"remote-address":"10.0.0.1",
"max-link-bandwidth":176258176.0,
"remote-vertex-id":3,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"local-address":"10.0.3.2",
"remote-address":"10.0.3.3",
"max-link-bandwidth":176258176.0,
"remote-vertex-id":2,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"admin-group":32,
"local-address":"10.0.3.3",
"remote-address":"10.0.3.2",
"remote-vertex-id":2,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"local-address":"10.0.4.4",
"remote-address":"10.0.4.2",
"max-link-bandwidth":176258176.0,
"remote-vertex-id":1,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"local-address-v6":"2001:db8::2",
"max-link-bandwidth":176258176.0,
"max-resv-link-bandwidth":176258176.0,
"remote-vertex-id":2,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"local-address-v6":"2001:db8:1::1:1",
"remote-address-v6":"2001:db8:1::1:2",
"max-link-bandwidth":176258176.0,
"remote-vertex-id":1,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"local-address-v6":"2001:db8:1::1:2",
"remote-address-v6":"2001:db8:1::1:1",
"max-link-bandwidth":176258176.0,
"remote-vertex-id":3,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"local-address-v6":"2001:db8:3::3:2",
"remote-address-v6":"2001:db8:3::3:3",
"max-link-bandwidth":176258176.0,
"remote-vertex-id":2,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"admin-group":32,
"local-address-v6":"2001:db8:3::3:3",
"remote-address-v6":"2001:db8:3::3:2",
"remote-vertex-id":3,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"local-address-v6":"2001:db8:5::3:4",
"remote-address-v6":"2001:db8:5::4:3",
"max-link-bandwidth":176258176.0,
"remote-vertex-id":1,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"local-address":"10.0.0.2",
"remote-address":"10.0.0.1",
"max-link-bandwidth":176258176.0,
"remote-vertex-id":2,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"local-address":"10.0.1.1",
"remote-address":"10.0.1.2",
"max-link-bandwidth":176258176.0,
"remote-vertex-id":1,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"local-address":"10.0.1.2",
"remote-address":"10.0.1.1",
"max-link-bandwidth":176258176.0,
"remote-vertex-id":3,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"local-address":"10.0.3.2",
"remote-address":"10.0.3.3",
"max-link-bandwidth":176258176.0,
"remote-vertex-id":2,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"admin-group":32,
"local-address":"10.0.3.3",
"remote-address":"10.0.3.2",
"remote-vertex-id":2,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"local-address":"10.0.4.4",
"remote-address":"10.0.4.2",
"max-link-bandwidth":176258176.0,
"remote-vertex-id":1,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"local-address-v6":"2001:db8::2",
"max-link-bandwidth":176258176.0,
"max-resv-link-bandwidth":176258176.0,
"remote-vertex-id":2,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"local-address-v6":"2001:db8:1::1:1",
"remote-address-v6":"2001:db8:1::1:2",
"max-link-bandwidth":176258176.0,
"remote-vertex-id":1,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"local-address-v6":"2001:db8:1::1:2",
"remote-address-v6":"2001:db8:1::1:1",
"max-link-bandwidth":176258176.0,
"remote-vertex-id":3,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"local-address-v6":"2001:db8:3::3:2",
"remote-address-v6":"2001:db8:3::3:3",
"max-link-bandwidth":176258176.0,
"remote-vertex-id":2,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"admin-group":32,
"local-address-v6":"2001:db8:3::3:3",
"remote-address-v6":"2001:db8:3::3:2",
"remote-vertex-id":3,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"local-address-v6":"2001:db8:5::3:4",
"remote-address-v6":"2001:db8:5::4:3",
"max-link-bandwidth":176258176.0,
"remote-vertex-id":1,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"local-address":"10.0.0.2",
"remote-address":"10.0.0.1",
"max-link-bandwidth":176258176.0,
"remote-vertex-id":2,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"local-address":"10.0.1.1",
"remote-address":"10.0.1.2",
"max-link-bandwidth":176258176.0,
"remote-vertex-id":1,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"local-address":"10.0.1.2",
"remote-address":"10.0.1.1",
"max-link-bandwidth":176258176.0,
"remote-vertex-id":3,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"local-address":"10.0.3.2",
"remote-address":"10.0.3.3",
"max-link-bandwidth":176258176.0,
"remote-vertex-id":2,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"admin-group":32,
"local-address":"10.0.3.3",
"remote-address":"10.0.3.2",
"remote-vertex-id":2,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"local-address":"10.0.4.4",
"remote-address":"10.0.4.2",
"max-link-bandwidth":176258176.0,
"11.0.20.5/32",
]
}
+
+NETWORK_APP_E = {"ipv4": ["12.0.0.0/24", "12.0.0.0/16", "12.0.0.0/8"]}
TOPOOLOGY = """
Please view in a fixed-width font such as Courier.
+---+ A1 +---+
write_test_footer(tc_name)
+def test_ospf_rfc2328_appendinxE_p0(request):
+ """
+ Test OSPF appendinx E RFC2328.
+
+ """
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ tgen = get_topogen()
+ global topo
+ step("Bring up the base config.")
+
+ reset_config_on_routers(tgen)
+
+ step("Verify that OSPF neighbours are Full.")
+ # Api call verify whether OSPF is converged
+ ospf_covergence = verify_ospf_neighbor(tgen, topo)
+ assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
+ ospf_covergence
+ )
+
+ redistribute_ospf(tgen, topo, "r0", "static")
+
+ step("Configure static route with prefix 24, 16, 8 to check ")
+ input_dict = {
+ "r0": {
+ "static_routes": [
+ {
+ "network": NETWORK_APP_E["ipv4"][0],
+ "no_of_ip": 1,
+ "next_hop": "Null0",
+ }
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ input_dict = {
+ "r0": {
+ "static_routes": [
+ {
+ "network": NETWORK_APP_E["ipv4"][1],
+ "no_of_ip": 1,
+ "next_hop": "Null0",
+ }
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ input_dict = {
+ "r0": {
+ "static_routes": [
+ {
+ "network": NETWORK_APP_E["ipv4"][2],
+ "no_of_ip": 1,
+ "next_hop": "Null0",
+ }
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Verify that ospf originates routes with mask 24, 16, 8")
+ ip_net = NETWORK_APP_E["ipv4"][0]
+ input_dict = {"r1": {"static_routes": [{"network": ip_net, "no_of_ip": 1}]}}
+
+ dut = "r1"
+ result = verify_ospf_rib(tgen, dut, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ protocol = "ospf"
+ result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ ip_net = NETWORK_APP_E["ipv4"][1]
+ input_dict = {"r1": {"static_routes": [{"network": ip_net, "no_of_ip": 1}]}}
+
+ dut = "r1"
+ result = verify_ospf_rib(tgen, dut, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ protocol = "ospf"
+ result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ ip_net = NETWORK_APP_E["ipv4"][2]
+ input_dict = {"r1": {"static_routes": [{"network": ip_net, "no_of_ip": 1}]}}
+
+ dut = "r1"
+ result = verify_ospf_rib(tgen, dut, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ protocol = "ospf"
+ result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Delete static route with prefix 24, 16, 8 to check ")
+ input_dict = {
+ "r0": {
+ "static_routes": [
+ {
+ "network": NETWORK_APP_E["ipv4"][0],
+ "no_of_ip": 1,
+ "next_hop": "Null0",
+ "delete": True,
+ }
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ input_dict = {
+ "r0": {
+ "static_routes": [
+ {
+ "network": NETWORK_APP_E["ipv4"][1],
+ "no_of_ip": 1,
+ "next_hop": "Null0",
+ "delete": True,
+ }
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ input_dict = {
+ "r0": {
+ "static_routes": [
+ {
+ "network": NETWORK_APP_E["ipv4"][2],
+ "no_of_ip": 1,
+ "next_hop": "Null0",
+ "delete": True,
+ }
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ write_test_footer(tc_name)
+
+
def test_ospf_cost_tc52_p0(request):
"""OSPF Cost - verifying ospf interface cost functionality"""
tc_name = request.node.name
"remote-vertex-id":167837441,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"local-address":"10.0.0.2",
"remote-address":"10.0.0.1",
"max-link-bandwidth":176258176.0,
"remote-vertex-id":167837442,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"local-address":"10.0.1.1",
"remote-address":"10.0.1.2",
"max-link-bandwidth":176258176.0,
"remote-vertex-id":167837441,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"local-address":"10.0.1.2",
"remote-address":"10.0.1.1",
"max-link-bandwidth":176258176.0,
"remote-vertex-id":167837442,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"admin-group":32,
"local-address":"10.0.3.1",
"remote-address":"10.0.3.2",
"remote-vertex-id":167837443,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"local-address":"10.0.3.2",
"remote-address":"10.0.3.1",
"max-link-bandwidth":176258176.0,
"remote-vertex-id":167837442,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"local-address":"10.0.4.1",
"remote-address":"10.0.4.2",
"max-link-bandwidth":176258176.0,
"remote-vertex-id":167837441,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"local-address":"10.0.0.2",
"remote-address":"10.0.0.1",
"max-link-bandwidth":176258176.0,
"remote-vertex-id":167837442,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"admin-group":32,
"local-address":"10.0.3.1",
"remote-address":"10.0.3.2",
"remote-vertex-id":167837443,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"local-address":"10.0.3.2",
"remote-address":"10.0.3.1",
"max-link-bandwidth":176258176.0,
"remote-vertex-id":167837442,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"local-address":"10.0.4.1",
"remote-address":"10.0.4.2",
"max-link-bandwidth":176258176.0,
"remote-vertex-id":167837441,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"local-address":"10.0.0.2",
"remote-address":"10.0.0.1",
"max-link-bandwidth":176258176.0,
"remote-vertex-id":167837442,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"admin-group":32,
"local-address":"10.0.3.1",
"remote-address":"10.0.3.2",
"remote-vertex-id":167837443,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"local-address":"10.0.3.2",
"remote-address":"10.0.3.1",
"max-link-bandwidth":176258176.0,
"remote-vertex-id":167837442,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"local-address":"10.0.4.1",
"remote-address":"10.0.4.2",
"max-link-bandwidth":176258176.0,
"remote-vertex-id":167837441,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"local-address":"10.0.0.2",
"remote-address":"10.0.0.1",
"max-link-bandwidth":176258176.0,
"remote-vertex-id":167837442,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"admin-group":32,
"local-address":"10.0.3.1",
"remote-address":"10.0.3.2",
"remote-vertex-id":167837443,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"local-address":"10.0.3.2",
"remote-address":"10.0.3.1",
"max-link-bandwidth":176258176.0,
"remote-vertex-id":167837442,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"local-address":"10.0.4.1",
"remote-address":"10.0.4.2",
"max-link-bandwidth":176258176.0,
"remote-vertex-id":167837441,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"local-address":"10.0.0.2",
"remote-address":"10.0.0.1",
"max-link-bandwidth":176258176.0,
"remote-vertex-id":167837442,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"local-address":"10.0.1.1",
"remote-address":"10.0.1.2",
"max-link-bandwidth":176258176.0,
"remote-vertex-id":167837441,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"local-address":"10.0.1.2",
"remote-address":"10.0.1.1",
"max-link-bandwidth":176258176.0,
"remote-vertex-id":167837442,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"admin-group":32,
"local-address":"10.0.3.1",
"remote-address":"10.0.3.2",
"remote-vertex-id":167837443,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"local-address":"10.0.3.2",
"remote-address":"10.0.3.1",
"max-link-bandwidth":176258176.0,
"remote-vertex-id":167837442,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"local-address":"10.0.4.1",
"remote-address":"10.0.4.2",
"max-link-bandwidth":176258176.0,
"remote-vertex-id":167837441,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"local-address":"10.0.0.2",
"remote-address":"10.0.0.1",
"max-link-bandwidth":176258176.0,
"remote-vertex-id":167837442,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"local-address":"10.0.1.1",
"remote-address":"10.0.1.2",
"max-link-bandwidth":176258176.0,
"remote-vertex-id":167837441,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"local-address":"10.0.1.2",
"remote-address":"10.0.1.1",
"max-link-bandwidth":176258176.0,
"remote-vertex-id":167837442,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"admin-group":32,
"local-address":"10.0.3.1",
"remote-address":"10.0.3.2",
"remote-vertex-id":167837443,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"local-address":"10.0.3.2",
"remote-address":"10.0.3.1",
"max-link-bandwidth":176258176.0,
"remote-vertex-id":167837442,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"local-address":"10.0.4.1",
"remote-address":"10.0.4.2",
"max-link-bandwidth":176258176.0,
"remote-vertex-id":167837441,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"local-address":"10.0.0.2",
"remote-address":"10.0.0.1",
"max-link-bandwidth":176258176.0,
"remote-vertex-id":167837442,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"local-address":"10.0.1.1",
"remote-address":"10.0.1.2",
"max-link-bandwidth":176258176.0,
"remote-vertex-id":167837441,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"local-address":"10.0.1.2",
"remote-address":"10.0.1.1",
"max-link-bandwidth":176258176.0,
"remote-vertex-id":167837442,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"admin-group":32,
"local-address":"10.0.3.1",
"remote-address":"10.0.3.2",
"remote-vertex-id":167837443,
"metric":10,
"edge-attributes":{
- "te-metric":0,
"local-address":"10.0.3.2",
"remote-address":"10.0.3.1",
"max-link-bandwidth":176258176.0,
if (tb_encap[SEG6_LOCAL_TABLE])
ctx->table = *(uint32_t *)RTA_DATA(tb_encap[SEG6_LOCAL_TABLE]);
+ if (tb_encap[SEG6_LOCAL_VRFTABLE])
+ ctx->table =
+ *(uint32_t *)RTA_DATA(tb_encap[SEG6_LOCAL_VRFTABLE]);
+
return act;
}
ctx->table))
return false;
break;
+ case ZEBRA_SEG6_LOCAL_ACTION_END_DT4:
+ if (!nl_attr_put32(nlmsg, req_size,
+ SEG6_LOCAL_ACTION,
+ SEG6_LOCAL_ACTION_END_DT4))
+ return false;
+ if (!nl_attr_put32(nlmsg, req_size,
+ SEG6_LOCAL_VRFTABLE,
+ ctx->table))
+ return false;
+ break;
default:
zlog_err("%s: unsupport seg6local behaviour action=%u",
__func__,
ctx->table))
return 0;
break;
+ case SEG6_LOCAL_ACTION_END_DT4:
+ if (!nl_attr_put32(
+ &req->n, buflen,
+ SEG6_LOCAL_ACTION,
+ SEG6_LOCAL_ACTION_END_DT4))
+ return 0;
+ if (!nl_attr_put32(
+ &req->n, buflen,
+ SEG6_LOCAL_VRFTABLE,
+ ctx->table))
+ return 0;
+ break;
default:
zlog_err("%s: unsupport seg6local behaviour action=%u",
__func__, action);
else if (rn->p.family == AF_INET6)
family = AFI_IP6;
else
- family = 0;
+ family = AF_UNSPEC;
if (IS_ZEBRA_DEBUG_NHG_DETAIL)
zlog_debug("%s: re %p, nexthop %pNHv", __func__, re, nexthop);