]> git.proxmox.com Git - mirror_frr.git/commitdiff
Merge pull request #10511 from anlancs/ospf-substitute
authorIgor Ryzhov <iryzhov@nfware.com>
Tue, 8 Feb 2022 17:50:22 +0000 (20:50 +0300)
committerGitHub <noreply@github.com>
Tue, 8 Feb 2022 17:50:22 +0000 (20:50 +0300)
ospfd: fix loss of mixed form in "range" command

95 files changed:
babeld/message.c
bfdd/ptm_adapter.c
bgpd/bgp_route.c
bgpd/rfapi/rfapi_import.c
bgpd/rfapi/rfapi_rib.c
doc/developer/cspf.rst [new file with mode: 0644]
doc/user/pim.rst
doc/user/sharp.rst
include/linux/seg6_local.h
isisd/isis_te.c
isisd/isis_tlvs.c
isisd/isis_tlvs.h
lib/cspf.c [new file with mode: 0644]
lib/cspf.h [new file with mode: 0644]
lib/filter_nb.c
lib/if.c
lib/subdir.am
ospfd/ospf_asbr.c
ospfd/ospf_lsa.c
ospfd/ospf_lsa.h
ospfd/ospf_lsdb.c
ospfd/ospf_snmp.c
ospfd/ospf_vty.c
pimd/pim_bsm.c
pimd/pim_cmd.c
pimd/pim_nht.c
sharpd/sharp_vty.c
sharpd/sharp_zebra.c
tests/isisd/test_fuzz_isis_tlv_tests.h.gz
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce1/bgpd.conf [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce1/ip_rib.json [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce1/zebra.conf [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce2/bgpd.conf [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce2/ip_rib.json [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce2/zebra.conf [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce3/bgpd.conf [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce3/ip_rib.json [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce3/zebra.conf [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce4/bgpd.conf [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce4/ip_rib.json [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce4/zebra.conf [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce5/bgpd.conf [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce5/ip_rib.json [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce5/zebra.conf [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce6/bgpd.conf [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce6/ip_rib.json [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce6/zebra.conf [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r1/bgpd.conf [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r1/vpnv4_rib.json [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r1/vrf10_rib.json [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r1/vrf20_rib.json [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r1/zebra.conf [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r2/bgpd.conf [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r2/vpnv4_rib.json [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r2/vrf10_rib.json [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r2/vrf20_rib.json [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r2/zebra.conf [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/test_bgp_srv6l3vpn_to_bgp_vrf2.py [new file with mode: 0755]
tests/topotests/cspf_topo1/r1/isisd.conf [new file with mode: 0644]
tests/topotests/cspf_topo1/r1/sharpd.conf [new file with mode: 0644]
tests/topotests/cspf_topo1/r1/zebra.conf [new file with mode: 0644]
tests/topotests/cspf_topo1/r2/isisd.conf [new file with mode: 0644]
tests/topotests/cspf_topo1/r2/zebra.conf [new file with mode: 0644]
tests/topotests/cspf_topo1/r3/isisd.conf [new file with mode: 0644]
tests/topotests/cspf_topo1/r3/zebra.conf [new file with mode: 0644]
tests/topotests/cspf_topo1/r4/isisd.conf [new file with mode: 0644]
tests/topotests/cspf_topo1/r4/zebra.conf [new file with mode: 0644]
tests/topotests/cspf_topo1/reference/cspf-failed-dst.txt [new file with mode: 0644]
tests/topotests/cspf_topo1/reference/cspf-failed-same.txt [new file with mode: 0644]
tests/topotests/cspf_topo1/reference/cspf-failed-src.txt [new file with mode: 0644]
tests/topotests/cspf_topo1/reference/cspf-failed.txt [new file with mode: 0644]
tests/topotests/cspf_topo1/reference/cspf-ipv4-delay.txt [new file with mode: 0644]
tests/topotests/cspf_topo1/reference/cspf-ipv4-metric.txt [new file with mode: 0644]
tests/topotests/cspf_topo1/reference/cspf-ipv4-te-metric.txt [new file with mode: 0644]
tests/topotests/cspf_topo1/reference/cspf-ipv6-delay.txt [new file with mode: 0644]
tests/topotests/cspf_topo1/reference/cspf-ipv6-metric.txt [new file with mode: 0644]
tests/topotests/cspf_topo1/reference/cspf-ipv6-te-metric.txt [new file with mode: 0644]
tests/topotests/cspf_topo1/reference/sharp-ted.json [new file with mode: 0644]
tests/topotests/cspf_topo1/test_cspf_topo1.py [new file with mode: 0644]
tests/topotests/isis_te_topo1/reference/ted_step1.json
tests/topotests/isis_te_topo1/reference/ted_step2.json
tests/topotests/isis_te_topo1/reference/ted_step3.json
tests/topotests/isis_te_topo1/reference/ted_step4.json
tests/topotests/isis_te_topo1/reference/ted_step5.json
tests/topotests/isis_te_topo1/reference/ted_step6.json
tests/topotests/ospf_basic_functionality/test_ospf_rte_calc.py
tests/topotests/ospf_te_topo1/reference/ted_step1.json
tests/topotests/ospf_te_topo1/reference/ted_step2.json
tests/topotests/ospf_te_topo1/reference/ted_step3.json
tests/topotests/ospf_te_topo1/reference/ted_step4.json
tests/topotests/ospf_te_topo1/reference/ted_step5.json
tests/topotests/ospf_te_topo1/reference/ted_step6.json
tests/topotests/ospf_te_topo1/reference/ted_step7.json
zebra/rt_netlink.c
zebra/zebra_nhg.c

index 3a29b6a60fe9409e5be919d4dee59d59cb5b1d6a..559b8c4e4ac829946d91fd876a7781019a8b2f29 100644 (file)
@@ -140,12 +140,12 @@ parse_update_subtlv(const unsigned char *a, int alen,
             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;
         }
@@ -182,19 +182,19 @@ parse_hello_subtlv(const unsigned char *a, int alen,
     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;
@@ -228,19 +228,19 @@ parse_ihu_subtlv(const unsigned char *a, int alen,
     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;
@@ -307,12 +307,12 @@ babel_packet_examin(const unsigned char *packet, int packetlen)
             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;
         }
index b0eb85e5f8371b495dd7ffecd01536e861091775..0e5f701fc2712d6d2d9ead25188fc4ae5dffb277 100644 (file)
@@ -457,7 +457,7 @@ static int _ptm_msg_read(struct stream *msg, int command, vrf_id_t vrf_id,
        }
 
        /* 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");
index f353abead07a893dd381cbe64aded3fd23d211b6..e390ba5c750009dea2bf9e38ddc756d3e88cbe3f 100644 (file)
@@ -2200,10 +2200,11 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi,
                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;
                }
        }
index 07aed045cab1a807b84934a8d497efd2ede6a648..4b50b46569cd2394e61d4bb5d4ba897c8bb531e1 100644 (file)
@@ -388,7 +388,7 @@ int rfapiGetVncTunnelUnAddr(struct attr *attr, struct prefix *p)
                        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;
@@ -457,7 +457,7 @@ int rfapiGetUnAddrOfVpnBi(struct bgp_path_info *bpi, struct prefix *p)
                        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",
@@ -1155,7 +1155,7 @@ static int rfapiVpnBiSamePtUn(struct bgp_path_info *bpi1,
                                        bpi1->extra->vnc.import.un.addr6;
                                break;
                        default:
-                               pfx_un1.family = 0;
+                               pfx_un1.family = AF_UNSPEC;
                                break;
                        }
                }
@@ -1174,13 +1174,13 @@ static int rfapiVpnBiSamePtUn(struct bgp_path_info *bpi1,
                                        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)
@@ -1358,7 +1358,7 @@ rfapiRouteInfo2NextHopEntry(struct rfapi_ip_prefix *rprefix,
                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;
                }
@@ -2609,7 +2609,7 @@ static void rfapiCopyUnEncap2VPN(struct bgp_path_info *encap_bpi,
        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;
        }
 }
@@ -2634,7 +2634,7 @@ rfapiWithdrawEncapUpdateCachedUn(struct rfapi_import_table *import_table,
                                __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)) {
@@ -3626,7 +3626,7 @@ void rfapiBgpInfoFilteredImportVPN(
                /* 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) {
index d1f335f54946306d39b32d4653748355d41d32a0..6b9a8fb4a75851dbcbce106a48f7ec5fb09c51e0 100644 (file)
@@ -1950,7 +1950,7 @@ rfapiRibPreload(struct bgp *bgp, struct rfapi_descriptor *rfd,
                            && 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;
                        }
                }
 
diff --git a/doc/developer/cspf.rst b/doc/developer/cspf.rst
new file mode 100644 (file)
index 0000000..426553f
--- /dev/null
@@ -0,0 +1,196 @@
+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.
index 1b418a434929c4fba12b76ba10cf70faf959f457..306feec0f75c249321e0a05e44c8aa42833f392c 100644 (file)
@@ -452,6 +452,7 @@ cause great confusion.
 .. 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
 
index e088c2f75b1d81e5991f7d3f5161cd4dc548a50c..e9d4e2763f3ed475725be540b5393e8f49d80169 100644 (file)
@@ -139,7 +139,7 @@ keyword. At present, no sharp commands will be preserved in the config.
 
 .. 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]
 
@@ -147,6 +147,15 @@ keyword. At present, no sharp commands will be preserved in the config.
 
    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
index 5312de80bcfae74c73bd308f58ec2881f5b4f357..bb5c8ddfcec52f06412fc7aedf69ef360698fc2f 100644 (file)
@@ -26,6 +26,7 @@ enum {
        SEG6_LOCAL_IIF,
        SEG6_LOCAL_OIF,
        SEG6_LOCAL_BPF,
+       SEG6_LOCAL_VRFTABLE,
        __SEG6_LOCAL_MAX,
 };
 #define SEG6_LOCAL_MAX (__SEG6_LOCAL_MAX - 1)
index 118bcf78000ada97eab15d17a484466655e63a75..95fbca17a83da10911ea81c59691914e52fff13c 100644 (file)
@@ -756,6 +756,7 @@ static int lsp_to_edge_cb(const uint8_t *id, uint32_t metric, bool old_metric,
                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);
index 9a442e0374888c7005fd3e3a356ea01dbf66a628..f1aae7caf1074895ab408bf8cdfab0d28bcb5d32 100644 (file)
@@ -3007,28 +3007,55 @@ static int unpack_tlv_router_cap(enum isis_tlv_context context,
 
                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
@@ -3042,9 +3069,12 @@ static int unpack_tlv_router_cap(enum isis_tlv_context context,
                        /* 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
@@ -3059,12 +3089,12 @@ static int unpack_tlv_router_cap(enum isis_tlv_context context,
                        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);
@@ -3072,10 +3102,27 @@ static int unpack_tlv_router_cap(enum isis_tlv_context context,
                        /* 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
@@ -3089,13 +3136,14 @@ static int unpack_tlv_router_cap(enum isis_tlv_context context,
                        /* 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);
index 38470ef85ecbeb1c8b2f213602f49d3121acd9b2..0c6ed11cb63e5196ecdd74410e1a50542374c77c 100644 (file)
@@ -447,6 +447,7 @@ enum ext_subtlv_size {
 
        /* 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,
diff --git a/lib/cspf.c b/lib/cspf.c
new file mode 100644 (file)
index 0000000..ef3e7c2
--- /dev/null
@@ -0,0 +1,646 @@
+/*
+ * 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;
+}
diff --git a/lib/cspf.h b/lib/cspf.h
new file mode 100644 (file)
index 0000000..6466ddb
--- /dev/null
@@ -0,0 +1,211 @@
+/*
+ * 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_ */
index 80ea7a57cb22faef874736f867513bc157692a4d..35b97a9bde8993539083544f22a46f1b4d14ecbd 100644 (file)
@@ -1135,7 +1135,7 @@ static int lib_access_list_entry_any_destroy(struct nb_cb_destroy_args *args)
 
        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);
 
index 158303a3879fb9adc7e48728caf7ab4fd2ff2ec3..a2918b6d748d7c0422236c521a603e8ce782ed77 100644 (file)
--- a/lib/if.c
+++ b/lib/if.c
@@ -1090,9 +1090,6 @@ struct if_link_params *if_link_params_get(struct interface *ifp)
        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)
@@ -1105,8 +1102,13 @@ struct if_link_params *if_link_params_get(struct interface *ifp)
                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;
index bb10d71ed1a116f4a80a4662c43a82d0a2562032..2cd329c8ad74f55668f80b5d3d938590a75520c8 100644 (file)
@@ -16,6 +16,7 @@ lib_libfrr_la_SOURCES = \
        lib/command_lex.l \
        lib/command_match.c \
        lib/command_parse.y \
+       lib/cspf.c \
        lib/csv.c \
        lib/debug.c \
        lib/defaults.c \
@@ -182,6 +183,7 @@ pkginclude_HEADERS += \
        lib/command_graph.h \
        lib/command_match.h \
        lib/compiler.h \
+       lib/cspf.h \
        lib/csv.h \
        lib/db.h \
        lib/debug.h \
index 8cb85b4626555170f82ec04df99eb3b70ba1e4ab..f44e1dde82737b40941c11dadbd978d7bc226a23 100644 (file)
@@ -223,8 +223,15 @@ struct ospf_lsa *ospf_external_info_find_lsa(struct ospf *ospf,
        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);
index c169996e013384eb34e05f0506871a1f2d56889d..e3ba1f1dd101b8d352865ce59496bacb93bc165b 100644 (file)
 #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;
@@ -1221,31 +1244,11 @@ static struct ospf_lsa *ospf_summary_lsa_new(struct ospf_area *area,
 }
 
 /* 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)))
@@ -1270,6 +1273,97 @@ struct ospf_lsa *ospf_summary_lsa_originate(struct prefix_ipv4 *p,
        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)
 {
@@ -1370,32 +1464,12 @@ static struct ospf_lsa *ospf_summary_asbr_lsa_new(struct ospf_area *area,
 }
 
 /* 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);
@@ -1421,6 +1495,37 @@ struct ospf_lsa *ospf_summary_asbr_lsa_originate(struct prefix_ipv4 *p,
        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)
 {
@@ -1612,42 +1717,15 @@ static void ospf_external_lsa_body_set(struct stream *s,
 }
 
 /* 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);
@@ -1677,6 +1755,99 @@ static struct ospf_lsa *ospf_external_lsa_new(struct ospf *ospf,
        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)
@@ -2983,7 +3154,7 @@ void ospf_lsa_maxage_delete(struct ospf *ospf, struct ospf_lsa *lsa)
        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;
 
@@ -3024,7 +3195,7 @@ void ospf_lsa_maxage(struct ospf *ospf, struct ospf_lsa *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;
 
@@ -3509,49 +3680,87 @@ int ospf_lsa_is_self_originated(struct ospf *ospf, struct ospf_lsa *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;
 }
 
 
index a979573715038d7bbc02172c38f144645706b328..d04d11841ecacf717db1c73c43e17e0efcf35a30 100644 (file)
@@ -208,6 +208,8 @@ struct as_external_lsa {
        } e[1];
 };
 
+enum lsid_status { LSID_AVAILABLE = 0, LSID_CHANGE, LSID_NOT_AVAILABLE };
+
 #include "ospfd/ospf_opaque.h"
 
 /* Macros. */
@@ -317,8 +319,10 @@ extern struct ospf_lsa *ospf_external_lsa_refresh(struct ospf *,
                                                  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 *);
 
index 86eb141312ebb72464a6f96c7d659e234b4445e5..b0881c098f568919b3f47a00468a663aa024b927 100644 (file)
@@ -70,7 +70,7 @@ void ospf_lsdb_cleanup(struct ospf_lsdb *lsdb)
 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;
@@ -199,7 +199,7 @@ struct ospf_lsa *ospf_lsdb_lookup_by_id(struct ospf_lsdb *lsdb, uint8_t type,
        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;
@@ -226,7 +226,7 @@ struct ospf_lsa *ospf_lsdb_lookup_by_id_next(struct ospf_lsdb *lsdb,
        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;
index 7ec3db7894634237c4120947f036c21b9157ffaa..bf375568633ae756fa3fc1066f745c16bd7df345 100644 (file)
@@ -1779,7 +1779,7 @@ static int ospf_snmp_vl_add(struct ospf_vl_data *vl_data)
        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;
@@ -1798,7 +1798,7 @@ static int ospf_snmp_vl_delete(struct ospf_vl_data *vl_data)
        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;
@@ -1820,7 +1820,7 @@ static struct ospf_vl_data *ospf_snmp_vl_lookup(struct in_addr *area_id,
        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;
@@ -1843,7 +1843,7 @@ static struct ospf_vl_data *ospf_snmp_vl_lookup_next(struct in_addr *area_id,
        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;
index 137a3cf2fff1aedf947f0149e43a00a71599c7e7..32d87b9a9183e0541c45b13006531dead835afd0 100644 (file)
@@ -6558,7 +6558,7 @@ static void show_lsa_prefix_set(struct vty *vty, struct prefix_ls *lp,
                                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) {
index 238c19d2cc29f2dafcfbb14acdc05e51460627f7..c8b6d4e404ddacfeb28370f63180956c2699f3c4 100644 (file)
@@ -557,8 +557,7 @@ static void pim_bsm_update(struct pim_instance *pim, struct in_addr bsr,
                           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;
@@ -582,8 +581,7 @@ void pim_bsm_clear(struct pim_instance *pim)
        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;
index 01cb35177e7e920dbdab27fc502b9e77c33d6188..90c0257483223d6988f579674481027632b4fc56 100644 (file)
@@ -143,6 +143,9 @@ static void pim_show_assert(struct pim_instance *pim, struct vty *vty)
                        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 */
        }
index cd6f4c45fa0c418efcdcf774693f3ba2da7f18c1..94a624e2c4a02e7bca5e8a21303edde74e49e2da 100644 (file)
@@ -259,6 +259,14 @@ void pim_nht_bsr_del(struct pim_instance *pim, struct in_addr addr)
        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;
index 0a323f744e188d017d27a9ba0186e6e3c29b0ae6..ceed9cf739ed5b316e1480a5f15355ac79a69a14 100644 (file)
@@ -29,7 +29,9 @@
 #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"
@@ -425,7 +427,8 @@ DEFPY (install_seg6local_routes,
              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"
@@ -444,6 +447,8 @@ DEFPY (install_seg6local_routes,
        "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")
@@ -494,6 +499,9 @@ DEFPY (install_seg6local_routes,
        } 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;
        }
@@ -1150,6 +1158,106 @@ DEFPY (show_sharp_segment_routing_srv6,
        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);
@@ -1175,6 +1283,7 @@ void sharp_vty_init(void)
 
        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,
index 8c9f0c2784167c9647bcbf8a77c209a8490cd383..313febd9bb6694ef9f27dece11254e5d2d63de84 100644 (file)
@@ -799,10 +799,12 @@ static int sharp_opaque_handler(ZAPI_CALLBACK_ARGS)
 
        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",
index accc906bf25853bd417cff25840b233f98d1221e..20b1dc33f9593661b8310dc0c205e68d022de480 100644 (file)
Binary files a/tests/isisd/test_fuzz_isis_tlv_tests.h.gz and b/tests/isisd/test_fuzz_isis_tlv_tests.h.gz differ
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce1/bgpd.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce1/bgpd.conf
new file mode 100644 (file)
index 0000000..3459796
--- /dev/null
@@ -0,0 +1,8 @@
+frr defaults traditional
+!
+hostname ce1
+password zebra
+!
+log stdout notifications
+log commands
+log file bgpd.log
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce1/ip_rib.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce1/ip_rib.json
new file mode 100644 (file)
index 0000000..1d33fee
--- /dev/null
@@ -0,0 +1,58 @@
+{
+  "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
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce1/zebra.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce1/zebra.conf
new file mode 100644 (file)
index 0000000..447d1b4
--- /dev/null
@@ -0,0 +1,14 @@
+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
+!
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce2/bgpd.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce2/bgpd.conf
new file mode 100644 (file)
index 0000000..8ed9978
--- /dev/null
@@ -0,0 +1,8 @@
+frr defaults traditional
+!
+hostname ce2
+password zebra
+!
+log stdout notifications
+log commands
+log file bgpd.log
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce2/ip_rib.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce2/ip_rib.json
new file mode 100644 (file)
index 0000000..a21f4a1
--- /dev/null
@@ -0,0 +1,58 @@
+{
+  "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
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce2/zebra.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce2/zebra.conf
new file mode 100644 (file)
index 0000000..1165225
--- /dev/null
@@ -0,0 +1,14 @@
+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
+!
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce3/bgpd.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce3/bgpd.conf
new file mode 100644 (file)
index 0000000..a85d970
--- /dev/null
@@ -0,0 +1,8 @@
+frr defaults traditional
+!
+hostname ce3
+password zebra
+!
+log stdout notifications
+log commands
+log file bgpd.log
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce3/ip_rib.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce3/ip_rib.json
new file mode 100644 (file)
index 0000000..38a7807
--- /dev/null
@@ -0,0 +1,58 @@
+{
+  "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
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce3/zebra.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce3/zebra.conf
new file mode 100644 (file)
index 0000000..299c659
--- /dev/null
@@ -0,0 +1,14 @@
+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
+!
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce4/bgpd.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce4/bgpd.conf
new file mode 100644 (file)
index 0000000..93fb32f
--- /dev/null
@@ -0,0 +1,8 @@
+frr defaults traditional
+!
+hostname ce4
+password zebra
+!
+log stdout notifications
+log commands
+log file bgpd.log
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce4/ip_rib.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce4/ip_rib.json
new file mode 100644 (file)
index 0000000..a0be78e
--- /dev/null
@@ -0,0 +1,58 @@
+{
+  "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
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce4/zebra.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce4/zebra.conf
new file mode 100644 (file)
index 0000000..30f3736
--- /dev/null
@@ -0,0 +1,14 @@
+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
+!
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce5/bgpd.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce5/bgpd.conf
new file mode 100644 (file)
index 0000000..2ab6f2d
--- /dev/null
@@ -0,0 +1,8 @@
+frr defaults traditional
+!
+hostname ce5
+password zebra
+!
+log stdout notifications
+log commands
+log file bgpd.log
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce5/ip_rib.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce5/ip_rib.json
new file mode 100644 (file)
index 0000000..dc338d5
--- /dev/null
@@ -0,0 +1,58 @@
+{
+  "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
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce5/zebra.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce5/zebra.conf
new file mode 100644 (file)
index 0000000..208dcb1
--- /dev/null
@@ -0,0 +1,14 @@
+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
+!
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce6/bgpd.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce6/bgpd.conf
new file mode 100644 (file)
index 0000000..e0b6540
--- /dev/null
@@ -0,0 +1,8 @@
+frr defaults traditional
+!
+hostname ce6
+password zebra
+!
+log stdout notifications
+log commands
+log file bgpd.log
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce6/ip_rib.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce6/ip_rib.json
new file mode 100644 (file)
index 0000000..4a603a5
--- /dev/null
@@ -0,0 +1,58 @@
+{
+  "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
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce6/zebra.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/ce6/zebra.conf
new file mode 100644 (file)
index 0000000..d68a008
--- /dev/null
@@ -0,0 +1,14 @@
+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
+!
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r1/bgpd.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r1/bgpd.conf
new file mode 100644 (file)
index 0000000..c061751
--- /dev/null
@@ -0,0 +1,66 @@
+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
+!
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r1/vpnv4_rib.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r1/vpnv4_rib.json
new file mode 100644 (file)
index 0000000..3cc2fdd
--- /dev/null
@@ -0,0 +1,167 @@
+{
+  "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
+              }
+            ]
+          }
+        ]
+      }
+    }
+  }
+}
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r1/vrf10_rib.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r1/vrf10_rib.json
new file mode 100644 (file)
index 0000000..8daa9b1
--- /dev/null
@@ -0,0 +1,86 @@
+{
+  "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
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r1/vrf20_rib.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r1/vrf20_rib.json
new file mode 100644 (file)
index 0000000..6f123cf
--- /dev/null
@@ -0,0 +1,92 @@
+{
+  "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"
+    }
+  ]
+}
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r1/zebra.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r1/zebra.conf
new file mode 100644 (file)
index 0000000..a43cec2
--- /dev/null
@@ -0,0 +1,41 @@
+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
+!
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r2/bgpd.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r2/bgpd.conf
new file mode 100644 (file)
index 0000000..0517057
--- /dev/null
@@ -0,0 +1,66 @@
+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
+!
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r2/vpnv4_rib.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r2/vpnv4_rib.json
new file mode 100644 (file)
index 0000000..9557054
--- /dev/null
@@ -0,0 +1,167 @@
+{
+  "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
+              }
+            ]
+          }
+        ]
+      }
+    }
+  }
+}
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r2/vrf10_rib.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r2/vrf10_rib.json
new file mode 100644 (file)
index 0000000..6268031
--- /dev/null
@@ -0,0 +1,92 @@
+{
+  "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"
+    }
+  ]
+}
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r2/vrf20_rib.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r2/vrf20_rib.json
new file mode 100644 (file)
index 0000000..ffe2e07
--- /dev/null
@@ -0,0 +1,86 @@
+{
+  "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
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r2/zebra.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r2/zebra.conf
new file mode 100644 (file)
index 0000000..71ddedf
--- /dev/null
@@ -0,0 +1,40 @@
+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
+!
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/test_bgp_srv6l3vpn_to_bgp_vrf2.py b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/test_bgp_srv6l3vpn_to_bgp_vrf2.py
new file mode 100755 (executable)
index 0000000..af66a5a
--- /dev/null
@@ -0,0 +1,171 @@
+#!/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))
diff --git a/tests/topotests/cspf_topo1/r1/isisd.conf b/tests/topotests/cspf_topo1/r1/isisd.conf
new file mode 100644 (file)
index 0000000..788ac5b
--- /dev/null
@@ -0,0 +1,33 @@
+!
+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
+!
+
diff --git a/tests/topotests/cspf_topo1/r1/sharpd.conf b/tests/topotests/cspf_topo1/r1/sharpd.conf
new file mode 100644 (file)
index 0000000..272eac9
--- /dev/null
@@ -0,0 +1,3 @@
+!
+import-te
+!
diff --git a/tests/topotests/cspf_topo1/r1/zebra.conf b/tests/topotests/cspf_topo1/r1/zebra.conf
new file mode 100644 (file)
index 0000000..3aa0cad
--- /dev/null
@@ -0,0 +1,27 @@
+!
+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
+!
diff --git a/tests/topotests/cspf_topo1/r2/isisd.conf b/tests/topotests/cspf_topo1/r2/isisd.conf
new file mode 100644 (file)
index 0000000..04df685
--- /dev/null
@@ -0,0 +1,46 @@
+!
+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
+!
diff --git a/tests/topotests/cspf_topo1/r2/zebra.conf b/tests/topotests/cspf_topo1/r2/zebra.conf
new file mode 100644 (file)
index 0000000..1cc37ba
--- /dev/null
@@ -0,0 +1,45 @@
+!
+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
+!
diff --git a/tests/topotests/cspf_topo1/r3/isisd.conf b/tests/topotests/cspf_topo1/r3/isisd.conf
new file mode 100644 (file)
index 0000000..9db82c7
--- /dev/null
@@ -0,0 +1,34 @@
+!
+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
+!
diff --git a/tests/topotests/cspf_topo1/r3/zebra.conf b/tests/topotests/cspf_topo1/r3/zebra.conf
new file mode 100644 (file)
index 0000000..29a4c51
--- /dev/null
@@ -0,0 +1,27 @@
+!
+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
+!
diff --git a/tests/topotests/cspf_topo1/r4/isisd.conf b/tests/topotests/cspf_topo1/r4/isisd.conf
new file mode 100644 (file)
index 0000000..c5c4d4e
--- /dev/null
@@ -0,0 +1,40 @@
+!
+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
+!
diff --git a/tests/topotests/cspf_topo1/r4/zebra.conf b/tests/topotests/cspf_topo1/r4/zebra.conf
new file mode 100644 (file)
index 0000000..bf5306d
--- /dev/null
@@ -0,0 +1,26 @@
+!
+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
+!
diff --git a/tests/topotests/cspf_topo1/reference/cspf-failed-dst.txt b/tests/topotests/cspf_topo1/reference/cspf-failed-dst.txt
new file mode 100644 (file)
index 0000000..df792ce
--- /dev/null
@@ -0,0 +1 @@
+Path computation failed: 2
diff --git a/tests/topotests/cspf_topo1/reference/cspf-failed-same.txt b/tests/topotests/cspf_topo1/reference/cspf-failed-same.txt
new file mode 100644 (file)
index 0000000..48f6fd9
--- /dev/null
@@ -0,0 +1 @@
+Path computation failed: 3
diff --git a/tests/topotests/cspf_topo1/reference/cspf-failed-src.txt b/tests/topotests/cspf_topo1/reference/cspf-failed-src.txt
new file mode 100644 (file)
index 0000000..62d00cc
--- /dev/null
@@ -0,0 +1 @@
+Path computation failed: 1
diff --git a/tests/topotests/cspf_topo1/reference/cspf-failed.txt b/tests/topotests/cspf_topo1/reference/cspf-failed.txt
new file mode 100644 (file)
index 0000000..de53a93
--- /dev/null
@@ -0,0 +1 @@
+Path computation failed: 0
diff --git a/tests/topotests/cspf_topo1/reference/cspf-ipv4-delay.txt b/tests/topotests/cspf_topo1/reference/cspf-ipv4-delay.txt
new file mode 100644 (file)
index 0000000..2cc0428
--- /dev/null
@@ -0,0 +1,3 @@
+Path computation success
+       Cost: 35000
+       Edges: 10.0.0.2 10.0.4.4
diff --git a/tests/topotests/cspf_topo1/reference/cspf-ipv4-metric.txt b/tests/topotests/cspf_topo1/reference/cspf-ipv4-metric.txt
new file mode 100644 (file)
index 0000000..060a39c
--- /dev/null
@@ -0,0 +1,3 @@
+Path computation success
+       Cost: 20
+       Edges: 10.0.0.2 10.0.4.4
diff --git a/tests/topotests/cspf_topo1/reference/cspf-ipv4-te-metric.txt b/tests/topotests/cspf_topo1/reference/cspf-ipv4-te-metric.txt
new file mode 100644 (file)
index 0000000..6d98306
--- /dev/null
@@ -0,0 +1,3 @@
+Path computation success
+       Cost: 35
+       Edges: 10.0.1.2 10.0.4.4
diff --git a/tests/topotests/cspf_topo1/reference/cspf-ipv6-delay.txt b/tests/topotests/cspf_topo1/reference/cspf-ipv6-delay.txt
new file mode 100644 (file)
index 0000000..b65869b
--- /dev/null
@@ -0,0 +1,3 @@
+Path computation success
+       Cost: 70000
+       Edges: 2001:db8:1::1:2 2001:db8:3::3:3 2001:db8:5::3:4
diff --git a/tests/topotests/cspf_topo1/reference/cspf-ipv6-metric.txt b/tests/topotests/cspf_topo1/reference/cspf-ipv6-metric.txt
new file mode 100644 (file)
index 0000000..5acbb74
--- /dev/null
@@ -0,0 +1,3 @@
+Path computation success
+       Cost: 30
+       Edges: 2001:db8:1::1:2 2001:db8:3::3:3 2001:db8:5::3:4
diff --git a/tests/topotests/cspf_topo1/reference/cspf-ipv6-te-metric.txt b/tests/topotests/cspf_topo1/reference/cspf-ipv6-te-metric.txt
new file mode 100644 (file)
index 0000000..2290a04
--- /dev/null
@@ -0,0 +1,3 @@
+Path computation success
+       Cost: 60
+       Edges: 2001:db8:1::1:2 2001:db8:3::3:3 2001:db8:5::3:4
diff --git a/tests/topotests/cspf_topo1/reference/sharp-ted.json b/tests/topotests/cspf_topo1/reference/sharp-ted.json
new file mode 100644 (file)
index 0000000..db50260
--- /dev/null
@@ -0,0 +1,860 @@
+{
+  "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
+      }
+    ]
+  }
+}
diff --git a/tests/topotests/cspf_topo1/test_cspf_topo1.py b/tests/topotests/cspf_topo1/test_cspf_topo1.py
new file mode 100644 (file)
index 0000000..1b71ac3
--- /dev/null
@@ -0,0 +1,253 @@
+#!/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))
index 7a4773380176323d724d9d74cd0458d9a4dc19c8..027dd806cff32c798f1ee7d075c105f16dbe403c 100644 (file)
@@ -58,7 +58,6 @@
         "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,
index 8277e6d532f21341d7a031488aa6c71642e9b0c3..2e9a5ec84c2144b5a759983cb1db74e571a1925e 100644 (file)
@@ -58,7 +58,6 @@
         "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,
index 0ade398847bd58c111c3d39547579f2e34436cad..5c7ccdd6a2bd032a69a07fda6a2a139d7b528f85 100644 (file)
         "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,
index 0ade398847bd58c111c3d39547579f2e34436cad..5c7ccdd6a2bd032a69a07fda6a2a139d7b528f85 100644 (file)
         "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,
index ba9bdb01ff77e3f0c8e4e7b29040d45adc5c2e3f..48d475c720f1897069d60a3a65af35f600277e99 100644 (file)
         "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,
index 83bb27235eb1e862976d63da8b63f1d0f1fcb822..75443a42e8436cea449477515d024c46f46b2af2 100644 (file)
         "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,
index fb96054dbcfc138ac77faffb66c0c31084a1a507..88c87dcecd06db2ff2c1cc2b46fd172ddb740285 100644 (file)
@@ -81,6 +81,8 @@ NETWORK = {
         "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       +---+
@@ -557,6 +559,154 @@ def test_ospf_redistribution_tc8_p1(request):
     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
index 9624292ccd025fc5ccd5f1fd5650a01e88727eb6..d6bfca63f0f325f78c49776df5b33d2a142acb72 100644 (file)
         "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,
index 623d1dc7e05a6c4847bf6218650fd77b17dde427..ec30af60350ff16ba7a3cd52933404de469be344 100644 (file)
         "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,
index 117011a43a8730ba7771935fd4b281229a9f5a6e..853704b4f610c00d144e1f815fd3e0830fe6f018 100644 (file)
         "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,
index 5c2dee1e4b1f9129f14c735316910df3f795c718..0aa57713c0b0a5ae7ea901b061bef04377924332 100644 (file)
         "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,
index 47e747f3cadb4819785b17b0ece07c9e275f5a01..07637f3048cc93e71f52f9ed03ae1a7bc5acae20 100644 (file)
         "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,
index 74bd83fbdb56106b5249678cb3143892843d8399..e9eee96ff40c3d67f31875b1c151d31cfe0a1f00 100644 (file)
         "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,
index 1cea9f0455d4b79499146165e3ade29a372b276a..f912ae4a876da9813175de4d71555c791c402de1 100644 (file)
         "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,
index 2d12ad4c8e619370d6a164b87a107df403519999..064c86b161b952778e54b65c1a552bbad9add77c 100644 (file)
@@ -438,6 +438,10 @@ parse_encap_seg6local(struct rtattr *tb,
        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;
 }
 
@@ -1467,6 +1471,16 @@ static bool _netlink_route_build_singlepath(const struct prefix *p,
                                                   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__,
@@ -2570,6 +2584,18 @@ ssize_t netlink_nexthop_msg_encode(uint16_t cmd,
                                                    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);
index fac312cf7c0c345e965714cc29d8eb192cb57cef..c1b104aec7ca8c4d123ceba5893c6b0ad9997f63 100644 (file)
@@ -2369,7 +2369,7 @@ static unsigned nexthop_active_check(struct route_node *rn,
        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);