]> git.proxmox.com Git - mirror_frr.git/commitdiff
Merge pull request #4731 from mjstapp/fix_redist_update
authorDonald Sharp <sharpd@cumulusnetworks.com>
Wed, 18 Sep 2019 23:43:43 +0000 (19:43 -0400)
committerGitHub <noreply@github.com>
Wed, 18 Sep 2019 23:43:43 +0000 (19:43 -0400)
zebra: redistribute deletes when updating selected route

169 files changed:
README.md
bfdd/bfd.c
bfdd/bfd.h
bfdd/bfdd_vty.c
bfdd/ptm_adapter.c
bgpd/bgp_attr.c
bgpd/bgp_attr.h
bgpd/bgp_bmp.c
bgpd/bgp_evpn.c
bgpd/bgp_fsm.c
bgpd/bgp_keepalives.c
bgpd/bgp_main.c
bgpd/bgp_mplsvpn.c
bgpd/bgp_open.c
bgpd/bgp_open.h
bgpd/bgp_packet.h
bgpd/bgp_route.c
bgpd/bgp_route.h
bgpd/bgp_routemap.c
bgpd/bgp_rpki.c
bgpd/bgpd.c
bgpd/bgpd.h
bgpd/rfapi/rfapi.c
bgpd/rfapi/vnc_export_bgp.c
debian/frr-pythontools.install
debian/rules
doc/user/bgp.rst
doc/user/index.rst
doc/user/ospf_fundamentals.rst
doc/user/pim.rst
doc/user/routemap.rst
doc/user/subdir.am
doc/user/watchfrr.rst [new file with mode: 0644]
doc/user/zebra.rst
eigrpd/eigrp_routemap.c
fpm/subdir.am
grpc/subdir.am
isisd/isis_circuit.c
isisd/isis_circuit.h
isisd/isis_cli.c
isisd/isis_lsp.c
isisd/isis_mt.c
isisd/isis_mt.h
isisd/isis_northbound.c
isisd/isis_pdu.c
isisd/isis_route.c
isisd/isis_route.h
isisd/isis_te.c
isisd/isis_te.h
isisd/isis_tlvs.c
isisd/isis_tlvs.h
isisd/isis_zebra.c
isisd/isis_zebra.h
isisd/isisd.h
ldpd/l2vpn.c
ldpd/lde.c
ldpd/lde.h
ldpd/lde_lib.c
ldpd/ldp_zebra.c
ldpd/ldpd.h
lib/command.c
lib/frr_pthread.c
lib/if.c
lib/libfrr.c
lib/log.c
lib/mpls.h
lib/northbound.c
lib/northbound.h
lib/northbound_cli.c
lib/northbound_confd.c
lib/northbound_grpc.cpp
lib/northbound_sysrepo.c
lib/routemap.c
lib/routemap.h
lib/vrf.c
lib/vty.c
lib/yang_wrappers.c
lib/yang_wrappers.h
lib/zclient.c
lib/zclient.h
ospf6d/ospf6_asbr.c
ospfd/ospf_main.c
ospfd/ospf_sr.c
ospfd/ospf_sr.h
ospfd/ospfd.c
pbrd/pbr_nht.c
pimd/pim_assert.c
qpb/subdir.am
redhat/frr.spec.in
ripd/ripd.c
ripngd/ripngd.c
staticd/static_routes.c
staticd/static_vty.c
staticd/static_zebra.c
tests/bgpd/test_aspath.c
tests/bgpd/test_capability.c
tests/bgpd/test_peer_attr.c
tests/isisd/test_fuzz_isis_tlv_tests.h.gz
tests/topotests/all-protocol-startup/r1/ipv4_routes.ref
tests/topotests/all-protocol-startup/r1/ipv6_routes.ref
tests/topotests/all-protocol-startup/r1/zebra.conf
tests/topotests/bgp_aggregate-address_route-map/__init__.py [new file with mode: 0644]
tests/topotests/bgp_aggregate-address_route-map/r1/bgpd.conf [new file with mode: 0644]
tests/topotests/bgp_aggregate-address_route-map/r1/zebra.conf [new file with mode: 0644]
tests/topotests/bgp_aggregate-address_route-map/r2/bgpd.conf [new file with mode: 0644]
tests/topotests/bgp_aggregate-address_route-map/r2/zebra.conf [new file with mode: 0644]
tests/topotests/bgp_aggregate-address_route-map/test_bgp_aggregate-address_route-map.py [new file with mode: 0644]
tests/topotests/ldp-topo1/r1/ip_mpls_route.ref-1 [deleted file]
tests/topotests/ldp-topo1/r1/show_ipv4_route.ref-1 [deleted file]
tests/topotests/ldp-topo1/r1/show_mpls_ldp_binding.ref-1 [deleted file]
tests/topotests/ldp-topo1/r1/show_mpls_ldp_discovery.ref-1 [deleted file]
tests/topotests/ldp-topo1/r1/show_mpls_ldp_interface.ref-1 [deleted file]
tests/topotests/ldp-topo1/r1/show_mpls_ldp_neighbor.ref-1 [deleted file]
tests/topotests/ldp-topo1/r1/show_mpls_table.ref
tests/topotests/ldp-topo1/r1/show_mpls_table.ref-1 [deleted file]
tests/topotests/ldp-topo1/r1/show_mpls_table.ref-no-impl-null [deleted file]
tests/topotests/ldp-topo1/r2/show_ipv4_route.ref-1 [deleted file]
tests/topotests/ldp-topo1/r2/show_mpls_ldp_binding.ref-1 [deleted file]
tests/topotests/ldp-topo1/r2/show_mpls_ldp_discovery.ref-1 [deleted file]
tests/topotests/ldp-topo1/r2/show_mpls_ldp_interface.ref-1 [deleted file]
tests/topotests/ldp-topo1/r2/show_mpls_ldp_neighbor.ref-1 [deleted file]
tests/topotests/ldp-topo1/r2/show_mpls_table.ref
tests/topotests/ldp-topo1/r2/show_mpls_table.ref-1 [deleted file]
tests/topotests/ldp-topo1/r2/show_mpls_table.ref-no-impl-null [deleted file]
tests/topotests/ldp-topo1/r3/show_ipv4_route.ref-1 [deleted file]
tests/topotests/ldp-topo1/r3/show_mpls_ldp_binding.ref-1 [deleted file]
tests/topotests/ldp-topo1/r3/show_mpls_ldp_discovery.ref-1 [deleted file]
tests/topotests/ldp-topo1/r3/show_mpls_ldp_interface.ref-1 [deleted file]
tests/topotests/ldp-topo1/r3/show_mpls_ldp_neighbor.ref-1 [deleted file]
tests/topotests/ldp-topo1/r3/show_mpls_table.ref
tests/topotests/ldp-topo1/r3/show_mpls_table.ref-1 [deleted file]
tests/topotests/ldp-topo1/r3/show_mpls_table.ref-no-impl-null [deleted file]
tests/topotests/ldp-topo1/r4/show_ipv4_route.ref-1 [deleted file]
tests/topotests/ldp-topo1/r4/show_mpls_ldp_binding.ref-1 [deleted file]
tests/topotests/ldp-topo1/r4/show_mpls_ldp_discovery.ref-1 [deleted file]
tests/topotests/ldp-topo1/r4/show_mpls_ldp_interface.ref-1 [deleted file]
tests/topotests/ldp-topo1/r4/show_mpls_ldp_neighbor.ref-1 [deleted file]
tests/topotests/ldp-topo1/r4/show_mpls_table.ref
tests/topotests/ldp-topo1/r4/show_mpls_table.ref-1 [deleted file]
tests/topotests/ldp-topo1/r4/show_mpls_table.ref-no-impl-null [deleted file]
tests/topotests/ldp-topo1/test_ldp_topo1.py
tests/topotests/ospf-sr-topo1/r1/zebra_mpls.json
tests/topotests/ospf-sr-topo1/r2/zebra_mpls.json
tests/topotests/ospf-sr-topo1/r3/zebra_mpls.json
tests/topotests/ospf-sr-topo1/r4/zebra_mpls.json
tests/topotests/pytest.ini
tools/etc/frr/support_bundle_commands.conf
tools/generate_support_bundle.py [changed mode: 0644->0755]
tools/subdir.am
vtysh/vtysh_config.c
watchfrr/subdir.am
watchfrr/watchfrr.c
watchfrr/watchfrr.h
watchfrr/watchfrr_vty.c
yang/frr-eigrpd.yang
yang/frr-interface.yang
yang/frr-isisd.yang
yang/frr-ripd.yang
yang/frr-ripngd.yang
yang/libyang_plugins/frr_user_types.c
zebra/main.c
zebra/zapi_msg.c
zebra/zebra_mpls.c
zebra/zebra_mpls.h
zebra/zebra_nhg.c
zebra/zebra_rib.c
zebra/zebra_rnh.c
zebra/zebra_routemap.c
zebra/zebra_vty.c

index e8c775684a5b5e86627fe8a5120a6958bac9a25c..bb13481cf29c2897d03e9f24dfd0cca4e206b2cb 100644 (file)
--- a/README.md
+++ b/README.md
@@ -27,14 +27,15 @@ FRR currently supports the following protocols:
 Installation & Use
 ------------------
 
-Packages are available for various distributions on our
+For source tarballs, see the
 [releases page](https://github.com/FRRouting/frr/releases).
 
-Snaps are also available [here](https://snapcraft.io/frr).
+For Debian and its derivatives, use the APT repository at
+[https://deb.frrouting.org/](https://deb.frrouting.org/).
 
 Instructions on building and installing from source for supported platforms may
-be found
-[here](http://docs.frrouting.org/projects/dev-guide/en/latest/building.html).
+be found in the
+[developer docs](http://docs.frrouting.org/projects/dev-guide/en/latest/building.html).
 
 Once installed, please refer to the [user guide](http://docs.frrouting.org/)
 for instructions on use.
index 1f1568f5114399dc439c830781591f4fccfa525e..245f2dc5ee2e5e057214479d6698be384ef806c7 100644 (file)
@@ -391,10 +391,8 @@ struct bfd_session *ptm_bfd_sess_find(struct bfd_pkt *cp,
 
        /* Search for session without using discriminator. */
        ifp = if_lookup_by_index(ifindex, vrfid);
-       if (vrfid != VRF_DEFAULT)
-               vrf = vrf_lookup_by_id(vrfid);
-       else
-               vrf = NULL;
+
+       vrf = vrf_lookup_by_id(vrfid);
 
        gen_bfd_key(&key, peer, local, is_mhop, ifp ? ifp->name : NULL,
                    vrf ? vrf->name : VRF_DEFAULT_NAME);
@@ -1632,6 +1630,16 @@ static int bfd_vrf_delete(struct vrf *vrf)
        return 0;
 }
 
+static int bfd_vrf_update(struct vrf *vrf)
+{
+       if (!vrf_is_enabled(vrf))
+               return 0;
+       log_debug("VRF update: %s(%u)", vrf->name, vrf->vrf_id);
+       /* a different name is given; update bfd list */
+       bfdd_sessions_enable_vrf(vrf);
+       return 0;
+}
+
 static int bfd_vrf_enable(struct vrf *vrf)
 {
        struct bfd_vrf_global *bvrf;
@@ -1719,7 +1727,7 @@ static int bfd_vrf_disable(struct vrf *vrf)
 void bfd_vrf_init(void)
 {
        vrf_init(bfd_vrf_new, bfd_vrf_enable, bfd_vrf_disable,
-                bfd_vrf_delete, NULL);
+                bfd_vrf_delete, bfd_vrf_update);
 }
 
 void bfd_vrf_terminate(void)
@@ -1743,3 +1751,54 @@ struct bfd_vrf_global *bfd_vrf_look_by_session(struct bfd_session *bfd)
                return NULL;
        return bfd->vrf->info;
 }
+
+void bfd_session_update_vrf_name(struct bfd_session *bs, struct vrf *vrf)
+{
+       if (!vrf || !bs)
+               return;
+       /* update key */
+       hash_release(bfd_key_hash, bs);
+       /*
+        * HACK: Change the BFD VRF in the running configuration directly,
+        * bypassing the northbound layer. This is necessary to avoid deleting
+        * the BFD and readding it in the new VRF, which would have
+        * several implications.
+        */
+       if (yang_module_find("frr-bfdd") && bs->key.vrfname[0]) {
+               struct lyd_node *bfd_dnode;
+               char xpath[XPATH_MAXLEN], xpath_srcaddr[XPATH_MAXLEN + 32];
+               char addr_buf[INET6_ADDRSTRLEN];
+               int slen;
+
+               /* build xpath */
+               if (bs->key.mhop) {
+                       inet_ntop(bs->key.family, &bs->key.local, addr_buf, sizeof(addr_buf));
+                       snprintf(xpath_srcaddr, sizeof(xpath_srcaddr), "[source-addr='%s']",
+                                addr_buf);
+               } else
+                       xpath_srcaddr[0] = 0;
+               inet_ntop(bs->key.family, &bs->key.peer, addr_buf, sizeof(addr_buf));
+               slen = snprintf(xpath, sizeof(xpath),
+                               "/frr-bfdd:bfdd/bfd/sessions/%s%s[dest-addr='%s']",
+                               bs->key.mhop ? "multi-hop" : "single-hop", xpath_srcaddr,
+                               addr_buf);
+               if (bs->key.ifname[0])
+                       slen += snprintf(xpath + slen, sizeof(xpath) - slen,
+                                        "[interface='%s']", bs->key.ifname);
+               else
+                       slen += snprintf(xpath + slen, sizeof(xpath) - slen,
+                                        "[interface='']");
+               snprintf(xpath + slen, sizeof(xpath) - slen, "[vrf='%s']/vrf",
+                        bs->key.vrfname);
+
+               bfd_dnode = yang_dnode_get(running_config->dnode, xpath,
+                                          bs->key.vrfname);
+               if (bfd_dnode) {
+                       yang_dnode_change_leaf(bfd_dnode, vrf->name);
+                       running_config->version++;
+               }
+       }
+       memset(bs->key.vrfname, 0, sizeof(bs->key.vrfname));
+       strlcpy(bs->key.vrfname, vrf->name, sizeof(bs->key.vrfname));
+       hash_get(bfd_key_hash, bs, hash_alloc_intern);
+}
index 10aeb3e52c9b6a704be4602764d63ba1738bdae7..cdec78d1226066ceb130c38f3cd5942628fbff20 100644 (file)
@@ -630,6 +630,7 @@ void bfdd_zclient_unregister(vrf_id_t vrf_id);
 void bfdd_zclient_register(vrf_id_t vrf_id);
 void bfdd_sessions_enable_vrf(struct vrf *vrf);
 void bfdd_sessions_disable_vrf(struct vrf *vrf);
+void bfd_session_update_vrf_name(struct bfd_session *bs, struct vrf *vrf);
 
 int ptm_bfd_notify(struct bfd_session *bs);
 
index a211f34219af8ef8a99ef05b5b634b30b20b1675..5663ce54cbc7e4e27d57caabacc27624109a07b3 100644 (file)
@@ -685,6 +685,9 @@ static int bfd_configure_peer(struct bfd_peer_cfg *bpc, bool mhop,
                        snprintf(ebuf, ebuflen, "vrf name too long");
                        return -1;
                }
+       } else {
+               bpc->bpc_has_vrfname = true;
+               strlcpy(bpc->bpc_vrfname, VRF_DEFAULT_NAME, sizeof(bpc->bpc_vrfname));
        }
 
        return 0;
index 3e2ace6ea630a95598150799c158be5e185a4730..ae6d04e77d5e72065a20304847d41b2c5fdf97c2 100644 (file)
@@ -376,6 +376,9 @@ static int _ptm_msg_read(struct stream *msg, int command, vrf_id_t vrf_id,
                        log_error("ptm-read: vrf id %u could not be identified", vrf_id);
                        return -1;
                }
+       } else {
+               bpc->bpc_has_vrfname = true;
+               strlcpy(bpc->bpc_vrfname, VRF_DEFAULT_NAME, sizeof(bpc->bpc_vrfname));
        }
 
        STREAM_GETC(msg, bpc->bpc_cbit);
@@ -627,6 +630,11 @@ void bfdd_sessions_enable_vrf(struct vrf *vrf)
        /* it may affect configs without interfaces */
        TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) {
                bs = bso->bso_bs;
+               /* update name */
+               if (bs->vrf && bs->vrf == vrf) {
+                       if (!strmatch(bs->key.vrfname, vrf->name))
+                               bfd_session_update_vrf_name(bs, vrf);
+               }
                if (bs->vrf)
                        continue;
                if (bs->key.vrfname[0] &&
index e21c84355e22cd34f9d41a5dadb16652b3f6f479..248bbca8cf15d6017c083e0f862c78a539304e86 100644 (file)
@@ -519,8 +519,7 @@ unsigned int attrhash_key_make(const void *p)
        MIX(attr->mp_nexthop_len);
        key = jhash(attr->mp_nexthop_global.s6_addr, IPV6_MAX_BYTELEN, key);
        key = jhash(attr->mp_nexthop_local.s6_addr, IPV6_MAX_BYTELEN, key);
-       MIX(attr->nh_ifindex);
-       MIX(attr->nh_lla_ifindex);
+       MIX3(attr->nh_ifindex, attr->nh_lla_ifindex, attr->distance);
 
        return key;
 }
@@ -562,7 +561,8 @@ bool attrhash_cmp(const void *p1, const void *p2)
                                      &attr2->originator_id)
                    && overlay_index_same(attr1, attr2)
                    && attr1->nh_ifindex == attr2->nh_ifindex
-                   && attr1->nh_lla_ifindex == attr2->nh_lla_ifindex)
+                   && attr1->nh_lla_ifindex == attr2->nh_lla_ifindex
+                   && attr1->distance == attr2->distance)
                        return true;
        }
 
@@ -724,10 +724,13 @@ struct attr *bgp_attr_aggregate_intern(struct bgp *bgp, uint8_t origin,
                                       struct community *community,
                                       struct ecommunity *ecommunity,
                                       struct lcommunity *lcommunity,
-                                      int as_set, uint8_t atomic_aggregate)
+                                      struct bgp_aggregate *aggregate,
+                                      uint8_t atomic_aggregate,
+                                      struct prefix *p)
 {
        struct attr attr;
        struct attr *new;
+       int ret;
 
        memset(&attr, 0, sizeof(struct attr));
 
@@ -778,7 +781,7 @@ struct attr *bgp_attr_aggregate_intern(struct bgp *bgp, uint8_t origin,
        attr.label = MPLS_INVALID_LABEL;
        attr.weight = BGP_ATTR_DEFAULT_WEIGHT;
        attr.mp_nexthop_len = IPV6_MAX_BYTELEN;
-       if (!as_set || atomic_aggregate)
+       if (!aggregate->as_set || atomic_aggregate)
                attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE);
        attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR);
        if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
@@ -789,7 +792,42 @@ struct attr *bgp_attr_aggregate_intern(struct bgp *bgp, uint8_t origin,
        attr.label_index = BGP_INVALID_LABEL_INDEX;
        attr.label = MPLS_INVALID_LABEL;
 
-       new = bgp_attr_intern(&attr);
+       /* Apply route-map */
+       if (aggregate->rmap.name) {
+               struct attr attr_tmp = attr;
+               struct bgp_path_info rmap_path;
+
+               memset(&rmap_path, 0, sizeof(struct bgp_path_info));
+               rmap_path.peer = bgp->peer_self;
+               rmap_path.attr = &attr_tmp;
+
+               SET_FLAG(bgp->peer_self->rmap_type, PEER_RMAP_TYPE_AGGREGATE);
+
+               ret = route_map_apply(aggregate->rmap.map, p, RMAP_BGP,
+                                     &rmap_path);
+
+               bgp->peer_self->rmap_type = 0;
+
+               if (ret == RMAP_DENYMATCH) {
+                       /* Free uninterned attribute. */
+                       bgp_attr_flush(&attr_tmp);
+
+                       /* Unintern original. */
+                       aspath_unintern(&attr.aspath);
+                       return NULL;
+               }
+
+               if (bgp_flag_check(bgp, BGP_FLAG_GRACEFUL_SHUTDOWN))
+                       bgp_attr_add_gshut_community(&attr_tmp);
+
+               new = bgp_attr_intern(&attr_tmp);
+       } else {
+
+               if (bgp_flag_check(bgp, BGP_FLAG_GRACEFUL_SHUTDOWN))
+                       bgp_attr_add_gshut_community(&attr);
+
+               new = bgp_attr_intern(&attr);
+       }
 
        aspath_unintern(&new->aspath);
        return new;
@@ -1647,8 +1685,8 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args,
 #define BGP_MP_REACH_MIN_SIZE 5
 #define LEN_LEFT       (length - (stream_get_getp(s) - start))
        if ((length > STREAM_READABLE(s)) || (length < BGP_MP_REACH_MIN_SIZE)) {
-               zlog_info("%s: %s sent invalid length, %lu", __func__,
-                         peer->host, (unsigned long)length);
+               zlog_info("%s: %s sent invalid length, %lu, of MP_REACH_NLRI",
+                         __func__, peer->host, (unsigned long)length);
                return BGP_ATTR_PARSE_ERROR_NOTIFYPLS;
        }
 
@@ -1664,7 +1702,7 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args,
                 */
                if (bgp_debug_update(peer, NULL, NULL, 0))
                        zlog_debug(
-                               "%s: MP_REACH received AFI %s or SAFI %s is unrecognized",
+                               "%s sent unrecognizable AFI, %s or, SAFI, %s, of MP_REACH_NLRI",
                                peer->host, iana_afi2str(pkt_afi),
                                iana_safi2str(pkt_safi));
                return BGP_ATTR_PARSE_ERROR;
@@ -1675,7 +1713,7 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args,
 
        if (LEN_LEFT < attr->mp_nexthop_len) {
                zlog_info(
-                       "%s: %s, MP nexthop length, %u, goes past end of attribute",
+                       "%s: %s sent next-hop length, %u, in MP_REACH_NLRI which goes past the end of attribute",
                        __func__, peer->host, attr->mp_nexthop_len);
                return BGP_ATTR_PARSE_ERROR_NOTIFYPLS;
        }
@@ -1684,7 +1722,7 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args,
        switch (attr->mp_nexthop_len) {
        case 0:
                if (safi != SAFI_FLOWSPEC) {
-                       zlog_info("%s: (%s) Wrong multiprotocol next hop length: %d",
+                       zlog_info("%s: %s sent wrong next-hop length, %d, in MP_REACH_NLRI",
                                  __func__, peer->host, attr->mp_nexthop_len);
                        return BGP_ATTR_PARSE_ERROR_NOTIFYPLS;
                }
@@ -1716,7 +1754,7 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args,
                stream_get(&attr->mp_nexthop_global, s, IPV6_MAX_BYTELEN);
                if (IN6_IS_ADDR_LINKLOCAL(&attr->mp_nexthop_global)) {
                        if (!peer->nexthop.ifp) {
-                               zlog_warn("%s: Received a V6/VPNV6 Global attribute but address is a V6 LL and we have no peer interface information, withdrawing",
+                               zlog_warn("%s sent a v6 global attribute but address is a V6 LL and there's no peer interface information. Hence, withdrawing",
                                          peer->host);
                                return BGP_ATTR_PARSE_WITHDRAW;
                        }
@@ -1733,7 +1771,7 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args,
                stream_get(&attr->mp_nexthop_global, s, IPV6_MAX_BYTELEN);
                if (IN6_IS_ADDR_LINKLOCAL(&attr->mp_nexthop_global)) {
                        if (!peer->nexthop.ifp) {
-                               zlog_warn("%s: Received V6/VPNV6 Global and LL attribute but global address is a V6 LL and we have no peer interface information, withdrawing",
+                               zlog_warn("%s sent a v6 global and LL attribute but global address is a V6 LL and there's no peer interface information. Hence, withdrawing",
                                          peer->host);
                                return BGP_ATTR_PARSE_WITHDRAW;
                        }
@@ -1751,7 +1789,7 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args,
 
                        if (bgp_debug_update(peer, NULL, NULL, 1))
                                zlog_debug(
-                                       "%s rcvd nexthops %s, %s -- ignoring non-LL value",
+                                       "%s sent next-hops %s and %s. Ignoring non-LL value",
                                        peer->host,
                                        inet_ntop(AF_INET6,
                                                  &attr->mp_nexthop_global,
@@ -1763,21 +1801,21 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args,
                        attr->mp_nexthop_len = IPV6_MAX_BYTELEN;
                }
                if (!peer->nexthop.ifp) {
-                       zlog_warn("%s: Received a V6 LL nexthop and we have no peer interface information, withdrawing",
+                       zlog_warn("%s sent a v6 LL next-hop and there's no peer interface information. Hence, withdrawing",
                                  peer->host);
                        return BGP_ATTR_PARSE_WITHDRAW;
                }
                attr->nh_lla_ifindex = peer->nexthop.ifp->ifindex;
                break;
        default:
-               zlog_info("%s: (%s) Wrong multiprotocol next hop length: %d",
+               zlog_info("%s: %s sent wrong next-hop length, %d, in MP_REACH_NLRI",
                          __func__, peer->host, attr->mp_nexthop_len);
                return BGP_ATTR_PARSE_ERROR_NOTIFYPLS;
        }
 
        if (!LEN_LEFT) {
-               zlog_info("%s: (%s) Failed to read SNPA and NLRI(s)", __func__,
-                         peer->host);
+               zlog_info("%s: %s sent SNPA which couldn't be read",
+                         __func__, peer->host);
                return BGP_ATTR_PARSE_ERROR_NOTIFYPLS;
        }
 
@@ -1793,12 +1831,13 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args,
        /* must have nrli_len, what is left of the attribute */
        nlri_len = LEN_LEFT;
        if (nlri_len > STREAM_READABLE(s)) {
-               zlog_info("%s: (%s) Failed to read NLRI", __func__, peer->host);
+               zlog_info("%s: %s sent MP_REACH_NLRI which couldn't be read",
+                         __func__, peer->host);
                return BGP_ATTR_PARSE_ERROR_NOTIFYPLS;
        }
 
        if (!nlri_len) {
-               zlog_info("%s: (%s) No Reachability, Treating as a EOR marker",
+               zlog_info("%s: %s sent a zero-length NLRI. Hence, treating as a EOR marker",
                          __func__, peer->host);
 
                mp_update->afi = afi;
@@ -2005,8 +2044,8 @@ static int bgp_attr_encap(uint8_t type, struct peer *peer, /* IN */
                length -= 4;
 
                if (tlv_length != length) {
-                       zlog_info("%s: tlv_length(%d) != length(%d)", __func__,
-                                 tlv_length, length);
+                       zlog_info("%s: tlv_length(%d) != length(%d)",
+                                 __func__, tlv_length, length);
                }
        }
 
index 1592a8df4edae90fe0d627dc39c13c95a8bf2082..cfa428a7969a0ec2ddf28b5ac1cb382992aaaef9 100644 (file)
@@ -206,6 +206,9 @@ struct attr {
 
        /* EVPN local router-mac */
        struct ethaddr rmac;
+
+       /* Distance as applied by Route map */
+       uint8_t distance;
 };
 
 /* rmap_change_flags definition */
@@ -272,8 +275,9 @@ extern struct attr *bgp_attr_aggregate_intern(struct bgp *bgp, uint8_t origin,
                                              struct community *community,
                                              struct ecommunity *ecommunity,
                                              struct lcommunity *lcommunity,
-                                             int as_set,
-                                             uint8_t atomic_aggregate);
+                                             struct bgp_aggregate *aggregate,
+                                             uint8_t atomic_aggregate,
+                                             struct prefix *p);
 extern bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *,
                                       struct stream *, struct attr *,
                                       struct bpacket_attr_vec_arr *vecarr,
index 3af373b5629938dce3aabdd7bc0ce23b8a26998a..551102151e04d54674a4863f37a33f75d2b65d99 100644 (file)
@@ -1767,7 +1767,7 @@ static struct cmd_node bmp_node = {BMP_NODE, "%s(config-bgp-bmp)# "};
 #define BMP_STR "BGP Monitoring Protocol\n"
 
 #ifndef VTYSH_EXTRACT_PL
-#include "bgp_bmp_clippy.c"
+#include "bgpd/bgp_bmp_clippy.c"
 #endif
 
 DEFPY_NOSH(bmp_targets_main,
index 6c77f18f33d1f3c4c2b804856ac529f5025af0b0..50fef00a96c94952f191878609a0457c24df22d9 100644 (file)
@@ -5668,6 +5668,8 @@ int bgp_evpn_local_l3vni_del(vni_t l3vni, vrf_id_t vrf_id)
        for (ALL_LIST_ELEMENTS(bgp_vrf->l2vnis, node, next, vpn))
                bgpevpn_unlink_from_l3vni(vpn);
 
+       UNSET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_L3VNI_PREFIX_ROUTES_ONLY);
+
        /* Delete the instance if it was autocreated */
        if (CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_AUTO))
                bgp_delete(bgp_vrf);
index 79c873e6019a20d666b5449af5adc6526b570a2e..0be8becbabc593c9aa66ecda158aad00ee8f45b3 100644 (file)
@@ -1324,7 +1324,7 @@ static int bgp_connect_check(struct thread *thread)
 
        /* If getsockopt is fail, this is fatal error. */
        if (ret < 0) {
-               zlog_info("can't get sockopt for nonblocking connect: %d(%s)",
+               zlog_err("can't get sockopt for nonblocking connect: %d(%s)",
                          errno, safe_strerror(errno));
                BGP_EVENT_ADD(peer, TCP_fatal_error);
                return -1;
index 6de1c216a65b4bc155061ab3978bd4544dfafcdd..3a49e8bc00afe5ba01104394cea2bb34b0f7dd60 100644 (file)
@@ -97,11 +97,18 @@ static void peer_process(struct hash_bucket *hb, void *arg)
 
        static struct timeval tolerance = {0, 100000};
 
+       uint32_t v_ka = atomic_load_explicit(&pkat->peer->v_keepalive,
+                                            memory_order_relaxed);
+
+       /* 0 keepalive timer means no keepalives */
+       if (v_ka == 0)
+               return;
+
        /* calculate elapsed time since last keepalive */
        monotime_since(&pkat->last, &elapsed);
 
        /* calculate difference between elapsed time and configured time */
-       ka.tv_sec = pkat->peer->v_keepalive;
+       ka.tv_sec = v_ka;
        timersub(&ka, &elapsed, &diff);
 
        int send_keepalive =
index abd8586f4c71d73ed392e32a3ba9c1ea17e10cfc..ef73b47ffb9407336403e32722bead0765e9e935 100644 (file)
@@ -269,12 +269,20 @@ static int bgp_vrf_enable(struct vrf *vrf)
                zlog_debug("VRF enable add %s id %u", vrf->name, vrf->vrf_id);
 
        bgp = bgp_lookup_by_name(vrf->name);
-       if (bgp) {
+       if (bgp && bgp->vrf_id != vrf->vrf_id) {
                if (bgp->name && strmatch(vrf->name, VRF_DEFAULT_NAME)) {
                        XFREE(MTYPE_BGP, bgp->name);
                        bgp->name = NULL;
                        XFREE(MTYPE_BGP, bgp->name_pretty);
                        bgp->name_pretty = XSTRDUP(MTYPE_BGP, "VRF default");
+                       bgp->inst_type = BGP_INSTANCE_TYPE_DEFAULT;
+#if ENABLE_BGP_VNC
+                       if (!bgp->rfapi) {
+                               bgp->rfapi = bgp_rfapi_new(bgp);
+                               assert(bgp->rfapi);
+                               assert(bgp->rfapi_cfg);
+                       }
+#endif /* ENABLE_BGP_VNC */
                }
                old_vrf_id = bgp->vrf_id;
                /* We have instance configured, link to VRF and make it "up". */
@@ -343,7 +351,7 @@ static int bgp_vrf_disable(struct vrf *vrf)
 static void bgp_vrf_init(void)
 {
        vrf_init(bgp_vrf_new, bgp_vrf_enable, bgp_vrf_disable,
-                bgp_vrf_delete, NULL);
+                bgp_vrf_delete, bgp_vrf_enable);
 }
 
 static void bgp_vrf_terminate(void)
index 1156810510d3c744ba416bd3702032b22412df6a..c81abd643ff705bdfca7e35d6bbaf621b5cff9be 100644 (file)
@@ -781,12 +781,12 @@ void vpn_leak_from_vrf_update(struct bgp *bgp_vpn,            /* to */
                        static_attr.nexthop.s_addr = nexthop->u.prefix4.s_addr;
 
                        static_attr.mp_nexthop_global_in = nexthop->u.prefix4;
-                       static_attr.mp_nexthop_len = 4;
+                       static_attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
                        break;
 
                case AF_INET6:
                        static_attr.mp_nexthop_global = nexthop->u.prefix6;
-                       static_attr.mp_nexthop_len = 16;
+                       static_attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV6_GLOBAL;
                        break;
 
                default:
@@ -802,7 +802,8 @@ void vpn_leak_from_vrf_update(struct bgp *bgp_vpn,      /* to */
                                 */
                                static_attr.mp_nexthop_global_in =
                                        static_attr.nexthop;
-                               static_attr.mp_nexthop_len = 4;
+                               static_attr.mp_nexthop_len =
+                                       BGP_ATTR_NHLEN_IPV4;
                                /*
                                 * XXX Leave static_attr.nexthop
                                 * intact for NHT
@@ -821,7 +822,8 @@ void vpn_leak_from_vrf_update(struct bgp *bgp_vpn,      /* to */
                            && !BGP_ATTR_NEXTHOP_AFI_IP6(path_vrf->attr)) {
                                static_attr.mp_nexthop_global_in.s_addr =
                                        static_attr.nexthop.s_addr;
-                               static_attr.mp_nexthop_len = 4;
+                               static_attr.mp_nexthop_len =
+                                       BGP_ATTR_NHLEN_IPV4;
                                static_attr.flag |=
                                        ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP);
                        }
index 7e5e07099d00022bc94c42bff2af6d7a7500b599..f17bc7b8c06e7de9d3844be140bd19bf5df1ec14 100644 (file)
@@ -1031,7 +1031,7 @@ as_t peek_for_as4_capability(struct peer *peer, uint8_t length)
        as_t as4 = 0;
 
        if (BGP_DEBUG(as4, AS4))
-               zlog_info(
+               zlog_debug(
                        "%s [AS4] rcv OPEN w/ OPTION parameter len: %u,"
                        " peeking for as4",
                        peer->host, length);
@@ -1075,7 +1075,7 @@ as_t peek_for_as4_capability(struct peer *peer, uint8_t length)
 
                                if (hdr.code == CAPABILITY_CODE_AS4) {
                                        if (BGP_DEBUG(as4, AS4))
-                                               zlog_info(
+                                               zlog_debug(
                                                        "[AS4] found AS4 capability, about to parse");
                                        as4 = bgp_capability_as4(peer, &hdr);
 
index 8359f59a4131908230a8aa074b8c391fd64df3da..5250a68581090d6dc870b20f821bbfa1bad9c6e8 100644 (file)
@@ -68,13 +68,13 @@ struct graceful_restart_af {
 /* Cooperative Route Filtering Capability.  */
 
 /* ORF Type */
-#define ORF_TYPE_PREFIX                64 
+#define ORF_TYPE_PREFIX                64
 #define ORF_TYPE_PREFIX_OLD           128
 
 /* ORF Mode */
-#define ORF_MODE_RECEIVE                1 
-#define ORF_MODE_SEND                   2 
-#define ORF_MODE_BOTH                   3 
+#define ORF_MODE_RECEIVE                1
+#define ORF_MODE_SEND                   2
+#define ORF_MODE_BOTH                   3
 
 /* Capability Message Action.  */
 #define CAPABILITY_ACTION_SET           0
index fc6fc66a4c3259a43765472924010b062cf59859..49e401790f18c44da490337aa19e385a1560a15e 100644 (file)
@@ -39,14 +39,14 @@ DECLARE_HOOK(bgp_packet_send,
 
 /* When to refresh */
 #define REFRESH_IMMEDIATE 1
-#define REFRESH_DEFER     2 
+#define REFRESH_DEFER     2
 
 /* ORF Common part flag */
-#define ORF_COMMON_PART_ADD        0x00 
-#define ORF_COMMON_PART_REMOVE     0x80 
-#define ORF_COMMON_PART_REMOVE_ALL 0xC0 
-#define ORF_COMMON_PART_PERMIT     0x00 
-#define ORF_COMMON_PART_DENY       0x20 
+#define ORF_COMMON_PART_ADD        0x00
+#define ORF_COMMON_PART_REMOVE     0x80
+#define ORF_COMMON_PART_REMOVE_ALL 0xC0
+#define ORF_COMMON_PART_PERMIT     0x00
+#define ORF_COMMON_PART_DENY       0x20
 
 /* Packet send and receive function prototypes. */
 extern void bgp_keepalive_send(struct peer *);
index 32c9fb16f3b35572e1debd9ed0f88837f63e73ff..05974bb2bac2ea140dbc243d0388d17008a44b3b 100644 (file)
@@ -5704,6 +5704,8 @@ static struct bgp_aggregate *bgp_aggregate_new(void)
 
 static void bgp_aggregate_free(struct bgp_aggregate *aggregate)
 {
+       XFREE(MTYPE_ROUTE_MAP_NAME, aggregate->rmap.name);
+       route_map_counter_decrement(aggregate->rmap.map);
        XFREE(MTYPE_BGP_AGGREGATE, aggregate);
 }
 
@@ -5754,6 +5756,7 @@ static void bgp_aggregate_install(struct bgp *bgp, afi_t afi, safi_t safi,
        struct bgp_node *rn;
        struct bgp_table *table;
        struct bgp_path_info *pi, *orig, *new;
+       struct attr *attr;
 
        table = bgp->rib[afi][safi];
 
@@ -5791,14 +5794,18 @@ static void bgp_aggregate_install(struct bgp *bgp, afi_t afi, safi_t safi,
                if (pi)
                        bgp_path_info_delete(rn, pi);
 
+               attr = bgp_attr_aggregate_intern(
+                       bgp, origin, aspath, community, ecommunity, lcommunity,
+                       aggregate, atomic_aggregate, p);
+
+               if (!attr) {
+                       bgp_aggregate_delete(bgp, p, afi, safi, aggregate);
+                       return;
+               }
+
                new = info_make(ZEBRA_ROUTE_BGP, BGP_ROUTE_AGGREGATE, 0,
-                               bgp->peer_self,
-                               bgp_attr_aggregate_intern(bgp, origin, aspath,
-                                                         community, ecommunity,
-                                                         lcommunity,
-                                                         aggregate->as_set,
-                                                         atomic_aggregate),
-                               rn);
+                               bgp->peer_self, attr, rn);
+
                SET_FLAG(new->flags, BGP_PATH_VALID);
 
                bgp_path_info_add(rn, new);
@@ -5821,7 +5828,7 @@ static void bgp_aggregate_install(struct bgp *bgp, afi_t afi, safi_t safi,
 }
 
 /* Update an aggregate as routes are added/removed from the BGP table */
-static void bgp_aggregate_route(struct bgp *bgp, struct prefix *p,
+void bgp_aggregate_route(struct bgp *bgp, struct prefix *p,
                                afi_t afi, safi_t safi,
                                struct bgp_aggregate *aggregate)
 {
@@ -5982,7 +5989,7 @@ static void bgp_aggregate_route(struct bgp *bgp, struct prefix *p,
                              aggregate);
 }
 
-static void bgp_aggregate_delete(struct bgp *bgp, struct prefix *p, afi_t afi,
+void bgp_aggregate_delete(struct bgp *bgp, struct prefix *p, afi_t afi,
                                 safi_t safi, struct bgp_aggregate *aggregate)
 {
        struct bgp_table *table;
@@ -6426,7 +6433,8 @@ static int bgp_aggregate_unset(struct vty *vty, const char *prefix_str,
 }
 
 static int bgp_aggregate_set(struct vty *vty, const char *prefix_str, afi_t afi,
-                            safi_t safi, uint8_t summary_only, uint8_t as_set)
+                            safi_t safi, const char *rmap, uint8_t summary_only,
+                            uint8_t as_set)
 {
        VTY_DECLVAR_CONTEXT(bgp, bgp);
        int ret;
@@ -6451,8 +6459,9 @@ static int bgp_aggregate_set(struct vty *vty, const char *prefix_str, afi_t afi,
 
        /* Old configuration check. */
        rn = bgp_node_get(bgp->aggregate[afi][safi], &p);
+       aggregate = bgp_node_get_bgp_aggregate_info(rn);
 
-       if (bgp_node_has_bgp_path_info_data(rn)) {
+       if (aggregate) {
                vty_out(vty, "There is already same aggregate network.\n");
                /* try to remove the old entry */
                ret = bgp_aggregate_unset(vty, prefix_str, afi, safi);
@@ -6468,6 +6477,15 @@ static int bgp_aggregate_set(struct vty *vty, const char *prefix_str, afi_t afi,
        aggregate->summary_only = summary_only;
        aggregate->as_set = as_set;
        aggregate->safi = safi;
+
+       if (rmap) {
+               XFREE(MTYPE_ROUTE_MAP_NAME, aggregate->rmap.name);
+               route_map_counter_decrement(aggregate->rmap.map);
+               aggregate->rmap.name =
+                       XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap);
+               aggregate->rmap.map = route_map_lookup_by_name(rmap);
+               route_map_counter_increment(aggregate->rmap.map);
+       }
        bgp_node_set_bgp_aggregate_info(rn, aggregate);
 
        /* Aggregate address insert into BGP routing table. */
@@ -6478,17 +6496,20 @@ static int bgp_aggregate_set(struct vty *vty, const char *prefix_str, afi_t afi,
 
 DEFUN (aggregate_address,
        aggregate_address_cmd,
-       "aggregate-address A.B.C.D/M [<as-set [summary-only]|summary-only [as-set]>]",
+       "aggregate-address A.B.C.D/M [<as-set [summary-only]|summary-only [as-set]>] [route-map WORD]",
        "Configure BGP aggregate entries\n"
        "Aggregate prefix\n"
        "Generate AS set path information\n"
        "Filter more specific routes from updates\n"
        "Filter more specific routes from updates\n"
-       "Generate AS set path information\n")
+       "Generate AS set path information\n"
+       "Apply route map to aggregate network\n"
+       "Name of route map\n")
 {
        int idx = 0;
        argv_find(argv, argc, "A.B.C.D/M", &idx);
        char *prefix = argv[idx]->arg;
+       char *rmap = NULL;
        int as_set =
                argv_find(argv, argc, "as-set", &idx) ? AGGREGATE_AS_SET : 0;
        idx = 0;
@@ -6496,25 +6517,33 @@ DEFUN (aggregate_address,
                                   ? AGGREGATE_SUMMARY_ONLY
                                   : 0;
 
+       idx = 0;
+       argv_find(argv, argc, "WORD", &idx);
+       if (idx)
+               rmap = argv[idx]->arg;
+
        return bgp_aggregate_set(vty, prefix, AFI_IP, bgp_node_safi(vty),
-                                summary_only, as_set);
+                                rmap, summary_only, as_set);
 }
 
 DEFUN (aggregate_address_mask,
        aggregate_address_mask_cmd,
-       "aggregate-address A.B.C.D A.B.C.D [<as-set [summary-only]|summary-only [as-set]>]",
+       "aggregate-address A.B.C.D A.B.C.D [<as-set [summary-only]|summary-only [as-set]>] [route-map WORD]",
        "Configure BGP aggregate entries\n"
        "Aggregate address\n"
        "Aggregate mask\n"
        "Generate AS set path information\n"
        "Filter more specific routes from updates\n"
        "Filter more specific routes from updates\n"
-       "Generate AS set path information\n")
+       "Generate AS set path information\n"
+       "Apply route map to aggregate network\n"
+       "Name of route map\n")
 {
        int idx = 0;
        argv_find(argv, argc, "A.B.C.D", &idx);
        char *prefix = argv[idx]->arg;
        char *mask = argv[idx + 1]->arg;
+       char *rmap = NULL;
        int as_set =
                argv_find(argv, argc, "as-set", &idx) ? AGGREGATE_AS_SET : 0;
        idx = 0;
@@ -6522,6 +6551,10 @@ DEFUN (aggregate_address_mask,
                                   ? AGGREGATE_SUMMARY_ONLY
                                   : 0;
 
+       argv_find(argv, argc, "WORD", &idx);
+       if (idx)
+               rmap = argv[idx]->arg;
+
        char prefix_str[BUFSIZ];
        int ret = netmask_str2prefix_str(prefix, mask, prefix_str);
 
@@ -6531,7 +6564,7 @@ DEFUN (aggregate_address_mask,
        }
 
        return bgp_aggregate_set(vty, prefix_str, AFI_IP, bgp_node_safi(vty),
-                                summary_only, as_set);
+                                rmap, summary_only, as_set);
 }
 
 DEFUN (no_aggregate_address,
@@ -6581,17 +6614,20 @@ DEFUN (no_aggregate_address_mask,
 
 DEFUN (ipv6_aggregate_address,
        ipv6_aggregate_address_cmd,
-       "aggregate-address X:X::X:X/M [<as-set [summary-only]|summary-only [as-set]>]",
+       "aggregate-address X:X::X:X/M [<as-set [summary-only]|summary-only [as-set]>] [route-map WORD]",
        "Configure BGP aggregate entries\n"
        "Aggregate prefix\n"
        "Generate AS set path information\n"
        "Filter more specific routes from updates\n"
        "Filter more specific routes from updates\n"
-       "Generate AS set path information\n")
+       "Generate AS set path information\n"
+       "Apply route map to aggregate network\n"
+       "Name of route map\n")
 {
        int idx = 0;
        argv_find(argv, argc, "X:X::X:X/M", &idx);
        char *prefix = argv[idx]->arg;
+       char *rmap = NULL;
        int as_set =
                argv_find(argv, argc, "as-set", &idx) ? AGGREGATE_AS_SET : 0;
 
@@ -6599,8 +6635,13 @@ DEFUN (ipv6_aggregate_address,
        int sum_only = argv_find(argv, argc, "summary-only", &idx)
                               ? AGGREGATE_SUMMARY_ONLY
                               : 0;
-       return bgp_aggregate_set(vty, prefix, AFI_IP6, SAFI_UNICAST, sum_only,
-                                as_set);
+
+       argv_find(argv, argc, "WORD", &idx);
+       if (idx)
+               rmap = argv[idx]->arg;
+
+       return bgp_aggregate_set(vty, prefix, AFI_IP6, SAFI_UNICAST, rmap,
+                                sum_only, as_set);
 }
 
 DEFUN (no_ipv6_aggregate_address,
@@ -7228,7 +7269,8 @@ void route_vty_out(struct vty *vty, struct prefix *p,
 
                        /* We display both LL & GL if both have been
                         * received */
-                       if ((attr->mp_nexthop_len == 32)
+                       if ((attr->mp_nexthop_len
+                            == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL)
                            || (path->peer->conf_if)) {
                                json_nexthop_ll = json_object_new_object();
                                json_object_string_add(
@@ -7260,7 +7302,8 @@ void route_vty_out(struct vty *vty, struct prefix *p,
                } else {
                        /* Display LL if LL/Global both in table unless
                         * prefer-global is set */
-                       if (((attr->mp_nexthop_len == 32)
+                       if (((attr->mp_nexthop_len
+                             == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL)
                             && !attr->mp_nexthop_prefer_global)
                            || (path->peer->conf_if)) {
                                if (path->peer->conf_if) {
@@ -11834,6 +11877,9 @@ uint8_t bgp_distance_apply(struct prefix *p, struct bgp_path_info *pinfo,
 
        peer = pinfo->peer;
 
+       if (pinfo->attr->distance)
+               return pinfo->attr->distance;
+
        /* Check source address. */
        sockunion2hostprefix(&peer->su, &q);
        rn = bgp_node_match(bgp_distance_table[afi][safi], &q);
@@ -12467,6 +12513,9 @@ void bgp_config_write_network(struct vty *vty, struct bgp *bgp, afi_t afi,
                if (bgp_aggregate->summary_only)
                        vty_out(vty, " summary-only");
 
+               if (bgp_aggregate->rmap.name)
+                       vty_out(vty, " route-map %s", bgp_aggregate->rmap.name);
+
                vty_out(vty, "\n");
        }
 }
index 704cd39710d8069909a2de8a673e357f3234972c..a710873ea7936da75eebd7779c53c57b0da04869 100644 (file)
@@ -236,9 +236,9 @@ struct bgp_path_info {
 #define BGP_ROUTE_NORMAL       0
 #define BGP_ROUTE_STATIC       1
 #define BGP_ROUTE_AGGREGATE    2
-#define BGP_ROUTE_REDISTRIBUTE 3 
+#define BGP_ROUTE_REDISTRIBUTE 3
 #ifdef ENABLE_BGP_VNC
-# define BGP_ROUTE_RFP          4 
+# define BGP_ROUTE_RFP          4
 #endif
 #define BGP_ROUTE_IMPORTED     5        /* from another bgp instance/safi */
 
@@ -313,7 +313,10 @@ struct bgp_aggregate {
        uint8_t as_set;
 
        /* Route-map for aggregated route. */
-       struct route_map *map;
+       struct {
+               char *name;
+               struct route_map *map;
+       } rmap;
 
        /* Suppress-count. */
        unsigned long count;
@@ -545,6 +548,10 @@ extern void bgp_config_write_network(struct vty *, struct bgp *, afi_t, safi_t);
 extern void bgp_config_write_distance(struct vty *, struct bgp *, afi_t,
                                      safi_t);
 
+extern void bgp_aggregate_delete(struct bgp *bgp, struct prefix *p, afi_t afi,
+                                safi_t safi, struct bgp_aggregate *aggregate);
+extern void bgp_aggregate_route(struct bgp *bgp, struct prefix *p, afi_t afi,
+                               safi_t safi, struct bgp_aggregate *aggregate);
 extern void bgp_aggregate_increment(struct bgp *bgp, struct prefix *p,
                                    struct bgp_path_info *path, afi_t afi,
                                    safi_t safi);
index 545ca19762997fd1d2e1db2b507090a7f9eee891..a5286cea690756a393c5454bfa94ec018993ff2e 100644 (file)
@@ -269,13 +269,16 @@ route_match_peer(void *rule, const struct prefix *prefix,
 
                /* If su='0.0.0.0' (command 'match peer local'), and it's a
                   NETWORK,
-                   REDISTRIBUTE or DEFAULT_GENERATED route => return RMAP_MATCH
+                   REDISTRIBUTE, AGGREGATE-ADDRESS or DEFAULT_GENERATED route
+                  => return RMAP_MATCH
                   */
                if (sockunion_same(su, &su_def)) {
                        int ret;
                        if (CHECK_FLAG(peer->rmap_type, PEER_RMAP_TYPE_NETWORK)
                            || CHECK_FLAG(peer->rmap_type,
                                          PEER_RMAP_TYPE_REDISTRIBUTE)
+                           || CHECK_FLAG(peer->rmap_type,
+                                         PEER_RMAP_TYPE_AGGREGATE)
                            || CHECK_FLAG(peer->rmap_type,
                                          PEER_RMAP_TYPE_DEFAULT))
                                ret = RMAP_MATCH;
@@ -1207,10 +1210,26 @@ static void route_match_community_free(void *rule)
        XFREE(MTYPE_ROUTE_MAP_COMPILED, rcom);
 }
 
+/*
+ * In routemap processing there is a need to add the
+ * name as a rule_key in the dependency table. Routemap
+ * lib is unaware of rule_key when exact-match clause
+ * is in use. routemap lib uses the compiled output to
+ * get the rule_key value.
+ */
+static void *route_match_get_community_key(void *rule)
+{
+       struct rmap_community *rcom;
+
+       rcom = rule;
+       return rcom->name;
+}
+
+
 /* Route map commands for community matching. */
 struct route_map_rule_cmd route_match_community_cmd = {
        "community", route_match_community, route_match_community_compile,
-       route_match_community_free};
+       route_match_community_free, route_match_get_community_key};
 
 /* Match function for lcommunity match. */
 static enum route_map_cmd_result_t
@@ -1281,7 +1300,8 @@ static void route_match_lcommunity_free(void *rule)
 /* Route map commands for community matching. */
 struct route_map_rule_cmd route_match_lcommunity_cmd = {
        "large-community", route_match_lcommunity,
-       route_match_lcommunity_compile, route_match_lcommunity_free};
+       route_match_lcommunity_compile, route_match_lcommunity_free,
+       route_match_get_community_key};
 
 
 /* Match function for extcommunity match. */
@@ -1680,6 +1700,30 @@ struct route_map_rule_cmd route_set_weight_cmd = {
        "weight", route_set_weight, route_value_compile, route_value_free,
 };
 
+/* `set distance DISTANCE */
+static enum route_map_cmd_result_t
+route_set_distance(void *rule, const struct prefix *prefix,
+                  route_map_object_t type, void *object)
+{
+       struct bgp_path_info *path = object;
+       struct rmap_value *rv = rule;
+
+       if (type != RMAP_BGP)
+               return RMAP_OKAY;
+
+       path->attr->distance = rv->value;
+
+       return RMAP_OKAY;
+}
+
+/* set distance rule structure */
+struct route_map_rule_cmd route_set_distance_cmd = {
+       "distance",
+       route_set_distance,
+       route_value_compile,
+       route_value_free,
+};
+
 /* `set metric METRIC' */
 
 /* Set metric to attribute. */
@@ -2728,10 +2772,8 @@ route_set_ipv6_nexthop_prefer_global(void *rule, const struct prefix *prefix,
                path = object;
                peer = path->peer;
 
-               if ((CHECK_FLAG(peer->rmap_type, PEER_RMAP_TYPE_IN)
-                    || CHECK_FLAG(peer->rmap_type, PEER_RMAP_TYPE_IMPORT))
-                   && peer->su_remote
-                   && sockunion_family(peer->su_remote) == AF_INET6) {
+               if (CHECK_FLAG(peer->rmap_type, PEER_RMAP_TYPE_IN)
+                   || CHECK_FLAG(peer->rmap_type, PEER_RMAP_TYPE_IMPORT)) {
                        /* Set next hop preference to global */
                        path->attr->mp_nexthop_prefer_global = true;
                        SET_FLAG(path->attr->rmap_change_flags,
@@ -2853,12 +2895,15 @@ route_set_ipv6_nexthop_peer(void *rule, const struct prefix *pfx,
                        /* Set next hop value and length in attribute. */
                        if (IN6_IS_ADDR_LINKLOCAL(&peer_address)) {
                                path->attr->mp_nexthop_local = peer_address;
-                               if (path->attr->mp_nexthop_len != 32)
-                                       path->attr->mp_nexthop_len = 32;
+                               if (path->attr->mp_nexthop_len
+                                   != BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL)
+                                       path->attr->mp_nexthop_len =
+                                               BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL;
                        } else {
                                path->attr->mp_nexthop_global = peer_address;
                                if (path->attr->mp_nexthop_len == 0)
-                                       path->attr->mp_nexthop_len = 16;
+                                       path->attr->mp_nexthop_len =
+                                               BGP_ATTR_NHLEN_IPV6_GLOBAL;
                        }
 
                } else if (CHECK_FLAG(peer->rmap_type, PEER_RMAP_TYPE_OUT)) {
@@ -2923,7 +2968,7 @@ route_set_vpnv4_nexthop(void *rule, const struct prefix *prefix,
 
                /* Set next hop value. */
                path->attr->mp_nexthop_global_in = *address;
-               path->attr->mp_nexthop_len = 4;
+               path->attr->mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
        }
 
        return RMAP_OKAY;
@@ -3070,11 +3115,6 @@ static int bgp_route_match_add(struct vty *vty, const char *command,
                retval = CMD_WARNING_CONFIG_FAILED;
                break;
        case RMAP_COMPILE_SUCCESS:
-               if (type != RMAP_EVENT_MATCH_ADDED) {
-                       route_map_upd8_dependency(type, arg, index->map->name);
-               }
-               break;
-       case RMAP_DUPLICATE_RULE:
                /*
                 * Intentionally doing nothing here.
                 */
@@ -3108,7 +3148,7 @@ static int bgp_route_match_delete(struct vty *vty, const char *command,
                rmap_name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, index->map->name);
        }
 
-       ret = route_map_delete_match(index, command, dep_name);
+       ret = route_map_delete_match(index, command, dep_name, type);
        switch (ret) {
        case RMAP_RULE_MISSING:
                vty_out(vty, "%% BGP Can't find rule.\n");
@@ -3119,10 +3159,6 @@ static int bgp_route_match_delete(struct vty *vty, const char *command,
                retval = CMD_WARNING_CONFIG_FAILED;
                break;
        case RMAP_COMPILE_SUCCESS:
-               if (type != RMAP_EVENT_MATCH_DELETED && dep_name)
-                       route_map_upd8_dependency(type, dep_name, rmap_name);
-               break;
-       case RMAP_DUPLICATE_RULE:
                /*
                 * Nothing to do here
                 */
@@ -3248,6 +3284,7 @@ static void bgp_route_map_process_update(struct bgp *bgp, const char *rmap_name,
        struct peer *peer;
        struct bgp_node *bn;
        struct bgp_static *bgp_static;
+       struct bgp_aggregate *aggregate;
        struct listnode *node, *nnode;
        struct route_map *map;
        char buf[INET6_ADDRSTRLEN];
@@ -3331,6 +3368,35 @@ static void bgp_route_map_process_update(struct bgp *bgp, const char *rmap_name,
                                                  safi);
                        }
                }
+
+               /* For aggregate-address route-map updates. */
+               for (bn = bgp_table_top(bgp->aggregate[afi][safi]); bn;
+                    bn = bgp_route_next(bn)) {
+                       aggregate = bgp_node_get_bgp_aggregate_info(bn);
+                       if (!aggregate)
+                               continue;
+
+                       if (!aggregate->rmap.name
+                           || (strcmp(rmap_name, aggregate->rmap.name) != 0))
+                               continue;
+
+                       if (!aggregate->rmap.map)
+                               route_map_counter_increment(map);
+
+                       aggregate->rmap.map = map;
+
+                       if (route_update) {
+                               if (bgp_debug_zebra(&bn->p))
+                                       zlog_debug(
+                                               "Processing route_map %s update on aggregate-address route %s",
+                                               rmap_name,
+                                               inet_ntop(bn->p.family,
+                                                         &bn->p.u.prefix, buf,
+                                                         INET6_ADDRSTRLEN));
+                               bgp_aggregate_route(bgp, &bn->p, afi, safi,
+                                                   aggregate);
+                       }
+               }
        }
 
        /* For redistribute route-map updates. */
@@ -4028,6 +4094,29 @@ DEFUN (set_ip_nexthop_unchanged,
                    "unchanged");
 }
 
+DEFUN (set_distance,
+       set_distance_cmd,
+       "set distance (0-255)",
+       SET_STR
+       "BGP Administrative Distance to use\n"
+       "Distance value\n")
+{
+       int idx_number = 2;
+
+       return generic_set_add(vty, VTY_GET_CONTEXT(route_map_index),
+                              "distance", argv[idx_number]->arg);
+}
+
+DEFUN (no_set_distance,
+       no_set_distance_cmd,
+       "no set distance [(0-255)]",
+       NO_STR SET_STR
+       "BGP Administrative Distance to use\n"
+       "Distance value\n")
+{
+       return generic_set_delete(vty, VTY_GET_CONTEXT(route_map_index),
+                                 "distance", NULL);
+}
 
 DEFUN (set_local_pref,
        set_local_pref_cmd,
@@ -5083,6 +5172,7 @@ void bgp_route_map_init(void)
        route_map_install_set(&route_set_weight_cmd);
        route_map_install_set(&route_set_label_index_cmd);
        route_map_install_set(&route_set_metric_cmd);
+       route_map_install_set(&route_set_distance_cmd);
        route_map_install_set(&route_set_aspath_prepend_cmd);
        route_map_install_set(&route_set_aspath_exclude_cmd);
        route_map_install_set(&route_set_origin_cmd);
@@ -5136,6 +5226,8 @@ void bgp_route_map_init(void)
        install_element(RMAP_NODE, &set_ip_nexthop_peer_cmd);
        install_element(RMAP_NODE, &set_ip_nexthop_unchanged_cmd);
        install_element(RMAP_NODE, &set_local_pref_cmd);
+       install_element(RMAP_NODE, &set_distance_cmd);
+       install_element(RMAP_NODE, &no_set_distance_cmd);
        install_element(RMAP_NODE, &no_set_local_pref_cmd);
        install_element(RMAP_NODE, &set_weight_cmd);
        install_element(RMAP_NODE, &set_label_index_cmd);
index 2cfd65896c9ac1160ca86a00ef0ef67b5276cd49..352e3b87e81fdb0adaa4f610b61b36851b63ac47 100644 (file)
@@ -1420,7 +1420,6 @@ DEFUN (match_rpki,
                        vty_out(vty, "%% BGP Argument is malformed.\n");
                        return CMD_WARNING_CONFIG_FAILED;
                case RMAP_COMPILE_SUCCESS:
-               case RMAP_DUPLICATE_RULE:
                        /*
                         * Intentionally doing nothing here
                         */
@@ -1443,7 +1442,8 @@ DEFUN (no_match_rpki,
        VTY_DECLVAR_CONTEXT(route_map_index, index);
        enum rmap_compile_rets ret;
 
-       ret = route_map_delete_match(index, "rpki", argv[3]->arg);
+       ret = route_map_delete_match(index, "rpki", argv[3]->arg,
+                                    RMAP_EVENT_MATCH_DELETED);
        if (ret) {
                switch (ret) {
                case RMAP_RULE_MISSING:
@@ -1453,7 +1453,6 @@ DEFUN (no_match_rpki,
                        vty_out(vty, "%% BGP Argument is malformed.\n");
                        break;
                case RMAP_COMPILE_SUCCESS:
-               case RMAP_DUPLICATE_RULE:
                        /*
                         * Nothing to do here
                         */
index 5b31fbb3a8c140cb8d77d460fbe74ac3d29d3ace..e815334bfcaba546fcae0dd42eac1724e6bbd83c 100644 (file)
@@ -2053,7 +2053,7 @@ int peer_activate(struct peer *peer, afi_t afi, safi_t safi)
            && !bgp->allocate_mpls_labels[afi][SAFI_UNICAST]) {
 
                if (BGP_DEBUG(zebra, ZEBRA))
-                       zlog_info(
+                       zlog_debug(
                                "peer(s) are now active for labeled-unicast, allocate MPLS labels");
 
                bgp->allocate_mpls_labels[afi][SAFI_UNICAST] = 1;
@@ -2156,7 +2156,7 @@ int peer_deactivate(struct peer *peer, afi_t afi, safi_t safi)
            && !bgp_afi_safi_peer_exists(bgp, afi, safi)) {
 
                if (BGP_DEBUG(zebra, ZEBRA))
-                       zlog_info(
+                       zlog_debug(
                                "peer(s) are no longer active for labeled-unicast, deallocate MPLS labels");
 
                bgp->allocate_mpls_labels[afi][SAFI_UNICAST] = 0;
@@ -7931,8 +7931,6 @@ static void bgp_pthreads_init(void)
        assert(!bgp_pth_io);
        assert(!bgp_pth_ka);
 
-       frr_pthread_init();
-
        struct frr_pthread_attr io = {
                .start = frr_pthread_attr_default.start,
                .stop = frr_pthread_attr_default.stop,
@@ -7958,7 +7956,6 @@ void bgp_pthreads_run(void)
 void bgp_pthreads_finish(void)
 {
        frr_pthread_stop_all();
-       frr_pthread_finish();
 }
 
 void bgp_init(unsigned short instance)
index e9b07bc40341079aca5520b1496220d511647775..9d45d96987db8a950505ca266e1f19be2afe31e4 100644 (file)
@@ -1211,6 +1211,7 @@ struct peer {
 #define PEER_RMAP_TYPE_NOSET          (1 << 5) /* not allow to set commands */
 #define PEER_RMAP_TYPE_IMPORT         (1 << 6) /* neighbor route-map import */
 #define PEER_RMAP_TYPE_EXPORT         (1 << 7) /* neighbor route-map export */
+#define PEER_RMAP_TYPE_AGGREGATE      (1 << 8) /* aggregate-address route-map */
 
        /* peer specific BFD information */
        struct bfd_info *bfd_info;
index 9b8f64ee678d4d7c6e786ed7f07f901f3d4ae8df..0aa102feab2c5c4b516d028998b3df23537f1e0a 100644 (file)
@@ -880,12 +880,12 @@ void add_vnc_route(struct rfapi_descriptor *rfd, /* cookie, VPN UN addr, peer */
                attr.nexthop.s_addr = nexthop->addr.v4.s_addr;
 
                attr.mp_nexthop_global_in = nexthop->addr.v4;
-               attr.mp_nexthop_len = 4;
+               attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
                break;
 
        case AF_INET6:
                attr.mp_nexthop_global = nexthop->addr.v6;
-               attr.mp_nexthop_len = 16;
+               attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV6_GLOBAL;
                break;
 
        default:
index 3d8d5bccb0febfa42e6758985ce82c009d1faf7f..b97c8c3030f890374055c51f66ee0c05e112bf9e 100644 (file)
@@ -86,13 +86,13 @@ static void encap_attr_export_ce(struct attr *new, struct attr *orig,
        switch (use_nexthop->family) {
        case AF_INET:
                new->nexthop = use_nexthop->u.prefix4;
-               new->mp_nexthop_len = 4; /* bytes */
+               new->mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; /* bytes */
                new->flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP);
                break;
 
        case AF_INET6:
                new->mp_nexthop_global = use_nexthop->u.prefix6;
-               new->mp_nexthop_len = 16; /* bytes */
+               new->mp_nexthop_len = BGP_ATTR_NHLEN_IPV6_GLOBAL; /* bytes */
                break;
 
        default:
@@ -624,13 +624,13 @@ encap_attr_export(struct attr *new, struct attr *orig,
        switch (use_nexthop->family) {
        case AF_INET:
                new->nexthop = use_nexthop->u.prefix4;
-               new->mp_nexthop_len = 4; /* bytes */
+               new->mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; /* bytes */
                new->flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP);
                break;
 
        case AF_INET6:
                new->mp_nexthop_global = use_nexthop->u.prefix6;
-               new->mp_nexthop_len = 16; /* bytes */
+               new->mp_nexthop_len = BGP_ATTR_NHLEN_IPV6_GLOBAL; /* bytes */
                break;
 
        default:
index 28140382f647a474c0cca6126417f01e91470c99..5f7eaebed5c85f83fc934aa6a9a205944e64a915 100644 (file)
@@ -1 +1,2 @@
 usr/lib/frr/frr-reload.py
+usr/lib/frr/generate_support_bundle.py
index a546f38d70c2c627e7a8049751d79a813adbf4fc..c8550ecb520563c3342dc51cbdc2c8298eb42cb9 100755 (executable)
@@ -71,6 +71,7 @@ override_dh_auto_install:
        dh_auto_install
 
        sed -e '1c #!/usr/bin/python3' -i debian/tmp/usr/lib/frr/frr-reload.py
+       sed -e '1c #!/usr/bin/python3' -i debian/tmp/usr/lib/frr/generate_support_bundle.py
 
 # let dh_systemd_* and dh_installinit do their thing automatically
 ifeq ($(filter pkg.frr.nosystemd,$(DEB_BUILD_PROFILES)),)
index 7883d0e4c65041e8507770e4492da6bb27ddb44d..7b3cdf2c4b1f07a6261b45d8e6da3b8b50265c33 100644 (file)
@@ -685,6 +685,11 @@ Route Aggregation-IPv4 Address Family
 
    This command specifies an aggregate address.
 
+.. index:: aggregate-address A.B.C.D/M route-map NAME
+.. clicmd:: aggregate-address A.B.C.D/M route-map NAME
+
+   Apply a route-map for an aggregated prefix.
+
 .. index:: aggregate-address A.B.C.D/M as-set
 .. clicmd:: aggregate-address A.B.C.D/M as-set
 
@@ -699,11 +704,11 @@ Route Aggregation-IPv4 Address Family
 
 .. index:: no aggregate-address A.B.C.D/M
 .. clicmd:: no aggregate-address A.B.C.D/M
-   
+
    This command removes an aggregate address.
 
 
-   This configuration example setup the aggregate-address under 
+   This configuration example setup the aggregate-address under
    ipv4 address-family.
 
    .. code-block:: frr
@@ -713,6 +718,7 @@ Route Aggregation-IPv4 Address Family
         aggregate-address 10.0.0.0/8
         aggregate-address 20.0.0.0/8 as-set
         aggregate-address 40.0.0.0/8 summary-only
+        aggregate-address 50.0.0.0/8 route-map aggr-rmap
        exit-address-family
 
 
@@ -726,6 +732,11 @@ Route Aggregation-IPv6 Address Family
 
    This command specifies an aggregate address.
 
+.. index:: aggregate-address X:X::X:X/M route-map NAME
+.. clicmd:: aggregate-address X:X::X:X/M route-map NAME
+
+   Apply a route-map for an aggregated prefix.
+
 .. index:: aggregate-address X:X::X:X/M as-set
 .. clicmd:: aggregate-address X:X::X:X/M as-set
 
@@ -744,16 +755,17 @@ Route Aggregation-IPv6 Address Family
    This command removes an aggregate address.
 
 
-   This configuration example setup the aggregate-address under 
-   ipv4 address-family.
+   This configuration example setup the aggregate-address under
+   ipv6 address-family.
 
    .. code-block:: frr
 
       router bgp 1
        address-family ipv6 unicast
         aggregate-address 10::0/64
-       aggregate-address 20::0/64 as-set
-       aggregate-address 40::0/64 summary-only
+        aggregate-address 20::0/64 as-set
+        aggregate-address 40::0/64 summary-only
+        aggregate-address 50::0/64 route-map aggr-rmap
        exit-address-family
 
 .. _bgp-redistribute-to-bgp:
@@ -2321,7 +2333,7 @@ attribute.
 Displaying Routes by Large Community Attribute
 ----------------------------------------------
 
-The following commands allow displaying routes based on their 
+The following commands allow displaying routes based on their
 large community attribute.
 
 .. index:: show [ip] bgp <ipv4|ipv6> large-community
@@ -2338,8 +2350,8 @@ large community attribute.
 
    These commands display BGP routes which have the large community attribute.
    attribute. When ``LARGE-COMMUNITY`` is specified, BGP routes that match that
-   large community are displayed. When `exact-match` is specified, it display 
-   only routes that have an exact match. When `json` is specified, it display 
+   large community are displayed. When `exact-match` is specified, it display
+   only routes that have an exact match. When `json` is specified, it display
    routes in json format.
 
 .. index:: show [ip] bgp <ipv4|ipv6> large-community-list WORD
@@ -2352,8 +2364,8 @@ large community attribute.
 .. clicmd:: show [ip] bgp <ipv4|ipv6> large-community-list WORD json
 
    These commands display BGP routes for the address family specified that
-   match the specified large community list. When `exact-match` is specified, 
-   it displays only routes that have an exact match. When `json` is specified, 
+   match the specified large community list. When `exact-match` is specified,
+   it displays only routes that have an exact match. When `json` is specified,
    it display routes in json format.
 
 .. _bgp-display-routes-by-as-path:
index 6c3b14e062813a862b5f131317859b4ac98e3b7e..416c51f13bd4154eb5e7f412edeffe8d1d9a0503 100644 (file)
@@ -58,6 +58,7 @@ Protocols
    vnc
    vrrp
    bmp
+   watchfrr
 
 ########
 Appendix
index 76a9364cf97037da0ed8ebd5bf3b57d91edb38c8..da348b02d234d2beb67d96a3c5eab47f66035953 100644 (file)
@@ -24,7 +24,7 @@ Each router thus builds up an :abbr:`LSDB (Link State Database)` of all the
 link-state messages. From this collection of LSAs in the LSDB, each router can
 then calculate the shortest path to any other router, based on some common
 metric, by using an algorithm such as
-`Edsger Djikstra's <http://www.cs.utexas.edu/users/EWD/>`_
+`Edsger Dijkstra's <http://www.cs.utexas.edu/users/EWD/>`_
 :abbr:`SPF (Shortest Path First)` algorithm.
 
 .. index:: Link-state routing protocol advantages
index 805d6264a87291f943c8d869267a44bc24de98c3..4f9c573a246bc685dde28bd1f32fdd11bfda8634 100644 (file)
@@ -201,14 +201,15 @@ is in a vrf, enter the interface command with the vrf keyword at the end.
 .. clicmd:: ip pim sm
 
    Tell pim that we would like to use this interface to form pim neighbors
-   over. Please note we will *not* accept igmp reports over this interface with
-   this command.
+   over. Please note that this command does not enable the reception of IGMP
+   reports on the interface. Refer to the next `ip igmp` command for IGMP
+   management.
 
 .. index:: ip igmp
 .. clicmd:: ip igmp
 
    Tell pim to receive IGMP reports and Query on this interface. The default
-   version is v3. This command is useful on the LHR.
+   version is v3. This command is useful on a LHR.
 
 .. index:: ip igmp join A.B.C.D A.B.C.D
 .. clicmd:: ip igmp join A.B.C.D A.B.C.D
index 09cbd7c7b0aeeffe6740f0dbc68f66c6fd20d932..e36783d176c2560f162a4b5167baa0cf41092510 100644 (file)
@@ -270,6 +270,12 @@ Route Map Set Command
 
    Set the BGP local preference to `local_pref`.
 
+.. index:: [no] set distance DISTANCE
+.. clicmd:: [no] set distance DISTANCE
+
+   Set the Administrative distance to DISTANCE to use for the route.
+   This is only locally significant and will not be dispersed to peers.
+
 .. index:: set weight WEIGHT
 .. clicmd:: set weight WEIGHT
 
index 0f0a8a07742cafbe257833ef80420a5301945ca6..ce519fbfbfb3a8377ae6b89eb3d32fe25c4fd931 100644 (file)
@@ -43,6 +43,7 @@ user_RSTFILES = \
        doc/user/zebra.rst \
        doc/user/bfd.rst \
        doc/user/flowspec.rst \
+       doc/user/watchfrr.rst \
        # end
 
 EXTRA_DIST += \
diff --git a/doc/user/watchfrr.rst b/doc/user/watchfrr.rst
new file mode 100644 (file)
index 0000000..df04a1e
--- /dev/null
@@ -0,0 +1,30 @@
+.. _watchfrr:
+
+********
+WATCHFRR
+********
+
+:abbr:`WATCHFRR` is a daemon that handles failed daemon processes and
+intelligently restarts them as needed.
+
+Starting WATCHFRR
+=================
+
+WATCHFRR is started as per normal systemd startup and typically does not
+require end users management.
+
+WATCHFRR commands
+=================
+
+.. index:: show watchfrr
+.. clicmd:: show watchfrr
+
+   Give status information about the state of the different daemons being
+   watched by WATCHFRR
+
+.. index:: [no] watchfrr ignore DAEMON
+.. clicmd:: [no] watchfrr ignore DAEMON
+
+   Tell WATCHFRR to ignore a particular DAEMON if it goes unresponsive.
+   This is particularly useful when you are a developer and need to debug
+   a working system, without watchfrr pulling the rug out from under you.
index 50c518d45661b742b70ea133f1235f2c4f3840b1..b7283d83deb3b2367cc8c90c77e1426f376dfb77 100644 (file)
@@ -292,6 +292,62 @@ Link Parameters Commands
 
 .. _zebra-vrf:
 
+Administrative Distance
+=======================
+
+Administrative distance allows FRR to make decisions about what routes
+should be installed in the rib based upon the originating protocol.
+The lowest Admin Distance is the route selected.  This is purely a
+subjective decision about ordering and care has been taken to choose
+the same distances that other routing suites have choosen.
+
++------------+-----------+
+| Protocol   | Distance  |
++------------+-----------+
+| System     | 0         |
++------------+-----------+
+| Kernel     | 0         |
++------------+-----------+
+| Connect    | 0         |
++------------+-----------+
+| Static     | 1         |
++------------+-----------+
+| NHRP       | 10        |
++------------+-----------+
+| EBGP       | 20        |
++------------+-----------+
+| EIGRP      | 90        |
++------------+-----------+
+| BABEL      | 100       |
++------------+-----------+
+| OSPF       | 110       |
++------------+-----------+
+| ISIS       | 115       |
++------------+-----------+
+| OPENFABRIC | 115       |
++------------+-----------+
+| RIP        | 120       |
++------------+-----------+
+| Table      | 150       |
++------------+-----------+
+| SHARP      | 150       |
++------------+-----------+
+| IBGP       | 200       |
++------------+-----------+
+| PBR        | 200       |
++------------+-----------+
+
+An admin distance of 255 indicates to Zebra that the route should not be
+installed into the Data Plane.  Additionally routes with an admin distance
+of 255 will not be redistributed.
+
+Zebra does treat Kernel routes as special case for the purposes of Admin
+Distance.  Upon learning about a route that is not originated by FRR
+we read the metric value as a uint32_t.  The top byte of the value
+is interpreted as the Administrative Distance and the low three bytes
+are read in as the metric.  This special case is to facilitate VRF
+default routes.
+
 Virtual Routing and Forwarding
 ==============================
 
@@ -374,6 +430,14 @@ commands in relationship to VRF. Here is an extract of some of those commands:
    This command will dump the routing tables within the vrf scope. If `vrf all`
    is executed, all routing tables will be dumped.
 
+.. index:: show <ip|ipv6> route summary [vrf VRF] [table TABLENO] [prefix]
+.. clicmd:: show <ip|ipv6> route summary [vrf VRF] [table TABLENO] [prefix]
+
+   This command will dump a summary output of the specified VRF and TABLENO
+   combination.  If neither VRF or TABLENO is specified FRR defaults to
+   the default vrf and default table.  If prefix is specified dump the
+   number of prefix routes.
+
 By using the :option:`-n` option, the *Linux network namespace* will be mapped
 over the *Zebra* VRF. One nice feature that is possible by handling *Linux
 network namespace* is the ability to name default VRF. At startup, *Zebra*
index d78588644f5cceba071b854bde3266d3fcc6b6c1..e7a7cc56aacfd66a5e1113855361630833f70fd9 100644 (file)
@@ -148,7 +148,6 @@ static int eigrp_route_match_add(struct vty *vty, struct route_map_index *index,
                return CMD_WARNING_CONFIG_FAILED;
                break;
        case RMAP_COMPILE_SUCCESS:
-       case RMAP_DUPLICATE_RULE:
                /*
                 * Intentionally not handling these cases
                 */
@@ -165,7 +164,7 @@ static int eigrp_route_match_delete(struct vty *vty,
 {
        enum rmap_compile_rets ret;
 
-       ret = route_map_delete_match(index, command, arg);
+       ret = route_map_delete_match(index, command, arg, type);
        switch (ret) {
        case RMAP_RULE_MISSING:
                vty_out(vty, "%% Can't find rule.\n");
@@ -176,7 +175,6 @@ static int eigrp_route_match_delete(struct vty *vty,
                return CMD_WARNING_CONFIG_FAILED;
                break;
        case RMAP_COMPILE_SUCCESS:
-       case RMAP_DUPLICATE_RULE:
                /*
                 * These cases intentionally ignored
                 */
@@ -211,7 +209,6 @@ static int eigrp_route_set_add(struct vty *vty, struct route_map_index *index,
                }
                break;
        case RMAP_COMPILE_SUCCESS:
-       case RMAP_DUPLICATE_RULE:
                /*
                 * These cases intentionally left blank here
                 */
@@ -239,7 +236,6 @@ static int eigrp_route_set_delete(struct vty *vty,
                return CMD_WARNING_CONFIG_FAILED;
                break;
        case RMAP_COMPILE_SUCCESS:
-       case RMAP_DUPLICATE_RULE:
                /*
                 * These cases intentionally not handled
                 */
index a0fa3d274f27436b28bcd86c50e71924140d0692..a645ca2b035f852e07548f85a5718d0e4f58eacf 100644 (file)
@@ -12,9 +12,13 @@ fpm_libfrrfpm_pb_la_SOURCES = \
        fpm/fpm_pb.c \
        # end
 
+if FPM
+if HAVE_PROTOBUF
 nodist_fpm_libfrrfpm_pb_la_SOURCES = \
        fpm/fpm.pb-c.c \
        # end
+endif
+endif
 
 CLEANFILES += \
        fpm/fpm.pb-c.c \
index 3fb163fccff2b8dfbc76e512db57b9d41a841a01..048e12a024381c751a319033e48fc0b850c0f3c9 100644 (file)
@@ -5,10 +5,12 @@ endif
 grpc_libfrrgrpc_pb_la_LDFLAGS = -version-info 0:0:0
 grpc_libfrrgrpc_pb_la_CPPFLAGS = $(AM_CPPFLAGS) $(GRPC_CXXFLAGS)
 
+if GRPC
 nodist_grpc_libfrrgrpc_pb_la_SOURCES = \
        grpc/frr-northbound.pb.cc \
        grpc/frr-northbound.grpc.pb.cc \
        # end
+endif
 
 CLEANFILES += \
        grpc/frr-northbound.pb.cc \
index 8d008d78bd4800d2e3618f1b3d66149d117e4f71..5da8e6ee9e2e97cff3d1ef0c589ccb2d385f7a4b 100644 (file)
@@ -135,8 +135,6 @@ struct isis_circuit *isis_circuit_new(void)
        }
 #endif /* ifndef FABRICD */
 
-       circuit->mtc = mpls_te_circuit_new();
-
        circuit_mt_init(circuit);
 
        QOBJ_REG(circuit, isis_circuit);
@@ -266,8 +264,11 @@ void isis_circuit_add_addr(struct isis_circuit *circuit,
                ipv4->prefix = connected->address->u.prefix4;
                listnode_add(circuit->ip_addrs, ipv4);
 
-               /* Update MPLS TE Local IP address parameter */
-               set_circuitparams_local_ipaddr(circuit->mtc, ipv4->prefix);
+               /* Update Local IP address parameter if MPLS TE is enable */
+               if (circuit->ext && IS_MPLS_TE(circuit->ext)) {
+                       circuit->ext->local_addr.s_addr = ipv4->prefix.s_addr;
+                       SET_SUBTLV(circuit->ext, EXT_LOCAL_ADDR);
+               }
 
                if (circuit->area)
                        lsp_regenerate_schedule(circuit->area, circuit->is_type,
@@ -478,6 +479,7 @@ void isis_circuit_if_add(struct isis_circuit *circuit, struct interface *ifp)
 
        for (ALL_LIST_ELEMENTS(ifp->connected, node, nnode, conn))
                isis_circuit_add_addr(circuit, conn);
+
 }
 
 void isis_circuit_if_del(struct isis_circuit *circuit, struct interface *ifp)
@@ -521,7 +523,6 @@ void isis_circuit_if_bind(struct isis_circuit *circuit, struct interface *ifp)
                assert(ifp->info == circuit);
        else
                ifp->info = circuit;
-       isis_link_params_update(circuit, ifp);
 }
 
 void isis_circuit_if_unbind(struct isis_circuit *circuit, struct interface *ifp)
index 2371c0b73a15c24444b05ef44de2fd847815ebd3..e3541644aa9052ec5d4a86f8da37406b7edb6840 100644 (file)
@@ -121,7 +121,7 @@ struct isis_circuit {
        uint16_t psnp_interval[2];    /* psnp-interval in seconds */
        uint8_t metric[2];
        uint32_t te_metric[2];
-       struct mpls_te_circuit *mtc; /* MPLS-TE parameters */
+       struct isis_ext_subtlvs *ext; /* Extended parameters (TE + Adj SID */
        int ip_router;  /* Route IP ? */
        int is_passive; /* Is Passive ? */
        struct list *mt_settings;   /* IS-IS MT Settings */
index bd06286755910d3563515c84c3d6a8e4bb8fdacc..37f4dcfabdec496d5b4b57d3307d0e037f21da02 100644 (file)
@@ -188,14 +188,10 @@ DEFPY(ip_router_isis, ip_router_isis_cmd, "ip router isis WORD$tag",
        }
 
        /* check if the interface is a loopback and if so set it as passive */
-       pthread_rwlock_rdlock(&running_config->lock);
-       {
-               ifp = nb_running_get_entry(NULL, VTY_CURR_XPATH, false);
-               if (ifp && if_is_loopback(ifp))
-                       nb_cli_enqueue_change(vty, "./frr-isisd:isis/passive",
-                                             NB_OP_MODIFY, "true");
-       }
-       pthread_rwlock_unlock(&running_config->lock);
+       ifp = nb_running_get_entry(NULL, VTY_CURR_XPATH, false);
+       if (ifp && if_is_loopback(ifp))
+               nb_cli_enqueue_change(vty, "./frr-isisd:isis/passive",
+                                     NB_OP_MODIFY, "true");
 
        return nb_cli_apply_changes(vty, NULL);
 }
@@ -262,14 +258,10 @@ DEFPY(ip6_router_isis, ip6_router_isis_cmd, "ipv6 router isis WORD$tag",
        }
 
        /* check if the interface is a loopback and if so set it as passive */
-       pthread_rwlock_rdlock(&running_config->lock);
-       {
-               ifp = nb_running_get_entry(NULL, VTY_CURR_XPATH, false);
-               if (ifp && if_is_loopback(ifp))
-                       nb_cli_enqueue_change(vty, "./frr-isisd:isis/passive",
-                                             NB_OP_MODIFY, "true");
-       }
-       pthread_rwlock_unlock(&running_config->lock);
+       ifp = nb_running_get_entry(NULL, VTY_CURR_XPATH, false);
+       if (ifp && if_is_loopback(ifp))
+               nb_cli_enqueue_change(vty, "./frr-isisd:isis/passive",
+                                     NB_OP_MODIFY, "true");
 
        return nb_cli_apply_changes(vty, NULL);
 }
@@ -410,26 +402,20 @@ DEFPY(no_is_type, no_is_type_cmd,
       "Act as both a station router and an area router\n"
       "Act as an area router only\n")
 {
-       const char *value;
-
-       pthread_rwlock_rdlock(&running_config->lock);
-       {
-               struct isis_area *area;
+       const char *value = NULL;
+       struct isis_area *area;
 
-               area = nb_running_get_entry(NULL, VTY_CURR_XPATH, false);
-
-               /*
-                * Put the is-type back to defaults:
-                * - level-1-2 on first area
-                * - level-1 for the rest
-                */
-               if (area && listgetdata(listhead(isis->area_list)) == area)
-                       value = "level-1-2";
-               else
-                       value = NULL;
-       }
-       pthread_rwlock_unlock(&running_config->lock);
+       area = nb_running_get_entry(NULL, VTY_CURR_XPATH, false);
 
+       /*
+        * Put the is-type back to defaults:
+        * - level-1-2 on first area
+        * - level-1 for the rest
+        */
+       if (area && listgetdata(listhead(isis->area_list)) == area)
+               value = "level-1-2";
+       else
+               value = NULL;
        nb_cli_enqueue_change(vty, "./is-type", NB_OP_MODIFY, value);
 
        return nb_cli_apply_changes(vty, NULL);
@@ -1817,45 +1803,52 @@ DEFPY(no_isis_circuit_type, no_isis_circuit_type_cmd,
       "Level-1-2 adjacencies are formed\n"
       "Level-2 only adjacencies are formed\n")
 {
-       const char *circ_type = NULL;
+       struct interface *ifp;
+       struct isis_circuit *circuit;
+       int is_type;
+       const char *circ_type;
 
        /*
         * Default value depends on whether the circuit is part of an area,
         * and the is-type of the area if there is one. So we need to do this
         * here.
         */
-       pthread_rwlock_rdlock(&running_config->lock);
-       {
-               struct interface *ifp;
-               struct isis_circuit *circuit;
+       ifp = nb_running_get_entry(NULL, VTY_CURR_XPATH, false);
+       if (!ifp)
+               goto def_val;
 
-               ifp = nb_running_get_entry(NULL, VTY_CURR_XPATH, false);
-               if (!ifp)
-                       goto unlock;
+       circuit = circuit_scan_by_ifp(ifp);
+       if (!circuit)
+               goto def_val;
 
-               circuit = circuit_scan_by_ifp(ifp);
-               if (!circuit || circuit->state != C_STATE_UP)
-                       goto unlock;
+       if (circuit->state == C_STATE_UP)
+               is_type = circuit->area->is_type;
+       else
+               goto def_val;
 
-               switch (circuit->area->is_type) {
-               case IS_LEVEL_1:
-                       circ_type = "level-1";
-                       break;
-               case IS_LEVEL_2:
-                       circ_type = "level-2";
-                       break;
-               case IS_LEVEL_1_AND_2:
-                       circ_type = "level-1-2";
-                       break;
-               }
+       switch (is_type) {
+       case IS_LEVEL_1:
+               circ_type = "level-1";
+               break;
+       case IS_LEVEL_2:
+               circ_type = "level-2";
+               break;
+       case IS_LEVEL_1_AND_2:
+               circ_type = "level-1-2";
+               break;
+       default:
+               return CMD_ERR_NO_MATCH;
        }
-unlock:
-       pthread_rwlock_unlock(&running_config->lock);
-
        nb_cli_enqueue_change(vty, "./frr-isisd:isis/circuit-type",
                              NB_OP_MODIFY, circ_type);
 
        return nb_cli_apply_changes(vty, NULL);
+
+def_val:
+       nb_cli_enqueue_change(vty, "./frr-isisd:isis/circuit-type",
+                             NB_OP_MODIFY, NULL);
+
+       return nb_cli_apply_changes(vty, NULL);
 }
 
 void cli_show_ip_isis_circ_type(struct vty *vty, struct lyd_node *dnode,
index 4b29e6dc7e0d7baee8faf159d5b7870b0741ebd3..061e7588314356098ce013214d924bf01895fcab 100644 (file)
@@ -52,9 +52,9 @@
 #include "isisd/isis_csm.h"
 #include "isisd/isis_adjacency.h"
 #include "isisd/isis_spf.h"
-#include "isisd/isis_te.h"
 #include "isisd/isis_mt.h"
 #include "isisd/isis_tlvs.h"
+#include "isisd/isis_te.h"
 #include "isisd/fabricd.h"
 #include "isisd/isis_tx_queue.h"
 
@@ -781,8 +781,8 @@ static void lsp_build_ext_reach_ipv6(struct isis_lsp *lsp,
                if (!rn->info)
                        continue;
                struct isis_ext_info *info = rn->info;
-
                struct prefix_ipv6 *p, *src_p;
+
                srcdest_rnode_prefixes(rn, (const struct prefix **)&p,
                                       (const struct prefix **)&src_p);
 
@@ -863,6 +863,7 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area)
        /* Protocols Supported */
        if (area->ip_circuits > 0 || area->ipv6_circuits > 0) {
                struct nlpids nlpids = {.count = 0};
+
                if (area->ip_circuits > 0) {
                        lsp_debug(
                                "ISIS (%s): Found IPv4 circuit, adding IPv4 to NLPIDs",
@@ -908,10 +909,12 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area)
                          area->area_tag);
        }
 
-       /* IPv4 address and TE router ID TLVs. In case of the first one we don't
-        * follow "C" vendor, but "J" vendor behavior - one IPv4 address is put
-        * into
-        * LSP and this address is same as router id. */
+       /* IPv4 address and TE router ID TLVs.
+        * In case of the first one we don't follow "C" vendor,
+        * but "J" vendor behavior - one IPv4 address is put
+        * into LSP. TE router ID will be the same if MPLS-TE
+        * is not activate or MPLS-TE router-id not specified
+        */
        if (isis->router_id != 0) {
                struct in_addr id = {.s_addr = isis->router_id};
                inet_ntop(AF_INET, &id, buf, sizeof(buf));
@@ -919,11 +922,14 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area)
                          area->area_tag, buf);
                isis_tlvs_add_ipv4_address(lsp->tlvs, &id);
 
-               /* Exactly same data is put into TE router ID TLV, but only if
-                * new style
-                * TLV's are in use. */
+               /* If new style TLV's are in use, add TE router ID TLV
+                * Check if MPLS-TE is activate and mpls-te router-id set
+                * otherwise add exactly same data as for IPv4 address
+                */
                if (area->newmetric) {
-
+                       if (IS_MPLS_TE(area->mta)
+                           && area->mta->router_id.s_addr != 0)
+                               id.s_addr = area->mta->router_id.s_addr;
                        lsp_debug(
                                "ISIS (%s): Adding router ID also as TE router ID tlv.",
                                area->area_tag);
@@ -1004,6 +1010,7 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area)
                    && circuit->ipv6_non_link->count > 0) {
                        struct listnode *ipnode;
                        struct prefix_ipv6 *ipv6;
+
                        for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_non_link,
                                                  ipnode, ipv6)) {
                                lsp_debug(
@@ -1036,25 +1043,10 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area)
                                                        lsp->tlvs, ne_id,
                                                        metric);
                                        }
-                                       if (area->newmetric) {
-                                               uint8_t subtlvs[256];
-                                               uint8_t subtlv_len;
-
-                                               if (IS_MPLS_TE(area->mta)
-                                                   && circuit->interface
-                                                   && HAS_LINK_PARAMS(
-                                                              circuit->interface))
-                                                       subtlv_len = add_te_subtlvs(
-                                                               subtlvs,
-                                                               circuit->mtc);
-                                               else
-                                                       subtlv_len = 0;
-
+                                       if (area->newmetric)
                                                tlvs_add_mt_bcast(
                                                        lsp->tlvs, circuit,
-                                                       level, ne_id, metric,
-                                                       subtlvs, subtlv_len);
-                                       }
+                                                       level, ne_id, metric);
                                }
                        } else {
                                lsp_debug(
@@ -1079,36 +1071,6 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area)
                                                lsp->tlvs, ne_id, metric);
                                }
                                if (area->newmetric) {
-                                       uint8_t subtlvs[256];
-                                       uint8_t subtlv_len;
-
-                                       if (IS_MPLS_TE(area->mta)
-                                           && circuit->interface != NULL
-                                           && HAS_LINK_PARAMS(
-                                                      circuit->interface))
-                                               /* Update Local and Remote IP
-                                                * address for MPLS TE circuit
-                                                * parameters */
-                                               /* NOTE sure that it is the
-                                                * pertinent place for that
-                                                * updates */
-                                               /* Local IP address could be
-                                                * updated in isis_circuit.c -
-                                                * isis_circuit_add_addr() */
-                                               /* But, where update remote IP
-                                                * address ? in isis_pdu.c -
-                                                * process_p2p_hello() ? */
-
-                                               /* Add SubTLVs & Adjust real
-                                                * size of SubTLVs */
-                                               subtlv_len = add_te_subtlvs(
-                                                       subtlvs, circuit->mtc);
-                                       else
-                                               /* Or keep only TE metric with
-                                                * no SubTLVs if MPLS_TE is off
-                                                */
-                                               subtlv_len = 0;
-
                                        uint32_t neighbor_metric;
                                        if (fabricd_tier(area) == 0) {
                                                neighbor_metric = 0xffe;
@@ -1117,8 +1079,7 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area)
                                        }
 
                                        tlvs_add_mt_p2p(lsp->tlvs, circuit,
-                                                       ne_id, neighbor_metric,
-                                                       subtlvs, subtlv_len);
+                                                       ne_id, neighbor_metric);
                                }
                        } else {
                                lsp_debug(
@@ -1512,7 +1473,7 @@ static void lsp_build_pseudo(struct isis_lsp *lsp, struct isis_circuit *circuit,
        }
        if (circuit->area->newmetric) {
                isis_tlvs_add_extended_reach(lsp->tlvs, ISIS_MT_IPV4_UNICAST,
-                                            ne_id, 0, NULL, 0);
+                                            ne_id, 0, circuit->ext);
                lsp_debug(
                        "ISIS (%s): Adding %s.%02x as te-style neighbor (self)",
                        area->area_tag, sysid_print(ne_id),
@@ -1554,7 +1515,7 @@ static void lsp_build_pseudo(struct isis_lsp *lsp, struct isis_circuit *circuit,
                if (circuit->area->newmetric) {
                        isis_tlvs_add_extended_reach(lsp->tlvs,
                                                     ISIS_MT_IPV4_UNICAST,
-                                                    ne_id, 0, NULL, 0);
+                                                    ne_id, 0, circuit->ext);
                        lsp_debug(
                                "ISIS (%s): Adding %s.%02x as te-style neighbor (peer)",
                                area->area_tag, sysid_print(ne_id),
index f7d4c7170f5c8a759a011e50e4d86d58c3ac5852..36413bac5949c8fe01b4a0cf5536b63d3c0b2f6d 100644 (file)
@@ -511,8 +511,8 @@ static uint16_t *circuit_bcast_mt_set(struct isis_circuit *circuit, int level,
 
 static void tlvs_add_mt_set(struct isis_area *area, struct isis_tlvs *tlvs,
                            unsigned int mt_count, uint16_t *mt_set,
-                           uint8_t *id, uint32_t metric, uint8_t *subtlvs,
-                           uint8_t subtlv_len)
+                           uint8_t *id, uint32_t metric,
+                           struct isis_ext_subtlvs *ext)
 {
        for (unsigned int i = 0; i < mt_count; i++) {
                uint16_t mtid = mt_set[i];
@@ -527,30 +527,27 @@ static void tlvs_add_mt_set(struct isis_area *area, struct isis_tlvs *tlvs,
                                area->area_tag, sysid_print(id),
                                LSP_PSEUDO_ID(id), isis_mtid2str(mtid));
                }
-               isis_tlvs_add_extended_reach(tlvs, mtid, id, metric, subtlvs,
-                                            subtlv_len);
+               isis_tlvs_add_extended_reach(tlvs, mtid, id, metric, ext);
        }
 }
 
 void tlvs_add_mt_bcast(struct isis_tlvs *tlvs, struct isis_circuit *circuit,
-                      int level, uint8_t *id, uint32_t metric,
-                      uint8_t *subtlvs, uint8_t subtlv_len)
+                      int level, uint8_t *id, uint32_t metric)
 {
        unsigned int mt_count;
        uint16_t *mt_set = circuit_bcast_mt_set(circuit, level, &mt_count);
 
        tlvs_add_mt_set(circuit->area, tlvs, mt_count, mt_set, id, metric,
-                       subtlvs, subtlv_len);
+                       circuit->ext);
 }
 
 void tlvs_add_mt_p2p(struct isis_tlvs *tlvs, struct isis_circuit *circuit,
-                    uint8_t *id, uint32_t metric, uint8_t *subtlvs,
-                    uint8_t subtlv_len)
+                    uint8_t *id, uint32_t metric)
 {
        struct isis_adjacency *adj = circuit->u.p2p.neighbor;
 
        tlvs_add_mt_set(circuit->area, tlvs, adj->mt_count, adj->mt_set, id,
-                       metric, subtlvs, subtlv_len);
+                       metric, circuit->ext);
 }
 
 void mt_init(void)
index 515b63f50f024c7329c233c252600714db786f72..b40139c50a8419ff525cf3891816e503bf96c484 100644 (file)
@@ -116,10 +116,8 @@ bool tlvs_to_adj_mt_set(struct isis_tlvs *tlvs, bool v4_usable, bool v6_usable,
 bool adj_has_mt(struct isis_adjacency *adj, uint16_t mtid);
 void adj_mt_finish(struct isis_adjacency *adj);
 void tlvs_add_mt_bcast(struct isis_tlvs *tlvs, struct isis_circuit *circuit,
-                      int level, uint8_t *id, uint32_t metric,
-                      uint8_t *subtlvs, uint8_t subtlv_len);
+                      int level, uint8_t *id, uint32_t metric);
 void tlvs_add_mt_p2p(struct isis_tlvs *tlvs, struct isis_circuit *circuit,
-                    uint8_t *id, uint32_t metric, uint8_t *subtlvs,
-                    uint8_t subtlv_len);
+                    uint8_t *id, uint32_t metric);
 void mt_init(void);
 #endif
index c1b630eb2db59a6396c360a1442ec0907460dc09..bd6191869782312eae9aaa5f5ee732e506261535 100644 (file)
@@ -1384,7 +1384,7 @@ static int isis_instance_mpls_te_create(enum nb_event event,
 
                struct mpls_te_area *new;
 
-               zlog_debug("ISIS MPLS-TE: Initialize area %s",
+               zlog_debug("ISIS-TE(%s): Initialize MPLS Traffic Engineering",
                        area->area_tag);
 
                new = XCALLOC(MTYPE_ISIS_MPLS_TE, sizeof(struct mpls_te_area));
@@ -1410,12 +1410,12 @@ static int isis_instance_mpls_te_create(enum nb_event event,
         * 2) MPLS-TE was once enabled then disabled, and now enabled again.
         */
        for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) {
-               if (circuit->mtc == NULL || IS_FLOOD_AS(circuit->mtc->type))
+               if (circuit->ext == NULL)
                        continue;
 
-               if (!IS_MPLS_TE(circuit->mtc)
+               if (!IS_EXT_TE(circuit->ext)
                    && HAS_LINK_PARAMS(circuit->interface))
-                       circuit->mtc->status = enable;
+                       isis_link_params_update(circuit, circuit->interface);
                else
                        continue;
 
@@ -1446,11 +1446,16 @@ static int isis_instance_mpls_te_destroy(enum nb_event event,
 
        /* Flush LSP if circuit engage */
        for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) {
-               if (circuit->mtc == NULL || (circuit->mtc->status == disable))
+               if (!IS_EXT_TE(circuit->ext))
                        continue;
 
-               /* disable MPLS_TE Circuit */
-               circuit->mtc->status = disable;
+               /* disable MPLS_TE Circuit keeping SR one's */
+               if (IS_SUBTLV(circuit->ext, EXT_ADJ_SID))
+                       circuit->ext->status = EXT_ADJ_SID;
+               else if (IS_SUBTLV(circuit->ext, EXT_LAN_ADJ_SID))
+                       circuit->ext->status = EXT_LAN_ADJ_SID;
+               else
+                       circuit->ext->status = 0;
 
                /* Re-originate circuit without STD_TE & GMPLS parameters */
                if (circuit->area)
@@ -1458,6 +1463,9 @@ static int isis_instance_mpls_te_destroy(enum nb_event event,
                                                0);
        }
 
+       zlog_debug("ISIS-TE(%s): Disabled MPLS Traffic Engineering",
+                  area->area_tag);
+
        return NB_OK;
 }
 
index 3d16d56016568ce53d40feb90aa676dec9a6bcf6..ecfce392ff5f61e55d858847d62b2776cde621b0 100644 (file)
@@ -199,13 +199,6 @@ static int process_p2p_hello(struct iih_info *iih)
        changed |= tlvs_to_adj_mt_set(iih->tlvs, iih->v4_usable, iih->v6_usable,
                                      adj);
 
-       /* Update MPLS TE Remote IP address parameter if possible */
-       if (IS_MPLS_TE(iih->circuit->area->mta)
-           && IS_MPLS_TE(iih->circuit->mtc)
-           && adj->ipv4_address_count)
-               set_circuitparams_rmt_ipaddr(iih->circuit->mtc,
-                                            adj->ipv4_addresses[0]);
-
        /* lets take care of the expiry */
        THREAD_TIMER_OFF(adj->t_expire);
        thread_add_timer(master, isis_adj_expire, adj, (long)adj->hold_time,
index 636a63e29094835461966641a25ec37da2e6dc6a..05394e0fe4bc8a2ac67fef377706845a80cd25a3 100644 (file)
 #include "isis_route.h"
 #include "isis_zebra.h"
 
+DEFINE_HOOK(isis_route_update_hook,
+           (struct isis_area * area, struct prefix *prefix,
+            struct isis_route_info *route_info),
+           (area, prefix, route_info))
+
 static struct isis_nexthop *nexthoplookup(struct list *nexthops, int family,
                                          union g_addr *ip, ifindex_t ifindex);
+static void isis_route_update(struct isis_area *area, struct prefix *prefix,
+                             struct prefix_ipv6 *src_p,
+                             struct isis_route_info *route_info);
 
 static struct isis_nexthop *isis_nexthop_create(int family, union g_addr *ip,
                                                ifindex_t ifindex)
@@ -316,7 +324,7 @@ struct isis_route_info *isis_route_create(struct prefix *prefix,
        return route_info;
 }
 
-static void isis_route_delete(struct route_node *rode,
+static void isis_route_delete(struct isis_area *area, struct route_node *rode,
                              struct route_table *table)
 {
        struct isis_route_info *rinfo;
@@ -343,13 +351,37 @@ static void isis_route_delete(struct route_node *rode,
                UNSET_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE);
                if (isis->debugs & DEBUG_RTE_EVENTS)
                        zlog_debug("ISIS-Rte: route delete  %s", buff);
-               isis_zebra_route_update(prefix, src_p, rinfo);
+               isis_route_update(area, prefix, src_p, rinfo);
        }
        isis_route_info_delete(rinfo);
        rode->info = NULL;
        route_unlock_node(rode);
 }
 
+static void isis_route_update(struct isis_area *area, struct prefix *prefix,
+                             struct prefix_ipv6 *src_p,
+                             struct isis_route_info *route_info)
+{
+       if (CHECK_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ACTIVE)) {
+               if (CHECK_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED))
+                       return;
+
+               isis_zebra_route_add_route(prefix, src_p, route_info);
+               hook_call(isis_route_update_hook, area, prefix, route_info);
+
+               SET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
+               UNSET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC);
+       } else {
+               if (!CHECK_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED))
+                       return;
+
+               isis_zebra_route_del_route(prefix, src_p, route_info);
+               hook_call(isis_route_update_hook, area, prefix, route_info);
+
+               UNSET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
+       }
+}
+
 static void _isis_route_verify_table(struct isis_area *area,
                                     struct route_table *table,
                                     struct route_table **tables)
@@ -390,7 +422,7 @@ static void _isis_route_verify_table(struct isis_area *area,
                                buff);
                }
 
-               isis_zebra_route_update(dst_p, src_p, rinfo);
+               isis_route_update(area, dst_p, src_p, rinfo);
 
                if (CHECK_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE))
                        continue;
@@ -399,7 +431,7 @@ static void _isis_route_verify_table(struct isis_area *area,
                 * directly for
                 * validating => no problems with deleting routes. */
                if (!tables) {
-                       isis_route_delete(rnode, table);
+                       isis_route_delete(area, rnode, table);
                        continue;
                }
 
@@ -422,7 +454,7 @@ static void _isis_route_verify_table(struct isis_area *area,
                        route_unlock_node(drnode);
                }
 
-               isis_route_delete(rnode, table);
+               isis_route_delete(area, rnode, table);
        }
 }
 
index a20a7e038f1c295cfe172e4171b46e7a62a9c5a4..2326bb8228c05569573c615de7d460a73cdf9d90 100644 (file)
@@ -44,6 +44,11 @@ struct isis_route_info {
        struct list *nexthops;
 };
 
+DECLARE_HOOK(isis_route_update_hook,
+            (struct isis_area * area, struct prefix *prefix,
+             struct isis_route_info *route_info),
+            (area, prefix, route_info))
+
 struct isis_route_info *isis_route_create(struct prefix *prefix,
                                          struct prefix_ipv6 *src_p,
                                          uint32_t cost,
index 4ea6c2c60d657901cb6c8f9a8ea1252348ea1baa..44fa45d02b0a9b0bdd05f2b331f3bc15d762b068 100644 (file)
@@ -3,8 +3,9 @@
  *
  * This is an implementation of RFC5305 & RFC 7810
  *
- *      Copyright (C) 2014 Orange Labs
- *      http://www.orange.com
+ * Author: Olivier Dugeon <olivier.dugeon@orange.com>
+ *
+ * Copyright (C) 2014 - 2019 Orange Labs http://www.orange.com
  *
  * This file is part of GNU Zebra.
  *
@@ -47,6 +48,7 @@
 #include "isisd/isis_common.h"
 #include "isisd/isis_flags.h"
 #include "isisd/isis_circuit.h"
+#include "isisd/isis_adjacency.h"
 #include "isisd/isisd.h"
 #include "isisd/isis_lsp.h"
 #include "isisd/isis_pdu.h"
@@ -56,6 +58,7 @@
 #include "isisd/isis_adjacency.h"
 #include "isisd/isis_spf.h"
 #include "isisd/isis_te.h"
+#include "isisd/isis_zebra.h"
 
 const char *mode2text[] = {"Disable", "Area", "AS", "Emulate"};
 
@@ -63,424 +66,6 @@ const char *mode2text[] = {"Disable", "Area", "AS", "Emulate"};
  * Followings are control functions for MPLS-TE parameters management.
  *------------------------------------------------------------------------*/
 
-/* Create new MPLS TE Circuit context */
-struct mpls_te_circuit *mpls_te_circuit_new(void)
-{
-       struct mpls_te_circuit *mtc;
-
-       zlog_debug("ISIS MPLS-TE: Create new MPLS TE Circuit context");
-
-       mtc = XCALLOC(MTYPE_ISIS_MPLS_TE, sizeof(struct mpls_te_circuit));
-
-       mtc->status = disable;
-       mtc->type = STD_TE;
-       mtc->length = 0;
-
-       return mtc;
-}
-
-/* Copy SUB TLVs parameters into a buffer - No space verification are performed
- */
-/* Caller must verify before that there is enough free space in the buffer */
-uint8_t add_te_subtlvs(uint8_t *buf, struct mpls_te_circuit *mtc)
-{
-       uint8_t size, *tlvs = buf;
-
-       zlog_debug("ISIS MPLS-TE: Add TE Sub TLVs to buffer");
-
-       if (mtc == NULL) {
-               zlog_debug(
-                       "ISIS MPLS-TE: Abort! No MPLS TE Circuit available has been specified");
-               return 0;
-       }
-
-       /* Create buffer if not provided */
-       if (buf == NULL) {
-               zlog_debug("ISIS MPLS-TE: Abort! No Buffer has been specified");
-               return 0;
-       }
-
-       /* TE_SUBTLV_ADMIN_GRP */
-       if (SUBTLV_TYPE(mtc->admin_grp) != 0) {
-               size = SUBTLV_SIZE(&(mtc->admin_grp.header));
-               memcpy(tlvs, &(mtc->admin_grp), size);
-               tlvs += size;
-       }
-
-       /* TE_SUBTLV_LLRI */
-       if (SUBTLV_TYPE(mtc->llri) != 0) {
-               size = SUBTLV_SIZE(&(mtc->llri.header));
-               memcpy(tlvs, &(mtc->llri), size);
-               tlvs += size;
-       }
-
-       /* TE_SUBTLV_LCLIF_IPADDR */
-       if (SUBTLV_TYPE(mtc->local_ipaddr) != 0) {
-               size = SUBTLV_SIZE(&(mtc->local_ipaddr.header));
-               memcpy(tlvs, &(mtc->local_ipaddr), size);
-               tlvs += size;
-       }
-
-       /* TE_SUBTLV_RMTIF_IPADDR */
-       if (SUBTLV_TYPE(mtc->rmt_ipaddr) != 0) {
-               size = SUBTLV_SIZE(&(mtc->rmt_ipaddr.header));
-               memcpy(tlvs, &(mtc->rmt_ipaddr), size);
-               tlvs += size;
-       }
-
-       /* TE_SUBTLV_MAX_BW */
-       if (SUBTLV_TYPE(mtc->max_bw) != 0) {
-               size = SUBTLV_SIZE(&(mtc->max_bw.header));
-               memcpy(tlvs, &(mtc->max_bw), size);
-               tlvs += size;
-       }
-
-       /* TE_SUBTLV_MAX_RSV_BW */
-       if (SUBTLV_TYPE(mtc->max_rsv_bw) != 0) {
-               size = SUBTLV_SIZE(&(mtc->max_rsv_bw.header));
-               memcpy(tlvs, &(mtc->max_rsv_bw), size);
-               tlvs += size;
-       }
-
-       /* TE_SUBTLV_UNRSV_BW */
-       if (SUBTLV_TYPE(mtc->unrsv_bw) != 0) {
-               size = SUBTLV_SIZE(&(mtc->unrsv_bw.header));
-               memcpy(tlvs, &(mtc->unrsv_bw), size);
-               tlvs += size;
-       }
-
-       /* TE_SUBTLV_TE_METRIC */
-       if (SUBTLV_TYPE(mtc->te_metric) != 0) {
-               size = SUBTLV_SIZE(&(mtc->te_metric.header));
-               memcpy(tlvs, &(mtc->te_metric), size);
-               tlvs += size;
-       }
-
-       /* TE_SUBTLV_AV_DELAY */
-       if (SUBTLV_TYPE(mtc->av_delay) != 0) {
-               size = SUBTLV_SIZE(&(mtc->av_delay.header));
-               memcpy(tlvs, &(mtc->av_delay), size);
-               tlvs += size;
-       }
-
-       /* TE_SUBTLV_MM_DELAY */
-       if (SUBTLV_TYPE(mtc->mm_delay) != 0) {
-               size = SUBTLV_SIZE(&(mtc->mm_delay.header));
-               memcpy(tlvs, &(mtc->mm_delay), size);
-               tlvs += size;
-       }
-
-       /* TE_SUBTLV_DELAY_VAR */
-       if (SUBTLV_TYPE(mtc->delay_var) != 0) {
-               size = SUBTLV_SIZE(&(mtc->delay_var.header));
-               memcpy(tlvs, &(mtc->delay_var), size);
-               tlvs += size;
-       }
-
-       /* TE_SUBTLV_PKT_LOSS */
-       if (SUBTLV_TYPE(mtc->pkt_loss) != 0) {
-               size = SUBTLV_SIZE(&(mtc->pkt_loss.header));
-               memcpy(tlvs, &(mtc->pkt_loss), size);
-               tlvs += size;
-       }
-
-       /* TE_SUBTLV_RES_BW */
-       if (SUBTLV_TYPE(mtc->res_bw) != 0) {
-               size = SUBTLV_SIZE(&(mtc->res_bw.header));
-               memcpy(tlvs, &(mtc->res_bw), size);
-               tlvs += size;
-       }
-
-       /* TE_SUBTLV_AVA_BW */
-       if (SUBTLV_TYPE(mtc->ava_bw) != 0) {
-               size = SUBTLV_SIZE(&(mtc->ava_bw.header));
-               memcpy(tlvs, &(mtc->ava_bw), size);
-               tlvs += size;
-       }
-
-       /* TE_SUBTLV_USE_BW */
-       if (SUBTLV_TYPE(mtc->use_bw) != 0) {
-               size = SUBTLV_SIZE(&(mtc->use_bw.header));
-               memcpy(tlvs, &(mtc->use_bw), size);
-               tlvs += size;
-       }
-
-       /* Add before this line any other parsing of TLV */
-       (void)tlvs;
-
-       /* Update SubTLVs length */
-       mtc->length = subtlvs_len(mtc);
-
-       zlog_debug("ISIS MPLS-TE: Add %d bytes length SubTLVs", mtc->length);
-
-       return mtc->length;
-}
-
-/* Compute total Sub-TLVs size */
-uint8_t subtlvs_len(struct mpls_te_circuit *mtc)
-{
-       int length = 0;
-
-       /* Sanity Check */
-       if (mtc == NULL)
-               return 0;
-
-       /* TE_SUBTLV_ADMIN_GRP */
-       if (SUBTLV_TYPE(mtc->admin_grp) != 0)
-               length += SUBTLV_SIZE(&(mtc->admin_grp.header));
-
-       /* TE_SUBTLV_LLRI */
-       if (SUBTLV_TYPE(mtc->llri) != 0)
-               length += SUBTLV_SIZE(&mtc->llri.header);
-
-       /* TE_SUBTLV_LCLIF_IPADDR */
-       if (SUBTLV_TYPE(mtc->local_ipaddr) != 0)
-               length += SUBTLV_SIZE(&mtc->local_ipaddr.header);
-
-       /* TE_SUBTLV_RMTIF_IPADDR */
-       if (SUBTLV_TYPE(mtc->rmt_ipaddr) != 0)
-               length += SUBTLV_SIZE(&mtc->rmt_ipaddr.header);
-
-       /* TE_SUBTLV_MAX_BW */
-       if (SUBTLV_TYPE(mtc->max_bw) != 0)
-               length += SUBTLV_SIZE(&mtc->max_bw.header);
-
-       /* TE_SUBTLV_MAX_RSV_BW */
-       if (SUBTLV_TYPE(mtc->max_rsv_bw) != 0)
-               length += SUBTLV_SIZE(&mtc->max_rsv_bw.header);
-
-       /* TE_SUBTLV_UNRSV_BW */
-       if (SUBTLV_TYPE(mtc->unrsv_bw) != 0)
-               length += SUBTLV_SIZE(&mtc->unrsv_bw.header);
-
-       /* TE_SUBTLV_TE_METRIC */
-       if (SUBTLV_TYPE(mtc->te_metric) != 0)
-               length += SUBTLV_SIZE(&mtc->te_metric.header);
-
-       /* TE_SUBTLV_AV_DELAY */
-       if (SUBTLV_TYPE(mtc->av_delay) != 0)
-               length += SUBTLV_SIZE(&mtc->av_delay.header);
-
-       /* TE_SUBTLV_MM_DELAY */
-       if (SUBTLV_TYPE(mtc->mm_delay) != 0)
-               length += SUBTLV_SIZE(&mtc->mm_delay.header);
-
-       /* TE_SUBTLV_DELAY_VAR */
-       if (SUBTLV_TYPE(mtc->delay_var) != 0)
-               length += SUBTLV_SIZE(&mtc->delay_var.header);
-
-       /* TE_SUBTLV_PKT_LOSS */
-       if (SUBTLV_TYPE(mtc->pkt_loss) != 0)
-               length += SUBTLV_SIZE(&mtc->pkt_loss.header);
-
-       /* TE_SUBTLV_RES_BW */
-       if (SUBTLV_TYPE(mtc->res_bw) != 0)
-               length += SUBTLV_SIZE(&mtc->res_bw.header);
-
-       /* TE_SUBTLV_AVA_BW */
-       if (SUBTLV_TYPE(mtc->ava_bw) != 0)
-               length += SUBTLV_SIZE(&mtc->ava_bw.header);
-
-       /* TE_SUBTLV_USE_BW */
-       if (SUBTLV_TYPE(mtc->use_bw) != 0)
-               length += SUBTLV_SIZE(&mtc->use_bw.header);
-
-       /* Check that length is lower than the MAXIMUM SUBTLV size i.e. 256 */
-       if (length > MAX_SUBTLV_SIZE) {
-               mtc->length = 0;
-               return 0;
-       }
-
-       mtc->length = (uint8_t)length;
-
-       return mtc->length;
-}
-
-/* Following are various functions to set MPLS TE parameters */
-static void set_circuitparams_admin_grp(struct mpls_te_circuit *mtc,
-                                       uint32_t admingrp)
-{
-       SUBTLV_TYPE(mtc->admin_grp) = TE_SUBTLV_ADMIN_GRP;
-       SUBTLV_LEN(mtc->admin_grp) = SUBTLV_DEF_SIZE;
-       mtc->admin_grp.value = htonl(admingrp);
-       return;
-}
-
-static void __attribute__((unused))
-set_circuitparams_llri(struct mpls_te_circuit *mtc, uint32_t local,
-                      uint32_t remote)
-{
-       SUBTLV_TYPE(mtc->llri) = TE_SUBTLV_LLRI;
-       SUBTLV_LEN(mtc->llri) = TE_SUBTLV_LLRI_SIZE;
-       mtc->llri.local = htonl(local);
-       mtc->llri.remote = htonl(remote);
-}
-
-void set_circuitparams_local_ipaddr(struct mpls_te_circuit *mtc,
-                                   struct in_addr addr)
-{
-
-       SUBTLV_TYPE(mtc->local_ipaddr) = TE_SUBTLV_LOCAL_IPADDR;
-       SUBTLV_LEN(mtc->local_ipaddr) = SUBTLV_DEF_SIZE;
-       mtc->local_ipaddr.value.s_addr = addr.s_addr;
-       return;
-}
-
-void set_circuitparams_rmt_ipaddr(struct mpls_te_circuit *mtc,
-                                 struct in_addr addr)
-{
-
-       SUBTLV_TYPE(mtc->rmt_ipaddr) = TE_SUBTLV_RMT_IPADDR;
-       SUBTLV_LEN(mtc->rmt_ipaddr) = SUBTLV_DEF_SIZE;
-       mtc->rmt_ipaddr.value.s_addr = addr.s_addr;
-       return;
-}
-
-static void set_circuitparams_max_bw(struct mpls_te_circuit *mtc, float fp)
-{
-       SUBTLV_TYPE(mtc->max_bw) = TE_SUBTLV_MAX_BW;
-       SUBTLV_LEN(mtc->max_bw) = SUBTLV_DEF_SIZE;
-       mtc->max_bw.value = htonf(fp);
-       return;
-}
-
-static void set_circuitparams_max_rsv_bw(struct mpls_te_circuit *mtc, float fp)
-{
-       SUBTLV_TYPE(mtc->max_rsv_bw) = TE_SUBTLV_MAX_RSV_BW;
-       SUBTLV_LEN(mtc->max_rsv_bw) = SUBTLV_DEF_SIZE;
-       mtc->max_rsv_bw.value = htonf(fp);
-       return;
-}
-
-static void set_circuitparams_unrsv_bw(struct mpls_te_circuit *mtc,
-                                      int priority, float fp)
-{
-       /* Note that TLV-length field is the size of array. */
-       SUBTLV_TYPE(mtc->unrsv_bw) = TE_SUBTLV_UNRSV_BW;
-       SUBTLV_LEN(mtc->unrsv_bw) = TE_SUBTLV_UNRSV_SIZE;
-       mtc->unrsv_bw.value[priority] = htonf(fp);
-       return;
-}
-
-static void set_circuitparams_te_metric(struct mpls_te_circuit *mtc,
-                                       uint32_t te_metric)
-{
-       SUBTLV_TYPE(mtc->te_metric) = TE_SUBTLV_TE_METRIC;
-       SUBTLV_LEN(mtc->te_metric) = TE_SUBTLV_TE_METRIC_SIZE;
-       mtc->te_metric.value[0] = (te_metric >> 16) & 0xFF;
-       mtc->te_metric.value[1] = (te_metric >> 8) & 0xFF;
-       mtc->te_metric.value[2] = te_metric & 0xFF;
-       return;
-}
-
-static void set_circuitparams_inter_as(struct mpls_te_circuit *mtc,
-                                      struct in_addr addr, uint32_t as)
-{
-
-       /* Set the Remote ASBR IP address and then the associated AS number */
-       SUBTLV_TYPE(mtc->rip) = TE_SUBTLV_RIP;
-       SUBTLV_LEN(mtc->rip) = SUBTLV_DEF_SIZE;
-       mtc->rip.value.s_addr = addr.s_addr;
-
-       SUBTLV_TYPE(mtc->ras) = TE_SUBTLV_RAS;
-       SUBTLV_LEN(mtc->ras) = SUBTLV_DEF_SIZE;
-       mtc->ras.value = htonl(as);
-}
-
-static void unset_circuitparams_inter_as(struct mpls_te_circuit *mtc)
-{
-
-       /* Reset the Remote ASBR IP address and then the associated AS number */
-       SUBTLV_TYPE(mtc->rip) = 0;
-       SUBTLV_LEN(mtc->rip) = 0;
-       mtc->rip.value.s_addr = 0;
-
-       SUBTLV_TYPE(mtc->ras) = 0;
-       SUBTLV_LEN(mtc->ras) = 0;
-       mtc->ras.value = 0;
-}
-
-static void set_circuitparams_av_delay(struct mpls_te_circuit *mtc,
-                                      uint32_t delay, uint8_t anormal)
-{
-       uint32_t tmp;
-       /* Note that TLV-length field is the size of array. */
-       SUBTLV_TYPE(mtc->av_delay) = TE_SUBTLV_AV_DELAY;
-       SUBTLV_LEN(mtc->av_delay) = SUBTLV_DEF_SIZE;
-       tmp = delay & TE_EXT_MASK;
-       if (anormal)
-               tmp |= TE_EXT_ANORMAL;
-       mtc->av_delay.value = htonl(tmp);
-       return;
-}
-
-static void set_circuitparams_mm_delay(struct mpls_te_circuit *mtc,
-                                      uint32_t low, uint32_t high,
-                                      uint8_t anormal)
-{
-       uint32_t tmp;
-       /* Note that TLV-length field is the size of array. */
-       SUBTLV_TYPE(mtc->mm_delay) = TE_SUBTLV_MM_DELAY;
-       SUBTLV_LEN(mtc->mm_delay) = TE_SUBTLV_MM_DELAY_SIZE;
-       tmp = low & TE_EXT_MASK;
-       if (anormal)
-               tmp |= TE_EXT_ANORMAL;
-       mtc->mm_delay.low = htonl(tmp);
-       mtc->mm_delay.high = htonl(high);
-       return;
-}
-
-static void set_circuitparams_delay_var(struct mpls_te_circuit *mtc,
-                                       uint32_t jitter)
-{
-       /* Note that TLV-length field is the size of array. */
-       SUBTLV_TYPE(mtc->delay_var) = TE_SUBTLV_DELAY_VAR;
-       SUBTLV_LEN(mtc->delay_var) = SUBTLV_DEF_SIZE;
-       mtc->delay_var.value = htonl(jitter & TE_EXT_MASK);
-       return;
-}
-
-static void set_circuitparams_pkt_loss(struct mpls_te_circuit *mtc,
-                                      uint32_t loss, uint8_t anormal)
-{
-       uint32_t tmp;
-       /* Note that TLV-length field is the size of array. */
-       SUBTLV_TYPE(mtc->pkt_loss) = TE_SUBTLV_PKT_LOSS;
-       SUBTLV_LEN(mtc->pkt_loss) = SUBTLV_DEF_SIZE;
-       tmp = loss & TE_EXT_MASK;
-       if (anormal)
-               tmp |= TE_EXT_ANORMAL;
-       mtc->pkt_loss.value = htonl(tmp);
-       return;
-}
-
-static void set_circuitparams_res_bw(struct mpls_te_circuit *mtc, float fp)
-{
-       /* Note that TLV-length field is the size of array. */
-       SUBTLV_TYPE(mtc->res_bw) = TE_SUBTLV_RES_BW;
-       SUBTLV_LEN(mtc->res_bw) = SUBTLV_DEF_SIZE;
-       mtc->res_bw.value = htonf(fp);
-       return;
-}
-
-static void set_circuitparams_ava_bw(struct mpls_te_circuit *mtc, float fp)
-{
-       /* Note that TLV-length field is the size of array. */
-       SUBTLV_TYPE(mtc->ava_bw) = TE_SUBTLV_AVA_BW;
-       SUBTLV_LEN(mtc->ava_bw) = SUBTLV_DEF_SIZE;
-       mtc->ava_bw.value = htonf(fp);
-       return;
-}
-
-static void set_circuitparams_use_bw(struct mpls_te_circuit *mtc, float fp)
-{
-       /* Note that TLV-length field is the size of array. */
-       SUBTLV_TYPE(mtc->use_bw) = TE_SUBTLV_USE_BW;
-       SUBTLV_LEN(mtc->use_bw) = SUBTLV_DEF_SIZE;
-       mtc->use_bw.value = htonf(fp);
-       return;
-}
-
 /* Main initialization / update function of the MPLS TE Circuit context */
 /* Call when interface TE Link parameters are modified */
 void isis_link_params_update(struct isis_circuit *circuit,
@@ -488,155 +73,223 @@ void isis_link_params_update(struct isis_circuit *circuit,
 {
        int i;
        struct prefix_ipv4 *addr;
-       struct mpls_te_circuit *mtc;
+       struct prefix_ipv6 *addr6;
+       struct isis_ext_subtlvs *ext;
+
+       /* Check if TE is enable or not */
+       if (!circuit->area || !IS_MPLS_TE(circuit->area->mta))
+               return;
 
        /* Sanity Check */
-       if ((circuit == NULL) || (ifp == NULL))
+       if ((circuit == NULL) || (ifp == NULL)
+           || (circuit->state != C_STATE_UP))
                return;
 
-       zlog_info("MPLS-TE: Initialize circuit parameters for interface %s",
-                 ifp->name);
+       zlog_debug("TE(%s): Update circuit parameters for interface %s",
+                  circuit->area->area_tag, ifp->name);
 
        /* Check if MPLS TE Circuit context has not been already created */
-       if (circuit->mtc == NULL)
-               circuit->mtc = mpls_te_circuit_new();
+       if (circuit->ext == NULL) {
+               circuit->ext = isis_alloc_ext_subtlvs();
+               zlog_debug("  |- Allocated new Ext-subTLVs for interface %s",
+                          ifp->name);
+       }
 
-       mtc = circuit->mtc;
+       ext = circuit->ext;
 
-       /* Fulfil MTC TLV from ifp TE Link parameters */
+       /* Fulfill Extended subTLVs from interface link parameters */
        if (HAS_LINK_PARAMS(ifp)) {
-               mtc->status = enable;
                /* STD_TE metrics */
-               if (IS_PARAM_SET(ifp->link_params, LP_ADM_GRP))
-                       set_circuitparams_admin_grp(
-                               mtc, ifp->link_params->admin_grp);
-               else
-                       SUBTLV_TYPE(mtc->admin_grp) = 0;
-
-               /* If not already set, register local IP addr from ip_addr list
-                * if it exists */
-               if (SUBTLV_TYPE(mtc->local_ipaddr) == 0) {
-                       if (circuit->ip_addrs != NULL
-                           && listcount(circuit->ip_addrs) != 0) {
-                               addr = (struct prefix_ipv4 *)listgetdata(
-                                       (struct listnode *)listhead(
-                                               circuit->ip_addrs));
-                               set_circuitparams_local_ipaddr(mtc,
-                                                              addr->prefix);
-                       }
-               }
-
-               /* If not already set, try to determine Remote IP addr if
-                * circuit is P2P */
-               if ((SUBTLV_TYPE(mtc->rmt_ipaddr) == 0)
-                   && (circuit->circ_type == CIRCUIT_T_P2P)) {
+               if (IS_PARAM_SET(ifp->link_params, LP_ADM_GRP)) {
+                       ext->adm_group = ifp->link_params->admin_grp;
+                       SET_SUBTLV(ext, EXT_ADM_GRP);
+               } else
+                       UNSET_SUBTLV(ext, EXT_ADM_GRP);
+
+               /* If known, register local IPv4 addr from ip_addr list */
+               if (circuit->ip_addrs != NULL
+                   && listcount(circuit->ip_addrs) != 0) {
+                       addr = (struct prefix_ipv4 *)listgetdata(
+                               (struct listnode *)listhead(circuit->ip_addrs));
+                       IPV4_ADDR_COPY(&ext->local_addr, &addr->prefix);
+                       SET_SUBTLV(ext, EXT_LOCAL_ADDR);
+               } else
+                       UNSET_SUBTLV(ext, EXT_LOCAL_ADDR);
+
+               /* Same for Remote IPv4 address */
+               if (circuit->circ_type == CIRCUIT_T_P2P) {
                        struct isis_adjacency *adj = circuit->u.p2p.neighbor;
+
                        if (adj && adj->adj_state == ISIS_ADJ_UP
                            && adj->ipv4_address_count) {
-                               set_circuitparams_rmt_ipaddr(
-                                       mtc, adj->ipv4_addresses[0]);
+                               IPV4_ADDR_COPY(&ext->neigh_addr,
+                                              &adj->ipv4_addresses[0]);
+                               SET_SUBTLV(ext, EXT_NEIGH_ADDR);
                        }
-               }
-
-               if (IS_PARAM_SET(ifp->link_params, LP_MAX_BW))
-                       set_circuitparams_max_bw(mtc, ifp->link_params->max_bw);
-               else
-                       SUBTLV_TYPE(mtc->max_bw) = 0;
-
-               if (IS_PARAM_SET(ifp->link_params, LP_MAX_RSV_BW))
-                       set_circuitparams_max_rsv_bw(
-                               mtc, ifp->link_params->max_rsv_bw);
-               else
-                       SUBTLV_TYPE(mtc->max_rsv_bw) = 0;
+               } else
+                       UNSET_SUBTLV(ext, EXT_NEIGH_ADDR);
+
+               /* If known, register local IPv6 addr from ip_addr list */
+               if (circuit->ipv6_non_link != NULL
+                   && listcount(circuit->ipv6_non_link) != 0) {
+                       addr6 = (struct prefix_ipv6 *)listgetdata(
+                               (struct listnode *)listhead(
+                                       circuit->ipv6_non_link));
+                       IPV6_ADDR_COPY(&ext->local_addr6, &addr6->prefix);
+                       SET_SUBTLV(ext, EXT_LOCAL_ADDR6);
+               } else
+                       UNSET_SUBTLV(ext, EXT_LOCAL_ADDR6);
+
+               /* Same for Remote IPv6 address */
+               if (circuit->circ_type == CIRCUIT_T_P2P) {
+                       struct isis_adjacency *adj = circuit->u.p2p.neighbor;
 
-               if (IS_PARAM_SET(ifp->link_params, LP_UNRSV_BW))
+                       if (adj && adj->adj_state == ISIS_ADJ_UP
+                           && adj->ipv6_address_count) {
+                               IPV6_ADDR_COPY(&ext->neigh_addr6,
+                                              &adj->ipv6_addresses[0]);
+                               SET_SUBTLV(ext, EXT_NEIGH_ADDR6);
+                       }
+               } else
+                       UNSET_SUBTLV(ext, EXT_NEIGH_ADDR6);
+
+               if (IS_PARAM_SET(ifp->link_params, LP_MAX_BW)) {
+                       ext->max_bw = ifp->link_params->max_bw;
+                       SET_SUBTLV(ext, EXT_MAX_BW);
+               } else
+                       UNSET_SUBTLV(ext, EXT_MAX_BW);
+
+               if (IS_PARAM_SET(ifp->link_params, LP_MAX_RSV_BW)) {
+                       ext->max_rsv_bw = ifp->link_params->max_rsv_bw;
+                       SET_SUBTLV(ext, EXT_MAX_RSV_BW);
+               } else
+                       UNSET_SUBTLV(ext, EXT_MAX_RSV_BW);
+
+               if (IS_PARAM_SET(ifp->link_params, LP_UNRSV_BW)) {
                        for (i = 0; i < MAX_CLASS_TYPE; i++)
-                               set_circuitparams_unrsv_bw(
-                                       mtc, i, ifp->link_params->unrsv_bw[i]);
-               else
-                       SUBTLV_TYPE(mtc->unrsv_bw) = 0;
-
-               if (IS_PARAM_SET(ifp->link_params, LP_TE_METRIC))
-                       set_circuitparams_te_metric(
-                               mtc, ifp->link_params->te_metric);
-               else
-                       SUBTLV_TYPE(mtc->te_metric) = 0;
-
-               /* TE metric Extensions */
-               if (IS_PARAM_SET(ifp->link_params, LP_DELAY))
-                       set_circuitparams_av_delay(
-                               mtc, ifp->link_params->av_delay, 0);
-               else
-                       SUBTLV_TYPE(mtc->av_delay) = 0;
+                               ext->unrsv_bw[i] =
+                                       ifp->link_params->unrsv_bw[i];
+                       SET_SUBTLV(ext, EXT_UNRSV_BW);
+               } else
+                       UNSET_SUBTLV(ext, EXT_UNRSV_BW);
+
+               if (IS_PARAM_SET(ifp->link_params, LP_TE_METRIC)) {
+                       ext->te_metric = ifp->link_params->te_metric;
+                       SET_SUBTLV(ext, EXT_TE_METRIC);
+               } else
+                       UNSET_SUBTLV(ext, EXT_TE_METRIC);
+
+               /* TE metric extensions */
+               if (IS_PARAM_SET(ifp->link_params, LP_DELAY)) {
+                       ext->delay = ifp->link_params->av_delay;
+                       SET_SUBTLV(ext, EXT_DELAY);
+               } else
+                       UNSET_SUBTLV(ext, EXT_DELAY);
+
+               if (IS_PARAM_SET(ifp->link_params, LP_MM_DELAY)) {
+                       ext->min_delay = ifp->link_params->min_delay;
+                       ext->max_delay = ifp->link_params->max_delay;
+                       SET_SUBTLV(ext, EXT_MM_DELAY);
+               } else
+                       UNSET_SUBTLV(ext, EXT_MM_DELAY);
+
+               if (IS_PARAM_SET(ifp->link_params, LP_DELAY_VAR)) {
+                       ext->delay_var = ifp->link_params->delay_var;
+                       SET_SUBTLV(ext, EXT_DELAY_VAR);
+               } else
+                       UNSET_SUBTLV(ext, EXT_DELAY_VAR);
+
+               if (IS_PARAM_SET(ifp->link_params, LP_PKT_LOSS)) {
+                       ext->pkt_loss = ifp->link_params->pkt_loss;
+                       SET_SUBTLV(ext, EXT_PKT_LOSS);
+               } else
+                       UNSET_SUBTLV(ext, EXT_PKT_LOSS);
+
+               if (IS_PARAM_SET(ifp->link_params, LP_RES_BW)) {
+                       ext->res_bw = ifp->link_params->res_bw;
+                       SET_SUBTLV(ext, EXT_RES_BW);
+               } else
+                       UNSET_SUBTLV(ext, EXT_RES_BW);
+
+               if (IS_PARAM_SET(ifp->link_params, LP_AVA_BW)) {
+                       ext->ava_bw = ifp->link_params->ava_bw;
+                       SET_SUBTLV(ext, EXT_AVA_BW);
+               } else
+                       UNSET_SUBTLV(ext, EXT_AVA_BW);
+
+               if (IS_PARAM_SET(ifp->link_params, LP_USE_BW)) {
+                       ext->use_bw = ifp->link_params->use_bw;
+                       SET_SUBTLV(ext, EXT_USE_BW);
+               } else
+                       UNSET_SUBTLV(ext, EXT_USE_BW);
 
-               if (IS_PARAM_SET(ifp->link_params, LP_MM_DELAY))
-                       set_circuitparams_mm_delay(
-                               mtc, ifp->link_params->min_delay,
-                               ifp->link_params->max_delay, 0);
-               else
-                       SUBTLV_TYPE(mtc->mm_delay) = 0;
-
-               if (IS_PARAM_SET(ifp->link_params, LP_DELAY_VAR))
-                       set_circuitparams_delay_var(
-                               mtc, ifp->link_params->delay_var);
-               else
-                       SUBTLV_TYPE(mtc->delay_var) = 0;
-
-               if (IS_PARAM_SET(ifp->link_params, LP_PKT_LOSS))
-                       set_circuitparams_pkt_loss(
-                               mtc, ifp->link_params->pkt_loss, 0);
+               /* INTER_AS */
+               if (IS_PARAM_SET(ifp->link_params, LP_RMT_AS)) {
+                       ext->remote_as = ifp->link_params->rmt_as;
+                       ext->remote_ip = ifp->link_params->rmt_ip;
+                       SET_SUBTLV(ext, EXT_RMT_AS);
+                       SET_SUBTLV(ext, EXT_RMT_IP);
+               } else {
+                       /* reset inter-as TE params */
+                       UNSET_SUBTLV(ext, EXT_RMT_AS);
+                       UNSET_SUBTLV(ext, EXT_RMT_IP);
+               }
+               zlog_debug("  |- New MPLS-TE link parameters status 0x%x",
+                          ext->status);
+       } else {
+               zlog_debug("  |- Reset Extended subTLVs status 0x%x",
+                          ext->status);
+               /* Reset TE subTLVs keeping SR one's */
+               if (IS_SUBTLV(ext, EXT_ADJ_SID))
+                       ext->status = EXT_ADJ_SID;
+               else if (IS_SUBTLV(ext, EXT_LAN_ADJ_SID))
+                       ext->status = EXT_LAN_ADJ_SID;
                else
-                       SUBTLV_TYPE(mtc->pkt_loss) = 0;
+                       ext->status = 0;
+       }
 
-               if (IS_PARAM_SET(ifp->link_params, LP_RES_BW))
-                       set_circuitparams_res_bw(mtc, ifp->link_params->res_bw);
-               else
-                       SUBTLV_TYPE(mtc->res_bw) = 0;
+       return;
+}
 
-               if (IS_PARAM_SET(ifp->link_params, LP_AVA_BW))
-                       set_circuitparams_ava_bw(mtc, ifp->link_params->ava_bw);
-               else
-                       SUBTLV_TYPE(mtc->ava_bw) = 0;
+static int isis_link_update_adj_hook(struct isis_adjacency *adj)
+{
 
-               if (IS_PARAM_SET(ifp->link_params, LP_USE_BW))
-                       set_circuitparams_use_bw(mtc, ifp->link_params->use_bw);
-               else
-                       SUBTLV_TYPE(mtc->use_bw) = 0;
+       struct isis_circuit *circuit = adj->circuit;
 
-               /* INTER_AS */
-               if (IS_PARAM_SET(ifp->link_params, LP_RMT_AS))
-                       set_circuitparams_inter_as(mtc,
-                                                  ifp->link_params->rmt_ip,
-                                                  ifp->link_params->rmt_as);
-               else
-                       /* reset inter-as TE params */
-                       unset_circuitparams_inter_as(mtc);
+       /* Update MPLS TE Remote IP address parameter if possible */
+       if (!IS_MPLS_TE(circuit->area->mta) || !IS_EXT_TE(circuit->ext))
+               return 0;
 
-               /* Compute total length of SUB TLVs */
-               mtc->length = subtlvs_len(mtc);
+       /* IPv4 first */
+       if (adj->ipv4_address_count > 0) {
+               IPV4_ADDR_COPY(&circuit->ext->neigh_addr,
+                              &adj->ipv4_addresses[0]);
+               SET_SUBTLV(circuit->ext, EXT_NEIGH_ADDR);
+       }
 
-       } else
-               mtc->status = disable;
+       /* and IPv6 */
+       if (adj->ipv6_address_count > 0) {
+               IPV6_ADDR_COPY(&circuit->ext->neigh_addr6,
+                              &adj->ipv6_addresses[0]);
+               SET_SUBTLV(circuit->ext, EXT_NEIGH_ADDR6);
+       }
 
-/* Finally Update LSP */
-#if 0
-  if (circuit->area && IS_MPLS_TE(circuit->area->mta))
-       lsp_regenerate_schedule (circuit->area, circuit->is_type, 0);
-#endif
-       return;
+       return 0;
 }
 
-void isis_mpls_te_update(struct interface *ifp)
+int isis_mpls_te_update(struct interface *ifp)
 {
        struct isis_circuit *circuit;
+       uint8_t rc = 1;
 
        /* Sanity Check */
        if (ifp == NULL)
-               return;
+               return rc;
 
        /* Get circuit context from interface */
-       if ((circuit = circuit_scan_by_ifp(ifp)) == NULL)
-               return;
+       circuit = circuit_scan_by_ifp(ifp);
+       if (circuit == NULL)
+               return rc;
 
        /* Update TE TLVs ... */
        isis_link_params_update(circuit, ifp);
@@ -645,418 +298,11 @@ void isis_mpls_te_update(struct interface *ifp)
        if (circuit->area && IS_MPLS_TE(circuit->area->mta))
                lsp_regenerate_schedule(circuit->area, circuit->is_type, 0);
 
-       return;
-}
-
-/*------------------------------------------------------------------------*
- * Followings are vty session control functions.
- *------------------------------------------------------------------------*/
-
-static uint8_t print_subtlv_admin_grp(struct sbuf *buf, int indent,
-                                     struct te_subtlv_admin_grp *tlv)
-{
-       sbuf_push(buf, indent, "Administrative Group: 0x%" PRIx32 "\n",
-                 ntohl(tlv->value));
-       return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE);
-}
-
-static uint8_t print_subtlv_llri(struct sbuf *buf, int indent,
-                                struct te_subtlv_llri *tlv)
-{
-       sbuf_push(buf, indent, "Link Local  ID: %" PRIu32 "\n",
-                 ntohl(tlv->local));
-       sbuf_push(buf, indent, "Link Remote ID: %" PRIu32 "\n",
-                 ntohl(tlv->remote));
-
-       return (SUBTLV_HDR_SIZE + TE_SUBTLV_LLRI_SIZE);
-}
-
-static uint8_t print_subtlv_local_ipaddr(struct sbuf *buf, int indent,
-                                        struct te_subtlv_local_ipaddr *tlv)
-{
-       sbuf_push(buf, indent, "Local Interface IP Address(es): %s\n",
-                 inet_ntoa(tlv->value));
-
-       return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE);
-}
-
-static uint8_t print_subtlv_rmt_ipaddr(struct sbuf *buf, int indent,
-                                      struct te_subtlv_rmt_ipaddr *tlv)
-{
-       sbuf_push(buf, indent, "Remote Interface IP Address(es): %s\n",
-                 inet_ntoa(tlv->value));
-
-       return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE);
-}
-
-static uint8_t print_subtlv_max_bw(struct sbuf *buf, int indent,
-                                  struct te_subtlv_max_bw *tlv)
-{
-       float fval;
-
-       fval = ntohf(tlv->value);
-
-       sbuf_push(buf, indent, "Maximum Bandwidth: %g (Bytes/sec)\n", fval);
-
-       return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE);
-}
-
-static uint8_t print_subtlv_max_rsv_bw(struct sbuf *buf, int indent,
-                                      struct te_subtlv_max_rsv_bw *tlv)
-{
-       float fval;
-
-       fval = ntohf(tlv->value);
-
-       sbuf_push(buf, indent, "Maximum Reservable Bandwidth: %g (Bytes/sec)\n",
-                 fval);
-
-       return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE);
-}
-
-static uint8_t print_subtlv_unrsv_bw(struct sbuf *buf, int indent,
-                                    struct te_subtlv_unrsv_bw *tlv)
-{
-       float fval1, fval2;
-       int i;
-
-       sbuf_push(buf, indent, "Unreserved Bandwidth:\n");
-
-       for (i = 0; i < MAX_CLASS_TYPE; i += 2) {
-               fval1 = ntohf(tlv->value[i]);
-               fval2 = ntohf(tlv->value[i + 1]);
-               sbuf_push(buf, indent + 2,
-                         "[%d]: %g (Bytes/sec),\t[%d]: %g (Bytes/sec)\n", i,
-                         fval1, i + 1, fval2);
-       }
-
-       return (SUBTLV_HDR_SIZE + TE_SUBTLV_UNRSV_SIZE);
-}
-
-static uint8_t print_subtlv_te_metric(struct sbuf *buf, int indent,
-                                     struct te_subtlv_te_metric *tlv)
-{
-       uint32_t te_metric;
-
-       te_metric = tlv->value[2] | tlv->value[1] << 8 | tlv->value[0] << 16;
-       sbuf_push(buf, indent, "Traffic Engineering Metric: %u\n", te_metric);
-
-       return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE);
-}
-
-static uint8_t print_subtlv_ras(struct sbuf *buf, int indent,
-                               struct te_subtlv_ras *tlv)
-{
-       sbuf_push(buf, indent, "Inter-AS TE Remote AS number: %" PRIu32 "\n",
-                 ntohl(tlv->value));
-
-       return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE);
-}
-
-static uint8_t print_subtlv_rip(struct sbuf *buf, int indent,
-                               struct te_subtlv_rip *tlv)
-{
-       sbuf_push(buf, indent, "Inter-AS TE Remote ASBR IP address: %s\n",
-                 inet_ntoa(tlv->value));
-
-       return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE);
+       rc = 0;
+       return rc;
 }
 
-static uint8_t print_subtlv_av_delay(struct sbuf *buf, int indent,
-                                    struct te_subtlv_av_delay *tlv)
-{
-       uint32_t delay;
-       uint32_t A;
-
-       delay = (uint32_t)ntohl(tlv->value) & TE_EXT_MASK;
-       A = (uint32_t)ntohl(tlv->value) & TE_EXT_ANORMAL;
-
-       sbuf_push(buf, indent,
-                 "%s Average Link Delay: %" PRIu32 " (micro-sec)\n",
-                 A ? "Anomalous" : "Normal", delay);
-
-       return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE);
-}
-
-static uint8_t print_subtlv_mm_delay(struct sbuf *buf, int indent,
-                                    struct te_subtlv_mm_delay *tlv)
-{
-       uint32_t low, high;
-       uint32_t A;
-
-       low = (uint32_t)ntohl(tlv->low) & TE_EXT_MASK;
-       A = (uint32_t)ntohl(tlv->low) & TE_EXT_ANORMAL;
-       high = (uint32_t)ntohl(tlv->high) & TE_EXT_MASK;
-
-       sbuf_push(buf, indent, "%s Min/Max Link Delay: %" PRIu32 " / %" PRIu32 " (micro-sec)\n",
-                 A ? "Anomalous" : "Normal", low, high);
-
-       return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE);
-}
-
-static uint8_t print_subtlv_delay_var(struct sbuf *buf, int indent,
-                                     struct te_subtlv_delay_var *tlv)
-{
-       uint32_t jitter;
-
-       jitter = (uint32_t)ntohl(tlv->value) & TE_EXT_MASK;
-
-       sbuf_push(buf, indent, "Delay Variation: %" PRIu32 " (micro-sec)\n",
-                 jitter);
-
-       return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE);
-}
-
-static uint8_t print_subtlv_pkt_loss(struct sbuf *buf, int indent,
-                                    struct te_subtlv_pkt_loss *tlv)
-{
-       uint32_t loss;
-       uint32_t A;
-       float fval;
-
-       loss = (uint32_t)ntohl(tlv->value) & TE_EXT_MASK;
-       fval = (float)(loss * LOSS_PRECISION);
-       A = (uint32_t)ntohl(tlv->value) & TE_EXT_ANORMAL;
-
-       sbuf_push(buf, indent, "%s Link Packet Loss: %g (%%)\n",
-                 A ? "Anomalous" : "Normal", fval);
-
-       return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE);
-}
-
-static uint8_t print_subtlv_res_bw(struct sbuf *buf, int indent,
-                                  struct te_subtlv_res_bw *tlv)
-{
-       float fval;
-
-       fval = ntohf(tlv->value);
-
-       sbuf_push(buf, indent,
-                 "Unidirectional Residual Bandwidth: %g (Bytes/sec)\n", fval);
-
-       return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE);
-}
-
-static uint8_t print_subtlv_ava_bw(struct sbuf *buf, int indent,
-                                  struct te_subtlv_ava_bw *tlv)
-{
-       float fval;
-
-       fval = ntohf(tlv->value);
-
-       sbuf_push(buf, indent,
-                 "Unidirectional Available Bandwidth: %g (Bytes/sec)\n", fval);
-
-       return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE);
-}
-
-static uint8_t print_subtlv_use_bw(struct sbuf *buf, int indent,
-                                  struct te_subtlv_use_bw *tlv)
-{
-       float fval;
-
-       fval = ntohf(tlv->value);
-
-       sbuf_push(buf, indent,
-                 "Unidirectional Utilized Bandwidth: %g (Bytes/sec)\n", fval);
-
-       return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE);
-}
-
-static uint8_t print_unknown_tlv(struct sbuf *buf, int indent,
-                                struct subtlv_header *tlvh)
-{
-       int i, rtn;
-       uint8_t *v = (uint8_t *)tlvh;
-
-       if (tlvh->length != 0) {
-               sbuf_push(buf, indent,
-                         "Unknown TLV: [type(%#.2x), length(%#.2x)]\n",
-                         tlvh->type, tlvh->length);
-               sbuf_push(buf, indent + 2, "Dump: [00]");
-               rtn = 1; /* initialize end of line counter */
-               for (i = 0; i < tlvh->length; i++) {
-                       sbuf_push(buf, 0, " %#.2x", v[i]);
-                       if (rtn == 8) {
-                               sbuf_push(buf, 0, "\n");
-                               sbuf_push(buf, indent + 8, "[%.2x]", i + 1);
-                               rtn = 1;
-                       } else
-                               rtn++;
-               }
-               sbuf_push(buf, 0, "\n");
-       } else {
-               sbuf_push(buf, indent,
-                         "Unknown TLV: [type(%#.2x), length(%#.2x)]\n",
-                         tlvh->type, tlvh->length);
-       }
-
-       return SUBTLV_SIZE(tlvh);
-}
-
-/* Main Show function */
-void mpls_te_print_detail(struct sbuf *buf, int indent,
-                         uint8_t *subtlvs, uint8_t subtlv_len)
-{
-       struct subtlv_header *tlvh = (struct subtlv_header *)subtlvs;
-       uint16_t sum = 0;
-
-       for (; sum < subtlv_len;
-            tlvh = (struct subtlv_header *)(subtlvs + sum)) {
-               if (subtlv_len - sum < SUBTLV_SIZE(tlvh)) {
-                       sbuf_push(buf, indent, "Available data %" PRIu8 " is less than TLV size %u!\n",
-                                 subtlv_len - sum, SUBTLV_SIZE(tlvh));
-                       return;
-               }
-
-               switch (tlvh->type) {
-               case TE_SUBTLV_ADMIN_GRP:
-                       if (tlvh->length != SUBTLV_DEF_SIZE) {
-                               sbuf_push(buf, indent, "TLV size does not match expected size for Administrative Group!\n");
-                               return;
-                       }
-                       sum += print_subtlv_admin_grp(buf, indent,
-                               (struct te_subtlv_admin_grp *)tlvh);
-                       break;
-               case TE_SUBTLV_LLRI:
-                       if (tlvh->length != TE_SUBTLV_LLRI_SIZE) {
-                               sbuf_push(buf, indent, "TLV size does not match expected size for Link ID!\n");
-                               return;
-                       }
-                       sum += print_subtlv_llri(buf, indent,
-                                                (struct te_subtlv_llri *)tlvh);
-                       break;
-               case TE_SUBTLV_LOCAL_IPADDR:
-                       if (tlvh->length != SUBTLV_DEF_SIZE) {
-                               sbuf_push(buf, indent, "TLV size does not match expected size for Local IP address!\n");
-                               return;
-                       }
-                       sum += print_subtlv_local_ipaddr(buf, indent,
-                               (struct te_subtlv_local_ipaddr *)tlvh);
-                       break;
-               case TE_SUBTLV_RMT_IPADDR:
-                       if (tlvh->length != SUBTLV_DEF_SIZE) {
-                               sbuf_push(buf, indent, "TLV size does not match expected size for Remote Interface address!\n");
-                               return;
-                       }
-                       sum += print_subtlv_rmt_ipaddr(buf, indent,
-                               (struct te_subtlv_rmt_ipaddr *)tlvh);
-                       break;
-               case TE_SUBTLV_MAX_BW:
-                       if (tlvh->length != SUBTLV_DEF_SIZE) {
-                               sbuf_push(buf, indent, "TLV size does not match expected size for Maximum Bandwidth!\n");
-                               return;
-                       }
-                       sum += print_subtlv_max_bw(buf, indent,
-                               (struct te_subtlv_max_bw *)tlvh);
-                       break;
-               case TE_SUBTLV_MAX_RSV_BW:
-                       if (tlvh->length != SUBTLV_DEF_SIZE) {
-                               sbuf_push(buf, indent, "TLV size does not match expected size for Maximum Reservable Bandwidth!\n");
-                               return;
-                       }
-                       sum += print_subtlv_max_rsv_bw(buf, indent,
-                               (struct te_subtlv_max_rsv_bw *)tlvh);
-                       break;
-               case TE_SUBTLV_UNRSV_BW:
-                       if (tlvh->length != TE_SUBTLV_UNRSV_SIZE) {
-                               sbuf_push(buf, indent, "TLV size does not match expected size for Unreserved Bandwidth!\n");
-                               return;
-                       }
-                       sum += print_subtlv_unrsv_bw(buf, indent,
-                               (struct te_subtlv_unrsv_bw *)tlvh);
-                       break;
-               case TE_SUBTLV_TE_METRIC:
-                       if (tlvh->length != SUBTLV_DEF_SIZE) {
-                               sbuf_push(buf, indent, "TLV size does not match expected size for Traffic Engineering Metric!\n");
-                               return;
-                       }
-                       sum += print_subtlv_te_metric(buf, indent,
-                               (struct te_subtlv_te_metric *)tlvh);
-                       break;
-               case TE_SUBTLV_RAS:
-                       if (tlvh->length != SUBTLV_DEF_SIZE) {
-                               sbuf_push(buf, indent, "TLV size does not match expected size for Remote AS number!\n");
-                               return;
-                       }
-                       sum += print_subtlv_ras(buf, indent,
-                                               (struct te_subtlv_ras *)tlvh);
-                       break;
-               case TE_SUBTLV_RIP:
-                       if (tlvh->length != SUBTLV_DEF_SIZE) {
-                               sbuf_push(buf, indent, "TLV size does not match expected size for Remote ASBR IP Address!\n");
-                               return;
-                       }
-                       sum += print_subtlv_rip(buf, indent,
-                                               (struct te_subtlv_rip *)tlvh);
-                       break;
-               case TE_SUBTLV_AV_DELAY:
-                       if (tlvh->length != SUBTLV_DEF_SIZE) {
-                               sbuf_push(buf, indent, "TLV size does not match expected size for Average Link Delay!\n");
-                               return;
-                       }
-                       sum += print_subtlv_av_delay(buf, indent,
-                               (struct te_subtlv_av_delay *)tlvh);
-                       break;
-               case TE_SUBTLV_MM_DELAY:
-                       if (tlvh->length != SUBTLV_DEF_SIZE) {
-                               sbuf_push(buf, indent, "TLV size does not match expected size for Min/Max Link Delay!\n");
-                               return;
-                       }
-                       sum += print_subtlv_mm_delay(buf, indent,
-                               (struct te_subtlv_mm_delay *)tlvh);
-                       break;
-               case TE_SUBTLV_DELAY_VAR:
-                       if (tlvh->length != SUBTLV_DEF_SIZE) {
-                               sbuf_push(buf, indent, "TLV size does not match expected size for Delay Variation!\n");
-                               return;
-                       }
-                       sum += print_subtlv_delay_var(buf, indent,
-                               (struct te_subtlv_delay_var *)tlvh);
-                       break;
-               case TE_SUBTLV_PKT_LOSS:
-                       if (tlvh->length != SUBTLV_DEF_SIZE) {
-                               sbuf_push(buf, indent, "TLV size does not match expected size for Link Packet Loss!\n");
-                               return;
-                       }
-                       sum += print_subtlv_pkt_loss(buf, indent,
-                               (struct te_subtlv_pkt_loss *)tlvh);
-                       break;
-               case TE_SUBTLV_RES_BW:
-                       if (tlvh->length != SUBTLV_DEF_SIZE) {
-                               sbuf_push(buf, indent, "TLV size does not match expected size for Unidirectional Residual Bandwidth!\n");
-                               return;
-                       }
-                       sum += print_subtlv_res_bw(buf, indent,
-                               (struct te_subtlv_res_bw *)tlvh);
-                       break;
-               case TE_SUBTLV_AVA_BW:
-                       if (tlvh->length != SUBTLV_DEF_SIZE) {
-                               sbuf_push(buf, indent, "TLV size does not match expected size for Unidirectional Available Bandwidth!\n");
-                               return;
-                       }
-                       sum += print_subtlv_ava_bw(buf, indent,
-                               (struct te_subtlv_ava_bw *)tlvh);
-                       break;
-               case TE_SUBTLV_USE_BW:
-                       if (tlvh->length != SUBTLV_DEF_SIZE) {
-                               sbuf_push(buf, indent, "TLV size does not match expected size for Unidirectional Utilized Bandwidth!\n");
-                               return;
-                       }
-                       sum += print_subtlv_use_bw(buf, indent,
-                               (struct te_subtlv_use_bw *)tlvh);
-                       break;
-               default:
-                       sum += print_unknown_tlv(buf, indent, tlvh);
-                       break;
-               }
-       }
-       return;
-}
-
-/*------------------------------------------------------------------------*
- * Followings are vty command functions.
- *------------------------------------------------------------------------*/
+/* Followings are vty command functions */
 #ifndef FABRICD
 
 DEFUN (show_isis_mpls_te_router,
@@ -1092,45 +338,104 @@ DEFUN (show_isis_mpls_te_router,
        return CMD_SUCCESS;
 }
 
-static void show_mpls_te_sub(struct vty *vty, char *name,
-                            struct mpls_te_circuit *mtc)
+static void show_ext_sub(struct vty *vty, char *name,
+                        struct isis_ext_subtlvs *ext)
 {
        struct sbuf buf;
+       char ibuf[PREFIX2STR_BUFFER];
 
        sbuf_init(&buf, NULL, 0);
 
-       if (mtc->status != enable)
+       if (!ext || ext->status == EXT_DISABLE)
                return;
 
        vty_out(vty, "-- MPLS-TE link parameters for %s --\n", name);
 
        sbuf_reset(&buf);
-       print_subtlv_admin_grp(&buf, 4, &mtc->admin_grp);
-
-       if (SUBTLV_TYPE(mtc->local_ipaddr) != 0)
-               print_subtlv_local_ipaddr(&buf, 4, &mtc->local_ipaddr);
-       if (SUBTLV_TYPE(mtc->rmt_ipaddr) != 0)
-               print_subtlv_rmt_ipaddr(&buf, 4, &mtc->rmt_ipaddr);
-
-       print_subtlv_max_bw(&buf, 4, &mtc->max_bw);
-       print_subtlv_max_rsv_bw(&buf, 4, &mtc->max_rsv_bw);
-       print_subtlv_unrsv_bw(&buf, 4, &mtc->unrsv_bw);
-       print_subtlv_te_metric(&buf, 4, &mtc->te_metric);
-
-       if (IS_INTER_AS(mtc->type)) {
-               if (SUBTLV_TYPE(mtc->ras) != 0)
-                       print_subtlv_ras(&buf, 4, &mtc->ras);
-               if (SUBTLV_TYPE(mtc->rip) != 0)
-                       print_subtlv_rip(&buf, 4, &mtc->rip);
-       }
 
-       print_subtlv_av_delay(&buf, 4, &mtc->av_delay);
-       print_subtlv_mm_delay(&buf, 4, &mtc->mm_delay);
-       print_subtlv_delay_var(&buf, 4, &mtc->delay_var);
-       print_subtlv_pkt_loss(&buf, 4, &mtc->pkt_loss);
-       print_subtlv_res_bw(&buf, 4, &mtc->res_bw);
-       print_subtlv_ava_bw(&buf, 4, &mtc->ava_bw);
-       print_subtlv_use_bw(&buf, 4, &mtc->use_bw);
+       if (IS_SUBTLV(ext, EXT_ADM_GRP))
+               sbuf_push(&buf, 4, "Administrative Group: 0x%" PRIx32 "\n",
+                       ext->adm_group);
+       if (IS_SUBTLV(ext, EXT_LLRI)) {
+               sbuf_push(&buf, 4, "Link Local  ID: %" PRIu32 "\n",
+                         ext->local_llri);
+               sbuf_push(&buf, 4, "Link Remote ID: %" PRIu32 "\n",
+                         ext->remote_llri);
+       }
+       if (IS_SUBTLV(ext, EXT_LOCAL_ADDR))
+               sbuf_push(&buf, 4, "Local Interface IP Address(es): %s\n",
+                         inet_ntoa(ext->local_addr));
+       if (IS_SUBTLV(ext, EXT_NEIGH_ADDR))
+               sbuf_push(&buf, 4, "Remote Interface IP Address(es): %s\n",
+                         inet_ntoa(ext->neigh_addr));
+       if (IS_SUBTLV(ext, EXT_LOCAL_ADDR6))
+               sbuf_push(&buf, 4, "Local Interface IPv6 Address(es): %s\n",
+                         inet_ntop(AF_INET6, &ext->local_addr6, ibuf,
+                                   PREFIX2STR_BUFFER));
+       if (IS_SUBTLV(ext, EXT_NEIGH_ADDR6))
+               sbuf_push(&buf, 4, "Remote Interface IPv6 Address(es): %s\n",
+                         inet_ntop(AF_INET6, &ext->local_addr6, ibuf,
+                                   PREFIX2STR_BUFFER));
+       if (IS_SUBTLV(ext, EXT_MAX_BW))
+               sbuf_push(&buf, 4, "Maximum Bandwidth: %g (Bytes/sec)\n",
+                         ext->max_bw);
+       if (IS_SUBTLV(ext, EXT_MAX_RSV_BW))
+               sbuf_push(&buf, 4,
+                         "Maximum Reservable Bandwidth: %g (Bytes/sec)\n",
+                         ext->max_rsv_bw);
+       if (IS_SUBTLV(ext, EXT_UNRSV_BW)) {
+               sbuf_push(&buf, 4, "Unreserved Bandwidth:\n");
+               for (int j = 0; j < MAX_CLASS_TYPE; j += 2) {
+                       sbuf_push(&buf, 4 + 2,
+                                 "[%d]: %g (Bytes/sec),\t[%d]: %g (Bytes/sec)\n",
+                                 j, ext->unrsv_bw[j],
+                                 j + 1, ext->unrsv_bw[j + 1]);
+               }
+       }
+       if (IS_SUBTLV(ext, EXT_TE_METRIC))
+               sbuf_push(&buf, 4, "Traffic Engineering Metric: %u\n",
+                         ext->te_metric);
+       if (IS_SUBTLV(ext, EXT_RMT_AS))
+               sbuf_push(&buf, 4,
+                         "Inter-AS TE Remote AS number: %" PRIu32 "\n",
+                         ext->remote_as);
+       if (IS_SUBTLV(ext, EXT_RMT_IP))
+               sbuf_push(&buf, 4,
+                         "Inter-AS TE Remote ASBR IP address: %s\n",
+                         inet_ntoa(ext->remote_ip));
+       if (IS_SUBTLV(ext, EXT_DELAY))
+               sbuf_push(&buf, 4,
+                         "%s Average Link Delay: %" PRIu32 " (micro-sec)\n",
+                         IS_ANORMAL(ext->delay) ? "Anomalous" : "Normal",
+                         ext->delay);
+       if (IS_SUBTLV(ext, EXT_MM_DELAY)) {
+               sbuf_push(&buf, 4, "%s Min/Max Link Delay: %" PRIu32 " / %"
+                         PRIu32 " (micro-sec)\n",
+                         IS_ANORMAL(ext->min_delay) ? "Anomalous" : "Normal",
+                         ext->min_delay & TE_EXT_MASK,
+                         ext->max_delay & TE_EXT_MASK);
+       }
+       if (IS_SUBTLV(ext, EXT_DELAY_VAR))
+               sbuf_push(&buf, 4,
+                         "Delay Variation: %" PRIu32 " (micro-sec)\n",
+                         ext->delay_var & TE_EXT_MASK);
+       if (IS_SUBTLV(ext, EXT_PKT_LOSS))
+               sbuf_push(&buf, 4, "%s Link Packet Loss: %g (%%)\n",
+                         IS_ANORMAL(ext->pkt_loss) ? "Anomalous" : "Normal",
+                         (float)((ext->pkt_loss & TE_EXT_MASK)
+                                 * LOSS_PRECISION));
+       if (IS_SUBTLV(ext, EXT_RES_BW))
+               sbuf_push(&buf, 4,
+                         "Unidirectional Residual Bandwidth: %g (Bytes/sec)\n",
+                         ext->res_bw);
+       if (IS_SUBTLV(ext, EXT_AVA_BW))
+               sbuf_push(&buf, 4,
+                         "Unidirectional Available Bandwidth: %g (Bytes/sec)\n",
+                         ext->ava_bw);
+       if (IS_SUBTLV(ext, EXT_USE_BW))
+               sbuf_push(&buf, 4,
+                         "Unidirectional Utilized Bandwidth: %g (Bytes/sec)\n",
+                         ext->use_bw);
 
        vty_multiline(vty, "", "%s", sbuf_buf(&buf));
        vty_out(vty, "---------------\n\n");
@@ -1170,8 +475,8 @@ DEFUN (show_isis_mpls_te_interface,
 
                        for (ALL_LIST_ELEMENTS_RO(area->circuit_list, cnode,
                                                  circuit))
-                               show_mpls_te_sub(vty, circuit->interface->name,
-                                                circuit->mtc);
+                               show_ext_sub(vty, circuit->interface->name,
+                                            circuit->ext);
                }
        } else {
                /* Interface name is specified. */
@@ -1185,7 +490,7 @@ DEFUN (show_isis_mpls_te_interface,
                                        "ISIS is not enabled on circuit %s\n",
                                        ifp->name);
                        else
-                               show_mpls_te_sub(vty, ifp->name, circuit->mtc);
+                               show_ext_sub(vty, ifp->name, circuit->ext);
                }
        }
 
@@ -1197,6 +502,11 @@ DEFUN (show_isis_mpls_te_interface,
 void isis_mpls_te_init(void)
 {
 
+       /* Register Circuit and Adjacency hook */
+       hook_register(isis_if_new_hook, isis_mpls_te_update);
+       hook_register(isis_adj_state_change_hook, isis_link_update_adj_hook);
+
+
 #ifndef FABRICD
        /* Register new VTY commands */
        install_element(VIEW_NODE, &show_isis_mpls_te_router_cmd);
index beb0c1836ff9b58c74529b9204514bed853207d4..2a6911d5006beaad1337376ba6b7ffe900bd362d 100644 (file)
@@ -3,8 +3,9 @@
  *
  * This is an implementation of RFC5305, RFC 5307 and RFC 7810
  *
- *      Copyright (C) 2014 Orange Labs
- *      http://www.orange.com
+ * Author: Olivier Dugeon <olivier.dugeon@orange.com>
+ *
+ * Copyright (C) 2014 - 2019 Orange Labs http://www.orange.com
  *
  * This file is part of GNU Zebra.
  *
  * Remote AS number                  24   RFC5316
  * IPv4 Remote ASBR identifier       25   RFC5316
  *
+ * NOTE: RFC5316 is not fully supported in this version
+ * only subTLVs decoding is provided
  */
 
-/* NOTE: RFC5316 is not yet supported in this version */
-
 /* Following define the type of TE link regarding the various RFC */
 #define STD_TE                 0x01
 #define GMPLS                  0x02
 #define IS_INTER_AS_AS(x)      (x & INTER_AS & FLOOD_AS)
 
 /*
- * Following section defines subTLV (tag, length, value) structures,
- * used for Traffic Engineering.
+ * Note (since release 7.2), subTLVs definition, serialization
+ * and de-serialization have mode to isis_tlvs.[c,h]
  */
-struct subtlv_header {
-       uint8_t type;   /* sub_TLV_XXX type (see above) */
-       uint8_t length; /* Value portion only, in byte */
-};
-
-#define MAX_SUBTLV_SIZE 256
-
-#define SUBTLV_HDR_SIZE        2  /* (sizeof (struct sub_tlv_header)) */
-
-#define SUBTLV_SIZE(stlvh)     (SUBTLV_HDR_SIZE + (stlvh)->length)
-
-#define SUBTLV_HDR_TOP(lsph)   (struct subtlv_header *)((char *)(lsph) + ISIS_LSP_HEADER_SIZE)
-
-#define SUBTLV_HDR_NEXT(stlvh)         (struct subtlv_header *)((char *)(stlvh) + SUBTLV_SIZE(stlvh))
-
-#define SUBTLV_TYPE(stlvh)     stlvh.header.type
-#define SUBTLV_LEN(stlvh)      stlvh.header.length
-#define SUBTLV_VAL(stlvh)      stlvh.value
-#define SUBTLV_DATA(stlvh)     stlvh + SUBTLV_HDR_SIZE
-
-#define SUBTLV_DEF_SIZE                4
-
-/* Link Sub-TLV: Resource Class/Color - RFC 5305 */
-#define TE_SUBTLV_ADMIN_GRP    3
-struct te_subtlv_admin_grp {
-       struct subtlv_header header; /* Value length is 4 octets. */
-       uint32_t value;              /* Admin. group membership. */
-} __attribute__((__packed__));
-
-/* Link Local/Remote Identifiers - RFC 5307 */
-#define TE_SUBTLV_LLRI         4
-#define TE_SUBTLV_LLRI_SIZE    8
-struct te_subtlv_llri {
-       struct subtlv_header header; /* Value length is 8 octets. */
-       uint32_t local;              /* Link Local Identifier */
-       uint32_t remote;             /* Link Remote Identifier */
-} __attribute__((__packed__));
-
-/* Link Sub-TLV: Local Interface IP Address - RFC 5305 */
-#define TE_SUBTLV_LOCAL_IPADDR 6
-struct te_subtlv_local_ipaddr {
-       struct subtlv_header header; /* Value length is 4 x N octets. */
-       struct in_addr value;   /* Local IP address(es). */
-} __attribute__((__packed__));
-
-/* Link Sub-TLV: Neighbor Interface IP Address - RFC 5305 */
-#define TE_SUBTLV_RMT_IPADDR   8
-struct te_subtlv_rmt_ipaddr {
-       struct subtlv_header header; /* Value length is 4 x N octets. */
-       struct in_addr value;   /* Neighbor's IP address(es). */
-} __attribute__((__packed__));
-
-/* Link Sub-TLV: Maximum Bandwidth - RFC 5305 */
-#define TE_SUBTLV_MAX_BW       9
-struct te_subtlv_max_bw {
-       struct subtlv_header header; /* Value length is 4 octets. */
-       float value;                 /* bytes/sec */
-} __attribute__((__packed__));
-
-/* Link Sub-TLV: Maximum Reservable Bandwidth - RFC 5305 */
-#define TE_SUBTLV_MAX_RSV_BW   10
-struct te_subtlv_max_rsv_bw {
-       struct subtlv_header header; /* Value length is 4 octets. */
-       float value;                 /* bytes/sec */
-} __attribute__((__packed__));
-
-/* Link Sub-TLV: Unreserved Bandwidth - RFC 5305 */
-#define TE_SUBTLV_UNRSV_BW     11
-#define TE_SUBTLV_UNRSV_SIZE   32
-struct te_subtlv_unrsv_bw {
-       struct subtlv_header header; /* Value length is 32 octets. */
-       float value[8];              /* One for each priority level. */
-} __attribute__((__packed__));
-
-/* Link Sub-TLV: Traffic Engineering Metric - RFC 5305 */
-#define TE_SUBTLV_TE_METRIC    18
-#define TE_SUBTLV_TE_METRIC_SIZE    3
-struct te_subtlv_te_metric {
-       struct subtlv_header header; /* Value length is 4 octets. */
-       uint8_t value[3];           /* Link metric for TE purpose. */
-} __attribute__((__packed__));
-
-/* Remote AS Number sub-TLV - RFC5316 */
-#define TE_SUBTLV_RAS          24
-struct te_subtlv_ras {
-       struct subtlv_header header; /* Value length is 4 octets. */
-       uint32_t value;              /* Remote AS number */
-} __attribute__((__packed__));
-
-/* IPv4 Remote ASBR ID Sub-TLV - RFC5316 */
-#define TE_SUBTLV_RIP          25
-struct te_subtlv_rip {
-       struct subtlv_header header; /* Value length is 4 octets. */
-       struct in_addr value;   /* Remote ASBR IP address */
-} __attribute__((__packed__));
-
-
-/* TE Metric Extensions - RFC 7810 */
-/* Link Sub-TLV: Average Link Delay */
-#define TE_SUBTLV_AV_DELAY     33
-struct te_subtlv_av_delay {
-       struct subtlv_header header; /* Value length is 4 bytes. */
-       uint32_t value; /* Average delay in micro-seconds only 24 bits => 0 ...
-                           16777215
-                           with Anomalous Bit (A) as Upper most bit */
-} __attribute__((__packed__));
-
-/* Link Sub-TLV: Low/High Link Delay */
-#define TE_SUBTLV_MM_DELAY      34
-#define TE_SUBTLV_MM_DELAY_SIZE    8
-struct te_subtlv_mm_delay {
-       struct subtlv_header header; /* Value length is 8 bytes. */
-       uint32_t low;  /* low delay in micro-seconds only 24 bits => 0 ...
-                          16777215
-                          with Anomalous Bit (A) as Upper most bit */
-       uint32_t high; /* high delay in micro-seconds only 24 bits => 0 ...
-                          16777215 */
-} __attribute__((__packed__));
-
-/* Link Sub-TLV: Link Delay Variation i.e. Jitter */
-#define TE_SUBTLV_DELAY_VAR     35
-struct te_subtlv_delay_var {
-       struct subtlv_header header; /* Value length is 4 bytes. */
-       uint32_t value; /* interval in micro-seconds only 24 bits => 0 ...
-                           16777215 */
-} __attribute__((__packed__));
-
-/* Link Sub-TLV: Routine Unidirectional Link Packet Loss */
-#define TE_SUBTLV_PKT_LOSS     36
-struct te_subtlv_pkt_loss {
-       struct subtlv_header header; /* Value length is 4 bytes. */
-       uint32_t
-               value; /* in percentage of total traffic only 24 bits (2^24 - 2)
-                         with Anomalous Bit (A) as Upper most bit */
-} __attribute__((__packed__));
-
-/* Link Sub-TLV: Unidirectional Residual Bandwidth */ /* Optional */
-#define TE_SUBTLV_RES_BW       37
-struct te_subtlv_res_bw {
-       struct subtlv_header header; /* Value length is 4 bytes. */
-       float value; /* bandwidth in IEEE floating point format with units in
-                       bytes per second */
-} __attribute__((__packed__));
-
-/* Link Sub-TLV: Unidirectional Available Bandwidth */ /* Optional */
-#define TE_SUBTLV_AVA_BW       38
-struct te_subtlv_ava_bw {
-       struct subtlv_header header; /* Value length is 4 octets. */
-       float value; /* bandwidth in IEEE floating point format with units in
-                       bytes per second */
-} __attribute__((__packed__));
-
-/* Link Sub-TLV: Unidirectional Utilized Bandwidth */ /* Optional */
-#define TE_SUBTLV_USE_BW        39
-struct te_subtlv_use_bw {
-       struct subtlv_header header; /* Value length is 4 octets. */
-       float value; /* bandwidth in IEEE floating point format with units in
-                       bytes per second */
-} __attribute__((__packed__));
-
-#define TE_SUBTLV_MAX          40      /* Last SUBTLV + 1 */
 
 /* Following declaration concerns the MPLS-TE and LINk-TE management */
 typedef enum _status_t { disable, enable, learn } status_t;
@@ -244,7 +84,10 @@ typedef enum _status_t { disable, enable, learn } status_t;
 /* Mode for Inter-AS LSP */ /* TODO: Check how if LSP is flooded in RFC5316 */
 typedef enum _interas_mode_t { off, region, as, emulate } interas_mode_t;
 
-#define IS_MPLS_TE(m)    (m && m->status == enable)
+#define IS_EXT_TE(e)    (e && e->status != 0                   \
+                          && e->status != EXT_ADJ_SID          \
+                          && e->status != EXT_LAN_ADJ_SID)
+#define IS_MPLS_TE(a)  (a && a->status == enable)
 
 /* Per area MPLS-TE parameters */
 struct mpls_te_area {
@@ -262,56 +105,9 @@ struct mpls_te_area {
        struct in_addr router_id;
 };
 
-/* Per Circuit MPLS-TE parameters */
-struct mpls_te_circuit {
-
-       /* Status of MPLS-TE on this interface */
-       status_t status;
-
-       /* Type of MPLS-TE circuit: STD_TE(RFC5305), INTER_AS(RFC5316),
-        * INTER_AS_EMU(RFC5316 emulated) */
-       uint8_t type;
-
-       /* Total size of sub_tlvs */
-       uint8_t length;
-
-       /* Store subTLV in network byte order. */
-       /* RFC5305 */
-       struct te_subtlv_admin_grp admin_grp;
-       /* RFC5307 */
-       struct te_subtlv_llri llri;
-       /* RFC5305 */
-       struct te_subtlv_local_ipaddr local_ipaddr;
-       struct te_subtlv_rmt_ipaddr rmt_ipaddr;
-       struct te_subtlv_max_bw max_bw;
-       struct te_subtlv_max_rsv_bw max_rsv_bw;
-       struct te_subtlv_unrsv_bw unrsv_bw;
-       struct te_subtlv_te_metric te_metric;
-       /* RFC5316 */
-       struct te_subtlv_ras ras;
-       struct te_subtlv_rip rip;
-       /* RFC7810 */
-       struct te_subtlv_av_delay av_delay;
-       struct te_subtlv_mm_delay mm_delay;
-       struct te_subtlv_delay_var delay_var;
-       struct te_subtlv_pkt_loss pkt_loss;
-       struct te_subtlv_res_bw res_bw;
-       struct te_subtlv_ava_bw ava_bw;
-       struct te_subtlv_use_bw use_bw;
-};
-
 /* Prototypes. */
 void isis_mpls_te_init(void);
-struct mpls_te_circuit *mpls_te_circuit_new(void);
-struct sbuf;
-void mpls_te_print_detail(struct sbuf *buf, int indent, uint8_t *subtlvs,
-                         uint8_t subtlv_len);
-void set_circuitparams_local_ipaddr(struct mpls_te_circuit *, struct in_addr);
-void set_circuitparams_rmt_ipaddr(struct mpls_te_circuit *, struct in_addr);
-uint8_t subtlvs_len(struct mpls_te_circuit *);
-uint8_t add_te_subtlvs(uint8_t *, struct mpls_te_circuit *);
-uint8_t build_te_subtlvs(uint8_t *, struct isis_circuit *);
 void isis_link_params_update(struct isis_circuit *, struct interface *);
-void isis_mpls_te_update(struct interface *);
+int isis_mpls_te_update(struct interface *);
 
 #endif /* _ZEBRA_ISIS_MPLS_TE_H */
index ee253c7a31ae4afb4aaff513146a2b6a414932d7..442442152cbeb31f20b4b1c97b5330aba0ac2a90 100644 (file)
@@ -3,6 +3,8 @@
  *
  * Copyright (C) 2015,2017 Christian Franke
  *
+ * Copyright (C) 2019 Olivier Dugeon - Orange Labs (for TE and SR)
+ *
  * This file is part of FRR.
  *
  * FRR is free software; you can redistribute it and/or modify it
@@ -28,6 +30,7 @@
 #include "memory.h"
 #include "stream.h"
 #include "sbuf.h"
+#include "network.h"
 
 #include "isisd/isisd.h"
 #include "isisd/isis_memory.h"
@@ -98,7 +101,8 @@ static struct pack_order_entry pack_order[] = {
        PACK_ENTRY(EXTENDED_IP_REACH, ISIS_ITEMS, extended_ip_reach),
        PACK_ENTRY(MT_IP_REACH, ISIS_MT_ITEMS, mt_ip_reach),
        PACK_ENTRY(IPV6_REACH, ISIS_ITEMS, ipv6_reach),
-       PACK_ENTRY(MT_IPV6_REACH, ISIS_MT_ITEMS, mt_ipv6_reach)};
+       PACK_ENTRY(MT_IPV6_REACH, ISIS_MT_ITEMS, mt_ipv6_reach)
+};
 
 /* This is a forward definition. The table is actually initialized
  * in at the bottom. */
@@ -108,9 +112,683 @@ static const struct tlv_ops *tlv_table[ISIS_CONTEXT_MAX][ISIS_TLV_MAX];
 
 /* Prototypes */
 static void append_item(struct isis_item_list *dest, struct isis_item *item);
+static void init_item_list(struct isis_item_list *items);
 
-/* Functions for Sub-TLV 3 SR Prefix-SID */
+/* Functions for Extended IS Reachability SubTLVs a.k.a Traffic Engineering */
+struct isis_ext_subtlvs *isis_alloc_ext_subtlvs(void)
+{
+       struct isis_ext_subtlvs *ext;
+
+       ext = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(struct isis_ext_subtlvs));
+       init_item_list(&ext->adj_sid);
+       init_item_list(&ext->lan_sid);
+
+       return ext;
+}
+
+/*
+ * mtid parameter is used to determine if Adjacency is related to IPv4 or IPv6.
+ * A negative value could be used to skip copy of Adjacency SID.
+ */
+static struct isis_ext_subtlvs *
+copy_item_ext_subtlvs(struct isis_ext_subtlvs *exts, int16_t mtid)
+{
+       struct isis_ext_subtlvs *rv = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(*rv));
+       struct isis_adj_sid *adj;
+       struct isis_lan_adj_sid *lan;
+
+       memcpy(rv, exts, sizeof(struct isis_ext_subtlvs));
+       init_item_list(&rv->adj_sid);
+       init_item_list(&rv->lan_sid);
+
+       UNSET_SUBTLV(rv, EXT_ADJ_SID);
+       UNSET_SUBTLV(rv, EXT_LAN_ADJ_SID);
+
+       /* Copy Adj SID and LAN Adj SID list for IPv4 if needed */
+       for (adj = (struct isis_adj_sid *)exts->adj_sid.head; adj != NULL;
+            adj = adj->next) {
+               if ((mtid != -1)
+                   && (((mtid == ISIS_MT_IPV4_UNICAST)
+                        && (adj->family != AF_INET))
+                       || ((mtid == ISIS_MT_IPV6_UNICAST)
+                           && (adj->family != AF_INET6))))
+                       continue;
+
+               struct isis_adj_sid *new;
+
+               new = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(struct isis_adj_sid));
+               new->family = adj->family;
+               new->flags = adj->flags;
+               new->weight = adj->weight;
+               new->sid = adj->sid;
+               append_item(&rv->adj_sid, (struct isis_item *)new);
+               SET_SUBTLV(rv, EXT_ADJ_SID);
+       }
+
+       for (lan = (struct isis_lan_adj_sid *)exts->lan_sid.head; lan != NULL;
+            lan = lan->next) {
+               if ((mtid != -1)
+                   && (((mtid == ISIS_MT_IPV4_UNICAST)
+                        && (lan->family != AF_INET))
+                       || ((mtid == ISIS_MT_IPV6_UNICAST)
+                           && (lan->family != AF_INET6))))
+                       continue;
+
+               struct isis_lan_adj_sid *new;
+
+               new = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(struct isis_lan_adj_sid));
+               new->family = lan->family;
+               new->flags = lan->flags;
+               new->weight = lan->weight;
+               memcpy(new->neighbor_id, lan->neighbor_id, 6);
+               new->sid = lan->sid;
+               append_item(&rv->lan_sid, (struct isis_item *)new);
+               SET_SUBTLV(rv, EXT_LAN_ADJ_SID);
+       }
+
+       return rv;
+}
+
+/* mtid parameter is used to manage multi-topology i.e. IPv4 / IPv6 */
+static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts,
+                                   struct sbuf *buf, int indent,
+                                   uint16_t mtid)
+{
+
+       char ibuf[PREFIX2STR_BUFFER];
+
+       /* Standard metrics */
+       if (IS_SUBTLV(exts, EXT_ADM_GRP))
+               sbuf_push(buf, indent, "Administrative Group: 0x%" PRIx32 "\n",
+                       exts->adm_group);
+       if (IS_SUBTLV(exts, EXT_LLRI)) {
+               sbuf_push(buf, indent, "Link Local  ID: %" PRIu32 "\n",
+                         exts->local_llri);
+               sbuf_push(buf, indent, "Link Remote ID: %" PRIu32 "\n",
+                         exts->remote_llri);
+       }
+       if (IS_SUBTLV(exts, EXT_LOCAL_ADDR))
+               sbuf_push(buf, indent, "Local Interface IP Address(es): %s\n",
+                         inet_ntoa(exts->local_addr));
+       if (IS_SUBTLV(exts, EXT_NEIGH_ADDR))
+               sbuf_push(buf, indent, "Remote Interface IP Address(es): %s\n",
+                         inet_ntoa(exts->neigh_addr));
+       if (IS_SUBTLV(exts, EXT_LOCAL_ADDR6))
+               sbuf_push(buf, indent, "Local Interface IPv6 Address(es): %s\n",
+                       inet_ntop(AF_INET6, &exts->local_addr6, ibuf,
+                                 PREFIX2STR_BUFFER));
+       if (IS_SUBTLV(exts, EXT_NEIGH_ADDR6))
+               sbuf_push(buf, indent, "Remote Interface IPv6 Address(es): %s\n",
+                       inet_ntop(AF_INET6, &exts->local_addr6, ibuf,
+                                 PREFIX2STR_BUFFER));
+       if (IS_SUBTLV(exts, EXT_MAX_BW))
+               sbuf_push(buf, indent, "Maximum Bandwidth: %g (Bytes/sec)\n",
+                         exts->max_bw);
+       if (IS_SUBTLV(exts, EXT_MAX_RSV_BW))
+               sbuf_push(buf, indent,
+                         "Maximum Reservable Bandwidth: %g (Bytes/sec)\n",
+                         exts->max_rsv_bw);
+       if (IS_SUBTLV(exts, EXT_UNRSV_BW)) {
+               sbuf_push(buf, indent, "Unreserved Bandwidth:\n");
+               for (int j = 0; j < MAX_CLASS_TYPE; j += 2) {
+                       sbuf_push(buf, indent + 2,
+                                 "[%d]: %g (Bytes/sec),\t[%d]: %g (Bytes/sec)\n",
+                                 j, exts->unrsv_bw[j],
+                                 j + 1, exts->unrsv_bw[j + 1]);
+               }
+       }
+       if (IS_SUBTLV(exts, EXT_TE_METRIC))
+               sbuf_push(buf, indent, "Traffic Engineering Metric: %u\n",
+                         exts->te_metric);
+       if (IS_SUBTLV(exts, EXT_RMT_AS))
+               sbuf_push(buf, indent,
+                         "Inter-AS TE Remote AS number: %" PRIu32 "\n",
+                         exts->remote_as);
+       if (IS_SUBTLV(exts, EXT_RMT_IP))
+               sbuf_push(buf, indent,
+                         "Inter-AS TE Remote ASBR IP address: %s\n",
+                         inet_ntoa(exts->remote_ip));
+       /* Extended metrics */
+       if (IS_SUBTLV(exts, EXT_DELAY))
+               sbuf_push(buf, indent,
+                         "%s Average Link Delay: %" PRIu32 " (micro-sec)\n",
+                         IS_ANORMAL(exts->delay) ? "Anomalous" : "Normal",
+                         exts->delay);
+       if (IS_SUBTLV(exts, EXT_MM_DELAY)) {
+               sbuf_push(buf, indent, "%s Min/Max Link Delay: %" PRIu32 " / %"
+                         PRIu32 " (micro-sec)\n",
+                         IS_ANORMAL(exts->min_delay) ? "Anomalous" : "Normal",
+                         exts->min_delay & TE_EXT_MASK,
+                         exts->max_delay & TE_EXT_MASK);
+       }
+       if (IS_SUBTLV(exts, EXT_DELAY_VAR)) {
+               sbuf_push(buf, indent,
+                         "Delay Variation: %" PRIu32 " (micro-sec)\n",
+                         exts->delay_var & TE_EXT_MASK);
+       }
+       if (IS_SUBTLV(exts, EXT_PKT_LOSS))
+               sbuf_push(buf, indent, "%s Link Packet Loss: %g (%%)\n",
+                         IS_ANORMAL(exts->pkt_loss) ? "Anomalous" : "Normal",
+                         (float)((exts->pkt_loss & TE_EXT_MASK)
+                                 * LOSS_PRECISION));
+       if (IS_SUBTLV(exts, EXT_RES_BW))
+               sbuf_push(buf, indent,
+                         "Unidir. Residual Bandwidth: %g (Bytes/sec)\n",
+                         exts->res_bw);
+       if (IS_SUBTLV(exts, EXT_AVA_BW))
+               sbuf_push(buf, indent,
+                         "Unidir. Available Bandwidth: %g (Bytes/sec)\n",
+                         exts->ava_bw);
+       if (IS_SUBTLV(exts, EXT_USE_BW))
+               sbuf_push(buf, indent,
+                         "Unidir. Utilized Bandwidth: %g (Bytes/sec)\n",
+                         exts->use_bw);
+       /* Segment Routing Adjacency */
+       if (IS_SUBTLV(exts, EXT_ADJ_SID)) {
+               struct isis_adj_sid *adj;
+
+               for (adj = (struct isis_adj_sid *)exts->adj_sid.head; adj;
+                    adj = adj->next) {
+                       if (((mtid == ISIS_MT_IPV4_UNICAST)
+                            && (adj->family != AF_INET))
+                           || ((mtid == ISIS_MT_IPV6_UNICAST)
+                               && (adj->family != AF_INET6)))
+                               continue;
+                       sbuf_push(
+                               buf, indent,
+                               "Adjacency-SID: %" PRIu32 ", Weight: %" PRIu8
+                               ", Flags: F:%c B:%c, V:%c, L:%c, S:%c, P:%c\n",
+                               adj->sid, adj->weight,
+                               adj->flags & EXT_SUBTLV_LINK_ADJ_SID_FFLG ? '1'
+                                                                         : '0',
+                               adj->flags & EXT_SUBTLV_LINK_ADJ_SID_BFLG ? '1'
+                                                                         : '0',
+                               adj->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG ? '1'
+                                                                         : '0',
+                               adj->flags & EXT_SUBTLV_LINK_ADJ_SID_LFLG ? '1'
+                                                                         : '0',
+                               adj->flags & EXT_SUBTLV_LINK_ADJ_SID_SFLG ? '1'
+                                                                         : '0',
+                               adj->flags & EXT_SUBTLV_LINK_ADJ_SID_PFLG
+                                       ? '1'
+                                       : '0');
+               }
+       }
+       if (IS_SUBTLV(exts, EXT_LAN_ADJ_SID)) {
+               struct isis_lan_adj_sid *lan;
+
+               for (lan = (struct isis_lan_adj_sid *)exts->lan_sid.head;
+                    lan; lan = lan->next) {
+                       if (((mtid == ISIS_MT_IPV4_UNICAST)
+                            && (lan->family != AF_INET))
+                           || ((mtid == ISIS_MT_IPV6_UNICAST)
+                               && (lan->family != AF_INET6)))
+                               continue;
+                       sbuf_push(buf, indent,
+                                 "Lan-Adjacency-SID: %" PRIu32
+                                 ", Weight: %" PRIu8
+                                 ", Flags: F:%c B:%c, V:%c, L:%c, S:%c, P:%c\n"
+                                 "  Neighbor-ID: %s\n",
+                                 lan->sid, lan->weight,
+                                 lan->flags & EXT_SUBTLV_LINK_ADJ_SID_FFLG
+                                         ? '1'
+                                         : '0',
+                                 lan->flags & EXT_SUBTLV_LINK_ADJ_SID_BFLG
+                                         ? '1'
+                                         : '0',
+                                 lan->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG
+                                         ? '1'
+                                         : '0',
+                                 lan->flags & EXT_SUBTLV_LINK_ADJ_SID_LFLG
+                                         ? '1'
+                                         : '0',
+                                 lan->flags & EXT_SUBTLV_LINK_ADJ_SID_SFLG
+                                         ? '1'
+                                         : '0',
+                                 lan->flags & EXT_SUBTLV_LINK_ADJ_SID_PFLG
+                                         ? '1'
+                                         : '0',
+                                 isis_format_id(lan->neighbor_id, 6));
+               }
+       }
+}
+
+static void free_item_ext_subtlvs(struct  isis_ext_subtlvs *exts)
+{
+       struct isis_item *item, *next_item;
+
+       /* First, free Adj SID and LAN Adj SID list if needed */
+       for (item = exts->adj_sid.head; item; item = next_item) {
+               next_item = item->next;
+               XFREE(MTYPE_ISIS_SUBTLV, item);
+       }
+       for (item = exts->lan_sid.head; item; item = next_item) {
+               next_item = item->next;
+               XFREE(MTYPE_ISIS_SUBTLV, item);
+       }
+       XFREE(MTYPE_ISIS_SUBTLV, exts);
+}
+
+static int pack_item_ext_subtlvs(struct isis_ext_subtlvs *exts,
+                                struct stream *s)
+{
+       uint8_t size;
+
+       if (STREAM_WRITEABLE(s) < ISIS_SUBTLV_MAX_SIZE)
+               return 1;
+
+       if (IS_SUBTLV(exts, EXT_ADM_GRP)) {
+               stream_putc(s, ISIS_SUBTLV_ADMIN_GRP);
+               stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
+               stream_putl(s, exts->adm_group);
+       }
+       if (IS_SUBTLV(exts, EXT_LLRI)) {
+               stream_putc(s, ISIS_SUBTLV_LLRI);
+               stream_putc(s, ISIS_SUBTLV_LLRI_SIZE);
+               stream_putl(s, exts->local_llri);
+               stream_putl(s, exts->remote_llri);
+       }
+       if (IS_SUBTLV(exts, EXT_LOCAL_ADDR)) {
+               stream_putc(s, ISIS_SUBTLV_LOCAL_IPADDR);
+               stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
+               stream_put(s, &exts->local_addr.s_addr, 4);
+       }
+       if (IS_SUBTLV(exts, EXT_NEIGH_ADDR)) {
+               stream_putc(s, ISIS_SUBTLV_RMT_IPADDR);
+               stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
+               stream_put(s, &exts->neigh_addr.s_addr, 4);
+       }
+       if (IS_SUBTLV(exts, EXT_LOCAL_ADDR6)) {
+               stream_putc(s, ISIS_SUBTLV_LOCAL_IPADDR6);
+               stream_putc(s, ISIS_SUBTLV_IPV6_ADDR_SIZE);
+               stream_put(s, &exts->local_addr6, 16);
+       }
+       if (IS_SUBTLV(exts, EXT_NEIGH_ADDR6)) {
+               stream_putc(s, ISIS_SUBTLV_RMT_IPADDR6);
+               stream_putc(s, ISIS_SUBTLV_IPV6_ADDR_SIZE);
+               stream_put(s, &exts->neigh_addr6, 16);
+       }
+       if (IS_SUBTLV(exts, EXT_MAX_BW)) {
+               stream_putc(s, ISIS_SUBTLV_MAX_BW);
+               stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
+               stream_putf(s, exts->max_bw);
+       }
+       if (IS_SUBTLV(exts, EXT_MAX_RSV_BW)) {
+               stream_putc(s, ISIS_SUBTLV_MAX_RSV_BW);
+               stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
+               stream_putf(s, exts->max_rsv_bw);
+       }
+       if (IS_SUBTLV(exts, EXT_UNRSV_BW)) {
+               stream_putc(s, ISIS_SUBTLV_UNRSV_BW);
+               stream_putc(s, ISIS_SUBTLV_UNRSV_BW_SIZE);
+               for (int j = 0; j < MAX_CLASS_TYPE; j++)
+                       stream_putf(s, exts->unrsv_bw[j]);
+       }
+       if (IS_SUBTLV(exts, EXT_TE_METRIC)) {
+               stream_putc(s, ISIS_SUBTLV_TE_METRIC);
+               stream_putc(s, ISIS_SUBTLV_TE_METRIC_SIZE);
+               stream_put3(s, exts->te_metric);
+       }
+       if (IS_SUBTLV(exts, EXT_RMT_AS)) {
+               stream_putc(s, ISIS_SUBTLV_RAS);
+               stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
+               stream_putl(s, exts->remote_as);
+       }
+       if (IS_SUBTLV(exts, EXT_RMT_IP)) {
+               stream_putc(s, ISIS_SUBTLV_RIP);
+               stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
+               stream_put(s, &exts->remote_ip.s_addr, 4);
+       }
+       if (IS_SUBTLV(exts, EXT_DELAY)) {
+               stream_putc(s, ISIS_SUBTLV_AV_DELAY);
+               stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
+               stream_putl(s, exts->delay);
+       }
+       if (IS_SUBTLV(exts, EXT_MM_DELAY)) {
+               stream_putc(s, ISIS_SUBTLV_MM_DELAY);
+               stream_putc(s, ISIS_SUBTLV_MM_DELAY_SIZE);
+               stream_putl(s, exts->min_delay);
+               stream_putl(s, exts->max_delay);
+       }
+       if (IS_SUBTLV(exts, EXT_DELAY_VAR)) {
+               stream_putc(s, ISIS_SUBTLV_DELAY_VAR);
+               stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
+               stream_putl(s, exts->delay_var);
+       }
+       if (IS_SUBTLV(exts, EXT_PKT_LOSS)) {
+               stream_putc(s, ISIS_SUBTLV_PKT_LOSS);
+               stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
+               stream_putl(s, exts->pkt_loss);
+       }
+       if (IS_SUBTLV(exts, EXT_RES_BW)) {
+               stream_putc(s, ISIS_SUBTLV_RES_BW);
+               stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
+               stream_putf(s, exts->res_bw);
+       }
+       if (IS_SUBTLV(exts, EXT_AVA_BW)) {
+               stream_putc(s, ISIS_SUBTLV_AVA_BW);
+               stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
+               stream_putf(s, exts->ava_bw);
+       }
+       if (IS_SUBTLV(exts, EXT_USE_BW)) {
+               stream_putc(s, ISIS_SUBTLV_USE_BW);
+               stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
+               stream_putf(s, exts->use_bw);
+       }
+       if (IS_SUBTLV(exts, EXT_ADJ_SID)) {
+               struct isis_adj_sid *adj;
+
+               for (adj = (struct isis_adj_sid *)exts->adj_sid.head; adj;
+                    adj = adj->next) {
+                       stream_putc(s, ISIS_SUBTLV_ADJ_SID);
+                       size = ISIS_SUBTLV_ADJ_SID_SIZE;
+                       if (!(adj->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG))
+                               size++;
+                       stream_putc(s, size);
+                       stream_putc(s, adj->flags);
+                       stream_putc(s, adj->weight);
+                       if (adj->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG)
+                               stream_put3(s, adj->sid);
+                       else
+                               stream_putl(s, adj->sid);
+
+               }
+       }
+       if (IS_SUBTLV(exts, EXT_LAN_ADJ_SID)) {
+               struct isis_lan_adj_sid *lan;
+
+               for (lan = (struct isis_lan_adj_sid *)exts->lan_sid.head; lan;
+                    lan = lan->next) {
+                       stream_putc(s, ISIS_SUBTLV_LAN_ADJ_SID);
+                       size = ISIS_SUBTLV_LAN_ADJ_SID_SIZE;
+                       if (!(lan->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG))
+                               size++;
+                       stream_putc(s, size);
+                       stream_putc(s, lan->flags);
+                       stream_putc(s, lan->weight);
+                       stream_put(s, lan->neighbor_id, 6);
+                       if (lan->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG)
+                               stream_put3(s, lan->sid);
+                       else
+                               stream_putl(s, lan->sid);
+               }
+       }
+
+       return 0;
+}
+
+static int unpack_item_ext_subtlvs(uint16_t mtid, uint8_t len, struct stream *s,
+                                  struct sbuf *log, void *dest, int indent)
+{
+       uint8_t sum = 0;
+       uint8_t subtlv_type;
+       uint8_t subtlv_len;
+
+       struct isis_extended_reach *rv = dest;
+       struct isis_ext_subtlvs *exts = isis_alloc_ext_subtlvs();
+
+       rv->subtlvs = exts;
+
+       /*
+        * Parse subTLVs until reach subTLV length
+        * Check that it remains at least 2 bytes: subTLV Type & Length
+        */
+       while (len > sum + 2) {
+               /* Read SubTLV Type and Length */
+               subtlv_type = stream_getc(s);
+               subtlv_len = stream_getc(s);
+               if (subtlv_len > len - sum) {
+                       sbuf_push(log, indent, "TLV %" PRIu8 ": Available data %" PRIu8 " is less than TLV size %u !\n",
+                                 subtlv_type, len - sum, subtlv_len);
+                       return 1;
+               }
 
+               switch (subtlv_type) {
+               /* Standard Metric as defined in RFC5305 */
+               case ISIS_SUBTLV_ADMIN_GRP:
+                       if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) {
+                               sbuf_push(log, indent,
+                                         "TLV size does not match expected size for Administrative Group!\n");
+                       } else {
+                               exts->adm_group = stream_getl(s);
+                               SET_SUBTLV(exts, EXT_ADM_GRP);
+                       }
+                       break;
+               case ISIS_SUBTLV_LLRI:
+                       if (subtlv_len != ISIS_SUBTLV_LLRI_SIZE) {
+                               sbuf_push(log, indent,
+                                         "TLV size does not match expected size for Link ID!\n");
+                       } else {
+                               exts->local_llri = stream_getl(s);
+                               exts->remote_llri = stream_getl(s);
+                               SET_SUBTLV(exts, EXT_LLRI);
+                       }
+                       break;
+               case ISIS_SUBTLV_LOCAL_IPADDR:
+                       if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) {
+                               sbuf_push(log, indent,
+                                         "TLV size does not match expected size for Local IP address!\n");
+                       } else {
+                               stream_get(&exts->local_addr.s_addr, s, 4);
+                               SET_SUBTLV(exts, EXT_LOCAL_ADDR);
+                       }
+                       break;
+               case ISIS_SUBTLV_RMT_IPADDR:
+                       if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) {
+                               sbuf_push(log, indent,
+                                         "TLV size does not match expected size for Remote IP address!\n");
+                       } else {
+                               stream_get(&exts->neigh_addr.s_addr, s, 4);
+                               SET_SUBTLV(exts, EXT_NEIGH_ADDR);
+                       }
+                       break;
+               case ISIS_SUBTLV_LOCAL_IPADDR6:
+                       if (subtlv_len != ISIS_SUBTLV_IPV6_ADDR_SIZE) {
+                               sbuf_push(log, indent,
+                                         "TLV size does not match expected size for Local IPv6 address!\n");
+                       } else {
+                               stream_get(&exts->local_addr6, s, 16);
+                               SET_SUBTLV(exts, EXT_LOCAL_ADDR6);
+                       }
+                       break;
+               case ISIS_SUBTLV_RMT_IPADDR6:
+                       if (subtlv_len != ISIS_SUBTLV_IPV6_ADDR_SIZE) {
+                               sbuf_push(log, indent,
+                                         "TLV size does not match expected size for Remote IPv6 address!\n");
+                       } else {
+                               stream_get(&exts->neigh_addr6, s, 16);
+                               SET_SUBTLV(exts, EXT_NEIGH_ADDR6);
+                       }
+                       break;
+               case ISIS_SUBTLV_MAX_BW:
+                       if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) {
+                               sbuf_push(log, indent,
+                                         "TLV size does not match expected size for Maximum Bandwidth!\n");
+                       } else {
+                               exts->max_bw = stream_getf(s);
+                               SET_SUBTLV(exts, EXT_MAX_BW);
+                       }
+                       break;
+               case ISIS_SUBTLV_MAX_RSV_BW:
+                       if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) {
+                               sbuf_push(log, indent,
+                                         "TLV size does not match expected size for Maximum Reservable Bandwidth!\n");
+                       } else {
+                               exts->max_rsv_bw = stream_getf(s);
+                               SET_SUBTLV(exts, EXT_MAX_RSV_BW);
+                       }
+                       break;
+               case ISIS_SUBTLV_UNRSV_BW:
+                       if (subtlv_len != ISIS_SUBTLV_UNRSV_BW_SIZE) {
+                               sbuf_push(log, indent,
+                                         "TLV size does not match expected size for Unreserved Bandwidth!\n");
+                       } else {
+                               for (int i = 0; i < MAX_CLASS_TYPE; i++)
+                                       exts->unrsv_bw[i] = stream_getf(s);
+                               SET_SUBTLV(exts, EXT_UNRSV_BW);
+                       }
+                       break;
+               case ISIS_SUBTLV_TE_METRIC:
+                       if (subtlv_len != ISIS_SUBTLV_TE_METRIC_SIZE) {
+                               sbuf_push(log, indent,
+                                         "TLV size does not match expected size for Traffic Engineering Metric!\n");
+                       } else {
+                               exts->te_metric = stream_get3(s);
+                               SET_SUBTLV(exts, EXT_TE_METRIC);
+                       }
+                       break;
+               case ISIS_SUBTLV_RAS:
+                       if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) {
+                               sbuf_push(log, indent,
+                                         "TLV size does not match expected size for Remote AS number!\n");
+                       } else {
+                               exts->remote_as = stream_getl(s);
+                               SET_SUBTLV(exts, EXT_RMT_AS);
+                       }
+                       break;
+               case ISIS_SUBTLV_RIP:
+                       if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) {
+                               sbuf_push(log, indent,
+                                         "TLV size does not match expected size for Remote ASBR IP Address!\n");
+                       } else {
+                               stream_get(&exts->remote_ip.s_addr, s, 4);
+                               SET_SUBTLV(exts, EXT_RMT_IP);
+                       }
+                       break;
+               /* Extended Metrics as defined in RFC 7810 */
+               case ISIS_SUBTLV_AV_DELAY:
+                       if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) {
+                               sbuf_push(log, indent,
+                                         "TLV size does not match expected size for Average Link Delay!\n");
+                       } else {
+                               exts->delay = stream_getl(s);
+                               SET_SUBTLV(exts, EXT_DELAY);
+                       }
+                       break;
+               case ISIS_SUBTLV_MM_DELAY:
+                       if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) {
+                               sbuf_push(log, indent,
+                                         "TLV size does not match expected size for Min/Max Link Delay!\n");
+                       } else {
+                               exts->min_delay = stream_getl(s);
+                               exts->max_delay = stream_getl(s);
+                               SET_SUBTLV(exts, EXT_MM_DELAY);
+                       }
+                       break;
+               case ISIS_SUBTLV_DELAY_VAR:
+                       if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) {
+                               sbuf_push(log, indent,
+                                         "TLV size does not match expected size for Delay Variation!\n");
+                       } else {
+                               exts->delay_var = stream_getl(s);
+                               SET_SUBTLV(exts, EXT_DELAY_VAR);
+                       }
+                       break;
+               case ISIS_SUBTLV_PKT_LOSS:
+                       if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) {
+                               sbuf_push(log, indent,
+                                         "TLV size does not match expected size for Link Packet Loss!\n");
+                       } else {
+                               exts->pkt_loss = stream_getl(s);
+                               SET_SUBTLV(exts, EXT_PKT_LOSS);
+                       }
+                       break;
+               case ISIS_SUBTLV_RES_BW:
+                       if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) {
+                               sbuf_push(log, indent,
+                                         "TLV size does not match expected size for Unidirectional Residual Bandwidth!\n");
+                       } else {
+                               exts->res_bw = stream_getf(s);
+                               SET_SUBTLV(exts, EXT_RES_BW);
+                       }
+                       break;
+               case ISIS_SUBTLV_AVA_BW:
+                       if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) {
+                               sbuf_push(log, indent,
+                                         "TLV size does not match expected size for Unidirectional Available Bandwidth!\n");
+                       } else {
+                               exts->ava_bw = stream_getf(s);
+                               SET_SUBTLV(exts, EXT_AVA_BW);
+                       }
+                       break;
+               case ISIS_SUBTLV_USE_BW:
+                       if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) {
+                               sbuf_push(log, indent,
+                                         "TLV size does not match expected size for Unidirectional Utilized Bandwidth!\n");
+                       } else {
+                               exts->use_bw = stream_getf(s);
+                               SET_SUBTLV(exts, EXT_USE_BW);
+                       }
+                       break;
+               /* Segment Routing Adjacency */
+               case ISIS_SUBTLV_ADJ_SID:
+                       if (subtlv_len != ISIS_SUBTLV_ADJ_SID_SIZE
+                           && subtlv_len != ISIS_SUBTLV_ADJ_SID_SIZE + 1) {
+                               sbuf_push(log, indent,
+                                         "TLV size does not match expected size for Adjacency SID!\n");
+                       } else {
+                               struct isis_adj_sid *adj;
+
+                               adj = XCALLOC(MTYPE_ISIS_SUBTLV,
+                                             sizeof(struct isis_adj_sid));
+                               adj->flags = stream_getc(s);
+                               adj->weight = stream_getc(s);
+                               if (adj->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG) {
+                                       adj->sid = stream_get3(s);
+                                       adj->sid &= MPLS_LABEL_VALUE_MASK;
+                               } else {
+                                       adj->sid = stream_getl(s);
+                               }
+                               if (mtid == ISIS_MT_IPV4_UNICAST)
+                                       adj->family = AF_INET;
+                               if (mtid == ISIS_MT_IPV6_UNICAST)
+                                       adj->family = AF_INET6;
+                               append_item(&exts->adj_sid,
+                                           (struct isis_item *)adj);
+                               SET_SUBTLV(exts, EXT_ADJ_SID);
+                       }
+                       break;
+               case ISIS_SUBTLV_LAN_ADJ_SID:
+                       if (subtlv_len != ISIS_SUBTLV_LAN_ADJ_SID_SIZE
+                           && subtlv_len != ISIS_SUBTLV_LAN_ADJ_SID_SIZE + 1) {
+                               sbuf_push(log, indent,
+                                         "TLV size does not match expected size for LAN-Adjacency SID!\n");
+                       } else {
+                               struct isis_lan_adj_sid *lan;
+
+                               lan = XCALLOC(MTYPE_ISIS_SUBTLV,
+                                             sizeof(struct isis_lan_adj_sid));
+                               lan->flags = stream_getc(s);
+                               lan->weight = stream_getc(s);
+                               stream_get(&(lan->neighbor_id), s,
+                                          ISIS_SYS_ID_LEN);
+                               if (lan->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG) {
+                                       lan->sid = stream_get3(s);
+                                       lan->sid &= MPLS_LABEL_VALUE_MASK;
+                               } else {
+                                       lan->sid = stream_getl(s);
+                               }
+                               if (mtid == ISIS_MT_IPV4_UNICAST)
+                                       lan->family = AF_INET;
+                               if (mtid == ISIS_MT_IPV6_UNICAST)
+                                       lan->family = AF_INET6;
+                               append_item(&exts->lan_sid,
+                                           (struct isis_item *)lan);
+                               SET_SUBTLV(exts, EXT_LAN_ADJ_SID);
+                       }
+                       break;
+               default:
+                       /* Skip unknown TLV */
+                       stream_forward_getp(s, subtlv_len);
+                       break;
+               }
+               sum += subtlv_len + ISIS_SUBTLV_HDR_SIZE;
+       }
+
+       return 0;
+}
+
+/* Functions for Sub-TLV 3 SR Prefix-SID */
 static struct isis_item *copy_item_prefix_sid(struct isis_item *i)
 {
        struct isis_prefix_sid *sid = (struct isis_prefix_sid *)i;
@@ -127,20 +805,22 @@ static void format_item_prefix_sid(uint16_t mtid, struct isis_item *i,
 {
        struct isis_prefix_sid *sid = (struct isis_prefix_sid *)i;
 
-       sbuf_push(buf, indent, "SR Prefix-SID:\n");
-       sbuf_push(buf, indent, "  Flags:%s%s%s%s%s%s\n",
-                 sid->flags & ISIS_PREFIX_SID_READVERTISED ? " READVERTISED" : "",
-                 sid->flags & ISIS_PREFIX_SID_NODE ? " NODE" : "",
-                 sid->flags & ISIS_PREFIX_SID_NO_PHP ? " NO_PHP" : "",
-                 sid->flags & ISIS_PREFIX_SID_EXPLICIT_NULL ? " EXPLICIT-NULL" : "",
-                 sid->flags & ISIS_PREFIX_SID_VALUE ? " VALUE" : "",
-                 sid->flags & ISIS_PREFIX_SID_LOCAL ? " LOCAL" : "");
-       sbuf_push(buf, indent, "  Algorithm: %" PRIu8 "\n", sid->algorithm);
+       sbuf_push(buf, indent, "SR Prefix-SID ");
        if (sid->flags & ISIS_PREFIX_SID_VALUE) {
-               sbuf_push(buf, indent,  "Label: %" PRIu32 "\n", sid->value);
+               sbuf_push(buf, 0, "Label: %" PRIu32 ", ", sid->value);
        } else {
-               sbuf_push(buf, indent,  "Index: %" PRIu32 "\n", sid->value);
+               sbuf_push(buf, 0, "Index: %" PRIu32 ", ", sid->value);
        }
+       sbuf_push(buf, 0, "Algorithm: %" PRIu8 ", ", sid->algorithm);
+       sbuf_push(buf, 0, "Flags:%s%s%s%s%s%s\n",
+                 sid->flags & ISIS_PREFIX_SID_READVERTISED ? " READVERTISED"
+                                                           : "",
+                 sid->flags & ISIS_PREFIX_SID_NODE ? " NODE" : "",
+                 sid->flags & ISIS_PREFIX_SID_NO_PHP ? " NO-PHP" : " PHP",
+                 sid->flags & ISIS_PREFIX_SID_EXPLICIT_NULL ? " EXPLICIT-NULL"
+                                                            : "",
+                 sid->flags & ISIS_PREFIX_SID_VALUE ? " VALUE" : "",
+                 sid->flags & ISIS_PREFIX_SID_LOCAL ? " LOCAL" : "");
 }
 
 static void free_item_prefix_sid(struct isis_item *i)
@@ -186,15 +866,17 @@ static int unpack_item_prefix_sid(uint16_t mtid, uint8_t len, struct stream *s,
        }
 
        sid.flags = stream_getc(s);
-       if ((sid.flags & ISIS_PREFIX_SID_VALUE)
-           != (sid.flags & ISIS_PREFIX_SID_LOCAL)) {
-               sbuf_push(log, indent, "Flags inplausible: Local Flag needs to match Value Flag\n");
-               return 0;
+       if (!!(sid.flags & ISIS_PREFIX_SID_VALUE)
+           != !!(sid.flags & ISIS_PREFIX_SID_LOCAL)) {
+               sbuf_push(log, indent, "Flags implausible: Local Flag needs to match Value Flag\n");
+               return 1;
        }
 
        sid.algorithm = stream_getc(s);
 
-       uint8_t expected_size = (sid.flags & ISIS_PREFIX_SID_VALUE) ? 5 : 6;
+       uint8_t expected_size = (sid.flags & ISIS_PREFIX_SID_VALUE)
+                                       ? ISIS_SUBTLV_PREFIX_SID_SIZE
+                                       : ISIS_SUBTLV_PREFIX_SID_SIZE + 1;
        if (len != expected_size) {
                sbuf_push(log, indent,
                          "TLV size differs from expected size. "
@@ -205,6 +887,7 @@ static int unpack_item_prefix_sid(uint16_t mtid, uint8_t len, struct stream *s,
 
        if (sid.flags & ISIS_PREFIX_SID_VALUE) {
                sid.value = stream_get3(s);
+               sid.value &= MPLS_LABEL_VALUE_MASK;
        } else {
                sid.value = stream_getl(s);
        }
@@ -276,7 +959,7 @@ static int unpack_subtlv_ipv6_source_prefix(enum isis_tlv_context context,
 
        p.prefixlen = stream_getc(s);
        if (p.prefixlen > 128) {
-               sbuf_push(log, indent, "Prefixlen %u is inplausible for IPv6\n",
+               sbuf_push(log, indent, "Prefixlen %u is implausible for IPv6\n",
                          p.prefixlen);
                return 1;
        }
@@ -305,7 +988,7 @@ static int unpack_subtlv_ipv6_source_prefix(enum isis_tlv_context context,
        memcpy(subtlvs->source_prefix, &p, sizeof(p));
        return 0;
 }
-static void init_item_list(struct isis_item_list *items);
+
 static struct isis_item *copy_item(enum isis_tlv_context context,
                                   enum isis_tlv_type type,
                                   struct isis_item *item);
@@ -703,11 +1386,8 @@ static struct isis_item *copy_item_extended_reach(struct isis_item *i)
        memcpy(rv->id, r->id, 7);
        rv->metric = r->metric;
 
-       if (r->subtlvs && r->subtlv_len) {
-               rv->subtlvs = XCALLOC(MTYPE_ISIS_TLV, r->subtlv_len);
-               memcpy(rv->subtlvs, r->subtlvs, r->subtlv_len);
-               rv->subtlv_len = r->subtlv_len;
-       }
+       if (r->subtlvs)
+               rv->subtlvs = copy_item_ext_subtlvs(r->subtlvs, -1);
 
        return (struct isis_item *)rv;
 }
@@ -724,28 +1404,37 @@ static void format_item_extended_reach(uint16_t mtid, struct isis_item *i,
                sbuf_push(buf, 0, " %s", isis_mtid2str(mtid));
        sbuf_push(buf, 0, "\n");
 
-       if (r->subtlv_len && r->subtlvs)
-               mpls_te_print_detail(buf, indent + 2, r->subtlvs,
-                                    r->subtlv_len);
+       if (r->subtlvs)
+               format_item_ext_subtlvs(r->subtlvs, buf, indent + 2, mtid);
 }
 
 static void free_item_extended_reach(struct isis_item *i)
 {
        struct isis_extended_reach *item = (struct isis_extended_reach *)i;
-       XFREE(MTYPE_ISIS_TLV, item->subtlvs);
+       if (item->subtlvs != NULL)
+               free_item_ext_subtlvs(item->subtlvs);
        XFREE(MTYPE_ISIS_TLV, item);
 }
 
 static int pack_item_extended_reach(struct isis_item *i, struct stream *s)
 {
        struct isis_extended_reach *r = (struct isis_extended_reach *)i;
+       size_t len;
+       size_t len_pos;
 
-       if (STREAM_WRITEABLE(s) < 11 + (unsigned)r->subtlv_len)
+       if (STREAM_WRITEABLE(s) < 11 + ISIS_SUBTLV_MAX_SIZE)
                return 1;
+
        stream_put(s, r->id, sizeof(r->id));
        stream_put3(s, r->metric);
-       stream_putc(s, r->subtlv_len);
-       stream_put(s, r->subtlvs, r->subtlv_len);
+       len_pos = stream_get_endp(s);
+        /* Real length will be adjust after adding subTLVs */
+       stream_putc(s, 11);
+       if (r->subtlvs)
+               pack_item_ext_subtlvs(r->subtlvs, s);
+       /* Adjust length */
+       len = stream_get_endp(s) - len_pos - 1;
+       stream_putc_at(s, len_pos, len);
        return 0;
 }
 
@@ -780,9 +1469,6 @@ static int unpack_item_extended_reach(uint16_t mtid, uint8_t len,
        rv->metric = stream_get3(s);
        subtlv_len = stream_getc(s);
 
-       format_item_extended_reach(mtid, (struct isis_item *)rv, log,
-                                  indent + 2);
-
        if ((size_t)len < ((size_t)11) + subtlv_len) {
                sbuf_push(log, indent,
                          "Not enough data left for subtlv size %" PRIu8
@@ -795,20 +1481,14 @@ static int unpack_item_extended_reach(uint16_t mtid, uint8_t len,
                  subtlv_len);
 
        if (subtlv_len) {
-               size_t subtlv_start = stream_get_getp(s);
-
-               if (unpack_tlvs(ISIS_CONTEXT_SUBTLV_NE_REACH, subtlv_len, s,
-                               log, NULL, indent + 4, NULL)) {
+               if (unpack_item_ext_subtlvs(mtid, subtlv_len, s, log, rv,
+                                           indent + 4)) {
                        goto out;
                }
-
-               stream_set_getp(s, subtlv_start);
-
-               rv->subtlvs = XCALLOC(MTYPE_ISIS_TLV, subtlv_len);
-               stream_get(rv->subtlvs, s, subtlv_len);
-               rv->subtlv_len = subtlv_len;
        }
 
+       format_item_extended_reach(mtid, (struct isis_item *)rv, log,
+                                  indent + 2);
        append_item(items, (struct isis_item *)rv);
        return 0;
 out:
@@ -1257,6 +1937,7 @@ static struct isis_item *copy_item_extended_ip_reach(struct isis_item *i)
        rv->metric = r->metric;
        rv->down = r->down;
        rv->prefix = r->prefix;
+       rv->subtlvs = copy_subtlvs(r->subtlvs);
 
        return (struct isis_item *)rv;
 }
@@ -1348,7 +2029,7 @@ static int unpack_item_extended_ip_reach(uint16_t mtid, uint8_t len,
        rv->prefix.family = AF_INET;
        rv->prefix.prefixlen = control & 0x3f;
        if (rv->prefix.prefixlen > 32) {
-               sbuf_push(log, indent, "Prefixlen %u is inplausible for IPv4\n",
+               sbuf_push(log, indent, "Prefixlen %u is implausible for IPv4\n",
                          rv->prefix.prefixlen);
                goto out;
        }
@@ -1834,7 +2515,7 @@ static int unpack_item_ipv6_reach(uint16_t mtid, uint8_t len, struct stream *s,
        rv->prefix.family = AF_INET6;
        rv->prefix.prefixlen = stream_getc(s);
        if (rv->prefix.prefixlen > 128) {
-               sbuf_push(log, indent, "Prefixlen %u is inplausible for IPv6\n",
+               sbuf_push(log, indent, "Prefixlen %u is implausible for IPv6\n",
                          rv->prefix.prefixlen);
                goto out;
        }
@@ -1848,6 +2529,7 @@ static int unpack_item_ipv6_reach(uint16_t mtid, uint8_t len, struct stream *s,
        }
        stream_get(&rv->prefix.prefix.s6_addr, s, PSIZE(rv->prefix.prefixlen));
        struct in6_addr orig_prefix = rv->prefix.prefix;
+
        apply_mask_ipv6(&rv->prefix);
        if (memcmp(&orig_prefix, &rv->prefix.prefix, sizeof(orig_prefix)))
                sbuf_push(log, indent + 2,
@@ -1898,6 +2580,222 @@ out:
        return 1;
 }
 
+/* Functions related to TLV 242 Router Capability */
+static struct isis_router_cap *copy_tlv_router_cap(
+                              const struct isis_router_cap *router_cap)
+{
+       struct isis_router_cap *rv = XMALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
+
+       if (!router_cap)
+               return NULL;
+
+       memcpy(rv, router_cap, sizeof(*rv));
+
+       return rv;
+}
+
+static void format_tlv_router_cap(const struct isis_router_cap *router_cap,
+                                 struct sbuf *buf, int indent)
+{
+       char addrbuf[INET_ADDRSTRLEN];
+
+       if (!router_cap)
+               return;
+
+       /* Router ID and Flags */
+       inet_ntop(AF_INET, &router_cap->router_id, addrbuf, sizeof(addrbuf));
+       sbuf_push(buf, indent, "Router Capability:");
+       sbuf_push(buf, indent, " %s , D:%c, S:%c\n", addrbuf,
+                 router_cap->flags & ISIS_ROUTER_CAP_FLAG_D ? '1' : '0',
+                 router_cap->flags & ISIS_ROUTER_CAP_FLAG_S ? '1' : '0');
+
+       /* SR Global Block */
+       if (router_cap->srgb.range_size != 0)
+               sbuf_push(buf, indent,
+                       "  Segment Routing: I:%s V:%s, SRGB Base: %d Range: %d\n",
+                       IS_SR_IPV4(router_cap->srgb) ? "1" : "0",
+                       IS_SR_IPV6(router_cap->srgb) ? "1" : "0",
+                       router_cap->srgb.lower_bound,
+                       router_cap->srgb.range_size);
+
+       /* SR Algorithms */
+       if (router_cap->algo[0] != SR_ALGORITHM_UNSET) {
+               sbuf_push(buf, indent, "    Algorithm: %s",
+                         router_cap->algo[0] == 0 ? "0: SPF"
+                                                  : "0: Strict SPF");
+               for (int i = 0; i < SR_ALGORITHM_COUNT; i++)
+                       if (router_cap->algo[i] != SR_ALGORITHM_UNSET)
+                               sbuf_push(buf, indent, " %s",
+                                         router_cap->algo[1] == 0
+                                                 ? "0: SPF"
+                                                 : "0: Strict SPF");
+               sbuf_push(buf, indent, "\n");
+       }
+
+       /* SR Node MSSD */
+       if (router_cap->msd != 0)
+               sbuf_push(buf, indent, "    Node MSD: %d\n", router_cap->msd);
+}
+
+static void free_tlv_router_cap(struct isis_router_cap *router_cap)
+{
+       XFREE(MTYPE_ISIS_TLV, router_cap);
+}
+
+static int pack_tlv_router_cap(const struct isis_router_cap *router_cap,
+                              struct stream *s)
+{
+       size_t tlv_len = ISIS_ROUTER_CAP_SIZE;
+       size_t len_pos;
+       uint8_t nb_algo;
+
+       if (!router_cap)
+               return 0;
+
+       /* Compute Maximum TLV size */
+       tlv_len += ISIS_SUBTLV_SID_LABEL_RANGE_SIZE
+               + ISIS_SUBTLV_HDR_SIZE
+               + ISIS_SUBTLV_ALGORITHM_SIZE
+               + ISIS_SUBTLV_NODE_MSD_SIZE;
+
+       if (STREAM_WRITEABLE(s) < (unsigned int)(2 + tlv_len))
+               return 1;
+
+       /* Add Router Capability TLV 242 with Router ID and Flags */
+       stream_putc(s, ISIS_TLV_ROUTER_CAPABILITY);
+       /* Real length will be adjusted later */
+       len_pos = stream_get_endp(s);
+       stream_putc(s, tlv_len);
+       stream_put_ipv4(s, router_cap->router_id.s_addr);
+       stream_putc(s, router_cap->flags);
+
+       /* Add SRGB if set */
+       if ((router_cap->srgb.range_size != 0)
+           && (router_cap->srgb.lower_bound != 0)) {
+               stream_putc(s, ISIS_SUBTLV_SID_LABEL_RANGE);
+               stream_putc(s, ISIS_SUBTLV_SID_LABEL_RANGE_SIZE);
+               stream_putc(s, router_cap->srgb.flags);
+               stream_put3(s, router_cap->srgb.range_size);
+               stream_putc(s, ISIS_SUBTLV_SID_LABEL);
+               stream_putc(s, ISIS_SUBTLV_SID_LABEL_SIZE);
+               stream_put3(s, router_cap->srgb.lower_bound);
+
+               /* Then SR Algorithm if set */
+               for (nb_algo = 0; nb_algo < SR_ALGORITHM_COUNT; nb_algo++)
+                       if (router_cap->algo[nb_algo] == SR_ALGORITHM_UNSET)
+                               break;
+               if (nb_algo > 0) {
+                       stream_putc(s, ISIS_SUBTLV_ALGORITHM);
+                       stream_putc(s, nb_algo);
+                       for (int i = 0; i < nb_algo; i++)
+                               stream_putc(s, router_cap->algo[i]);
+               }
+               /* And finish with MSD if set */
+               if (router_cap->msd != 0) {
+                       stream_putc(s, ISIS_SUBTLV_NODE_MSD);
+                       stream_putc(s, ISIS_SUBTLV_NODE_MSD_SIZE);
+                       stream_putc(s, MSD_TYPE_BASE_MPLS_IMPOSITION);
+                       stream_putc(s, router_cap->msd);
+               }
+       }
+
+       /* Adjust TLV length which depends on subTLVs presence */
+       tlv_len = stream_get_endp(s) - len_pos - 1;
+       stream_putc_at(s, len_pos, tlv_len);
+
+       return 0;
+}
+
+static int unpack_tlv_router_cap(enum isis_tlv_context context,
+                                      uint8_t tlv_type, uint8_t tlv_len,
+                                      struct stream *s, struct sbuf *log,
+                                      void *dest, int indent)
+{
+       struct isis_tlvs *tlvs = dest;
+       uint8_t type;
+       uint8_t length;
+       uint8_t subtlv_len;
+       uint8_t sid_len;
+
+       sbuf_push(log, indent, "Unpacking Router Capability TLV...\n");
+       if (tlv_len < ISIS_ROUTER_CAP_SIZE) {
+               sbuf_push(log, indent, "WARNING: Unexpected TLV size\n");
+               stream_forward_getp(s, tlv_len);
+               return 0;
+       }
+
+       if (tlvs->router_cap) {
+               sbuf_push(log, indent,
+                         "WARNING: Router Capability TLV present multiple times.\n");
+               stream_forward_getp(s, tlv_len);
+               return 0;
+       }
+
+       /* Allocate router cap structure and initialize SR Algorithms */
+       tlvs->router_cap = XCALLOC(MTYPE_ISIS_TLV, sizeof(*tlvs->router_cap));
+       for (int i = 0; i < SR_ALGORITHM_COUNT; i++)
+               tlvs->router_cap->algo[i] = SR_ALGORITHM_UNSET;
+
+       /* Get Router ID and Flags */
+       tlvs->router_cap->router_id.s_addr = stream_get_ipv4(s);
+       tlvs->router_cap->flags = stream_getc(s);
+
+       /* Parse remaining part of the TLV if present */
+       subtlv_len = tlv_len - ISIS_ROUTER_CAP_SIZE;
+       while (subtlv_len > 2) {
+               struct isis_router_cap *rc = tlvs->router_cap;
+               uint8_t msd_type;
+
+               type = stream_getc(s);
+               length = stream_getc(s);
+               switch (type) {
+               case ISIS_SUBTLV_SID_LABEL_RANGE:
+                       rc->srgb.flags = stream_getc(s);
+                       rc->srgb.range_size = stream_get3(s);
+                       /* Skip Type and get Length of SID Label */
+                       stream_getc(s);
+                       sid_len = stream_getc(s);
+                       if (sid_len == ISIS_SUBTLV_SID_LABEL_SIZE)
+                               rc->srgb.lower_bound = stream_get3(s);
+                       else
+                               rc->srgb.lower_bound = stream_getl(s);
+
+                       /* SRGB sanity checks. */
+                       if (rc->srgb.range_size == 0
+                           || (rc->srgb.lower_bound <= MPLS_LABEL_RESERVED_MAX)
+                           || ((rc->srgb.lower_bound + rc->srgb.range_size - 1)
+                               > MPLS_LABEL_UNRESERVED_MAX)) {
+                               sbuf_push(log, indent, "Invalid label range. Reset SRGB\n");
+                               rc->srgb.lower_bound = 0;
+                               rc->srgb.range_size = 0;
+                       }
+                       break;
+               case ISIS_SUBTLV_ALGORITHM:
+                       /* Only 2 algorithms are supported: SPF & Strict SPF */
+                       stream_get(&rc->algo, s,
+                                  length > SR_ALGORITHM_COUNT
+                                          ? SR_ALGORITHM_COUNT
+                                          : length);
+                       if (length > SR_ALGORITHM_COUNT)
+                               stream_forward_getp(
+                                       s, length - SR_ALGORITHM_COUNT);
+                       break;
+               case ISIS_SUBTLV_NODE_MSD:
+                       msd_type = stream_getc(s);
+                       rc->msd = stream_getc(s);
+                       /* Only BMI-MSD type has been defined in RFC 8491 */
+                       if (msd_type != MSD_TYPE_BASE_MPLS_IMPOSITION)
+                               rc->msd = 0;
+                       break;
+               default:
+                       stream_forward_getp(s, length);
+                       break;
+               }
+               subtlv_len = subtlv_len - length - 2;
+       }
+       return 0;
+}
+
 /* Functions related to TLV 10 Authentication */
 static struct isis_item *copy_item_auth(struct isis_item *i)
 {
@@ -2318,6 +3216,39 @@ static void append_item(struct isis_item_list *dest, struct isis_item *item)
        dest->count++;
 }
 
+static void delete_item(struct isis_item_list *dest, struct isis_item *del)
+{
+       struct isis_item *item, *prev = NULL, *next;
+
+       /* Sanity Check */
+       if ((dest == NULL) || (del == NULL))
+               return;
+
+       /*
+        * TODO: delete is tricky because "dest" is a singly linked list.
+        * We need to switch a doubly linked list.
+        */
+       for (item = dest->head; item; item = next) {
+               if (item->next == del) {
+                       prev = item;
+                       break;
+               }
+               next = item->next;
+       }
+       if (prev)
+               prev->next = del->next;
+       if (dest->head == del)
+               dest->head = del->next;
+       if ((struct isis_item *)dest->tail == del) {
+               *dest->tail = prev;
+               if (prev)
+                       dest->tail = &(*dest->tail)->next;
+               else
+                       dest->tail = &dest->head;
+       }
+       dest->count--;
+}
+
 static struct isis_item *last_item(struct isis_item_list *list)
 {
        return container_of(list->tail, struct isis_item, next);
@@ -2596,6 +3527,8 @@ struct isis_tlvs *isis_copy_tlvs(struct isis_tlvs *tlvs)
 
        rv->threeway_adj = copy_tlv_threeway_adj(tlvs->threeway_adj);
 
+       rv->router_cap = copy_tlv_router_cap(tlvs->router_cap);
+
        rv->spine_leaf = copy_tlv_spine_leaf(tlvs->spine_leaf);
 
        return rv;
@@ -2631,6 +3564,7 @@ static void format_tlvs(struct isis_tlvs *tlvs, struct sbuf *buf, int indent)
 
        format_tlv_dynamic_hostname(tlvs->hostname, buf, indent);
        format_tlv_te_router_id(tlvs->te_router_id, buf, indent);
+       format_tlv_router_cap(tlvs->router_cap, buf, indent);
 
        format_items(ISIS_CONTEXT_LSP, ISIS_TLV_EXTENDED_REACH,
                     &tlvs->extended_reach, buf, indent);
@@ -2717,6 +3651,7 @@ void isis_free_tlvs(struct isis_tlvs *tlvs)
        free_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_IPV6_REACH,
                      &tlvs->mt_ipv6_reach);
        free_tlv_threeway_adj(tlvs->threeway_adj);
+       free_tlv_router_cap(tlvs->router_cap);
        free_tlv_spine_leaf(tlvs->spine_leaf);
 
        XFREE(MTYPE_ISIS_TLV, tlvs);
@@ -2897,6 +3832,14 @@ static int pack_tlvs(struct isis_tlvs *tlvs, struct stream *stream,
                fragment_tlvs->hostname =
                        copy_tlv_dynamic_hostname(tlvs->hostname);
 
+       rv = pack_tlv_router_cap(tlvs->router_cap, stream);
+       if (rv)
+               return rv;
+       if (fragment_tlvs) {
+               fragment_tlvs->router_cap =
+                       copy_tlv_router_cap(tlvs->router_cap);
+       }
+
        rv = pack_tlv_te_router_id(tlvs->te_router_id, stream);
        if (rv)
                return rv;
@@ -3131,6 +4074,7 @@ ITEM_TLV_OPS(mt_router_info, "TLV 229 MT Router Information");
 TLV_OPS(threeway_adj, "TLV 240 P2P Three-Way Adjacency");
 ITEM_TLV_OPS(ipv6_address, "TLV 232 IPv6 Interface Address");
 ITEM_TLV_OPS(ipv6_reach, "TLV 236 IPv6 Reachability");
+TLV_OPS(router_cap, "TLV 242 Router Capability");
 
 ITEM_SUBTLV_OPS(prefix_sid, "Sub-TLV 3 SR Prefix-SID");
 SUBTLV_OPS(ipv6_source_prefix, "Sub-TLV 22 IPv6 Source Prefix");
@@ -3144,21 +4088,22 @@ static const struct tlv_ops *tlv_table[ISIS_CONTEXT_MAX][ISIS_TLV_MAX] = {
                [ISIS_TLV_AUTH] = &tlv_auth_ops,
                [ISIS_TLV_PURGE_ORIGINATOR] = &tlv_purge_originator_ops,
                [ISIS_TLV_EXTENDED_REACH] = &tlv_extended_reach_ops,
-               [ISIS_TLV_MT_REACH] = &tlv_extended_reach_ops,
                [ISIS_TLV_OLDSTYLE_IP_REACH] = &tlv_oldstyle_ip_reach_ops,
                [ISIS_TLV_PROTOCOLS_SUPPORTED] = &tlv_protocols_supported_ops,
                [ISIS_TLV_OLDSTYLE_IP_REACH_EXT] = &tlv_oldstyle_ip_reach_ops,
                [ISIS_TLV_IPV4_ADDRESS] = &tlv_ipv4_address_ops,
                [ISIS_TLV_TE_ROUTER_ID] = &tlv_te_router_id_ops,
                [ISIS_TLV_EXTENDED_IP_REACH] = &tlv_extended_ip_reach_ops,
-               [ISIS_TLV_MT_IP_REACH] = &tlv_extended_ip_reach_ops,
                [ISIS_TLV_DYNAMIC_HOSTNAME] = &tlv_dynamic_hostname_ops,
                [ISIS_TLV_SPINE_LEAF_EXT] = &tlv_spine_leaf_ops,
+               [ISIS_TLV_MT_REACH] = &tlv_extended_reach_ops,
                [ISIS_TLV_MT_ROUTER_INFO] = &tlv_mt_router_info_ops,
-               [ISIS_TLV_THREE_WAY_ADJ] = &tlv_threeway_adj_ops,
                [ISIS_TLV_IPV6_ADDRESS] = &tlv_ipv6_address_ops,
+               [ISIS_TLV_MT_IP_REACH] = &tlv_extended_ip_reach_ops,
                [ISIS_TLV_IPV6_REACH] = &tlv_ipv6_reach_ops,
                [ISIS_TLV_MT_IPV6_REACH] = &tlv_ipv6_reach_ops,
+               [ISIS_TLV_THREE_WAY_ADJ] = &tlv_threeway_adj_ops,
+               [ISIS_TLV_ROUTER_CAPABILITY] = &tlv_router_cap_ops,
        },
        [ISIS_CONTEXT_SUBTLV_NE_REACH] = {},
        [ISIS_CONTEXT_SUBTLV_IP_REACH] = {
@@ -3593,6 +4538,18 @@ void isis_tlvs_set_dynamic_hostname(struct isis_tlvs *tlvs,
                tlvs->hostname = XSTRDUP(MTYPE_ISIS_TLV, hostname);
 }
 
+/* Set Router Capability TLV parameters */
+void isis_tlvs_set_router_capability(struct isis_tlvs *tlvs,
+                                    const struct isis_router_cap *cap)
+{
+       XFREE(MTYPE_ISIS_TLV, tlvs->router_cap);
+       if (!cap)
+               return;
+
+       tlvs->router_cap = XCALLOC(MTYPE_ISIS_TLV, sizeof(*tlvs->router_cap));
+       *tlvs->router_cap = *cap;
+}
+
 void isis_tlvs_set_te_router_id(struct isis_tlvs *tlvs,
                                const struct in_addr *id)
 {
@@ -3614,6 +4571,38 @@ void isis_tlvs_add_oldstyle_ip_reach(struct isis_tlvs *tlvs,
        append_item(&tlvs->oldstyle_ip_reach, (struct isis_item *)r);
 }
 
+void isis_tlvs_add_adj_sid(struct isis_ext_subtlvs *exts,
+                          struct isis_adj_sid *adj)
+{
+       append_item(&exts->adj_sid, (struct isis_item *)adj);
+       SET_SUBTLV(exts, EXT_ADJ_SID);
+}
+
+void isis_tlvs_del_adj_sid(struct isis_ext_subtlvs *exts,
+                          struct isis_adj_sid *adj)
+{
+       delete_item(&exts->adj_sid, (struct isis_item *)adj);
+       XFREE(MTYPE_ISIS_SUBTLV, adj);
+       if (exts->adj_sid.count == 0)
+               UNSET_SUBTLV(exts, EXT_ADJ_SID);
+}
+
+void isis_tlvs_add_lan_adj_sid(struct isis_ext_subtlvs *exts,
+                              struct isis_lan_adj_sid *lan)
+{
+       append_item(&exts->lan_sid, (struct isis_item *)lan);
+       SET_SUBTLV(exts, EXT_LAN_ADJ_SID);
+}
+
+void isis_tlvs_del_lan_adj_sid(struct isis_ext_subtlvs *exts,
+                              struct isis_lan_adj_sid *lan)
+{
+       delete_item(&exts->lan_sid, (struct isis_item *)lan);
+       XFREE(MTYPE_ISIS_SUBTLV, lan);
+       if (exts->lan_sid.count == 0)
+               UNSET_SUBTLV(exts, EXT_LAN_ADJ_SID);
+}
+
 void isis_tlvs_add_extended_ip_reach(struct isis_tlvs *tlvs,
                                     struct prefix_ipv4 *dest, uint32_t metric)
 {
@@ -3668,17 +4657,14 @@ void isis_tlvs_add_oldstyle_reach(struct isis_tlvs *tlvs, uint8_t *id,
 
 void isis_tlvs_add_extended_reach(struct isis_tlvs *tlvs, uint16_t mtid,
                                  uint8_t *id, uint32_t metric,
-                                 uint8_t *subtlvs, uint8_t subtlv_len)
+                                 struct isis_ext_subtlvs *exts)
 {
        struct isis_extended_reach *r = XCALLOC(MTYPE_ISIS_TLV, sizeof(*r));
 
        memcpy(r->id, id, sizeof(r->id));
        r->metric = metric;
-       if (subtlvs && subtlv_len) {
-               r->subtlvs = XCALLOC(MTYPE_ISIS_TLV, subtlv_len);
-               memcpy(r->subtlvs, subtlvs, subtlv_len);
-               r->subtlv_len = subtlv_len;
-       }
+       if (exts)
+               r->subtlvs = copy_item_ext_subtlvs(exts, mtid);
 
        struct isis_item_list *l;
        if (mtid == ISIS_MT_IPV4_UNICAST)
index 4954d791d86e2fd5279e485623ada2b655f66bee..2948728e2b49b4dba369e5c961278dc7349990bb 100644 (file)
@@ -2,6 +2,8 @@
  * IS-IS TLV Serializer/Deserializer
  *
  * Copyright (C) 2015,2017 Christian Franke
+
+ * Copyright (C) 2019 Olivier Dugeon - Orange Labs (for TE and SR)
  *
  * This file is part of FRR.
  *
@@ -66,14 +68,14 @@ struct isis_lsp_entry {
 };
 
 struct isis_extended_reach;
+struct isis_ext_subtlvs;
 struct isis_extended_reach {
        struct isis_extended_reach *next;
 
        uint8_t id[7];
        uint32_t metric;
 
-       uint8_t *subtlvs;
-       uint8_t subtlv_len;
+       struct isis_ext_subtlvs *subtlvs;
 };
 
 struct isis_extended_ip_reach;
@@ -130,6 +132,95 @@ struct isis_threeway_adj {
        uint32_t neighbor_circuit_id;
 };
 
+/*
+ * Segment Routing subTLV's as per
+ * draft-ietf-isis-segment-routing-extension-25
+ */
+#define ISIS_SUBTLV_SRGB_FLAG_I                0x80
+#define ISIS_SUBTLV_SRGB_FLAG_V                0x40
+#define IS_SR_IPV4(srgb)               (srgb.flags & ISIS_SUBTLV_SRGB_FLAG_I)
+#define IS_SR_IPV6(srgb)               (srgb.flags & ISIS_SUBTLV_SRGB_FLAG_V)
+
+/* Structure aggregating SRGB info */
+struct isis_srgb {
+       uint8_t flags;
+       uint32_t range_size;
+       uint32_t lower_bound;
+};
+
+/* Prefix-SID sub-TLVs flags */
+#define ISIS_PREFIX_SID_READVERTISED  0x80
+#define ISIS_PREFIX_SID_NODE          0x40
+#define ISIS_PREFIX_SID_NO_PHP        0x20
+#define ISIS_PREFIX_SID_EXPLICIT_NULL 0x10
+#define ISIS_PREFIX_SID_VALUE         0x08
+#define ISIS_PREFIX_SID_LOCAL         0x04
+
+struct isis_prefix_sid;
+struct isis_prefix_sid {
+       struct isis_prefix_sid *next;
+
+       uint8_t flags;
+       uint8_t algorithm;
+       uint32_t value;
+};
+
+/* Adj-SID and LAN-Ajd-SID sub-TLVs flags */
+#define EXT_SUBTLV_LINK_ADJ_SID_FFLG   0x80
+#define EXT_SUBTLV_LINK_ADJ_SID_BFLG   0x40
+#define EXT_SUBTLV_LINK_ADJ_SID_VFLG   0x20
+#define EXT_SUBTLV_LINK_ADJ_SID_LFLG   0x10
+#define EXT_SUBTLV_LINK_ADJ_SID_SFLG   0x08
+#define EXT_SUBTLV_LINK_ADJ_SID_PFLG   0x04
+
+struct isis_adj_sid;
+struct isis_adj_sid {
+       struct isis_adj_sid *next;
+
+       uint8_t family;
+       uint8_t flags;
+       uint8_t weight;
+       uint32_t sid;
+};
+
+struct isis_lan_adj_sid;
+struct isis_lan_adj_sid {
+       struct isis_lan_adj_sid *next;
+
+       uint8_t family;
+       uint8_t flags;
+       uint8_t weight;
+       uint8_t neighbor_id[ISIS_SYS_ID_LEN];
+       uint32_t sid;
+};
+
+/* RFC 4971 & RFC 7981 */
+#define ISIS_ROUTER_CAP_FLAG_S 0x01
+#define ISIS_ROUTER_CAP_FLAG_D 0x02
+#define ISIS_ROUTER_CAP_SIZE   5
+
+/* Number of supported algorithm for Segment Routing.
+ * Right now only 2 have been standardized:
+ *  - 0: SPF
+ *  - 1: Strict SPF
+ */
+#define SR_ALGORITHM_COUNT     2
+#define SR_ALGORITHM_SPF       0
+#define SR_ALGORITHM_STRICT_SPF        1
+#define SR_ALGORITHM_UNSET     255
+
+struct isis_router_cap {
+       struct in_addr router_id;
+       uint8_t flags;
+
+       /* draft-ietf-segment-routing-extensions-25 */
+       struct isis_srgb srgb;
+       uint8_t algo[SR_ALGORITHM_COUNT];
+       /* RFC 8491 */
+#define MSD_TYPE_BASE_MPLS_IMPOSITION  0x01
+       uint8_t msd;
+};
+
 struct isis_item;
 struct isis_item {
        struct isis_item *next;
@@ -233,26 +324,10 @@ struct isis_tlvs {
        struct isis_item_list ipv6_reach;
        struct isis_mt_item_list mt_ipv6_reach;
        struct isis_threeway_adj *threeway_adj;
+       struct isis_router_cap *router_cap;
        struct isis_spine_leaf *spine_leaf;
 };
 
-#define ISIS_PREFIX_SID_READVERTISED  0x80
-#define ISIS_PREFIX_SID_NODE          0x40
-#define ISIS_PREFIX_SID_NO_PHP        0x20
-#define ISIS_PREFIX_SID_EXPLICIT_NULL 0x10
-#define ISIS_PREFIX_SID_VALUE         0x08
-#define ISIS_PREFIX_SID_LOCAL         0x04
-
-struct isis_prefix_sid;
-struct isis_prefix_sid {
-       struct isis_prefix_sid *next;
-
-       uint8_t flags;
-       uint8_t algorithm;
-
-       uint32_t value;
-};
-
 enum isis_tlv_context {
        ISIS_CONTEXT_LSP,
        ISIS_CONTEXT_SUBTLV_NE_REACH,
@@ -266,11 +341,12 @@ struct isis_subtlvs {
 
        /* draft-baker-ipv6-isis-dst-src-routing-06 */
        struct prefix_ipv6 *source_prefix;
-       /* draft-ietf-isis-segment-routing-extensions-16 */
+       /* draft-ietf-isis-segment-routing-extensions-25 */
        struct isis_item_list prefix_sids;
 };
 
 enum isis_tlv_type {
+       /* TLVs code point */
        ISIS_TLV_AREA_ADDRESSES = 1,
        ISIS_TLV_OLDSTYLE_REACH = 2,
        ISIS_TLV_LAN_NEIGHBORS = 6,
@@ -295,10 +371,149 @@ enum isis_tlv_type {
        ISIS_TLV_IPV6_REACH = 236,
        ISIS_TLV_MT_IPV6_REACH = 237,
        ISIS_TLV_THREE_WAY_ADJ = 240,
+       ISIS_TLV_ROUTER_CAPABILITY = 242,
        ISIS_TLV_MAX = 256,
 
+       /* subTLVs code point */
+       ISIS_SUBTLV_IPV6_SOURCE_PREFIX = 22,
+
+       /* RFC 5305 & RFC 6119 */
+       ISIS_SUBTLV_ADMIN_GRP = 3,
+       ISIS_SUBTLV_LOCAL_IPADDR = 6,
+       ISIS_SUBTLV_RMT_IPADDR = 8,
+       ISIS_SUBTLV_MAX_BW = 9,
+       ISIS_SUBTLV_MAX_RSV_BW = 10,
+       ISIS_SUBTLV_UNRSV_BW = 11,
+       ISIS_SUBTLV_LOCAL_IPADDR6 = 12,
+       ISIS_SUBTLV_RMT_IPADDR6 = 13,
+       ISIS_SUBTLV_TE_METRIC = 18,
+
+       /* RFC 5307 */
+       ISIS_SUBTLV_LLRI = 4,
+
+       /* RFC 5316 */
+       ISIS_SUBTLV_RAS = 24,
+       ISIS_SUBTLV_RIP = 25,
+
+       /* draft-isis-segment-routing-extension-25 */
+       ISIS_SUBTLV_SID_LABEL = 1,
+       ISIS_SUBTLV_SID_LABEL_RANGE = 2,
+       ISIS_SUBTLV_ALGORITHM = 19,
+       ISIS_SUBTLV_NODE_MSD = 23,
        ISIS_SUBTLV_PREFIX_SID = 3,
-       ISIS_SUBTLV_IPV6_SOURCE_PREFIX = 22
+       ISIS_SUBTLV_ADJ_SID = 31,
+       ISIS_SUBTLV_LAN_ADJ_SID = 32,
+
+       /* RFC 7810 */
+       ISIS_SUBTLV_AV_DELAY = 33,
+       ISIS_SUBTLV_MM_DELAY = 34,
+       ISIS_SUBTLV_DELAY_VAR = 35,
+       ISIS_SUBTLV_PKT_LOSS = 36,
+       ISIS_SUBTLV_RES_BW = 37,
+       ISIS_SUBTLV_AVA_BW = 38,
+       ISIS_SUBTLV_USE_BW = 39,
+
+       ISIS_SUBTLV_MAX = 40
+};
+
+/* subTLVs size for TE and SR */
+enum ext_subtlv_size {
+       ISIS_SUBTLV_LLRI_SIZE = 8,
+
+       ISIS_SUBTLV_UNRSV_BW_SIZE = 32,
+       ISIS_SUBTLV_TE_METRIC_SIZE = 3,
+       ISIS_SUBTLV_IPV6_ADDR_SIZE = 16,
+
+       /* draft-isis-segment-routing-extension-25 */
+       ISIS_SUBTLV_SID_LABEL_SIZE = 3,
+       ISIS_SUBTLV_SID_LABEL_RANGE_SIZE = 9,
+       ISIS_SUBTLV_ALGORITHM_SIZE = 4,
+       ISIS_SUBTLV_NODE_MSD_SIZE = 2,
+       ISIS_SUBTLV_ADJ_SID_SIZE = 5,
+       ISIS_SUBTLV_LAN_ADJ_SID_SIZE = 11,
+       ISIS_SUBTLV_PREFIX_SID_SIZE = 5,
+
+       ISIS_SUBTLV_MM_DELAY_SIZE = 8,
+
+       ISIS_SUBTLV_HDR_SIZE = 2,
+       ISIS_SUBTLV_DEF_SIZE = 4,
+
+       ISIS_SUBTLV_MAX_SIZE = 180
+};
+
+/* Macros to manage the optional presence of EXT subTLVs */
+#define SET_SUBTLV(s, t) ((s->status) |= (t))
+#define UNSET_SUBTLV(s, t) ((s->status) &= ~(t))
+#define IS_SUBTLV(s, t) (s->status & t)
+
+#define EXT_DISABLE            0x000000
+#define EXT_ADM_GRP            0x000001
+#define EXT_LLRI               0x000002
+#define EXT_LOCAL_ADDR         0x000004
+#define EXT_NEIGH_ADDR         0x000008
+#define EXT_LOCAL_ADDR6                0x000010
+#define EXT_NEIGH_ADDR6                0x000020
+#define EXT_MAX_BW             0x000040
+#define EXT_MAX_RSV_BW         0x000080
+#define EXT_UNRSV_BW           0x000100
+#define EXT_TE_METRIC          0x000200
+#define EXT_RMT_AS             0x000400
+#define EXT_RMT_IP             0x000800
+#define EXT_ADJ_SID            0x001000
+#define EXT_LAN_ADJ_SID                0x002000
+#define EXT_DELAY              0x004000
+#define EXT_MM_DELAY           0x008000
+#define EXT_DELAY_VAR          0x010000
+#define EXT_PKT_LOSS           0x020000
+#define EXT_RES_BW             0x040000
+#define EXT_AVA_BW             0x080000
+#define EXT_USE_BW             0x100000
+
+/*
+ * This structure groups all Extended IS Reachability subTLVs.
+ *
+ * Each bit of the status field indicates if a subTLVs is valid or not.
+ * SubTLVs values use following units:
+ *  - Bandwidth in bytes/sec following IEEE format,
+ *  - Delay in micro-seconds with only 24 bits significant
+ *  - Packet Loss in percentage of total traffic with only 24 bits (2^24 - 2)
+ *
+ * For Delay and packet Loss, upper bit (A) indicates if the value is
+ * normal (0) or anomalous (1).
+ */
+#define IS_ANORMAL(v) (v & 0x80000000)
+
+struct isis_ext_subtlvs {
+
+       uint32_t status;
+
+       uint32_t adm_group; /* Resource Class/Color - RFC 5305 */
+       /* Link Local/Remote Identifiers - RFC 5307 */
+       uint32_t local_llri;
+       uint32_t remote_llri;
+       struct in_addr local_addr; /* Local IP Address - RFC 5305 */
+       struct in_addr neigh_addr; /* Neighbor IP Address - RFC 5305 */
+       struct in6_addr local_addr6; /* Local IPv6 Address - RFC 6119 */
+       struct in6_addr neigh_addr6; /* Neighbor IPv6 Address - RFC 6119 */
+       float max_bw; /* Maximum Bandwidth - RFC 5305 */
+       float max_rsv_bw; /* Maximum Reservable Bandwidth - RFC 5305 */
+       float unrsv_bw[8]; /* Unreserved Bandwidth - RFC 5305 */
+       uint32_t te_metric; /* Traffic Engineering Metric - RFC 5305 */
+       uint32_t remote_as; /* Remote AS Number sub-TLV - RFC5316 */
+       struct in_addr remote_ip; /* IPv4 Remote ASBR ID Sub-TLV - RFC5316 */
+
+       uint32_t delay; /* Average Link Delay  - RFC 8570 */
+       uint32_t min_delay; /* Low Link Delay  - RFC 8570 */
+       uint32_t max_delay; /* High Link Delay  - RFC 8570 */
+       uint32_t delay_var; /* Link Delay Variation i.e. Jitter - RFC 8570 */
+       uint32_t pkt_loss; /* Unidirectional Link Packet Loss - RFC 8570 */
+       float res_bw; /* Unidirectional Residual Bandwidth - RFC 8570 */
+       float ava_bw; /* Unidirectional Available Bandwidth - RFC 8570 */
+       float use_bw; /* Unidirectional Utilized Bandwidth - RFC 8570 */
+
+       /* Segment Routing Adjacency & LAN Adjacency Segment ID */
+       struct isis_item_list adj_sid;
+       struct isis_item_list lan_sid;
 };
 
 #define IS_COMPAT_MT_TLV(tlv_type)                                             \
@@ -329,7 +544,6 @@ struct list *isis_fragment_tlvs(struct isis_tlvs *tlvs, size_t size);
 #define ISIS_MT_AT_MASK        0x4000
 #endif
 
-
 void isis_tlvs_add_auth(struct isis_tlvs *tlvs, struct isis_passwd *passwd);
 void isis_tlvs_add_area_addresses(struct isis_tlvs *tlvs,
                                  struct list *addresses);
@@ -359,6 +573,8 @@ void isis_tlvs_add_csnp_entries(struct isis_tlvs *tlvs, uint8_t *start_id,
                                struct isis_lsp **last_lsp);
 void isis_tlvs_set_dynamic_hostname(struct isis_tlvs *tlvs,
                                    const char *hostname);
+void isis_tlvs_set_router_capability(struct isis_tlvs *tlvs,
+                     const struct isis_router_cap *cap);
 void isis_tlvs_set_te_router_id(struct isis_tlvs *tlvs,
                                const struct in_addr *id);
 void isis_tlvs_add_oldstyle_ip_reach(struct isis_tlvs *tlvs,
@@ -371,11 +587,21 @@ void isis_tlvs_add_ipv6_dstsrc_reach(struct isis_tlvs *tlvs, uint16_t mtid,
                                     struct prefix_ipv6 *dest,
                                     struct prefix_ipv6 *src,
                                     uint32_t metric);
+struct isis_ext_subtlvs *isis_alloc_ext_subtlvs(void);
+void isis_tlvs_add_adj_sid(struct isis_ext_subtlvs *exts,
+                          struct isis_adj_sid *adj);
+void isis_tlvs_del_adj_sid(struct isis_ext_subtlvs *exts,
+                          struct isis_adj_sid *adj);
+void isis_tlvs_add_lan_adj_sid(struct isis_ext_subtlvs *exts,
+                              struct isis_lan_adj_sid *lan);
+void isis_tlvs_del_lan_adj_sid(struct isis_ext_subtlvs *exts,
+                              struct isis_lan_adj_sid *lan);
+
 void isis_tlvs_add_oldstyle_reach(struct isis_tlvs *tlvs, uint8_t *id,
                                  uint8_t metric);
 void isis_tlvs_add_extended_reach(struct isis_tlvs *tlvs, uint16_t mtid,
                                  uint8_t *id, uint32_t metric,
-                                 uint8_t *subtlvs, uint8_t subtlv_len);
+                                 struct isis_ext_subtlvs *subtlvs);
 
 const char *isis_threeway_state_name(enum isis_threeway_state state);
 
index e8481a558b430514cd1ca9eb293beb7d1308055e..39a2f6ef3502de674fe85e87cd8801c05ca863bd 100644 (file)
@@ -53,6 +53,8 @@
 
 struct zclient *zclient = NULL;
 
+DEFINE_HOOK(isis_if_new_hook, (struct interface *ifp), (ifp))
+
 /* Router-id update message from zebra. */
 static int isis_router_id_update_zebra(ZAPI_CALLBACK_ARGS)
 {
@@ -82,6 +84,8 @@ static int isis_zebra_if_add(ZAPI_CALLBACK_ARGS)
                isis_csm_state_change(IF_UP_FROM_Z, circuit_scan_by_ifp(ifp),
                                      ifp);
 
+       hook_call(isis_if_new_hook, ifp);
+
        return 0;
 }
 
@@ -219,9 +223,9 @@ static int isis_zebra_link_params(ZAPI_CALLBACK_ARGS)
        return 0;
 }
 
-static void isis_zebra_route_add_route(struct prefix *prefix,
-                                      struct prefix_ipv6 *src_p,
-                                      struct isis_route_info *route_info)
+void isis_zebra_route_add_route(struct prefix *prefix,
+                               struct prefix_ipv6 *src_p,
+                               struct isis_route_info *route_info)
 {
        struct zapi_route api;
        struct zapi_nexthop *api_nh;
@@ -229,7 +233,7 @@ static void isis_zebra_route_add_route(struct prefix *prefix,
        struct listnode *node;
        int count = 0;
 
-       if (CHECK_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED))
+       if (zclient->sock < 0)
                return;
 
        memset(&api, 0, sizeof(api));
@@ -292,17 +296,15 @@ static void isis_zebra_route_add_route(struct prefix *prefix,
        api.nexthop_num = count;
 
        zclient_route_send(ZEBRA_ROUTE_ADD, zclient, &api);
-       SET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
-       UNSET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC);
 }
 
-static void isis_zebra_route_del_route(struct prefix *prefix,
-                                      struct prefix_ipv6 *src_p,
-                                      struct isis_route_info *route_info)
+void isis_zebra_route_del_route(struct prefix *prefix,
+                               struct prefix_ipv6 *src_p,
+                               struct isis_route_info *route_info)
 {
        struct zapi_route api;
 
-       if (!CHECK_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED))
+       if (zclient->sock < 0)
                return;
 
        memset(&api, 0, sizeof(api));
@@ -316,20 +318,6 @@ static void isis_zebra_route_del_route(struct prefix *prefix,
        }
 
        zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api);
-       UNSET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
-}
-
-void isis_zebra_route_update(struct prefix *prefix,
-                            struct prefix_ipv6 *src_p,
-                            struct isis_route_info *route_info)
-{
-       if (zclient->sock < 0)
-               return;
-
-       if (CHECK_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ACTIVE))
-               isis_zebra_route_add_route(prefix, src_p, route_info);
-       else
-               isis_zebra_route_del_route(prefix, src_p, route_info);
 }
 
 static int isis_zebra_read(ZAPI_CALLBACK_ARGS)
index 20c10d0b2372936119f253a61387104b3515340e..83a32108eb13c74b642cc585b58b888df2845d5b 100644 (file)
 
 extern struct zclient *zclient;
 
+DECLARE_HOOK(isis_if_new_hook, (struct interface *ifp), (ifp));
+
 void isis_zebra_init(struct thread_master *);
 void isis_zebra_stop(void);
 
 struct isis_route_info;
 
-void isis_zebra_route_update(struct prefix *prefix,
-                            struct prefix_ipv6 *src_p,
-                            struct isis_route_info *route_info);
+void isis_zebra_route_add_route(struct prefix *prefix,
+                               struct prefix_ipv6 *src_p,
+                               struct isis_route_info *route_info);
+void isis_zebra_route_del_route(struct prefix *prefix,
+                               struct prefix_ipv6 *src_p,
+                               struct isis_route_info *route_info);
 int isis_distribute_list_update(int routetype);
 void isis_zebra_redistribute_set(afi_t afi, int type);
 void isis_zebra_redistribute_unset(afi_t afi, int type);
index 393b1d67c7c7d9bd6e18dbb741cf72cc096b823c..308f018c1928c7fdafc6e1a8b18bef0127cd5822 100644 (file)
@@ -58,7 +58,6 @@ extern struct zebra_privs_t isisd_privs;
 
 /* uncomment if you are a developer in bug hunt */
 /* #define EXTREME_DEBUG  */
-/* #define EXTREME_DICT_DEBUG */
 
 struct fabricd;
 
index 7f2e396a7f5c849f9e41bf51133eac3bbcd076a0..b234e3ebe34f1ba3f78c8de03fd957fca911a031 100644 (file)
@@ -249,7 +249,7 @@ l2vpn_pw_init(struct l2vpn_pw *pw)
 
        l2vpn_pw_fec(pw, &fec);
        lde_kernel_insert(&fec, AF_INET, (union ldpd_addr*)&pw->lsr_id, 0, 0,
-           0, (void *)pw);
+           0, 0, (void *)pw);
        lde_kernel_update(&fec);
 }
 
@@ -260,7 +260,7 @@ l2vpn_pw_exit(struct l2vpn_pw *pw)
        struct zapi_pw   zpw;
 
        l2vpn_pw_fec(pw, &fec);
-       lde_kernel_remove(&fec, AF_INET, (union ldpd_addr*)&pw->lsr_id, 0, 0);
+       lde_kernel_remove(&fec, AF_INET, (union ldpd_addr*)&pw->lsr_id, 0, 0, 0);
        lde_kernel_update(&fec);
 
        pw2zpw(pw, &zpw);
@@ -433,7 +433,7 @@ l2vpn_recv_pw_status(struct lde_nbr *ln, struct notify_msg *nm)
        if (pw == NULL)
                return;
 
-       fnh = fec_nh_find(fn, AF_INET, (union ldpd_addr *)&ln->id, 0, 0);
+       fnh = fec_nh_find(fn, AF_INET, (union ldpd_addr *)&ln->id, 0, 0, 0);
        if (fnh == NULL)
                return;
 
@@ -482,7 +482,7 @@ l2vpn_recv_pw_status_wcard(struct lde_nbr *ln, struct notify_msg *nm)
                }
 
                fnh = fec_nh_find(fn, AF_INET, (union ldpd_addr *)&ln->id,
-                   0, 0);
+                   0, 0, 0);
                if (fnh == NULL)
                        continue;
 
index ac680b47a93230b1a7d88fffc2195a2c12dbe7ec..006d27f6abb873fbd6a1afee0c001b1b8bc0af77 100644 (file)
@@ -520,7 +520,8 @@ lde_dispatch_parent(struct thread *thread)
                        switch (imsg.hdr.type) {
                        case IMSG_NETWORK_ADD:
                                lde_kernel_insert(&fec, kr->af, &kr->nexthop,
-                                   kr->ifindex, kr->priority,
+                                   kr->ifindex, kr->route_type,
+                                   kr->route_instance,
                                    kr->flags & F_CONNECTED, NULL);
                                break;
                        case IMSG_NETWORK_UPDATE:
@@ -747,7 +748,8 @@ lde_send_change_klabel(struct fec_node *fn, struct fec_nh *fnh)
                kr.ifindex = fnh->ifindex;
                kr.local_label = fn->local_label;
                kr.remote_label = fnh->remote_label;
-               kr.priority = fnh->priority;
+               kr.route_type = fnh->route_type;
+               kr.route_instance = fnh->route_instance;
 
                lde_imsg_compose_parent(IMSG_KLABEL_CHANGE, 0, &kr,
                    sizeof(kr));
@@ -761,7 +763,8 @@ lde_send_change_klabel(struct fec_node *fn, struct fec_nh *fnh)
                kr.ifindex = fnh->ifindex;
                kr.local_label = fn->local_label;
                kr.remote_label = fnh->remote_label;
-               kr.priority = fnh->priority;
+               kr.route_type = fnh->route_type;
+               kr.route_instance = fnh->route_instance;
 
                lde_imsg_compose_parent(IMSG_KLABEL_CHANGE, 0, &kr,
                    sizeof(kr));
@@ -798,7 +801,8 @@ lde_send_delete_klabel(struct fec_node *fn, struct fec_nh *fnh)
                kr.ifindex = fnh->ifindex;
                kr.local_label = fn->local_label;
                kr.remote_label = fnh->remote_label;
-               kr.priority = fnh->priority;
+               kr.route_type = fnh->route_type;
+               kr.route_instance = fnh->route_instance;
 
                lde_imsg_compose_parent(IMSG_KLABEL_DELETE, 0, &kr,
                    sizeof(kr));
@@ -812,7 +816,8 @@ lde_send_delete_klabel(struct fec_node *fn, struct fec_nh *fnh)
                kr.ifindex = fnh->ifindex;
                kr.local_label = fn->local_label;
                kr.remote_label = fnh->remote_label;
-               kr.priority = fnh->priority;
+               kr.route_type = fnh->route_type;
+               kr.route_instance = fnh->route_instance;
 
                lde_imsg_compose_parent(IMSG_KLABEL_DELETE, 0, &kr,
                    sizeof(kr));
index 0a7d0a58fe4a1b62f1ac7f886bf75f198e70db00..ce466c16b9cd2266c70a87a15e63595f1bab9857 100644 (file)
@@ -108,7 +108,8 @@ struct fec_nh {
        union ldpd_addr          nexthop;
        ifindex_t                ifindex;
        uint32_t                 remote_label;
-       uint8_t                  priority;
+       uint8_t                  route_type;
+       unsigned short           route_instance;
        uint8_t                  flags;
 };
 #define F_FEC_NH_NEW           0x01
@@ -193,11 +194,11 @@ void               rt_dump(pid_t);
 void            fec_snap(struct lde_nbr *);
 void            fec_tree_clear(void);
 struct fec_nh  *fec_nh_find(struct fec_node *, int, union ldpd_addr *,
-                   ifindex_t, uint8_t);
+                   ifindex_t, uint8_t, unsigned short);
 void            lde_kernel_insert(struct fec *, int, union ldpd_addr *,
-                   ifindex_t, uint8_t, int, void *);
+                   ifindex_t, uint8_t, unsigned short, int, void *);
 void            lde_kernel_remove(struct fec *, int, union ldpd_addr *,
-                   ifindex_t, uint8_t);
+                   ifindex_t, uint8_t, unsigned short);
 void            lde_kernel_update(struct fec *);
 void            lde_check_mapping(struct map *, struct lde_nbr *);
 void            lde_check_request(struct map *, struct lde_nbr *);
index 0957a5455e3dfc99db93c59eba0c48a9154c1de9..eb1a6d94349bb0c42de9148945c67ad9d2091866 100644 (file)
@@ -31,7 +31,7 @@ static int             lde_nbr_is_nexthop(struct fec_node *,
 static void             fec_free(void *);
 static struct fec_node *fec_add(struct fec *fec);
 static struct fec_nh   *fec_nh_add(struct fec_node *, int, union ldpd_addr *,
-                           ifindex_t, uint8_t);
+                           ifindex_t, uint8_t, unsigned short);
 static void             fec_nh_del(struct fec_nh *);
 
 RB_GENERATE(fec_tree, fec, entry, fec_compare)
@@ -275,7 +275,7 @@ fec_add(struct fec *fec)
 
 struct fec_nh *
 fec_nh_find(struct fec_node *fn, int af, union ldpd_addr *nexthop,
-    ifindex_t ifindex, uint8_t priority)
+    ifindex_t ifindex, uint8_t route_type, unsigned short route_instance)
 {
        struct fec_nh   *fnh;
 
@@ -283,7 +283,8 @@ fec_nh_find(struct fec_node *fn, int af, union ldpd_addr *nexthop,
                if (fnh->af == af &&
                    ldp_addrcmp(af, &fnh->nexthop, nexthop) == 0 &&
                    fnh->ifindex == ifindex &&
-                   fnh->priority == priority)
+                   fnh->route_type == route_type &&
+                   fnh->route_instance == route_instance)
                        return (fnh);
 
        return (NULL);
@@ -291,7 +292,7 @@ fec_nh_find(struct fec_node *fn, int af, union ldpd_addr *nexthop,
 
 static struct fec_nh *
 fec_nh_add(struct fec_node *fn, int af, union ldpd_addr *nexthop,
-    ifindex_t ifindex, uint8_t priority)
+    ifindex_t ifindex, uint8_t route_type, unsigned short route_instance)
 {
        struct fec_nh   *fnh;
 
@@ -303,7 +304,8 @@ fec_nh_add(struct fec_node *fn, int af, union ldpd_addr *nexthop,
        fnh->nexthop = *nexthop;
        fnh->ifindex = ifindex;
        fnh->remote_label = NO_LABEL;
-       fnh->priority = priority;
+       fnh->route_type = route_type;
+       fnh->route_instance = route_instance;
        LIST_INSERT_HEAD(&fn->nexthops, fnh, entry);
 
        return (fnh);
@@ -318,7 +320,8 @@ fec_nh_del(struct fec_nh *fnh)
 
 void
 lde_kernel_insert(struct fec *fec, int af, union ldpd_addr *nexthop,
-    ifindex_t ifindex, uint8_t priority, int connected, void *data)
+    ifindex_t ifindex, uint8_t route_type, unsigned short route_instance,
+    int connected, void *data)
 {
        struct fec_node         *fn;
        struct fec_nh           *fnh;
@@ -329,9 +332,10 @@ lde_kernel_insert(struct fec *fec, int af, union ldpd_addr *nexthop,
        if (data)
                fn->data = data;
 
-       fnh = fec_nh_find(fn, af, nexthop, ifindex, priority);
+       fnh = fec_nh_find(fn, af, nexthop, ifindex, route_type, route_instance);
        if (fnh == NULL)
-               fnh = fec_nh_add(fn, af, nexthop, ifindex, priority);
+               fnh = fec_nh_add(fn, af, nexthop, ifindex, route_type,
+                   route_instance);
        fnh->flags |= F_FEC_NH_NEW;
        if (connected)
                fnh->flags |= F_FEC_NH_CONNECTED;
@@ -339,7 +343,7 @@ lde_kernel_insert(struct fec *fec, int af, union ldpd_addr *nexthop,
 
 void
 lde_kernel_remove(struct fec *fec, int af, union ldpd_addr *nexthop,
-    ifindex_t ifindex, uint8_t priority)
+    ifindex_t ifindex, uint8_t route_type, unsigned short route_instance)
 {
        struct fec_node         *fn;
        struct fec_nh           *fnh;
@@ -348,7 +352,7 @@ lde_kernel_remove(struct fec *fec, int af, union ldpd_addr *nexthop,
        if (fn == NULL)
                /* route lost */
                return;
-       fnh = fec_nh_find(fn, af, nexthop, ifindex, priority);
+       fnh = fec_nh_find(fn, af, nexthop, ifindex, route_type, route_instance);
        if (fnh == NULL)
                /* route lost */
                return;
index 35a7d944d30c66d9dc77e55d87acbe851bc9c56c..884ae159be437b7c4062bbc099fd62b10e69c9f5 100644 (file)
@@ -37,7 +37,7 @@
 static void     ifp2kif(struct interface *, struct kif *);
 static void     ifc2kaddr(struct interface *, struct connected *,
                    struct kaddr *);
-static int      zebra_send_mpls_labels(int, struct kroute *);
+static int      ldp_zebra_send_mpls_labels(int, struct kroute *);
 static int      ldp_router_id_update(ZAPI_CALLBACK_ARGS);
 static int      ldp_interface_add(ZAPI_CALLBACK_ARGS);
 static int      ldp_interface_delete(ZAPI_CALLBACK_ARGS);
@@ -106,9 +106,10 @@ pw2zpw(struct l2vpn_pw *pw, struct zapi_pw *zpw)
 }
 
 static int
-zebra_send_mpls_labels(int cmd, struct kroute *kr)
+ldp_zebra_send_mpls_labels(int cmd, struct kroute *kr)
 {
-       struct stream           *s;
+       struct zapi_labels zl = {};
+       struct zapi_nexthop_label *znh;
 
        if (kr->local_label < MPLS_LABEL_RESERVED_MAX ||
            kr->remote_label == NO_LABEL)
@@ -120,48 +121,65 @@ zebra_send_mpls_labels(int cmd, struct kroute *kr)
            log_label(kr->local_label), log_label(kr->remote_label),
            (cmd == ZEBRA_MPLS_LABELS_ADD) ? "add" : "delete");
 
-       /* Reset stream. */
-       s = zclient->obuf;
-       stream_reset(s);
+       zl.type = ZEBRA_LSP_LDP;
+       zl.local_label = kr->local_label;
 
-       zclient_create_header(s, cmd, VRF_DEFAULT);
-       stream_putc(s, ZEBRA_LSP_LDP);
-       stream_putl(s, kr->af);
+       /* Set prefix. */
+       SET_FLAG(zl.message, ZAPI_LABELS_FTN);
+       zl.route.prefix.family = kr->af;
        switch (kr->af) {
        case AF_INET:
-               stream_put_in_addr(s, &kr->prefix.v4);
-               stream_putc(s, kr->prefixlen);
-               stream_put_in_addr(s, &kr->nexthop.v4);
+               zl.route.prefix.u.prefix4 = kr->prefix.v4;
                break;
        case AF_INET6:
-               stream_write(s, (uint8_t *)&kr->prefix.v6, 16);
-               stream_putc(s, kr->prefixlen);
-               stream_write(s, (uint8_t *)&kr->nexthop.v6, 16);
+               zl.route.prefix.u.prefix6 = kr->prefix.v6;
                break;
        default:
-               fatalx("kr_change: unknown af");
+               fatalx("ldp_zebra_send_mpls_labels: unknown af");
        }
-       stream_putl(s, kr->ifindex);
-       stream_putc(s, kr->priority);
-       stream_putl(s, kr->local_label);
-       stream_putl(s, kr->remote_label);
+       zl.route.prefix.prefixlen = kr->prefixlen;
+       zl.route.type = kr->route_type;
+       zl.route.instance = kr->route_instance;
 
-       /* Put length at the first point of the stream. */
-       stream_putw_at(s, 0, stream_get_endp(s));
+       /* Set nexthop. */
+       zl.nexthop_num = 1;
+       znh = &zl.nexthops[0];
+       switch (kr->af) {
+       case AF_INET:
+               znh->family = AF_INET;
+               znh->address.ipv4 = kr->nexthop.v4;
+               if (kr->ifindex)
+                       znh->type = NEXTHOP_TYPE_IPV4_IFINDEX;
+               else
+                       znh->type = NEXTHOP_TYPE_IPV4;
+               break;
+       case AF_INET6:
+               znh->family = AF_INET6;
+               znh->address.ipv6 = kr->nexthop.v6;
+               if (kr->ifindex)
+                       znh->type = NEXTHOP_TYPE_IPV6_IFINDEX;
+               else
+                       znh->type = NEXTHOP_TYPE_IPV6;
+               break;
+       default:
+               break;
+       }
+       znh->ifindex = kr->ifindex;
+       znh->label = kr->remote_label;
 
-       return (zclient_send_message(zclient));
+       return zebra_send_mpls_labels(zclient, cmd, &zl);
 }
 
 int
 kr_change(struct kroute *kr)
 {
-       return (zebra_send_mpls_labels(ZEBRA_MPLS_LABELS_ADD, kr));
+       return (ldp_zebra_send_mpls_labels(ZEBRA_MPLS_LABELS_ADD, kr));
 }
 
 int
 kr_delete(struct kroute *kr)
 {
-       return (zebra_send_mpls_labels(ZEBRA_MPLS_LABELS_DELETE, kr));
+       return (ldp_zebra_send_mpls_labels(ZEBRA_MPLS_LABELS_DELETE, kr));
 }
 
 int
@@ -407,7 +425,8 @@ ldp_zebra_read_route(ZAPI_CALLBACK_ARGS)
                break;
        }
        kr.prefixlen = api.prefix.prefixlen;
-       kr.priority = api.distance;
+       kr.route_type = api.type;
+       kr.route_instance = api.instance;
 
        switch (api.type) {
        case ZEBRA_ROUTE_CONNECT:
index 91135055817fa1cb8b477383b554bfe2ef1c1888..bd7562e5ad5b16b070a778a2165615d59eb1e4b0 100644 (file)
@@ -543,7 +543,8 @@ struct kroute {
        uint32_t                 local_label;
        uint32_t                 remote_label;
        unsigned short           ifindex;
-       uint8_t                  priority;
+       uint8_t                  route_type;
+       uint8_t                  route_instance;
        uint16_t                 flags;
 };
 
index eecca2a5f54dd0b7b30e28e1ffe732b0c507e778..04f2bd95a08177e4789f0a32869181f35e1fb8ae 100644 (file)
@@ -1718,16 +1718,12 @@ static int vty_write_config(struct vty *vty)
        vty_out(vty, "frr defaults %s\n", DFLT_NAME);
        vty_out(vty, "!\n");
 
-       pthread_rwlock_rdlock(&running_config->lock);
-       {
-               for (i = 0; i < vector_active(cmdvec); i++)
-                       if ((node = vector_slot(cmdvec, i)) && node->func
-                           && (node->vtysh || vty->type != VTY_SHELL)) {
-                               if ((*node->func)(vty))
-                                       vty_out(vty, "!\n");
-                       }
-       }
-       pthread_rwlock_unlock(&running_config->lock);
+       for (i = 0; i < vector_active(cmdvec); i++)
+               if ((node = vector_slot(cmdvec, i)) && node->func
+                   && (node->vtysh || vty->type != VTY_SHELL)) {
+                       if ((*node->func)(vty))
+                               vty_out(vty, "!\n");
+               }
 
        if (vty->type == VTY_TERM) {
                vty_out(vty, "end\n");
index 21dfc9256ff9fd7708062b51d4f0c3af829166b1..5c71fac10a332deb52f1cfa3cb4a09d4d983801a 100644 (file)
@@ -35,6 +35,9 @@ DEFINE_MTYPE_STATIC(LIB, PTHREAD_PRIM, "POSIX sync primitives")
 static void *fpt_run(void *arg);
 static int fpt_halt(struct frr_pthread *fpt, void **res);
 
+/* misc sigs */
+static void frr_pthread_destroy_nolock(struct frr_pthread *fpt);
+
 /* default frr_pthread attributes */
 struct frr_pthread_attr frr_pthread_attr_default = {
        .start = fpt_run,
@@ -51,13 +54,22 @@ void frr_pthread_init(void)
 {
        frr_with_mutex(&frr_pthread_list_mtx) {
                frr_pthread_list = list_new();
-               frr_pthread_list->del = (void (*)(void *))&frr_pthread_destroy;
        }
 }
 
 void frr_pthread_finish(void)
 {
+       frr_pthread_stop_all();
+
        frr_with_mutex(&frr_pthread_list_mtx) {
+               struct listnode *n, *nn;
+               struct frr_pthread *fpt;
+
+               for (ALL_LIST_ELEMENTS(frr_pthread_list, n, nn, fpt)) {
+                       listnode_delete(frr_pthread_list, fpt);
+                       frr_pthread_destroy_nolock(fpt);
+               }
+
                list_delete(&frr_pthread_list);
        }
 }
@@ -97,10 +109,9 @@ struct frr_pthread *frr_pthread_new(struct frr_pthread_attr *attr,
        return fpt;
 }
 
-void frr_pthread_destroy(struct frr_pthread *fpt)
+static void frr_pthread_destroy_nolock(struct frr_pthread *fpt)
 {
        thread_master_free(fpt->master);
-
        pthread_mutex_destroy(&fpt->mtx);
        pthread_mutex_destroy(fpt->running_cond_mtx);
        pthread_cond_destroy(fpt->running_cond);
@@ -110,6 +121,15 @@ void frr_pthread_destroy(struct frr_pthread *fpt)
        XFREE(MTYPE_FRR_PTHREAD, fpt);
 }
 
+void frr_pthread_destroy(struct frr_pthread *fpt)
+{
+       frr_with_mutex(&frr_pthread_list_mtx) {
+               listnode_delete(frr_pthread_list, fpt);
+       }
+
+       frr_pthread_destroy_nolock(fpt);
+}
+
 int frr_pthread_set_name(struct frr_pthread *fpt)
 {
        int ret = 0;
@@ -183,8 +203,11 @@ void frr_pthread_stop_all(void)
        frr_with_mutex(&frr_pthread_list_mtx) {
                struct listnode *n;
                struct frr_pthread *fpt;
-               for (ALL_LIST_ELEMENTS_RO(frr_pthread_list, n, fpt))
-                       frr_pthread_stop(fpt, NULL);
+               for (ALL_LIST_ELEMENTS_RO(frr_pthread_list, n, fpt)) {
+                       if (atomic_load_explicit(&fpt->running,
+                                                memory_order_relaxed))
+                               frr_pthread_stop(fpt, NULL);
+               }
        }
 }
 
index 5f92327562e490a18af3807a675b57acd4986f1b..1e34ff4b847c47a899b91409fbb9aa5caaebec98 100644 (file)
--- a/lib/if.c
+++ b/lib/if.c
@@ -207,21 +207,18 @@ void if_update_to_new_vrf(struct interface *ifp, vrf_id_t vrf_id)
        if (yang_module_find("frr-interface")) {
                struct lyd_node *if_dnode;
 
-               pthread_rwlock_wrlock(&running_config->lock);
-               {
-                       if_dnode = yang_dnode_get(
-                               running_config->dnode,
-                               "/frr-interface:lib/interface[name='%s'][vrf='%s']/vrf",
-                               ifp->name, old_vrf->name);
-                       if (if_dnode) {
-                               yang_dnode_change_leaf(if_dnode, vrf->name);
-                               running_config->version++;
-                       }
+               if_dnode = yang_dnode_get(
+                       running_config->dnode,
+                       "/frr-interface:lib/interface[name='%s'][vrf='%s']/vrf",
+                       ifp->name, old_vrf->name);
+               if (if_dnode) {
+                       yang_dnode_change_leaf(if_dnode, vrf->name);
+                       running_config->version++;
                }
-               pthread_rwlock_unlock(&running_config->lock);
        }
 }
 
+
 /* Delete interface structure. */
 void if_delete_retain(struct interface *ifp)
 {
@@ -1460,6 +1457,60 @@ static int lib_interface_destroy(enum nb_event event,
        return NB_OK;
 }
 
+/*
+ * XPath: /frr-interface:lib/interface
+ */
+static const void *lib_interface_get_next(const void *parent_list_entry,
+                                         const void *list_entry)
+{
+       struct vrf *vrf;
+       struct interface *pif = (struct interface *)list_entry;
+
+       if (list_entry == NULL) {
+               vrf = RB_MIN(vrf_name_head, &vrfs_by_name);
+               assert(vrf);
+               pif = RB_MIN(if_name_head, &vrf->ifaces_by_name);
+       } else {
+               vrf = vrf_lookup_by_id(pif->vrf_id);
+               pif = RB_NEXT(if_name_head, pif);
+               /* if no more interfaces, switch to next vrf */
+               while (pif == NULL) {
+                       vrf = RB_NEXT(vrf_name_head, vrf);
+                       if (!vrf)
+                               return NULL;
+                       pif = RB_MIN(if_name_head, &vrf->ifaces_by_name);
+               }
+       }
+
+       return pif;
+}
+
+static int lib_interface_get_keys(const void *list_entry,
+                                 struct yang_list_keys *keys)
+{
+       const struct interface *ifp = list_entry;
+
+       struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id);
+
+       assert(vrf);
+
+       keys->num = 2;
+       strlcpy(keys->key[0], ifp->name, sizeof(keys->key[0]));
+       strlcpy(keys->key[1], vrf->name, sizeof(keys->key[1]));
+
+       return NB_OK;
+}
+
+static const void *lib_interface_lookup_entry(const void *parent_list_entry,
+                                             const struct yang_list_keys *keys)
+{
+       const char *ifname = keys->key[0];
+       const char *vrfname = keys->key[1];
+       struct vrf *vrf = vrf_lookup_by_name(vrfname);
+
+       return if_lookup_by_name(ifname, vrf->vrf_id);
+}
+
 /*
  * XPath: /frr-interface:lib/interface/description
  */
@@ -1505,6 +1556,9 @@ const struct frr_yang_module_info frr_interface_info = {
                                .create = lib_interface_create,
                                .destroy = lib_interface_destroy,
                                .cli_show = cli_show_interface,
+                               .get_next = lib_interface_get_next,
+                               .get_keys = lib_interface_get_keys,
+                               .lookup_entry = lib_interface_lookup_entry,
                        },
                },
                {
index 4301dc20ad957c95661e6d67075df516f4ada59f..d4aa1f899a11bf6450999d85f7a13907b5ee478c 100644 (file)
@@ -42,6 +42,7 @@
 #include "northbound_db.h"
 #include "debug.h"
 #include "frrcu.h"
+#include "frr_pthread.h"
 
 DEFINE_HOOK(frr_late_init, (struct thread_master * tm), (tm))
 DEFINE_KOOH(frr_early_fini, (), ())
@@ -681,6 +682,8 @@ struct thread_master *frr_init(void)
        memory_init();
        log_filter_cmd_init();
 
+       frr_pthread_init();
+
        log_ref_init();
        log_ref_vty_init();
        lib_error_init();
@@ -865,12 +868,7 @@ static int frr_config_read_in(struct thread *t)
        /*
         * Update the shared candidate after reading the startup configuration.
         */
-       pthread_rwlock_rdlock(&running_config->lock);
-       {
-               nb_config_replace(vty_shared_candidate_config, running_config,
-                                 true);
-       }
-       pthread_rwlock_unlock(&running_config->lock);
+       nb_config_replace(vty_shared_candidate_config, running_config, true);
 
        return 0;
 }
@@ -1076,6 +1074,7 @@ void frr_fini(void)
        db_close();
 #endif
        log_ref_fini();
+       frr_pthread_finish();
        zprivs_terminate(di->privs);
        /* signal_init -> nothing needed */
        thread_master_free(master);
index f1c0fabfbab944a49eeb692d72dac1d20f239f3d..c77786873601024fec83ed7165a1c057aaae0e99 100644 (file)
--- a/lib/log.c
+++ b/lib/log.c
@@ -1041,6 +1041,7 @@ static const struct zebra_desc_table command_types[] = {
        DESC_ENTRY(ZEBRA_INTERFACE_LINK_PARAMS),
        DESC_ENTRY(ZEBRA_MPLS_LABELS_ADD),
        DESC_ENTRY(ZEBRA_MPLS_LABELS_DELETE),
+       DESC_ENTRY(ZEBRA_MPLS_LABELS_REPLACE),
        DESC_ENTRY(ZEBRA_IPMR_ROUTE_STATS),
        DESC_ENTRY(ZEBRA_LABEL_MANAGER_CONNECT),
        DESC_ENTRY(ZEBRA_LABEL_MANAGER_CONNECT_ASYNC),
index d7b56c47bd072267aafa6546fbf615f53e3289eb..635ecc77a1f962851c613bb63164f2dd85209ddf 100644 (file)
@@ -47,6 +47,7 @@ extern "C" {
 #define MPLS_LABEL_OAM_ALERT           14      /* [RFC3429] */
 #define MPLS_LABEL_EXTENSION           15      /* [RFC7274] */
 #define MPLS_LABEL_MAX                 1048575
+#define MPLS_LABEL_VALUE_MASK          0x000FFFFF
 #define MPLS_LABEL_NONE                0xFFFFFFFF /* for internal use only */
 
 /* Minimum and maximum label values */
@@ -125,7 +126,7 @@ enum lsp_types_t {
        ZEBRA_LSP_STATIC = 1, /* Static LSP. */
        ZEBRA_LSP_LDP = 2,    /* LDP LSP. */
        ZEBRA_LSP_BGP = 3,    /* BGP LSP. */
-       ZEBRA_LSP_SR = 4,     /* Segment Routing LSP. */
+       ZEBRA_LSP_OSPF_SR = 4,/* OSPF Segment Routing LSP. */
        ZEBRA_LSP_SHARP = 5,  /* Identifier for test protocol */
 };
 
index a814f23e14421d0b65a832d7fc4e5b33758c234a..1b332fb1e8bd692c59ebb7255afc96999a5ea99b 100644 (file)
@@ -64,6 +64,9 @@ static bool transaction_in_progress;
 
 static int nb_callback_configuration(const enum nb_event event,
                                     struct nb_config_change *change);
+static void nb_log_callback(const enum nb_event event,
+                           enum nb_operation operation, const char *xpath,
+                           const char *value);
 static struct nb_transaction *nb_transaction_new(struct nb_config *config,
                                                 struct nb_config_cbs *changes,
                                                 enum nb_client client,
@@ -180,7 +183,18 @@ static int nb_node_validate_cb(const struct nb_node *nb_node,
 
        valid = nb_operation_is_valid(operation, nb_node->snode);
 
-       if (!valid && callback_implemented)
+       /*
+        * Add an exception for operational data callbacks. A rw list usually
+        * doesn't need any associated operational data callbacks. But if this
+        * rw list is augmented by another module which adds state nodes under
+        * it, then this list will need to have the 'get_next()', 'get_keys()'
+        * and 'lookup_entry()' callbacks. As such, never log a warning when
+        * these callbacks are implemented when they are not needed, since this
+        * depends on context (e.g. some daemons might augment "frr-interface"
+        * while others don't).
+        */
+       if (!valid && callback_implemented && operation != NB_OP_GET_NEXT
+           && operation != NB_OP_GET_KEYS && operation != NB_OP_LOOKUP_ENTRY)
                flog_warn(EC_LIB_NB_CB_UNNEEDED,
                          "unneeded '%s' callback for '%s'",
                          nb_operation_name(operation), nb_node->xpath);
@@ -211,6 +225,8 @@ static unsigned int nb_node_validate_cbs(const struct nb_node *nb_node)
                                     !!nb_node->cbs.destroy, false);
        error += nb_node_validate_cb(nb_node, NB_OP_MOVE, !!nb_node->cbs.move,
                                     false);
+       error += nb_node_validate_cb(nb_node, NB_OP_PRE_VALIDATE,
+                                    !!nb_node->cbs.pre_validate, true);
        error += nb_node_validate_cb(nb_node, NB_OP_APPLY_FINISH,
                                     !!nb_node->cbs.apply_finish, true);
        error += nb_node_validate_cb(nb_node, NB_OP_GET_ELEM,
@@ -265,7 +281,6 @@ struct nb_config *nb_config_new(struct lyd_node *dnode)
        else
                config->dnode = yang_dnode_new(ly_native_ctx, true);
        config->version = 0;
-       pthread_rwlock_init(&config->lock, NULL);
 
        return config;
 }
@@ -274,7 +289,6 @@ void nb_config_free(struct nb_config *config)
 {
        if (config->dnode)
                yang_dnode_free(config->dnode);
-       pthread_rwlock_destroy(&config->lock);
        XFREE(MTYPE_NB_CONFIG, config);
 }
 
@@ -285,7 +299,6 @@ struct nb_config *nb_config_dup(const struct nb_config *config)
        dup = XCALLOC(MTYPE_NB_CONFIG, sizeof(*dup));
        dup->dnode = yang_dnode_dup(config->dnode);
        dup->version = config->version;
-       pthread_rwlock_init(&dup->lock, NULL);
 
        return dup;
 }
@@ -335,21 +348,23 @@ static inline int nb_config_cb_compare(const struct nb_config_cb *a,
                return 1;
 
        /*
-        * Use XPath as a tie-breaker. This will naturally sort parent nodes
-        * before their children.
+        * Preserve the order of the configuration changes as told by libyang.
         */
-       return strcmp(a->xpath, b->xpath);
+       return a->seq - b->seq;
 }
 RB_GENERATE(nb_config_cbs, nb_config_cb, entry, nb_config_cb_compare);
 
 static void nb_config_diff_add_change(struct nb_config_cbs *changes,
                                      enum nb_operation operation,
+                                     uint32_t *seq,
                                      const struct lyd_node *dnode)
 {
        struct nb_config_change *change;
 
        change = XCALLOC(MTYPE_TMP, sizeof(*change));
        change->cb.operation = operation;
+       change->cb.seq = *seq;
+       *seq = *seq + 1;
        change->cb.nb_node = dnode->schema->priv;
        yang_dnode_get_path(dnode, change->cb.xpath, sizeof(change->cb.xpath));
        change->cb.dnode = dnode;
@@ -374,7 +389,7 @@ static void nb_config_diff_del_changes(struct nb_config_cbs *changes)
  * configurations. Given a new subtree, calculate all new YANG data nodes,
  * excluding default leafs and leaf-lists. This is a recursive function.
  */
-static void nb_config_diff_created(const struct lyd_node *dnode,
+static void nb_config_diff_created(const struct lyd_node *dnode, uint32_t *seq,
                                   struct nb_config_cbs *changes)
 {
        enum nb_operation operation;
@@ -393,16 +408,17 @@ static void nb_config_diff_created(const struct lyd_node *dnode,
                else
                        return;
 
-               nb_config_diff_add_change(changes, operation, dnode);
+               nb_config_diff_add_change(changes, operation, seq, dnode);
                break;
        case LYS_CONTAINER:
        case LYS_LIST:
                if (nb_operation_is_valid(NB_OP_CREATE, dnode->schema))
-                       nb_config_diff_add_change(changes, NB_OP_CREATE, dnode);
+                       nb_config_diff_add_change(changes, NB_OP_CREATE, seq,
+                                                 dnode);
 
                /* Process child nodes recursively. */
                LY_TREE_FOR (dnode->child, child) {
-                       nb_config_diff_created(child, changes);
+                       nb_config_diff_created(child, seq, changes);
                }
                break;
        default:
@@ -410,11 +426,11 @@ static void nb_config_diff_created(const struct lyd_node *dnode,
        }
 }
 
-static void nb_config_diff_deleted(const struct lyd_node *dnode,
+static void nb_config_diff_deleted(const struct lyd_node *dnode, uint32_t *seq,
                                   struct nb_config_cbs *changes)
 {
        if (nb_operation_is_valid(NB_OP_DESTROY, dnode->schema))
-               nb_config_diff_add_change(changes, NB_OP_DESTROY, dnode);
+               nb_config_diff_add_change(changes, NB_OP_DESTROY, seq, dnode);
        else if (CHECK_FLAG(dnode->schema->nodetype, LYS_CONTAINER)) {
                struct lyd_node *child;
 
@@ -425,7 +441,7 @@ static void nb_config_diff_deleted(const struct lyd_node *dnode,
                 * when applicable (i.e. optional nodes).
                 */
                LY_TREE_FOR (dnode->child, child) {
-                       nb_config_diff_deleted(child, changes);
+                       nb_config_diff_deleted(child, seq, changes);
                }
        }
 }
@@ -436,6 +452,7 @@ static void nb_config_diff(const struct nb_config *config1,
                           struct nb_config_cbs *changes)
 {
        struct lyd_difflist *diff;
+       uint32_t seq = 0;
 
        diff = lyd_diff(config1->dnode, config2->dnode,
                        LYD_DIFFOPT_WITHDEFAULTS);
@@ -450,15 +467,16 @@ static void nb_config_diff(const struct nb_config *config1,
                switch (type) {
                case LYD_DIFF_CREATED:
                        dnode = diff->second[i];
-                       nb_config_diff_created(dnode, changes);
+                       nb_config_diff_created(dnode, &seq, changes);
                        break;
                case LYD_DIFF_DELETED:
                        dnode = diff->first[i];
-                       nb_config_diff_deleted(dnode, changes);
+                       nb_config_diff_deleted(dnode, &seq, changes);
                        break;
                case LYD_DIFF_CHANGED:
                        dnode = diff->second[i];
-                       nb_config_diff_add_change(changes, NB_OP_MODIFY, dnode);
+                       nb_config_diff_add_change(changes, NB_OP_MODIFY, &seq,
+                                                 dnode);
                        break;
                case LYD_DIFF_MOVEDAFTER1:
                case LYD_DIFF_MOVEDAFTER2:
@@ -535,28 +553,17 @@ int nb_candidate_edit(struct nb_config *candidate,
 
 bool nb_candidate_needs_update(const struct nb_config *candidate)
 {
-       bool ret = false;
-
-       pthread_rwlock_rdlock(&running_config->lock);
-       {
-               if (candidate->version < running_config->version)
-                       ret = true;
-       }
-       pthread_rwlock_unlock(&running_config->lock);
+       if (candidate->version < running_config->version)
+               return true;
 
-       return ret;
+       return false;
 }
 
 int nb_candidate_update(struct nb_config *candidate)
 {
        struct nb_config *updated_config;
 
-       pthread_rwlock_rdlock(&running_config->lock);
-       {
-               updated_config = nb_config_dup(running_config);
-       }
-       pthread_rwlock_unlock(&running_config->lock);
-
+       updated_config = nb_config_dup(running_config);
        if (nb_config_merge(updated_config, candidate, true) != NB_OK)
                return NB_ERR;
 
@@ -583,14 +590,45 @@ static int nb_candidate_validate_yang(struct nb_config *candidate)
 }
 
 /* Perform code-level validation using the northbound callbacks. */
-static int nb_candidate_validate_changes(struct nb_config *candidate,
-                                        struct nb_config_cbs *changes)
+static int nb_candidate_validate_code(struct nb_config *candidate,
+                                     struct nb_config_cbs *changes)
 {
        struct nb_config_cb *cb;
+       struct lyd_node *root, *next, *child;
+       int ret;
+
+       /* First validate the candidate as a whole. */
+       LY_TREE_FOR (candidate->dnode, root) {
+               LY_TREE_DFS_BEGIN (root, next, child) {
+                       struct nb_node *nb_node;
+
+                       nb_node = child->schema->priv;
+                       if (!nb_node->cbs.pre_validate)
+                               goto next;
+
+                       if (DEBUG_MODE_CHECK(&nb_dbg_cbs_config,
+                                            DEBUG_MODE_ALL)) {
+                               char xpath[XPATH_MAXLEN];
+
+                               yang_dnode_get_path(child, xpath,
+                                                   sizeof(xpath));
+                               nb_log_callback(NB_EV_VALIDATE,
+                                               NB_OP_PRE_VALIDATE, xpath,
+                                               NULL);
+                       }
+
+                       ret = (*nb_node->cbs.pre_validate)(child);
+                       if (ret != NB_OK)
+                               return NB_ERR_VALIDATION;
 
+               next:
+                       LY_TREE_DFS_END(root, next, child);
+               }
+       }
+
+       /* Now validate the configuration changes. */
        RB_FOREACH (cb, nb_config_cbs, changes) {
                struct nb_config_change *change = (struct nb_config_change *)cb;
-               int ret;
 
                ret = nb_callback_configuration(NB_EV_VALIDATE, change);
                if (ret != NB_OK)
@@ -609,13 +647,9 @@ int nb_candidate_validate(struct nb_config *candidate)
                return NB_ERR_VALIDATION;
 
        RB_INIT(nb_config_cbs, &changes);
-       pthread_rwlock_rdlock(&running_config->lock);
-       {
-               nb_config_diff(running_config, candidate, &changes);
-               ret = nb_candidate_validate_changes(candidate, &changes);
-               nb_config_diff_del_changes(&changes);
-       }
-       pthread_rwlock_unlock(&running_config->lock);
+       nb_config_diff(running_config, candidate, &changes);
+       ret = nb_candidate_validate_code(candidate, &changes);
+       nb_config_diff_del_changes(&changes);
 
        return ret;
 }
@@ -635,36 +669,26 @@ int nb_candidate_commit_prepare(struct nb_config *candidate,
        }
 
        RB_INIT(nb_config_cbs, &changes);
-       pthread_rwlock_rdlock(&running_config->lock);
-       {
-               nb_config_diff(running_config, candidate, &changes);
-               if (RB_EMPTY(nb_config_cbs, &changes)) {
-                       pthread_rwlock_unlock(&running_config->lock);
-                       return NB_ERR_NO_CHANGES;
-               }
+       nb_config_diff(running_config, candidate, &changes);
+       if (RB_EMPTY(nb_config_cbs, &changes))
+               return NB_ERR_NO_CHANGES;
 
-               if (nb_candidate_validate_changes(candidate, &changes)
-                   != NB_OK) {
-                       flog_warn(
-                               EC_LIB_NB_CANDIDATE_INVALID,
-                               "%s: failed to validate candidate configuration",
-                               __func__);
-                       nb_config_diff_del_changes(&changes);
-                       pthread_rwlock_unlock(&running_config->lock);
-                       return NB_ERR_VALIDATION;
-               }
+       if (nb_candidate_validate_code(candidate, &changes) != NB_OK) {
+               flog_warn(EC_LIB_NB_CANDIDATE_INVALID,
+                         "%s: failed to validate candidate configuration",
+                         __func__);
+               nb_config_diff_del_changes(&changes);
+               return NB_ERR_VALIDATION;
+       }
 
-               *transaction = nb_transaction_new(candidate, &changes, client,
-                                                 user, comment);
-               if (*transaction == NULL) {
-                       flog_warn(EC_LIB_NB_TRANSACTION_CREATION_FAILED,
-                                 "%s: failed to create transaction", __func__);
-                       nb_config_diff_del_changes(&changes);
-                       pthread_rwlock_unlock(&running_config->lock);
-                       return NB_ERR_LOCKED;
-               }
+       *transaction =
+               nb_transaction_new(candidate, &changes, client, user, comment);
+       if (*transaction == NULL) {
+               flog_warn(EC_LIB_NB_TRANSACTION_CREATION_FAILED,
+                         "%s: failed to create transaction", __func__);
+               nb_config_diff_del_changes(&changes);
+               return NB_ERR_LOCKED;
        }
-       pthread_rwlock_unlock(&running_config->lock);
 
        return nb_transaction_process(NB_EV_PREPARE, *transaction);
 }
@@ -683,11 +707,7 @@ void nb_candidate_commit_apply(struct nb_transaction *transaction,
 
        /* Replace running by candidate. */
        transaction->config->version++;
-       pthread_rwlock_wrlock(&running_config->lock);
-       {
-               nb_config_replace(running_config, transaction->config, true);
-       }
-       pthread_rwlock_unlock(&running_config->lock);
+       nb_config_replace(running_config, transaction->config, true);
 
        /* Record transaction. */
        if (save_transaction
@@ -961,52 +981,40 @@ static int nb_transaction_process(enum nb_event event,
 {
        struct nb_config_cb *cb;
 
-       /*
-        * Need to lock the running configuration since transaction->changes
-        * can contain pointers to data nodes from the running configuration.
-        */
-       pthread_rwlock_rdlock(&running_config->lock);
-       {
-               RB_FOREACH (cb, nb_config_cbs, &transaction->changes) {
-                       struct nb_config_change *change =
-                               (struct nb_config_change *)cb;
-                       int ret;
+       RB_FOREACH (cb, nb_config_cbs, &transaction->changes) {
+               struct nb_config_change *change = (struct nb_config_change *)cb;
+               int ret;
 
+               /*
+                * Only try to release resources that were allocated
+                * successfully.
+                */
+               if (event == NB_EV_ABORT && change->prepare_ok == false)
+                       break;
+
+               /* Call the appropriate callback. */
+               ret = nb_callback_configuration(event, change);
+               switch (event) {
+               case NB_EV_PREPARE:
+                       if (ret != NB_OK)
+                               return ret;
+                       change->prepare_ok = true;
+                       break;
+               case NB_EV_ABORT:
+               case NB_EV_APPLY:
                        /*
-                        * Only try to release resources that were allocated
-                        * successfully.
+                        * At this point it's not possible to reject the
+                        * transaction anymore, so any failure here can lead to
+                        * inconsistencies and should be treated as a bug.
+                        * Operations prone to errors, like validations and
+                        * resource allocations, should be performed during the
+                        * 'prepare' phase.
                         */
-                       if (event == NB_EV_ABORT && change->prepare_ok == false)
-                               break;
-
-                       /* Call the appropriate callback. */
-                       ret = nb_callback_configuration(event, change);
-                       switch (event) {
-                       case NB_EV_PREPARE:
-                               if (ret != NB_OK) {
-                                       pthread_rwlock_unlock(
-                                               &running_config->lock);
-                                       return ret;
-                               }
-                               change->prepare_ok = true;
-                               break;
-                       case NB_EV_ABORT:
-                       case NB_EV_APPLY:
-                               /*
-                                * At this point it's not possible to reject the
-                                * transaction anymore, so any failure here can
-                                * lead to inconsistencies and should be treated
-                                * as a bug. Operations prone to errors, like
-                                * validations and resource allocations, should
-                                * be performed during the 'prepare' phase.
-                                */
-                               break;
-                       default:
-                               break;
-                       }
+                       break;
+               default:
+                       break;
                }
        }
-       pthread_rwlock_unlock(&running_config->lock);
 
        return NB_OK;
 }
@@ -1310,9 +1318,27 @@ static int nb_oper_data_iter_node(const struct lys_node *snode,
 
        /* Update XPath. */
        strlcpy(xpath, xpath_parent, sizeof(xpath));
-       if (!first && snode->nodetype != LYS_USES)
-               snprintf(xpath + strlen(xpath), sizeof(xpath) - strlen(xpath),
-                        "/%s", snode->name);
+       if (!first && snode->nodetype != LYS_USES) {
+               struct lys_node *parent;
+
+               /* Get the real parent. */
+               parent = snode->parent;
+               while (parent && parent->nodetype == LYS_USES)
+                       parent = parent->parent;
+
+               /*
+                * When necessary, include the namespace of the augmenting
+                * module.
+                */
+               if (parent && parent->nodetype == LYS_AUGMENT)
+                       snprintf(xpath + strlen(xpath),
+                                sizeof(xpath) - strlen(xpath), "/%s:%s",
+                                snode->module->name, snode->name);
+               else
+                       snprintf(xpath + strlen(xpath),
+                                sizeof(xpath) - strlen(xpath), "/%s",
+                                snode->name);
+       }
 
        nb_node = snode->priv;
        switch (snode->nodetype) {
@@ -1550,6 +1576,7 @@ bool nb_operation_is_valid(enum nb_operation operation,
                        return false;
                }
                return true;
+       case NB_OP_PRE_VALIDATE:
        case NB_OP_APPLY_FINISH:
                if (!CHECK_FLAG(snode->flags, LYS_CONFIG_W))
                        return false;
@@ -1768,6 +1795,8 @@ const char *nb_operation_name(enum nb_operation operation)
                return "destroy";
        case NB_OP_MOVE:
                return "move";
+       case NB_OP_PRE_VALIDATE:
+               return "pre_validate";
        case NB_OP_APPLY_FINISH:
                return "apply_finish";
        case NB_OP_GET_ELEM:
index ce79d907f9fd9aca81e6eb2bb97b823688f7be12..fbd7771db74813a768ce8a403c4be39037f96897 100644 (file)
@@ -72,6 +72,7 @@ enum nb_operation {
        NB_OP_MODIFY,
        NB_OP_DESTROY,
        NB_OP_MOVE,
+       NB_OP_PRE_VALIDATE,
        NB_OP_APPLY_FINISH,
        NB_OP_GET_ELEM,
        NB_OP_GET_NEXT,
@@ -196,6 +197,19 @@ struct nb_callbacks {
         */
        int (*move)(enum nb_event event, const struct lyd_node *dnode);
 
+       /*
+        * Optional configuration callback.
+        *
+        * This callback can be used to validate subsections of the
+        * configuration being committed before validating the configuration
+        * changes themselves. It's useful to perform more complex validations
+        * that depend on the relationship between multiple nodes.
+        *
+        * dnode
+        *    libyang data node associated with the 'pre_validate' callback.
+        */
+       int (*pre_validate)(const struct lyd_node *dnode);
+
        /*
         * Optional configuration callback.
         *
@@ -435,25 +449,15 @@ enum nb_client {
 
 /* Northbound configuration. */
 struct nb_config {
-       /* Configuration data. */
        struct lyd_node *dnode;
-
-       /* Configuration version. */
        uint32_t version;
-
-       /*
-        * Lock protecting this structure. The use of this lock is always
-        * necessary when reading or modifying the global running configuration.
-        * For candidate configurations, use of this lock is optional depending
-        * on the threading scheme of the northbound plugin.
-        */
-       pthread_rwlock_t lock;
 };
 
 /* Northbound configuration callback. */
 struct nb_config_cb {
        RB_ENTRY(nb_config_cb) entry;
        enum nb_operation operation;
+       uint32_t seq;
        char xpath[XPATH_MAXLEN];
        const struct nb_node *nb_node;
        const struct lyd_node *dnode;
index 884c01a457ec712de33cfe6bb45fbfd73e9e16cc..a15fe3d1c957283f9801d9b06093838c5c1ab7b6 100644 (file)
@@ -193,13 +193,8 @@ int nb_cli_apply_changes(struct vty *vty, const char *xpath_base_fmt, ...)
                                "Please check the logs for more details.\n");
 
                        /* Regenerate candidate for consistency. */
-                       pthread_rwlock_rdlock(&running_config->lock);
-                       {
-                               nb_config_replace(vty->candidate_config,
-                                                 running_config, true);
-                       }
-                       pthread_rwlock_unlock(&running_config->lock);
-
+                       nb_config_replace(vty->candidate_config, running_config,
+                                         true);
                        return CMD_WARNING_CONFIG_FAILED;
                }
        }
@@ -307,12 +302,7 @@ static int nb_cli_commit(struct vty *vty, bool force,
 
        /* "confirm" parameter. */
        if (confirmed_timeout) {
-               pthread_rwlock_rdlock(&running_config->lock);
-               {
-                       vty->confirmed_commit_rollback =
-                               nb_config_dup(running_config);
-               }
-               pthread_rwlock_unlock(&running_config->lock);
+               vty->confirmed_commit_rollback = nb_config_dup(running_config);
 
                vty->t_confirmed_commit_timeout = NULL;
                thread_add_timer(master, nb_cli_confirmed_commit_timeout, vty,
@@ -326,13 +316,8 @@ static int nb_cli_commit(struct vty *vty, bool force,
        /* Map northbound return code to CLI return code. */
        switch (ret) {
        case NB_OK:
-               pthread_rwlock_rdlock(&running_config->lock);
-               {
-                       nb_config_replace(vty->candidate_config_base,
-                                         running_config, true);
-               }
-               pthread_rwlock_unlock(&running_config->lock);
-
+               nb_config_replace(vty->candidate_config_base, running_config,
+                                 true);
                vty_out(vty,
                        "%% Configuration committed successfully (Transaction ID #%u).\n\n",
                        transaction_id);
@@ -729,12 +714,7 @@ DEFPY (config_update,
                return CMD_WARNING;
        }
 
-       pthread_rwlock_rdlock(&running_config->lock);
-       {
-               nb_config_replace(vty->candidate_config_base, running_config,
-                                 true);
-       }
-       pthread_rwlock_unlock(&running_config->lock);
+       nb_config_replace(vty->candidate_config_base, running_config, true);
 
        vty_out(vty, "%% Candidate configuration updated successfully.\n\n");
 
@@ -834,12 +814,8 @@ DEFPY (show_config_running,
                }
        }
 
-       pthread_rwlock_rdlock(&running_config->lock);
-       {
-               nb_cli_show_config(vty, running_config, format, translator,
-                                  !!with_defaults);
-       }
-       pthread_rwlock_unlock(&running_config->lock);
+       nb_cli_show_config(vty, running_config, format, translator,
+                          !!with_defaults);
 
        return CMD_SUCCESS;
 }
@@ -953,68 +929,57 @@ DEFPY (show_config_compare,
        struct nb_config *config2, *config_transaction2 = NULL;
        int ret = CMD_WARNING;
 
-       /*
-        * For simplicity, lock the running configuration regardless if it's
-        * going to be used or not.
-        */
-       pthread_rwlock_rdlock(&running_config->lock);
-       {
-               if (c1_candidate)
-                       config1 = vty->candidate_config;
-               else if (c1_running)
-                       config1 = running_config;
-               else {
-                       config_transaction1 = nb_db_transaction_load(c1_tid);
-                       if (!config_transaction1) {
-                               vty_out(vty,
-                                       "%% Transaction %u does not exist\n\n",
-                                       (unsigned int)c1_tid);
-                               goto exit;
-                       }
-                       config1 = config_transaction1;
+       if (c1_candidate)
+               config1 = vty->candidate_config;
+       else if (c1_running)
+               config1 = running_config;
+       else {
+               config_transaction1 = nb_db_transaction_load(c1_tid);
+               if (!config_transaction1) {
+                       vty_out(vty, "%% Transaction %u does not exist\n\n",
+                               (unsigned int)c1_tid);
+                       goto exit;
                }
+               config1 = config_transaction1;
+       }
 
-               if (c2_candidate)
-                       config2 = vty->candidate_config;
-               else if (c2_running)
-                       config2 = running_config;
-               else {
-                       config_transaction2 = nb_db_transaction_load(c2_tid);
-                       if (!config_transaction2) {
-                               vty_out(vty,
-                                       "%% Transaction %u does not exist\n\n",
-                                       (unsigned int)c2_tid);
-                               goto exit;
-                       }
-                       config2 = config_transaction2;
+       if (c2_candidate)
+               config2 = vty->candidate_config;
+       else if (c2_running)
+               config2 = running_config;
+       else {
+               config_transaction2 = nb_db_transaction_load(c2_tid);
+               if (!config_transaction2) {
+                       vty_out(vty, "%% Transaction %u does not exist\n\n",
+                               (unsigned int)c2_tid);
+                       goto exit;
                }
+               config2 = config_transaction2;
+       }
 
-               if (json)
-                       format = NB_CFG_FMT_JSON;
-               else if (xml)
-                       format = NB_CFG_FMT_XML;
-               else
-                       format = NB_CFG_FMT_CMDS;
+       if (json)
+               format = NB_CFG_FMT_JSON;
+       else if (xml)
+               format = NB_CFG_FMT_XML;
+       else
+               format = NB_CFG_FMT_CMDS;
 
-               if (translator_family) {
-                       translator = yang_translator_find(translator_family);
-                       if (!translator) {
-                               vty_out(vty,
-                                       "%% Module translator \"%s\" not found\n",
-                                       translator_family);
-                               goto exit;
-                       }
+       if (translator_family) {
+               translator = yang_translator_find(translator_family);
+               if (!translator) {
+                       vty_out(vty, "%% Module translator \"%s\" not found\n",
+                               translator_family);
+                       goto exit;
                }
-
-               ret = nb_cli_show_config_compare(vty, config1, config2, format,
-                                                translator);
-       exit:
-               if (config_transaction1)
-                       nb_config_free(config_transaction1);
-               if (config_transaction2)
-                       nb_config_free(config_transaction2);
        }
-       pthread_rwlock_unlock(&running_config->lock);
+
+       ret = nb_cli_show_config_compare(vty, config1, config2, format,
+                                        translator);
+exit:
+       if (config_transaction1)
+               nb_config_free(config_transaction1);
+       if (config_transaction2)
+               nb_config_free(config_transaction2);
 
        return ret;
 }
index e9669fc7e16c8d5cb6a313f022b0a5acb75c20e4..2fc3c81cf2a5987bfd0bb815bdc192a83abda8e7 100644 (file)
@@ -289,11 +289,7 @@ static int frr_confd_cdb_read_cb_prepare(int fd, int *subp, int reslen)
        struct cdb_iter_args iter_args;
        int ret;
 
-       pthread_rwlock_rdlock(&running_config->lock);
-       {
-               candidate = nb_config_dup(running_config);
-       }
-       pthread_rwlock_unlock(&running_config->lock);
+       candidate = nb_config_dup(running_config);
 
        /* Iterate over all configuration changes. */
        iter_args.candidate = candidate;
index a55da23dd12de5cabce812aaef4a56180369f1c4..1d6317b005511419d3fe43048513a5217b421c62 100644 (file)
@@ -702,15 +702,10 @@ class NorthboundImpl final : public frr::Northbound::Service
        {
                struct lyd_node *dnode;
 
-               pthread_rwlock_rdlock(&running_config->lock);
-               {
-                       dnode = yang_dnode_get(running_config->dnode,
-                                              path.empty() ? NULL
-                                                           : path.c_str());
-                       if (dnode)
-                               dnode = yang_dnode_dup(dnode);
-               }
-               pthread_rwlock_unlock(&running_config->lock);
+               dnode = yang_dnode_get(running_config->dnode,
+                                      path.empty() ? NULL : path.c_str());
+               if (dnode)
+                       dnode = yang_dnode_dup(dnode);
 
                return dnode;
        }
@@ -817,11 +812,7 @@ class NorthboundImpl final : public frr::Northbound::Service
 
                struct candidate *candidate = &_candidates[candidate_id];
                candidate->id = candidate_id;
-               pthread_rwlock_rdlock(&running_config->lock);
-               {
-                       candidate->config = nb_config_dup(running_config);
-               }
-               pthread_rwlock_unlock(&running_config->lock);
+               candidate->config = nb_config_dup(running_config);
                candidate->transaction = NULL;
 
                return candidate;
index 77183282bab1ffff83a2f75e099a30817ea17d3e..b94c939763341645efcc129ca4dc387dd0dd8745 100644 (file)
@@ -256,11 +256,7 @@ static int frr_sr_config_change_cb_verify(sr_session_ctx_t *session,
                return ret;
        }
 
-       pthread_rwlock_rdlock(&running_config->lock);
-       {
-               candidate = nb_config_dup(running_config);
-       }
-       pthread_rwlock_unlock(&running_config->lock);
+       candidate = nb_config_dup(running_config);
 
        while ((ret = sr_get_change_next(session, it, &sr_op, &sr_old_val,
                                         &sr_new_val))
index fc15183bf95c8d029b5438f42c0d06751f4c6304..580d898448d4d4e0dfa559d1400326493a1c874e 100644 (file)
@@ -478,11 +478,6 @@ int generic_match_add(struct vty *vty, struct route_map_index *index,
 
        ret = route_map_add_match(index, command, arg, type);
        switch (ret) {
-       case RMAP_COMPILE_SUCCESS:
-               if (type != RMAP_EVENT_MATCH_ADDED) {
-                       route_map_upd8_dependency(type, arg, index->map->name);
-               }
-               break;
        case RMAP_RULE_MISSING:
                vty_out(vty, "%% [%s] Can't find rule.\n", frr_protonameinst);
                return CMD_WARNING_CONFIG_FAILED;
@@ -493,7 +488,7 @@ int generic_match_add(struct vty *vty, struct route_map_index *index,
                        frr_protonameinst);
                return CMD_WARNING_CONFIG_FAILED;
                break;
-       case RMAP_DUPLICATE_RULE:
+       case RMAP_COMPILE_SUCCESS:
                /*
                 * Nothing to do here move along
                 */
@@ -526,7 +521,7 @@ int generic_match_delete(struct vty *vty, struct route_map_index *index,
                rmap_name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, index->map->name);
        }
 
-       ret = route_map_delete_match(index, command, dep_name);
+       ret = route_map_delete_match(index, command, dep_name, type);
        switch (ret) {
        case RMAP_RULE_MISSING:
                vty_out(vty, "%% [%s] Can't find rule.\n", frr_protonameinst);
@@ -539,10 +534,6 @@ int generic_match_delete(struct vty *vty, struct route_map_index *index,
                retval = CMD_WARNING_CONFIG_FAILED;
                break;
        case RMAP_COMPILE_SUCCESS:
-               if (type != RMAP_EVENT_MATCH_DELETED && dep_name)
-                       route_map_upd8_dependency(type, dep_name, rmap_name);
-               break;
-       case RMAP_DUPLICATE_RULE:
                /*
                 * Nothing to do here
                 */
@@ -573,7 +564,6 @@ int generic_set_add(struct vty *vty, struct route_map_index *index,
                return CMD_WARNING_CONFIG_FAILED;
                break;
        case RMAP_COMPILE_SUCCESS:
-       case RMAP_DUPLICATE_RULE:
                break;
        }
 
@@ -598,7 +588,6 @@ int generic_set_delete(struct vty *vty, struct route_map_index *index,
                return CMD_WARNING_CONFIG_FAILED;
                break;
        case RMAP_COMPILE_SUCCESS:
-       case RMAP_DUPLICATE_RULE:
                break;
        }
 
@@ -1410,6 +1399,7 @@ enum rmap_compile_rets route_map_add_match(struct route_map_index *index,
        struct route_map_rule_cmd *cmd;
        void *compile;
        int8_t delete_rmap_event_type = 0;
+       const char *rule_key;
 
        /* First lookup rule for add match statement. */
        cmd = route_map_lookup_match(match_name);
@@ -1423,6 +1413,12 @@ enum rmap_compile_rets route_map_add_match(struct route_map_index *index,
                        return RMAP_COMPILE_ERROR;
        } else
                compile = NULL;
+       /* use the compiled results if applicable */
+       if (compile && cmd->func_get_rmap_rule_key)
+               rule_key = (*cmd->func_get_rmap_rule_key)
+                          (compile);
+       else
+               rule_key = match_arg;
 
        /* If argument is completely same ignore it. */
        for (rule = index->match_list.head; rule; rule = next) {
@@ -1436,7 +1432,7 @@ enum rmap_compile_rets route_map_add_match(struct route_map_index *index,
                                if (cmd->func_free)
                                        (*cmd->func_free)(compile);
 
-                               return RMAP_DUPLICATE_RULE;
+                               return RMAP_COMPILE_SUCCESS;
                        }
 
                        /* Remove the dependency of the route-map on the rule
@@ -1447,7 +1443,7 @@ enum rmap_compile_rets route_map_add_match(struct route_map_index *index,
                                        get_route_map_delete_event(type);
                                route_map_upd8_dependency(
                                                        delete_rmap_event_type,
-                                                       rule->rule_str,
+                                                       rule_key,
                                                        index->map->name);
                        }
 
@@ -1473,6 +1469,8 @@ enum rmap_compile_rets route_map_add_match(struct route_map_index *index,
                route_map_notify_dependencies(index->map->name,
                                              RMAP_EVENT_CALL_ADDED);
        }
+       if (type != RMAP_EVENT_MATCH_ADDED)
+               route_map_upd8_dependency(type, rule_key, index->map->name);
 
        return RMAP_COMPILE_SUCCESS;
 }
@@ -1480,10 +1478,12 @@ enum rmap_compile_rets route_map_add_match(struct route_map_index *index,
 /* Delete specified route match rule. */
 enum rmap_compile_rets route_map_delete_match(struct route_map_index *index,
                                              const char *match_name,
-                                             const char *match_arg)
+                                             const char *match_arg,
+                                             route_map_event_t type)
 {
        struct route_map_rule *rule;
        struct route_map_rule_cmd *cmd;
+       const char *rule_key;
 
        cmd = route_map_lookup_match(match_name);
        if (cmd == NULL)
@@ -1492,7 +1492,6 @@ enum rmap_compile_rets route_map_delete_match(struct route_map_index *index,
        for (rule = index->match_list.head; rule; rule = rule->next)
                if (rule->cmd == cmd && (rulecmp(rule->rule_str, match_arg) == 0
                                         || match_arg == NULL)) {
-                       route_map_rule_delete(&index->match_list, rule);
                        /* Execute event hook. */
                        if (route_map_master.event_hook) {
                                (*route_map_master.event_hook)(index->map->name);
@@ -1500,6 +1499,17 @@ enum rmap_compile_rets route_map_delete_match(struct route_map_index *index,
                                        index->map->name,
                                        RMAP_EVENT_CALL_ADDED);
                        }
+                       if (cmd->func_get_rmap_rule_key)
+                               rule_key = (*cmd->func_get_rmap_rule_key)
+                                          (rule->value);
+                       else
+                               rule_key = match_arg;
+
+                       if (type != RMAP_EVENT_MATCH_DELETED && rule_key)
+                               route_map_upd8_dependency(type, rule_key,
+                                               index->map->name);
+
+                       route_map_rule_delete(&index->match_list, rule);
                        return RMAP_COMPILE_SUCCESS;
                }
        /* Can't find matched rule. */
index 40525987e94662d8ef0b544d1f9fbd96ea111c12..e6eccd4b291d69d438db27c985f55a2e6bee353a 100644 (file)
@@ -123,6 +123,9 @@ struct route_map_rule_cmd {
 
        /* Free allocated value by func_compile (). */
        void (*func_free)(void *);
+
+       /** To get the rule key after Compilation **/
+       void *(*func_get_rmap_rule_key)(void *val);
 };
 
 /* Route map apply error. */
@@ -135,8 +138,6 @@ enum rmap_compile_rets {
        /* Route map rule can't compile */
        RMAP_COMPILE_ERROR,
 
-       /* Route map rule is duplicate */
-       RMAP_DUPLICATE_RULE
 };
 
 /* Route map rule list. */
@@ -228,7 +229,8 @@ extern enum rmap_compile_rets route_map_add_match(struct route_map_index *index,
 /* Delete specified route match rule. */
 extern enum rmap_compile_rets
 route_map_delete_match(struct route_map_index *index,
-                      const char *match_name, const char *match_arg);
+                      const char *match_name, const char *match_arg,
+                      route_map_event_t type);
 
 extern const char *route_map_get_match_arg(struct route_map_index *index,
                                           const char *match_name);
index 575e96bae4540ca5fd024a3ee323185b461ca41f..4c6df797ad49a87ee1678a7bd004c6e997dc5ae7 100644 (file)
--- a/lib/vrf.c
+++ b/lib/vrf.c
@@ -199,9 +199,14 @@ struct vrf *vrf_get(vrf_id_t vrf_id, const char *name)
 
        /* Set name */
        if (name && vrf->name[0] != '\0' && strcmp(name, vrf->name)) {
+               /* update the vrf name */
                RB_REMOVE(vrf_name_head, &vrfs_by_name, vrf);
+               strlcpy(vrf->data.l.netns_name,
+                       name, NS_NAMSIZ);
                strlcpy(vrf->name, name, sizeof(vrf->name));
                RB_INSERT(vrf_name_head, &vrfs_by_name, vrf);
+               if (vrf->vrf_id == VRF_DEFAULT)
+                       vrf_set_default_name(vrf->name, false);
        } else if (name && vrf->name[0] == '\0') {
                strlcpy(vrf->name, name, sizeof(vrf->name));
                RB_INSERT(vrf_name_head, &vrfs_by_name, vrf);
@@ -870,7 +875,8 @@ void vrf_set_default_name(const char *default_name, bool force)
                           def_vrf->vrf_id);
                return;
        }
-
+       if (strmatch(vrf_default_name, default_name))
+               return;
        snprintf(vrf_default_name, VRF_NAMSIZ, "%s", default_name);
        if (def_vrf) {
                if (force)
index deb9391bd506a0951bf6e8108e1944ff2dcf441e..502d2c9d04bdf35b72d640ede49c1bb9814d784a 100644 (file)
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -2582,22 +2582,17 @@ int vty_config_enter(struct vty *vty, bool private_config, bool exclusive)
        vty->private_config = private_config;
        vty->xpath_index = 0;
 
-       pthread_rwlock_rdlock(&running_config->lock);
-       {
-               if (private_config) {
-                       vty->candidate_config = nb_config_dup(running_config);
+       if (private_config) {
+               vty->candidate_config = nb_config_dup(running_config);
+               vty->candidate_config_base = nb_config_dup(running_config);
+               vty_out(vty,
+                       "Warning: uncommitted changes will be discarded on exit.\n\n");
+       } else {
+               vty->candidate_config = vty_shared_candidate_config;
+               if (frr_get_cli_mode() == FRR_CLI_TRANSACTIONAL)
                        vty->candidate_config_base =
                                nb_config_dup(running_config);
-                       vty_out(vty,
-                               "Warning: uncommitted changes will be discarded on exit.\n\n");
-               } else {
-                       vty->candidate_config = vty_shared_candidate_config;
-                       if (frr_get_cli_mode() == FRR_CLI_TRANSACTIONAL)
-                               vty->candidate_config_base =
-                                       nb_config_dup(running_config);
-               }
        }
-       pthread_rwlock_unlock(&running_config->lock);
 
        return CMD_SUCCESS;
 }
index 0558383823e55d8fbb9c9816918dbda098c9f291..50225f35a08e8c41da808d277aec851350888061 100644 (file)
@@ -781,6 +781,60 @@ void yang_get_default_string_buf(char *buf, size_t size, const char *xpath_fmt,
                          xpath);
 }
 
+/*
+ * Derived type: IP prefix.
+ */
+void yang_str2prefix(const char *value, union prefixptr prefix)
+{
+       (void)str2prefix(value, prefix.p);
+       apply_mask(prefix.p);
+}
+
+struct yang_data *yang_data_new_prefix(const char *xpath,
+                                      union prefixconstptr prefix)
+{
+       char value_str[PREFIX2STR_BUFFER];
+
+       (void)prefix2str(prefix.p, value_str, sizeof(value_str));
+       return yang_data_new(xpath, value_str);
+}
+
+void yang_dnode_get_prefix(union prefixptr prefix, const struct lyd_node *dnode,
+                          const char *xpath_fmt, ...)
+{
+       const struct lyd_node_leaf_list *dleaf;
+
+       assert(dnode);
+       if (xpath_fmt) {
+               va_list ap;
+               char xpath[XPATH_MAXLEN];
+
+               va_start(ap, xpath_fmt);
+               vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap);
+               va_end(ap);
+               dnode = yang_dnode_get(dnode, xpath);
+               YANG_DNODE_GET_ASSERT(dnode, xpath);
+       }
+
+       dleaf = (const struct lyd_node_leaf_list *)dnode;
+       assert(dleaf->value_type == LY_TYPE_STRING);
+       (void)str2prefix(dleaf->value_str, prefix.p);
+}
+
+void yang_get_default_prefix(union prefixptr var, const char *xpath_fmt, ...)
+{
+       char xpath[XPATH_MAXLEN];
+       const char *value;
+       va_list ap;
+
+       va_start(ap, xpath_fmt);
+       vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap);
+       va_end(ap);
+
+       value = yang_get_default_value(xpath);
+       yang_str2prefix(value, var);
+}
+
 /*
  * Derived type: ipv4.
  */
@@ -1000,3 +1054,56 @@ void yang_get_default_ipv6p(union prefixptr var, const char *xpath_fmt, ...)
        value = yang_get_default_value(xpath);
        yang_str2ipv6p(value, var);
 }
+
+/*
+ * Derived type: ip.
+ */
+void yang_str2ip(const char *value, struct ipaddr *ip)
+{
+       (void)str2ipaddr(value, ip);
+}
+
+struct yang_data *yang_data_new_ip(const char *xpath, const struct ipaddr *addr)
+{
+       size_t sz = IS_IPADDR_V4(addr) ? INET_ADDRSTRLEN : INET6_ADDRSTRLEN;
+       char value_str[sz];
+
+       ipaddr2str(addr, value_str, sizeof(value_str));
+       return yang_data_new(xpath, value_str);
+}
+
+void yang_dnode_get_ip(struct ipaddr *addr, const struct lyd_node *dnode,
+                      const char *xpath_fmt, ...)
+{
+       const struct lyd_node_leaf_list *dleaf;
+
+       assert(dnode);
+       if (xpath_fmt) {
+               va_list ap;
+               char xpath[XPATH_MAXLEN];
+
+               va_start(ap, xpath_fmt);
+               vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap);
+               va_end(ap);
+               dnode = yang_dnode_get(dnode, xpath);
+               YANG_DNODE_GET_ASSERT(dnode, xpath);
+       }
+
+       dleaf = (const struct lyd_node_leaf_list *)dnode;
+       assert(dleaf->value_type == LY_TYPE_STRING);
+       (void)str2ipaddr(dleaf->value_str, addr);
+}
+
+void yang_get_default_ip(struct ipaddr *var, const char *xpath_fmt, ...)
+{
+       char xpath[XPATH_MAXLEN];
+       const char *value;
+       va_list ap;
+
+       va_start(ap, xpath_fmt);
+       vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap);
+       va_end(ap);
+
+       value = yang_get_default_value(xpath);
+       yang_str2ip(value, var);
+}
index 5203a033ad15edda5179daeed2d0033cbd7771d9..1a30ff3686240450aa3f6de55d08f6426233ed96 100644 (file)
@@ -114,6 +114,16 @@ extern const char *yang_get_default_string(const char *xpath_fmt, ...);
 extern void yang_get_default_string_buf(char *buf, size_t size,
                                        const char *xpath_fmt, ...);
 
+/* ip prefix */
+extern void yang_str2prefix(const char *value, union prefixptr prefix);
+extern struct yang_data *yang_data_new_prefix(const char *xpath,
+                                             union prefixconstptr prefix);
+extern void yang_dnode_get_prefix(union prefixptr prefix,
+                                 const struct lyd_node *dnode,
+                                 const char *xpath_fmt, ...);
+extern void yang_get_default_prefix(union prefixptr var, const char *xpath_fmt,
+                                   ...);
+
 /* ipv4 */
 extern void yang_str2ipv4(const char *value, struct in_addr *addr);
 extern struct yang_data *yang_data_new_ipv4(const char *xpath,
@@ -154,4 +164,12 @@ extern void yang_dnode_get_ipv6p(union prefixptr prefix,
 extern void yang_get_default_ipv6p(union prefixptr var, const char *xpath_fmt,
                                   ...);
 
+/* ip */
+extern void yang_str2ip(const char *value, struct ipaddr *addr);
+extern struct yang_data *yang_data_new_ip(const char *xpath,
+                                         const struct ipaddr *addr);
+extern void yang_dnode_get_ip(struct ipaddr *addr, const struct lyd_node *dnode,
+                             const char *xpath_fmt, ...);
+extern void yang_get_default_ip(struct ipaddr *var, const char *xpath_fmt, ...);
+
 #endif /* _FRR_NORTHBOUND_WRAPPERS_H_ */
index f809704f8679b195c13a9a4d2cbd2f5f1242979e..92a495ac61719954ac1f1e6c799104e27d23b0f8 100644 (file)
@@ -2451,6 +2451,143 @@ int tm_release_table_chunk(struct zclient *zclient, uint32_t start,
        return zclient_send_message(zclient);
 }
 
+int zebra_send_mpls_labels(struct zclient *zclient, int cmd,
+                          struct zapi_labels *zl)
+{
+       if (zapi_labels_encode(zclient->obuf, cmd, zl) < 0)
+               return -1;
+       return zclient_send_message(zclient);
+}
+
+int zapi_labels_encode(struct stream *s, int cmd, struct zapi_labels *zl)
+{
+       struct zapi_nexthop_label *znh;
+
+       stream_reset(s);
+
+       zclient_create_header(s, cmd, VRF_DEFAULT);
+       stream_putc(s, zl->message);
+       stream_putc(s, zl->type);
+       stream_putl(s, zl->local_label);
+
+       if (CHECK_FLAG(zl->message, ZAPI_LABELS_FTN)) {
+               stream_putw(s, zl->route.prefix.family);
+               stream_put_prefix(s, &zl->route.prefix);
+               stream_putc(s, zl->route.type);
+               stream_putw(s, zl->route.instance);
+       }
+
+       if (zl->nexthop_num > MULTIPATH_NUM) {
+               flog_err(
+                       EC_LIB_ZAPI_ENCODE,
+                       "%s: label %u: can't encode %u nexthops (maximum is %u)",
+                       __func__, zl->local_label, zl->nexthop_num,
+                       MULTIPATH_NUM);
+               return -1;
+       }
+       stream_putw(s, zl->nexthop_num);
+
+       for (int i = 0; i < zl->nexthop_num; i++) {
+               znh = &zl->nexthops[i];
+
+               stream_putc(s, znh->type);
+               stream_putw(s, znh->family);
+               switch (znh->family) {
+               case AF_INET:
+                       stream_put_in_addr(s, &znh->address.ipv4);
+                       break;
+               case AF_INET6:
+                       stream_write(s, (uint8_t *)&znh->address.ipv6, 16);
+                       break;
+               default:
+                       break;
+               }
+               stream_putl(s, znh->ifindex);
+               stream_putl(s, znh->label);
+       }
+
+       /* Put length at the first point of the stream. */
+       stream_putw_at(s, 0, stream_get_endp(s));
+
+       return 0;
+}
+
+int zapi_labels_decode(struct stream *s, struct zapi_labels *zl)
+{
+       struct zapi_nexthop_label *znh;
+
+       memset(zl, 0, sizeof(*zl));
+
+       /* Get data. */
+       STREAM_GETC(s, zl->message);
+       STREAM_GETC(s, zl->type);
+       STREAM_GETL(s, zl->local_label);
+
+       if (CHECK_FLAG(zl->message, ZAPI_LABELS_FTN)) {
+               size_t psize;
+
+               STREAM_GETW(s, zl->route.prefix.family);
+               STREAM_GETC(s, zl->route.prefix.prefixlen);
+
+               psize = PSIZE(zl->route.prefix.prefixlen);
+               switch (zl->route.prefix.family) {
+               case AF_INET:
+                       if (zl->route.prefix.prefixlen > IPV4_MAX_BITLEN) {
+                               zlog_debug(
+                                       "%s: Specified prefix length %d is greater than a v4 address can support",
+                                       __PRETTY_FUNCTION__,
+                                       zl->route.prefix.prefixlen);
+                               return -1;
+                       }
+                       STREAM_GET(&zl->route.prefix.u.prefix4.s_addr, s,
+                                  psize);
+                       break;
+               case AF_INET6:
+                       if (zl->route.prefix.prefixlen > IPV6_MAX_BITLEN) {
+                               zlog_debug(
+                                       "%s: Specified prefix length %d is greater than a v6 address can support",
+                                       __PRETTY_FUNCTION__,
+                                       zl->route.prefix.prefixlen);
+                               return -1;
+                       }
+                       STREAM_GET(&zl->route.prefix.u.prefix6, s, psize);
+                       break;
+               default:
+                       flog_err(EC_LIB_ZAPI_ENCODE,
+                                "%s: Specified family %u is not v4 or v6",
+                                __PRETTY_FUNCTION__, zl->route.prefix.family);
+                       return -1;
+               }
+
+               STREAM_GETC(s, zl->route.type);
+               STREAM_GETW(s, zl->route.instance);
+       }
+
+       STREAM_GETW(s, zl->nexthop_num);
+       for (int i = 0; i < zl->nexthop_num; i++) {
+               znh = &zl->nexthops[i];
+
+               STREAM_GETC(s, znh->type);
+               STREAM_GETW(s, znh->family);
+               switch (znh->family) {
+               case AF_INET:
+                       STREAM_GET(&znh->address.ipv4.s_addr, s,
+                                  IPV4_MAX_BYTELEN);
+                       break;
+               case AF_INET6:
+                       STREAM_GET(&znh->address.ipv6, s, 16);
+                       break;
+               default:
+                       break;
+               }
+               STREAM_GETL(s, znh->ifindex);
+               STREAM_GETL(s, znh->label);
+       }
+
+       return 0;
+stream_failure:
+       return -1;
+}
 
 int zebra_send_pw(struct zclient *zclient, int command, struct zapi_pw *pw)
 {
index 81e454d1924ec4791e505edd8376c3e5de382f53..eb3c97b111c4912f1da7d0b48bbe90b8d8c98a21 100644 (file)
@@ -126,6 +126,7 @@ typedef enum {
        ZEBRA_INTERFACE_LINK_PARAMS,
        ZEBRA_MPLS_LABELS_ADD,
        ZEBRA_MPLS_LABELS_DELETE,
+       ZEBRA_MPLS_LABELS_REPLACE,
        ZEBRA_IPMR_ROUTE_STATS,
        ZEBRA_LABEL_MANAGER_CONNECT,
        ZEBRA_LABEL_MANAGER_CONNECT_ASYNC,
@@ -395,6 +396,28 @@ struct zapi_route {
        uint32_t tableid;
 };
 
+struct zapi_nexthop_label {
+       enum nexthop_types_t type;
+       int family;
+       union g_addr address;
+       ifindex_t ifindex;
+       mpls_label_t label;
+};
+
+struct zapi_labels {
+       uint8_t message;
+#define ZAPI_LABELS_FTN      0x01
+       enum lsp_types_t type;
+       mpls_label_t local_label;
+       struct {
+               struct prefix prefix;
+               uint8_t type;
+               unsigned short instance;
+       } route;
+       uint16_t nexthop_num;
+       struct zapi_nexthop_label nexthops[MULTIPATH_NUM];
+};
+
 struct zapi_pw {
        char ifname[IF_NAMESIZE];
        ifindex_t ifindex;
@@ -625,6 +648,12 @@ extern int tm_get_table_chunk(struct zclient *zclient, uint32_t chunk_size,
 extern int tm_release_table_chunk(struct zclient *zclient, uint32_t start,
                                  uint32_t end);
 
+extern int zebra_send_mpls_labels(struct zclient *zclient, int cmd,
+                                 struct zapi_labels *zl);
+extern int zapi_labels_encode(struct stream *s, int cmd,
+                             struct zapi_labels *zl);
+extern int zapi_labels_decode(struct stream *s, struct zapi_labels *zl);
+
 extern int zebra_send_pw(struct zclient *zclient, int command,
                         struct zapi_pw *pw);
 extern void zebra_read_pw_status_update(ZAPI_CALLBACK_ARGS, struct zapi_pw_status *pw);
index 4d1c085081760c061829e5588c3b53d95d7d2d5c..7914412e875bb43632fa0bbc3763f6cb3587963b 100644 (file)
@@ -1593,7 +1593,6 @@ static int route_map_command_status(struct vty *vty, enum rmap_compile_rets ret)
                return CMD_WARNING_CONFIG_FAILED;
                break;
        case RMAP_COMPILE_SUCCESS:
-       case RMAP_DUPLICATE_RULE:
                break;
        }
 
index 36bb8d49b595caefd3c4c3af2fbad29482a7a0c2..bee7bbb21d02de10a4de2b09732534a3c33ab016 100644 (file)
@@ -216,16 +216,6 @@ int main(int argc, char **argv)
        /* OSPF errors init */
        ospf_error_init();
 
-       /* Need to initialize the default ospf structure, so the interface mode
-          commands can be duly processed if they are received before 'router
-          ospf',
-          when quagga(ospfd) is restarted */
-       if (!ospf_get_instance(instance)) {
-               flog_err(EC_OSPF_INIT_FAIL, "OSPF instance init failed: %s",
-                        strerror(errno));
-               exit(1);
-       }
-
        frr_config_fork();
        frr_run(master);
 
index 6947393a6086b1983cfa0b3a77f7cadec4b91487..ff2039bec84984a977671afe36627bd66be4cf99 100644 (file)
@@ -608,26 +608,8 @@ static int compute_prefix_nhlfe(struct sr_prefix *srp)
 /* Send MPLS Label entry to Zebra for installation or deletion */
 static int ospf_zebra_send_mpls_labels(int cmd, struct sr_nhlfe nhlfe)
 {
-       struct stream *s;
-
-       /* Reset stream. */
-       s = zclient->obuf;
-       stream_reset(s);
-
-       zclient_create_header(s, cmd, VRF_DEFAULT);
-       stream_putc(s, ZEBRA_LSP_SR);
-       /* OSPF Segment Routing currently support only IPv4 */
-       stream_putl(s, nhlfe.prefv4.family);
-       stream_put_in_addr(s, &nhlfe.prefv4.prefix);
-       stream_putc(s, nhlfe.prefv4.prefixlen);
-       stream_put_in_addr(s, &nhlfe.nexthop);
-       stream_putl(s, nhlfe.ifindex);
-       stream_putc(s, OSPF_SR_PRIORITY_DEFAULT);
-       stream_putl(s, nhlfe.label_in);
-       stream_putl(s, nhlfe.label_out);
-
-       /* Put length at the first point of the stream. */
-       stream_putw_at(s, 0, stream_get_endp(s));
+       struct zapi_labels zl = {};
+       struct zapi_nexthop_label *znh;
 
        if (IS_DEBUG_OSPF_SR)
                zlog_debug("    |-  %s LSP %u/%u for %s/%u via %u",
@@ -636,70 +618,39 @@ static int ospf_zebra_send_mpls_labels(int cmd, struct sr_nhlfe nhlfe)
                           inet_ntoa(nhlfe.prefv4.prefix),
                           nhlfe.prefv4.prefixlen, nhlfe.ifindex);
 
-       return zclient_send_message(zclient);
-}
-
-/* Request zebra to install/remove FEC in FIB */
-static int ospf_zebra_send_mpls_ftn(int cmd, struct sr_nhlfe nhlfe)
-{
-       struct zapi_route api;
-       struct zapi_nexthop *api_nh;
-
-       /* Support only IPv4 */
-       if (nhlfe.prefv4.family != AF_INET)
-               return -1;
-
-       memset(&api, 0, sizeof(api));
-       api.vrf_id = VRF_DEFAULT;
-       api.type = ZEBRA_ROUTE_OSPF;
-       api.safi = SAFI_UNICAST;
-       memcpy(&api.prefix, &nhlfe.prefv4, sizeof(struct prefix_ipv4));
-
-       if (cmd == ZEBRA_ROUTE_ADD) {
-               /* Metric value. */
-               SET_FLAG(api.message, ZAPI_MESSAGE_METRIC);
-               api.metric = OSPF_SR_DEFAULT_METRIC;
-               /* Nexthop */
-               SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
-               api_nh = &api.nexthops[0];
-               IPV4_ADDR_COPY(&api_nh->gate.ipv4, &nhlfe.nexthop);
-               api_nh->type = NEXTHOP_TYPE_IPV4_IFINDEX;
-               api_nh->ifindex = nhlfe.ifindex;
-               /* MPLS labels */
-               SET_FLAG(api.message, ZAPI_MESSAGE_LABEL);
-               api_nh->labels[0] = nhlfe.label_out;
-               api_nh->label_num = 1;
-               api_nh->vrf_id = VRF_DEFAULT;
-               api.nexthop_num = 1;
-       }
-
-       if (IS_DEBUG_OSPF_SR)
-               zlog_debug("    |-  %s FEC %u for %s/%u via %u",
-                          cmd == ZEBRA_ROUTE_ADD ? "Add" : "Delete",
-                          nhlfe.label_out, inet_ntoa(nhlfe.prefv4.prefix),
-                          nhlfe.prefv4.prefixlen, nhlfe.ifindex);
-
-       return zclient_route_send(cmd, zclient, &api);
+       zl.type = ZEBRA_LSP_OSPF_SR;
+       zl.local_label = nhlfe.label_in;
+
+       SET_FLAG(zl.message, ZAPI_LABELS_FTN);
+       zl.route.prefix.family = nhlfe.prefv4.family;
+       zl.route.prefix.prefixlen = nhlfe.prefv4.prefixlen;
+       zl.route.prefix.u.prefix4 = nhlfe.prefv4.prefix;
+       zl.route.type = ZEBRA_ROUTE_OSPF;
+       zl.route.instance = 0;
+
+       zl.nexthop_num = 1;
+       znh = &zl.nexthops[0];
+       znh->type = NEXTHOP_TYPE_IPV4_IFINDEX;
+       znh->family = AF_INET;
+       znh->address.ipv4 = nhlfe.nexthop;
+       znh->ifindex = nhlfe.ifindex;
+       znh->label = nhlfe.label_out;
+
+       return zebra_send_mpls_labels(zclient, cmd, &zl);
 }
 
 /* Add new NHLFE entry for SID */
 static inline void add_sid_nhlfe(struct sr_nhlfe nhlfe)
 {
-       if ((nhlfe.label_in != 0) && (nhlfe.label_out != 0)) {
+       if ((nhlfe.label_in != 0) && (nhlfe.label_out != 0))
                ospf_zebra_send_mpls_labels(ZEBRA_MPLS_LABELS_ADD, nhlfe);
-               if (nhlfe.label_out != MPLS_LABEL_IMPLICIT_NULL)
-                       ospf_zebra_send_mpls_ftn(ZEBRA_ROUTE_ADD, nhlfe);
-       }
 }
 
 /* Remove NHLFE entry for SID */
 static inline void del_sid_nhlfe(struct sr_nhlfe nhlfe)
 {
-       if ((nhlfe.label_in != 0) && (nhlfe.label_out != 0)) {
+       if ((nhlfe.label_in != 0) && (nhlfe.label_out != 0))
                ospf_zebra_send_mpls_labels(ZEBRA_MPLS_LABELS_DELETE, nhlfe);
-               if (nhlfe.label_out != MPLS_LABEL_IMPLICIT_NULL)
-                       ospf_zebra_send_mpls_ftn(ZEBRA_ROUTE_DELETE, nhlfe);
-       }
 }
 
 /* Update NHLFE entry for SID */
index 4d3f5f441a902c0587d6f639e29c14bd9a461532..df923e970fa1ffc8a196bbc942cb0318ee2f9c25 100644 (file)
@@ -27,9 +27,6 @@
 #ifndef _FRR_OSPF_SR_H
 #define _FRR_OSPF_SR_H
 
-/* Default Route priority for OSPF Segment Routing */
-#define OSPF_SR_PRIORITY_DEFAULT       10
-
 /* macros and constants for segment routing */
 #define SET_RANGE_SIZE_MASK             0xffffff00
 #define GET_RANGE_SIZE_MASK             0x00ffffff
index e48a5b4d369bce43d37c8c91756ed6e3420ce655..f4de2558778cd7edd5315a361d803e692670016f 100644 (file)
@@ -2158,7 +2158,7 @@ static int ospf_vrf_disable(struct vrf *vrf)
 void ospf_vrf_init(void)
 {
        vrf_init(ospf_vrf_new, ospf_vrf_enable, ospf_vrf_disable,
-                ospf_vrf_delete, NULL);
+                ospf_vrf_delete, ospf_vrf_enable);
 }
 
 void ospf_vrf_terminate(void)
index 57e8cf5742c27c228cb8aeddc2f3084a97941512..359f869c4277b85cfd4cde2bd68b84dee056fc2d 100644 (file)
@@ -682,29 +682,119 @@ struct pbr_nht_individual {
        uint32_t valid;
 };
 
-static void pbr_nht_individual_nexthop_update_lookup(struct hash_bucket *b,
-                                                    void *data)
+static bool
+pbr_nht_individual_nexthop_gw_update(struct pbr_nexthop_cache *pnhc,
+                                    const struct pbr_nht_individual *pnhi)
 {
-       struct pbr_nexthop_cache *pnhc = b->data;
-       struct pbr_nht_individual *pnhi = data;
-       char buf[PREFIX_STRLEN];
-       bool old_valid;
+       bool is_valid = pnhc->valid;
 
-       old_valid = pnhc->valid;
+       if (!pnhi->nhr) /* It doesn't care about non-nexthop updates */
+               goto done;
 
        switch (pnhi->nhr->prefix.family) {
        case AF_INET:
                if (pnhc->nexthop->gate.ipv4.s_addr
-                   == pnhi->nhr->prefix.u.prefix4.s_addr)
-                       pnhc->valid = !!pnhi->nhr->nexthop_num;
+                   != pnhi->nhr->prefix.u.prefix4.s_addr)
+                       goto done; /* Unrelated change */
                break;
        case AF_INET6:
                if (memcmp(&pnhc->nexthop->gate.ipv6,
                           &pnhi->nhr->prefix.u.prefix6, 16)
-                   == 0)
-                       pnhc->valid = !!pnhi->nhr->nexthop_num;
+                   != 0)
+                       goto done; /* Unrelated change */
+               break;
+       }
+
+       if (!pnhi->nhr->nexthop_num) {
+               is_valid = false;
+               goto done;
+       }
+
+       if (pnhc->nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
+           || pnhc->nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) {
+
+               /* GATEWAY_IFINDEX type shouldn't resolve to group */
+               if (pnhi->nhr->nexthop_num > 1) {
+                       is_valid = false;
+                       goto done;
+               }
+
+               /* If whatever we resolved to wasn't on the interface we
+                * specified. (i.e. not a connected route), its invalid.
+                */
+               if (pnhi->nhr->nexthops[0].ifindex != pnhc->nexthop->ifindex) {
+                       is_valid = false;
+                       goto done;
+               }
+       }
+
+       is_valid = true;
+
+done:
+       pnhc->valid = is_valid;
+
+       return pnhc->valid;
+}
+
+static bool pbr_nht_individual_nexthop_interface_update(
+       struct pbr_nexthop_cache *pnhc, const struct pbr_nht_individual *pnhi)
+{
+       bool is_valid = pnhc->valid;
+
+       if (!pnhi->ifp) /* It doesn't care about non-interface updates */
+               goto done;
+
+       if (pnhc->nexthop->ifindex
+           != pnhi->ifp->ifindex) /* Un-related interface */
+               goto done;
+
+       is_valid = !!if_is_up(pnhi->ifp);
+
+done:
+       pnhc->valid = is_valid;
+
+       return pnhc->valid;
+}
+
+/* Given this update either from interface or nexthop tracking, re-validate this
+ * nexthop.
+ *
+ * If the update is un-related, the subroutines shoud just return their cached
+ * valid state.
+ */
+static void
+pbr_nht_individual_nexthop_update(struct pbr_nexthop_cache *pnhc,
+                                 const struct pbr_nht_individual *pnhi)
+{
+       assert(pnhi->nhr || pnhi->ifp); /* Either nexthop or interface update */
+
+       switch (pnhc->nexthop->type) {
+       case NEXTHOP_TYPE_IFINDEX:
+               pbr_nht_individual_nexthop_interface_update(pnhc, pnhi);
+               break;
+       case NEXTHOP_TYPE_IPV4:
+       case NEXTHOP_TYPE_IPV6:
+       case NEXTHOP_TYPE_IPV4_IFINDEX:
+       case NEXTHOP_TYPE_IPV6_IFINDEX:
+               pbr_nht_individual_nexthop_gw_update(pnhc, pnhi);
+               break;
+       case NEXTHOP_TYPE_BLACKHOLE:
+               pnhc->valid = true;
                break;
        }
+}
+
+static void pbr_nht_individual_nexthop_update_lookup(struct hash_bucket *b,
+                                                    void *data)
+{
+       struct pbr_nexthop_cache *pnhc = b->data;
+       struct pbr_nht_individual *pnhi = data;
+       char buf[PREFIX_STRLEN];
+       bool old_valid;
+
+       old_valid = pnhc->valid;
+
+       pbr_nht_individual_nexthop_update(pnhc, pnhi);
 
        DEBUGD(&pbr_dbg_nht, "\tFound %s: old: %d new: %d",
               prefix2str(&pnhi->nhr->prefix, buf, sizeof(buf)), old_valid,
@@ -736,7 +826,7 @@ pbr_nexthop_group_cache_to_nexthop_group(struct nexthop_group *nhg,
 static void pbr_nht_nexthop_update_lookup(struct hash_bucket *b, void *data)
 {
        struct pbr_nexthop_group_cache *pnhgc = b->data;
-       struct pbr_nht_individual pnhi;
+       struct pbr_nht_individual pnhi = {};
        struct nexthop_group nhg = {};
        bool old_valid;
 
@@ -778,9 +868,7 @@ pbr_nht_individual_nexthop_interface_update_lookup(struct hash_backet *b,
 
        old_valid = pnhc->valid;
 
-       if (pnhc->nexthop->type == NEXTHOP_TYPE_IFINDEX
-           && pnhc->nexthop->ifindex == pnhi->ifp->ifindex)
-               pnhc->valid = !!if_is_up(pnhi->ifp);
+       pbr_nht_individual_nexthop_update(pnhc, pnhi);
 
        DEBUGD(&pbr_dbg_nht, "\tFound %s: old: %d new: %d", pnhi->ifp->name,
               old_valid, pnhc->valid);
@@ -793,7 +881,7 @@ static void pbr_nht_nexthop_interface_update_lookup(struct hash_backet *b,
                                                    void *data)
 {
        struct pbr_nexthop_group_cache *pnhgc = b->data;
-       struct pbr_nht_individual pnhi;
+       struct pbr_nht_individual pnhi = {};
        bool old_valid;
 
        old_valid = pnhgc->valid;
index 3aa2a9224176be698aa5d4c8cd4e6a43ea6a508a..53ab22754ca1103336300b75138a4c6f829dd25c 100644 (file)
@@ -259,11 +259,11 @@ int pim_assert_recv(struct interface *ifp, struct pim_neighbor *neigh,
        curr += offset;
        curr_size -= offset;
 
-       if (curr_size != 8) {
+       if (curr_size < 8) {
                char src_str[INET_ADDRSTRLEN];
                pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
                zlog_warn(
-                       "%s: preference/metric size is not 8: size=%d from %s on interface %s",
+                       "%s: preference/metric size is less than 8 bytes: size=%d from %s on interface %s",
                        __PRETTY_FUNCTION__, curr_size, src_str, ifp->name);
                return -3;
        }
index 75a733f8fcfeba54682d169d492814cac42cf40c..1864ba7369d411fbf375bfa4445d7a2cfd373ba2 100644 (file)
@@ -10,9 +10,12 @@ qpb_libfrr_pb_la_SOURCES = \
        qpb/qpb.c \
        qpb/qpb_allocator.c \
        # end
+
+if HAVE_PROTOBUF
 nodist_qpb_libfrr_pb_la_SOURCES = \
        qpb/qpb.pb-c.c \
        # end
+endif
 
 noinst_HEADERS += \
        qpb/linear_allocator.h \
index fa0a6d8a0a33f1f03b04877ff9bc6002551143fe..b3f9ac763085dc8157cb5d63fcc008fca53577a8 100644 (file)
@@ -656,6 +656,9 @@ fi
 
 
 %files pythontools
+%{_sbindir}/generate_support_bundle.py
+%{_sbindir}/generate_support_bundle.pyc
+%{_sbindir}/generate_support_bundle.pyo
 %{_sbindir}/frr-reload.py
 %{_sbindir}/frr-reload.pyc
 %{_sbindir}/frr-reload.pyo
index ad373aebdfbbf3cfc9af9edb1de934d2705cfdde..1b5a582cb1006014c47f03d3caa7b435d624f732 100644 (file)
@@ -3641,6 +3641,37 @@ static int rip_vrf_enable(struct vrf *vrf)
        int socket;
 
        rip = rip_lookup_by_vrf_name(vrf->name);
+       if (!rip) {
+               char *old_vrf_name = NULL;
+
+               rip = (struct rip *)vrf->info;
+               if (!rip)
+                       return 0;
+               /* update vrf name */
+               if (rip->vrf_name)
+                       old_vrf_name = rip->vrf_name;
+               rip->vrf_name = XSTRDUP(MTYPE_RIP_VRF_NAME, vrf->name);
+               /*
+                * HACK: Change the RIP VRF in the running configuration directly,
+                * bypassing the northbound layer. This is necessary to avoid deleting
+                * the RIP and readding it in the new VRF, which would have
+                * several implications.
+                */
+               if (yang_module_find("frr-ripd") && old_vrf_name) {
+                       struct lyd_node *rip_dnode;
+
+                       rip_dnode = yang_dnode_get(
+                               running_config->dnode,
+                               "/frr-ripd:ripd/instance[vrf='%s']/vrf",
+                               old_vrf_name);
+                       if (rip_dnode) {
+                               yang_dnode_change_leaf(rip_dnode, vrf->name);
+                               running_config->version++;
+                       }
+               }
+               if (old_vrf_name)
+                       XFREE(MTYPE_RIP_VRF_NAME, old_vrf_name);
+       }
        if (!rip || rip->enabled)
                return 0;
 
@@ -3682,7 +3713,7 @@ static int rip_vrf_disable(struct vrf *vrf)
 void rip_vrf_init(void)
 {
        vrf_init(rip_vrf_new, rip_vrf_enable, rip_vrf_disable, rip_vrf_delete,
-                NULL);
+                rip_vrf_enable);
 }
 
 void rip_vrf_terminate(void)
index 49f7dda646a9cac67282986bfab019e1fd7b0451..ef4e474737d58614eecf5169d792cf75382210fa 100644 (file)
@@ -2776,7 +2776,39 @@ static int ripng_vrf_enable(struct vrf *vrf)
        int socket;
 
        ripng = ripng_lookup_by_vrf_name(vrf->name);
-       if (!ripng || ripng->enabled)
+       if (!ripng) {
+               char *old_vrf_name = NULL;
+
+               ripng = (struct ripng *)vrf->info;
+               if (!ripng)
+                       return 0;
+               /* update vrf name */
+               if (ripng->vrf_name)
+                       old_vrf_name = ripng->vrf_name;
+               ripng->vrf_name = XSTRDUP(MTYPE_RIPNG_VRF_NAME, vrf->name);
+               /*
+                * HACK: Change the RIPng VRF in the running configuration directly,
+                * bypassing the northbound layer. This is necessary to avoid deleting
+                * the RIPng and readding it in the new VRF, which would have
+                * several implications.
+                */
+               if (yang_module_find("frr-ripngd") && old_vrf_name) {
+                       struct lyd_node *ripng_dnode;
+
+                       ripng_dnode = yang_dnode_get(
+                               running_config->dnode,
+                               "/frr-ripngd:ripngd/instance[vrf='%s']/vrf",
+                               old_vrf_name);
+                       if (ripng_dnode) {
+                               yang_dnode_change_leaf(ripng_dnode, vrf->name);
+                               running_config->version++;
+                       }
+               }
+               if (old_vrf_name)
+                       XFREE(MTYPE_RIPNG_VRF_NAME, old_vrf_name);
+       }
+
+       if (ripng->enabled)
                return 0;
 
        if (IS_RIPNG_DEBUG_EVENT)
@@ -2784,13 +2816,11 @@ static int ripng_vrf_enable(struct vrf *vrf)
                           vrf->vrf_id);
 
        /* Activate the VRF RIPng instance. */
-       if (!ripng->enabled) {
-               socket = ripng_make_socket(vrf);
-               if (socket < 0)
-                       return -1;
+       socket = ripng_make_socket(vrf);
+       if (socket < 0)
+               return -1;
 
-               ripng_instance_enable(ripng, vrf, socket);
-       }
+       ripng_instance_enable(ripng, vrf, socket);
 
        return 0;
 }
@@ -2817,7 +2847,7 @@ static int ripng_vrf_disable(struct vrf *vrf)
 void ripng_vrf_init(void)
 {
        vrf_init(ripng_vrf_new, ripng_vrf_enable, ripng_vrf_disable,
-                ripng_vrf_delete, NULL);
+                ripng_vrf_delete, ripng_vrf_enable);
 }
 
 void ripng_vrf_terminate(void)
index 34f58a98e23ff8d6b63aad239c8623a9f7d6b7c5..a8a5ca523a279e0f12061317696157794825994a 100644 (file)
@@ -100,7 +100,8 @@ int static_add_route(afi_t afi, safi_t safi, uint8_t type, struct prefix *p,
                             && IPV4_ADDR_SAME(&gate->ipv4, &si->addr.ipv4))
                            || (afi == AFI_IP6
                                && IPV6_ADDR_SAME(gate, &si->addr.ipv6))))
-                   && (!strcmp(ifname ? ifname : "", si->ifname))) {
+                   && (!strcmp(ifname ? ifname : "", si->ifname))
+                   && nh_svrf->vrf->vrf_id == si->nh_vrf_id) {
                        if ((distance == si->distance) && (tag == si->tag)
                            && (table_id == si->table_id)
                            && !memcmp(&si->snh_label, snh_label,
index 3a9e4e8fa4671c933c7464fef325a248e25991e0..f926e1d9cd2ad4f967770260046816bb178876ff 100644 (file)
@@ -35,7 +35,6 @@
 #ifndef VTYSH_EXTRACT_PL
 #include "staticd/static_vty_clippy.c"
 #endif
-
 static struct static_vrf *static_vty_get_unknown_vrf(struct vty *vty,
                                                     const char *vrf_name)
 {
@@ -479,6 +478,23 @@ static int static_route_leak(
                        return CMD_WARNING_CONFIG_FAILED;
                }
                gatep = &gate;
+
+               if (afi == AFI_IP && !negate) {
+                       if (if_lookup_exact_address(&gatep->ipv4, AF_INET,
+                                                       svrf->vrf->vrf_id))
+                               if (vty)
+                                       vty_out(vty,
+                                               "%% Warning!! Local connected address is configured as Gateway IP(%s)\n",
+                                               gate_str);
+               } else if (afi == AFI_IP6 && !negate) {
+                       if (if_lookup_exact_address(&gatep->ipv6, AF_INET6,
+                                                       svrf->vrf->vrf_id))
+                               if (vty)
+                                       vty_out(vty,
+                                               "%% Warning!! Local connected address is configured as Gateway IPv6(%s)\n",
+                                               gate_str);
+               }
+
        }
 
        if (gate_str == NULL && ifname == NULL)
index 27605da63fafbc11b1fd290a19571509ef47e07c..1965c2968ef3deea29cd3c1820ca5e0b10a862b7 100644 (file)
@@ -200,6 +200,25 @@ struct static_nht_data {
        uint8_t nh_num;
 };
 
+/* API to check whether the configured nexthop address is
+ * one of its local connected address or not.
+ */
+static bool
+static_nexthop_is_local(vrf_id_t vrfid, struct prefix *addr, int family)
+{
+       if (family == AF_INET) {
+               if (if_lookup_exact_address(&addr->u.prefix4,
+                                       AF_INET,
+                                       vrfid))
+                       return true;
+       } else if (family == AF_INET6) {
+               if (if_lookup_exact_address(&addr->u.prefix6,
+                                       AF_INET6,
+                                       vrfid))
+                       return true;
+       }
+       return false;
+}
 static int static_zebra_nexthop_update(ZAPI_CALLBACK_ARGS)
 {
        struct static_nht_data *nhtd, lookup;
@@ -214,6 +233,12 @@ static int static_zebra_nexthop_update(ZAPI_CALLBACK_ARGS)
        if (nhr.prefix.family == AF_INET6)
                afi = AFI_IP6;
 
+       if (nhr.type == ZEBRA_ROUTE_CONNECT) {
+               if (static_nexthop_is_local(vrf_id, &nhr.prefix,
+                                       nhr.prefix.family))
+                       nhr.nexthop_num = 0;
+       }
+
        memset(&lookup, 0, sizeof(lookup));
        lookup.nh = &nhr.prefix;
        lookup.nh_vrf_id = vrf_id;
index b2612892f99cfd6c88718f406f330b6f480861fd..b5db36703a58f75d15e6ebaf6d7f03d3d1b089af 100644 (file)
@@ -1379,6 +1379,7 @@ int main(void)
 
        i = 0;
 
+       frr_pthread_init();
        bgp_pthreads_init();
        bgp_pth_ka->running = true;
 
index 968f9ac445d25b610730574d9199aca94a5b189f..db1cf0611d4eeb117fe6e14e9db7b954c30ecafd 100644 (file)
@@ -916,6 +916,7 @@ int main(void)
        vrf_init(NULL, NULL, NULL, NULL, NULL);
        bgp_option_set(BGP_OPT_NO_LISTEN);
 
+       frr_pthread_init();
        bgp_pthreads_init();
        bgp_pth_ka->running = true;
 
index 8e1b62ac15e513a9d5fc52df07e3715a0445bb6a..e5d3030ed1e0565b1b48fb1bad4fbabd784f768c 100644 (file)
@@ -1391,6 +1391,7 @@ static void bgp_startup(void)
        bgp_master_init(master);
        bgp_option_set(BGP_OPT_NO_LISTEN);
        vrf_init(NULL, NULL, NULL, NULL, NULL);
+       frr_pthread_init();
        bgp_init(0);
        bgp_pthreads_run();
 }
index 6f8bc2218e2f7bcca388a9f7185bcb2816223ca9..46e45e5ee07abe69c86bb889e46916ff29187517 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
index 0a20231371d85bd3ceadf6103bea65d29e5176a6..a7d6fe11a6dd313915e9742ad93fbcb116ec098d 100644 (file)
@@ -15,6 +15,7 @@ S>* 4.5.6.11/32 [1/0] via 192.168.0.2, r1-eth0, XX:XX:XX
 S>* 4.5.6.12/32 [1/0] is directly connected, r1-eth0, XX:XX:XX
 S>* 4.5.6.13/32 [1/0] unreachable (blackhole), XX:XX:XX
 S>* 4.5.6.14/32 [1/0] unreachable (blackhole), XX:XX:XX
+S   4.5.6.15/32 [255/0] via 192.168.0.2, r1-eth0, XX:XX:XX
 S>* 4.5.6.7/32 [1/0] unreachable (blackhole), XX:XX:XX
 S>* 4.5.6.8/32 [1/0] unreachable (blackhole), XX:XX:XX
 S>* 4.5.6.9/32 [1/0] unreachable (ICMP unreachable), XX:XX:XX
index 6e3e9c87c140a414d09efbcd8785f7ccf34e8129..d5bc16a2bfde792a99dfd3b1c5911e7ed8326d14 100644 (file)
@@ -20,9 +20,10 @@ C * fe80::/64 is directly connected, r1-eth7, XX:XX:XX
 C * fe80::/64 is directly connected, r1-eth8, XX:XX:XX
 C * fe80::/64 is directly connected, r1-eth9, XX:XX:XX
 O   fc00:0:0:4::/64 [110/10] is directly connected, r1-eth4, XX:XX:XX
-S>* 4:5::/32 [1/0] is directly connected, r1-eth0, XX:XX:XX
 S>* 4:5::6:10/128 [1/0] via fc00::2, r1-eth0, XX:XX:XX
 S>* 4:5::6:11/128 [1/0] via fc00::2, r1-eth0, XX:XX:XX
+S>* 4:5::6:12/128 [1/0] is directly connected, r1-eth0, XX:XX:XX
+S   4:5::6:15/128 [255/0] via fc00::2, r1-eth0, XX:XX:XX
 S>* 4:5::6:7/128 [1/0] unreachable (blackhole), XX:XX:XX
 S>* 4:5::6:8/128 [1/0] unreachable (blackhole), XX:XX:XX
 S>* 4:5::6:9/128 [1/0] unreachable (ICMP unreachable), XX:XX:XX
index c621593ef741805282f6e4a765d4d1a8df482ea2..85c867696485e02a9c07965ba78ccc1ebb5d6390 100644 (file)
@@ -20,7 +20,12 @@ ip route 4.5.6.11/32 192.168.0.2 r1-eth0
 ipv6 route 4:5::6:11/128 fc00:0:0:0::2 r1-eth0
 # Create ifname routes
 ip route 4.5.6.12/32 r1-eth0
-ipv6 route 4:5::6:12/32 r1-eth0
+ipv6 route 4:5::6:12/128 r1-eth0
+# Create a route that has a large admin distance
+# an admin distance of 255 should be accepted
+# by zebra but not installed.
+ip route 4.5.6.15/32 192.168.0.2 255
+ipv6 route 4:5::6:15/128 fc00:0:0:0::2 255
 !
 interface r1-eth0
  description to sw0 - no routing protocol
diff --git a/tests/topotests/bgp_aggregate-address_route-map/__init__.py b/tests/topotests/bgp_aggregate-address_route-map/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/topotests/bgp_aggregate-address_route-map/r1/bgpd.conf b/tests/topotests/bgp_aggregate-address_route-map/r1/bgpd.conf
new file mode 100644 (file)
index 0000000..ef34817
--- /dev/null
@@ -0,0 +1,10 @@
+router bgp 65000
+  neighbor 192.168.255.2 remote-as 65001
+  address-family ipv4 unicast
+    redistribute connected
+    aggregate-address 172.16.255.0/24 route-map aggr-rmap
+  exit-address-family
+!
+route-map aggr-rmap permit 10
+  set metric 123
+!
diff --git a/tests/topotests/bgp_aggregate-address_route-map/r1/zebra.conf b/tests/topotests/bgp_aggregate-address_route-map/r1/zebra.conf
new file mode 100644 (file)
index 0000000..0a283c0
--- /dev/null
@@ -0,0 +1,9 @@
+!
+interface lo
+ ip address 172.16.255.254/32
+!
+interface r1-eth0
+ ip address 192.168.255.1/24
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_aggregate-address_route-map/r2/bgpd.conf b/tests/topotests/bgp_aggregate-address_route-map/r2/bgpd.conf
new file mode 100644 (file)
index 0000000..73d4d0a
--- /dev/null
@@ -0,0 +1,4 @@
+router bgp 65001
+  neighbor 192.168.255.1 remote-as 65000
+  exit-address-family
+!
diff --git a/tests/topotests/bgp_aggregate-address_route-map/r2/zebra.conf b/tests/topotests/bgp_aggregate-address_route-map/r2/zebra.conf
new file mode 100644 (file)
index 0000000..606c17b
--- /dev/null
@@ -0,0 +1,6 @@
+!
+interface r2-eth0
+ ip address 192.168.255.2/24
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_aggregate-address_route-map/test_bgp_aggregate-address_route-map.py b/tests/topotests/bgp_aggregate-address_route-map/test_bgp_aggregate-address_route-map.py
new file mode 100644 (file)
index 0000000..d6753e9
--- /dev/null
@@ -0,0 +1,131 @@
+#!/usr/bin/env python
+
+#
+# bgp_aggregate-address_route-map.py
+# Part of NetDEF Topology Tests
+#
+# Copyright (c) 2019 by
+# Network Device Education Foundation, Inc. ("NetDEF")
+#
+# 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.
+#
+
+"""
+bgp_aggregate-address_route-map.py:
+
+Test if works the following commands:
+router bgp 65031
+  address-family ipv4 unicast
+    aggregate-address 192.168.255.0/24 route-map aggr-rmap
+
+route-map aggr-rmap permit 10
+  set metric 123
+"""
+
+import os
+import sys
+import json
+import time
+import pytest
+import functools
+
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, '../'))
+
+# pylint: disable=C0413
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
+from mininet.topo import Topo
+
+class TemplateTopo(Topo):
+    def build(self, *_args, **_opts):
+        tgen = get_topogen(self)
+
+        for routern in range(1, 3):
+            tgen.add_router('r{}'.format(routern))
+
+        switch = tgen.add_switch('s1')
+        switch.add_link(tgen.gears['r1'])
+        switch.add_link(tgen.gears['r2'])
+
+def setup_module(mod):
+    tgen = Topogen(TemplateTopo, mod.__name__)
+    tgen.start_topology()
+
+    router_list = tgen.routers()
+
+    for i, (rname, router) in enumerate(router_list.iteritems(), 1):
+        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.start_router()
+
+def teardown_module(mod):
+    tgen = get_topogen()
+    tgen.stop_topology()
+
+def test_bgp_maximum_prefix_invalid():
+    tgen = get_topogen()
+
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    router = tgen.gears['r2']
+
+    def _bgp_converge(router):
+        output = json.loads(router.vtysh_cmd("show ip bgp neighbor 192.168.255.1 json"))
+        expected = {
+            '192.168.255.1': {
+                'bgpState': 'Established',
+                'addressFamilyInfo': {
+                    'ipv4Unicast': {
+                        'acceptedPrefixCounter': 3
+                    }
+                }
+            }
+        }
+        return topotest.json_cmp(output, expected)
+
+    def _bgp_aggregate_address_has_metric(router):
+        output = json.loads(router.vtysh_cmd("show ip bgp 172.16.255.0/24 json"))
+        expected = {
+            'paths': [
+                {
+                    'med': 123
+                }
+            ]
+        }
+        return topotest.json_cmp(output, expected)
+
+    test_func = functools.partial(_bgp_converge, router)
+    success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5)
+
+    assert result is None, 'Failed to see bgp convergence in "{}"'.format(router)
+
+    test_func = functools.partial(_bgp_aggregate_address_has_metric, router)
+    success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5)
+
+    assert result is None, 'Failed to see applied metric for aggregated prefix in "{}"'.format(router)
+
+if __name__ == '__main__':
+    args = ["-s"] + sys.argv[1:]
+    sys.exit(pytest.main(args))
diff --git a/tests/topotests/ldp-topo1/r1/ip_mpls_route.ref-1 b/tests/topotests/ldp-topo1/r1/ip_mpls_route.ref-1
deleted file mode 100644 (file)
index f244122..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-xx as to xx via inet 10.0.1.2 dev r1-eth0 proto xx
-xx as to xx via inet 10.0.1.2 dev r1-eth0 proto xx
-xx via inet 10.0.1.2 dev r1-eth0 proto xx
-xx via inet 10.0.1.2 dev r1-eth0 proto xx
-xx via inet 10.0.1.2 dev r1-eth0 proto xx
diff --git a/tests/topotests/ldp-topo1/r1/show_ipv4_route.ref-1 b/tests/topotests/ldp-topo1/r1/show_ipv4_route.ref-1
deleted file mode 100644 (file)
index ff99ff9..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-O   1.1.1.1/32 [110/0] is directly connected, lo
-O>* 2.2.2.2/32 [110/10] via 10.0.1.2, r1-eth0
-O>* 3.3.3.3/32 [110/20] via 10.0.1.2, r1-eth0, label xxx
-O>* 4.4.4.4/32 [110/20] via 10.0.1.2, r1-eth0, label xxx
-O   10.0.1.0/24 [110/10] is directly connected, r1-eth0
-O>* 10.0.2.0/24 [110/20] via 10.0.1.2, r1-eth0
-O>* 10.0.3.0/24 [110/20] via 10.0.1.2, r1-eth0
diff --git a/tests/topotests/ldp-topo1/r1/show_mpls_ldp_binding.ref-1 b/tests/topotests/ldp-topo1/r1/show_mpls_ldp_binding.ref-1
deleted file mode 100644 (file)
index ff72a1c..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-1.1.1.1/32
-        Local binding: label: imp-null
-        Remote bindings:
-            Peer                Label
-            -----------------   ---------
-            2.2.2.2             xxx
-2.2.2.2/32
-        Local binding: label: xxx
-        Remote bindings:
-            Peer                Label
-            -----------------   ---------
-            2.2.2.2             imp-null
-3.3.3.3/32
-        Local binding: label: xxx
-        Remote bindings:
-            Peer                Label
-            -----------------   ---------
-            2.2.2.2             xxx
-4.4.4.4/32
-        Local binding: label: xxx
-        Remote bindings:
-            Peer                Label
-            -----------------   ---------
-            2.2.2.2             xxx
-10.0.1.0/24
-        Local binding: label: imp-null
-        Remote bindings:
-            Peer                Label
-            -----------------   ---------
-            2.2.2.2             imp-null
-10.0.2.0/24
-        Local binding: label: xxx
-        Remote bindings:
-            Peer                Label
-            -----------------   ---------
-            2.2.2.2             imp-null
-10.0.3.0/24
-        Local binding: label: xxx
-        Remote bindings:
-            Peer                Label
-            -----------------   ---------
-            2.2.2.2             imp-null
diff --git a/tests/topotests/ldp-topo1/r1/show_mpls_ldp_discovery.ref-1 b/tests/topotests/ldp-topo1/r1/show_mpls_ldp_discovery.ref-1
deleted file mode 100644 (file)
index 38522e1..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-Local LDP Identifier: 1.1.1.1:0
-Discovery Sources:
-  Interfaces:
-    r1-eth0: xmit/recv
-      LDP Id: 2.2.2.2:0, Transport address: 2.2.2.2
-          Hold time: 15 sec
-  Targeted Hellos:
diff --git a/tests/topotests/ldp-topo1/r1/show_mpls_ldp_interface.ref-1 b/tests/topotests/ldp-topo1/r1/show_mpls_ldp_interface.ref-1
deleted file mode 100644 (file)
index 0fb15d2..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-AF   Interface   State  Uptime   Hello Timers  ac
-ipv4 r1-eth0     ACTIVE xx:xx:xx 5/15           1
diff --git a/tests/topotests/ldp-topo1/r1/show_mpls_ldp_neighbor.ref-1 b/tests/topotests/ldp-topo1/r1/show_mpls_ldp_neighbor.ref-1
deleted file mode 100644 (file)
index 3df98bf..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-Peer LDP Identifier: 2.2.2.2:0
-  TCP connection: 1.1.1.1:xxx - 2.2.2.2:xxx
-  Session Holdtime: 180 sec
-  State: OPERATIONAL; Downstream-Unsolicited
-  Up time: xx:xx:xx
-  LDP Discovery Sources:
-    IPv4:
-      Interface: r1-eth0
index 61cb9eec82617fc0e5b63083a3f4ceece7c298f2..7e24359af39c9381e5224eee8913409c97254c8b 100644 (file)
@@ -1,8 +1,8 @@
- Inbound                            Outbound
-   Label     Type          Nexthop     Label
---------  -------  ---------------  --------
-      XX      LDP         10.0.1.2        XX
-      XX      LDP         10.0.1.2        XX
-      XX      LDP         10.0.1.2  implicit-null
-      XX      LDP         10.0.1.2  implicit-null
-      XX      LDP         10.0.1.2  implicit-null
+ Inbound Label  Type  Nexthop   Outbound Label  
+ -----------------------------------------------
+ XX             LDP   10.0.1.2  XX              
+ XX             LDP   10.0.1.2  XX              
+ XX             LDP   10.0.1.2  implicit-null   
+ XX             LDP   10.0.1.2  implicit-null   
+ XX             LDP   10.0.1.2  implicit-null   
+
diff --git a/tests/topotests/ldp-topo1/r1/show_mpls_table.ref-1 b/tests/topotests/ldp-topo1/r1/show_mpls_table.ref-1
deleted file mode 100644 (file)
index 912a082..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
- Inbound                            Outbound
-   Label     Type          Nexthop     Label
---------  -------  ---------------  --------
-      XX      LDP         10.0.1.2         3
-      XX      LDP         10.0.1.2         3
-      XX      LDP         10.0.1.2         3
-      XX      LDP         10.0.1.2        XX
-      XX      LDP         10.0.1.2        XX
diff --git a/tests/topotests/ldp-topo1/r1/show_mpls_table.ref-no-impl-null b/tests/topotests/ldp-topo1/r1/show_mpls_table.ref-no-impl-null
deleted file mode 100644 (file)
index 912a082..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
- Inbound                            Outbound
-   Label     Type          Nexthop     Label
---------  -------  ---------------  --------
-      XX      LDP         10.0.1.2         3
-      XX      LDP         10.0.1.2         3
-      XX      LDP         10.0.1.2         3
-      XX      LDP         10.0.1.2        XX
-      XX      LDP         10.0.1.2        XX
diff --git a/tests/topotests/ldp-topo1/r2/show_ipv4_route.ref-1 b/tests/topotests/ldp-topo1/r2/show_ipv4_route.ref-1
deleted file mode 100644 (file)
index eaec2f1..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-O>* 1.1.1.1/32 [110/10] via 10.0.1.1, r2-eth0
-O   2.2.2.2/32 [110/0] is directly connected, lo
-O>* 3.3.3.3/32 [110/10] via 10.0.2.3, r2-eth1
-O>* 4.4.4.4/32 [110/10] via 10.0.2.4, r2-eth1
-O   10.0.1.0/24 [110/10] is directly connected, r2-eth0
-O   10.0.2.0/24 [110/10] is directly connected, r2-eth1
-O   10.0.3.0/24 [110/10] is directly connected, r2-eth2
diff --git a/tests/topotests/ldp-topo1/r2/show_mpls_ldp_binding.ref-1 b/tests/topotests/ldp-topo1/r2/show_mpls_ldp_binding.ref-1
deleted file mode 100644 (file)
index 54ee390..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-1.1.1.1/32
-        Local binding: label: xxx
-        Remote bindings:
-            Peer                Label
-            -----------------   ---------
-            1.1.1.1             imp-null
-            3.3.3.3             xxx
-            4.4.4.4             xxx
-2.2.2.2/32
-        Local binding: label: imp-null
-        Remote bindings:
-            Peer                Label
-            -----------------   ---------
-            1.1.1.1             xxx
-            3.3.3.3             xxx
-            4.4.4.4             xxx
-3.3.3.3/32
-        Local binding: label: xxx
-        Remote bindings:
-            Peer                Label
-            -----------------   ---------
-            1.1.1.1             xxx
-            3.3.3.3             imp-null
-            4.4.4.4             xxx
-4.4.4.4/32
-        Local binding: label: xxx
-        Remote bindings:
-            Peer                Label
-            -----------------   ---------
-            1.1.1.1             xxx
-            3.3.3.3             xxx
-            4.4.4.4             imp-null
-10.0.1.0/24
-        Local binding: label: imp-null
-        Remote bindings:
-            Peer                Label
-            -----------------   ---------
-            1.1.1.1             imp-null
-            3.3.3.3             xxx
-            4.4.4.4             xxx
-10.0.2.0/24
-        Local binding: label: imp-null
-        Remote bindings:
-            Peer                Label
-            -----------------   ---------
-            1.1.1.1             xxx
-            3.3.3.3             imp-null
-            4.4.4.4             imp-null
-10.0.3.0/24
-        Local binding: label: imp-null
-        Remote bindings:
-            Peer                Label
-            -----------------   ---------
-            1.1.1.1             xxx
-            3.3.3.3             imp-null
-            4.4.4.4             xxx
diff --git a/tests/topotests/ldp-topo1/r2/show_mpls_ldp_discovery.ref-1 b/tests/topotests/ldp-topo1/r2/show_mpls_ldp_discovery.ref-1
deleted file mode 100644 (file)
index b1bebd7..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-Local LDP Identifier: 2.2.2.2:0
-Discovery Sources:
-  Interfaces:
-    r2-eth0: xmit/recv
-      LDP Id: 1.1.1.1:0, Transport address: 1.1.1.1
-          Hold time: 15 sec
-    r2-eth1: xmit/recv
-      LDP Id: 3.3.3.3:0, Transport address: 3.3.3.3
-          Hold time: 15 sec
-      LDP Id: 4.4.4.4:0, Transport address: 4.4.4.4
-          Hold time: 15 sec
-  Targeted Hellos:
diff --git a/tests/topotests/ldp-topo1/r2/show_mpls_ldp_interface.ref-1 b/tests/topotests/ldp-topo1/r2/show_mpls_ldp_interface.ref-1
deleted file mode 100644 (file)
index f9fc984..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-AF   Interface   State  Uptime   Hello Timers  ac
-ipv4 r2-eth0     ACTIVE xx:xx:xx 5/15           1
-ipv4 r2-eth1     ACTIVE xx:xx:xx 5/15           2
diff --git a/tests/topotests/ldp-topo1/r2/show_mpls_ldp_neighbor.ref-1 b/tests/topotests/ldp-topo1/r2/show_mpls_ldp_neighbor.ref-1
deleted file mode 100644 (file)
index a70e2f4..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-Peer LDP Identifier: 1.1.1.1:0
-  TCP connection: 2.2.2.2:xxx - 1.1.1.1:xxx
-  Session Holdtime: 180 sec
-  State: OPERATIONAL; Downstream-Unsolicited
-  Up time: xx:xx:xx
-  LDP Discovery Sources:
-    IPv4:
-      Interface: r2-eth0
-
-Peer LDP Identifier: 3.3.3.3:0
-  TCP connection: 2.2.2.2:xxx - 3.3.3.3:xxx
-  Session Holdtime: 180 sec
-  State: OPERATIONAL; Downstream-Unsolicited
-  Up time: xx:xx:xx
-  LDP Discovery Sources:
-    IPv4:
-      Interface: r2-eth1
-
-Peer LDP Identifier: 4.4.4.4:0
-  TCP connection: 2.2.2.2:xxx - 4.4.4.4:xxx
-  Session Holdtime: 180 sec
-  State: OPERATIONAL; Downstream-Unsolicited
-  Up time: xx:xx:xx
-  LDP Discovery Sources:
-    IPv4:
-      Interface: r2-eth1
index 46420ccd11727e5d70d8fb7516f5b9269b82d7c6..df05a6b31aeb6f8829c34fb9b7f6f5e7453ce66f 100644 (file)
@@ -1,7 +1,7 @@
- Inbound                            Outbound
-   Label     Type          Nexthop     Label
---------  -------  ---------------  --------
-      XX      LDP         10.0.1.1  implicit-null
-      XX      LDP         10.0.2.3  implicit-null
-      XX      LDP         10.0.2.4  implicit-null
-      XX      LDP         10.0.3.3  implicit-null
+ Inbound Label  Type  Nexthop   Outbound Label  
+ -----------------------------------------------
+ XX             LDP   10.0.1.1  implicit-null   
+ XX             LDP   10.0.2.3  implicit-null   
+ XX             LDP   10.0.2.4  implicit-null   
+ XX             LDP   10.0.3.3  implicit-null   
+
diff --git a/tests/topotests/ldp-topo1/r2/show_mpls_table.ref-1 b/tests/topotests/ldp-topo1/r2/show_mpls_table.ref-1
deleted file mode 100644 (file)
index ba244e7..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
- Inbound                            Outbound
-   Label     Type          Nexthop     Label
---------  -------  ---------------  --------
-      XX      LDP         10.0.1.1         3
-      XX      LDP         10.0.2.3         3
-      XX      LDP         10.0.2.4         3
-      XX      LDP         10.0.3.3         3
diff --git a/tests/topotests/ldp-topo1/r2/show_mpls_table.ref-no-impl-null b/tests/topotests/ldp-topo1/r2/show_mpls_table.ref-no-impl-null
deleted file mode 100644 (file)
index ba244e7..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
- Inbound                            Outbound
-   Label     Type          Nexthop     Label
---------  -------  ---------------  --------
-      XX      LDP         10.0.1.1         3
-      XX      LDP         10.0.2.3         3
-      XX      LDP         10.0.2.4         3
-      XX      LDP         10.0.3.3         3
diff --git a/tests/topotests/ldp-topo1/r3/show_ipv4_route.ref-1 b/tests/topotests/ldp-topo1/r3/show_ipv4_route.ref-1
deleted file mode 100644 (file)
index c8a2940..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-O>* 1.1.1.1/32 [110/20] via 10.0.2.2, r3-eth0, label xxx
-O>* 2.2.2.2/32 [110/10] via 10.0.2.2, r3-eth0
-O   3.3.3.3/32 [110/0] is directly connected, lo
-O>* 4.4.4.4/32 [110/10] via 10.0.2.4, r3-eth0
-O>* 10.0.1.0/24 [110/20] via 10.0.2.2, r3-eth0
-O   10.0.2.0/24 [110/10] is directly connected, r3-eth0
-O   10.0.3.0/24 [110/10] is directly connected, r3-eth1
diff --git a/tests/topotests/ldp-topo1/r3/show_mpls_ldp_binding.ref-1 b/tests/topotests/ldp-topo1/r3/show_mpls_ldp_binding.ref-1
deleted file mode 100644 (file)
index e04d2b7..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-1.1.1.1/32
-        Local binding: label: xxx
-        Remote bindings:
-            Peer                Label
-            -----------------   ---------
-            2.2.2.2             xxx
-            4.4.4.4             xxx
-2.2.2.2/32
-        Local binding: label: xxx
-        Remote bindings:
-            Peer                Label
-            -----------------   ---------
-            2.2.2.2             imp-null
-            4.4.4.4             xxx
-3.3.3.3/32
-        Local binding: label: imp-null
-        Remote bindings:
-            Peer                Label
-            -----------------   ---------
-            2.2.2.2             xxx
-            4.4.4.4             xxx
-4.4.4.4/32
-        Local binding: label: xxx
-        Remote bindings:
-            Peer                Label
-            -----------------   ---------
-            2.2.2.2             xxx
-            4.4.4.4             imp-null
-10.0.1.0/24
-        Local binding: label: xxx
-        Remote bindings:
-            Peer                Label
-            -----------------   ---------
-            2.2.2.2             imp-null
-            4.4.4.4             xxx
-10.0.2.0/24
-        Local binding: label: imp-null
-        Remote bindings:
-            Peer                Label
-            -----------------   ---------
-            2.2.2.2             imp-null
-            4.4.4.4             imp-null
-10.0.3.0/24
-        Local binding: label: imp-null
-        Remote bindings:
-            Peer                Label
-            -----------------   ---------
-            2.2.2.2             imp-null
-            4.4.4.4             xxx
diff --git a/tests/topotests/ldp-topo1/r3/show_mpls_ldp_discovery.ref-1 b/tests/topotests/ldp-topo1/r3/show_mpls_ldp_discovery.ref-1
deleted file mode 100644 (file)
index 5e299ff..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-Local LDP Identifier: 3.3.3.3:0
-Discovery Sources:
-  Interfaces:
-    r3-eth0: xmit/recv
-      LDP Id: 2.2.2.2:0, Transport address: 2.2.2.2
-          Hold time: 15 sec
-      LDP Id: 4.4.4.4:0, Transport address: 4.4.4.4
-          Hold time: 15 sec
-  Targeted Hellos:
diff --git a/tests/topotests/ldp-topo1/r3/show_mpls_ldp_interface.ref-1 b/tests/topotests/ldp-topo1/r3/show_mpls_ldp_interface.ref-1
deleted file mode 100644 (file)
index 243811e..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-AF   Interface   State  Uptime   Hello Timers  ac
-ipv4 r3-eth0     ACTIVE xx:xx:xx 5/15           2
diff --git a/tests/topotests/ldp-topo1/r3/show_mpls_ldp_neighbor.ref-1 b/tests/topotests/ldp-topo1/r3/show_mpls_ldp_neighbor.ref-1
deleted file mode 100644 (file)
index ee1983a..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-Peer LDP Identifier: 2.2.2.2:0
-  TCP connection: 3.3.3.3:xxx - 2.2.2.2:xxx
-  Session Holdtime: 180 sec
-  State: OPERATIONAL; Downstream-Unsolicited
-  Up time: xx:xx:xx
-  LDP Discovery Sources:
-    IPv4:
-      Interface: r3-eth0
-
-Peer LDP Identifier: 4.4.4.4:0
-  TCP connection: 3.3.3.3:xxx - 4.4.4.4:xxx
-  Session Holdtime: 180 sec
-  State: OPERATIONAL; Downstream-Unsolicited
-  Up time: xx:xx:xx
-  LDP Discovery Sources:
-    IPv4:
-      Interface: r3-eth0
index c367f240f4248545faf6e8d1b1af7b7ebf284154..39788956135c87318e97b70636fd307412cb009e 100644 (file)
@@ -1,10 +1,10 @@
- Inbound                            Outbound
-   Label     Type          Nexthop     Label
---------  -------  ---------------  --------
-      XX      LDP         10.0.2.2        XX
-      XX      LDP         10.0.2.2  implicit-null
-      XX      LDP         10.0.2.2  implicit-null
-      XX      LDP         10.0.2.4  implicit-null
-      XX      LDP         10.0.3.2        XX
-      XX      LDP         10.0.3.2  implicit-null
-      XX      LDP         10.0.3.2  implicit-null
+ Inbound Label  Type  Nexthop   Outbound Label  
+ -----------------------------------------------
+ XX             LDP   10.0.2.2  XX              
+ XX             LDP   10.0.2.2  implicit-null   
+ XX             LDP   10.0.2.2  implicit-null   
+ XX             LDP   10.0.2.4  implicit-null   
+ XX             LDP   10.0.3.2  XX              
+ XX             LDP   10.0.3.2  implicit-null   
+ XX             LDP   10.0.3.2  implicit-null   
+
diff --git a/tests/topotests/ldp-topo1/r3/show_mpls_table.ref-1 b/tests/topotests/ldp-topo1/r3/show_mpls_table.ref-1
deleted file mode 100644 (file)
index 9198969..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
- Inbound                            Outbound
-   Label     Type          Nexthop     Label
---------  -------  ---------------  --------
-      XX      LDP         10.0.2.2         3
-      XX      LDP         10.0.2.2         3
-      XX      LDP         10.0.2.2        XX
-      XX      LDP         10.0.2.4         3
-      XX      LDP         10.0.3.2         3
-      XX      LDP         10.0.3.2         3
-      XX      LDP         10.0.3.2        XX
diff --git a/tests/topotests/ldp-topo1/r3/show_mpls_table.ref-no-impl-null b/tests/topotests/ldp-topo1/r3/show_mpls_table.ref-no-impl-null
deleted file mode 100644 (file)
index 9198969..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
- Inbound                            Outbound
-   Label     Type          Nexthop     Label
---------  -------  ---------------  --------
-      XX      LDP         10.0.2.2         3
-      XX      LDP         10.0.2.2         3
-      XX      LDP         10.0.2.2        XX
-      XX      LDP         10.0.2.4         3
-      XX      LDP         10.0.3.2         3
-      XX      LDP         10.0.3.2         3
-      XX      LDP         10.0.3.2        XX
diff --git a/tests/topotests/ldp-topo1/r4/show_ipv4_route.ref-1 b/tests/topotests/ldp-topo1/r4/show_ipv4_route.ref-1
deleted file mode 100644 (file)
index df2a2b5..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-O>* 1.1.1.1/32 [110/20] via 10.0.2.2, r4-eth0, label xxx
-O>* 2.2.2.2/32 [110/10] via 10.0.2.2, r4-eth0
-O>* 3.3.3.3/32 [110/10] via 10.0.2.3, r4-eth0
-O   4.4.4.4/32 [110/0] is directly connected, lo
-O>* 10.0.1.0/24 [110/20] via 10.0.2.2, r4-eth0
-O   10.0.2.0/24 [110/10] is directly connected, r4-eth0
-O>* 10.0.3.0/24 [110/20] via 10.0.2.2, r4-eth0
diff --git a/tests/topotests/ldp-topo1/r4/show_mpls_ldp_binding.ref-1 b/tests/topotests/ldp-topo1/r4/show_mpls_ldp_binding.ref-1
deleted file mode 100644 (file)
index 3d55805..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-1.1.1.1/32
-        Local binding: label: xxx
-        Remote bindings:
-            Peer                Label
-            -----------------   ---------
-            2.2.2.2             xxx
-            3.3.3.3             xxx
-2.2.2.2/32
-        Local binding: label: xxx
-        Remote bindings:
-            Peer                Label
-            -----------------   ---------
-            2.2.2.2             imp-null
-            3.3.3.3             xxx
-3.3.3.3/32
-        Local binding: label: xxx
-        Remote bindings:
-            Peer                Label
-            -----------------   ---------
-            2.2.2.2             xxx
-            3.3.3.3             imp-null
-4.4.4.4/32
-        Local binding: label: imp-null
-        Remote bindings:
-            Peer                Label
-            -----------------   ---------
-            2.2.2.2             xxx
-            3.3.3.3             xxx
-10.0.1.0/24
-        Local binding: label: xxx
-        Remote bindings:
-            Peer                Label
-            -----------------   ---------
-            2.2.2.2             imp-null
-            3.3.3.3             xxx
-10.0.2.0/24
-        Local binding: label: imp-null
-        Remote bindings:
-            Peer                Label
-            -----------------   ---------
-            2.2.2.2             imp-null
-            3.3.3.3             imp-null
-10.0.3.0/24
-        Local binding: label: xxx
-        Remote bindings:
-            Peer                Label
-            -----------------   ---------
-            2.2.2.2             imp-null
-            3.3.3.3             imp-null
diff --git a/tests/topotests/ldp-topo1/r4/show_mpls_ldp_discovery.ref-1 b/tests/topotests/ldp-topo1/r4/show_mpls_ldp_discovery.ref-1
deleted file mode 100644 (file)
index 3ebddd6..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-Local LDP Identifier: 4.4.4.4:0
-Discovery Sources:
-  Interfaces:
-    r4-eth0: xmit/recv
-      LDP Id: 2.2.2.2:0, Transport address: 2.2.2.2
-          Hold time: 15 sec
-      LDP Id: 3.3.3.3:0, Transport address: 3.3.3.3
-          Hold time: 15 sec
-  Targeted Hellos:
diff --git a/tests/topotests/ldp-topo1/r4/show_mpls_ldp_interface.ref-1 b/tests/topotests/ldp-topo1/r4/show_mpls_ldp_interface.ref-1
deleted file mode 100644 (file)
index dd57656..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-AF   Interface   State  Uptime   Hello Timers  ac
-ipv4 r4-eth0     ACTIVE xx:xx:xx 5/15           2
diff --git a/tests/topotests/ldp-topo1/r4/show_mpls_ldp_neighbor.ref-1 b/tests/topotests/ldp-topo1/r4/show_mpls_ldp_neighbor.ref-1
deleted file mode 100644 (file)
index fb0e7d7..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-Peer LDP Identifier: 2.2.2.2:0
-  TCP connection: 4.4.4.4:xxx - 2.2.2.2:xxx
-  Session Holdtime: 180 sec
-  State: OPERATIONAL; Downstream-Unsolicited
-  Up time: xx:xx:xx
-  LDP Discovery Sources:
-    IPv4:
-      Interface: r4-eth0
-
-Peer LDP Identifier: 3.3.3.3:0
-  TCP connection: 4.4.4.4:xxx - 3.3.3.3:xxx
-  Session Holdtime: 180 sec
-  State: OPERATIONAL; Downstream-Unsolicited
-  Up time: xx:xx:xx
-  LDP Discovery Sources:
-    IPv4:
-      Interface: r4-eth0
index 9f86cd67cc8d71441cd5e250a7daa705d4ffc7c3..174dcebd4d9d431366b50061a784dad3ba2804a3 100644 (file)
@@ -1,9 +1,9 @@
- Inbound                            Outbound
-   Label     Type          Nexthop     Label
---------  -------  ---------------  --------
-      XX      LDP         10.0.2.2        XX
-      XX      LDP         10.0.2.2  implicit-null
-      XX      LDP         10.0.2.2  implicit-null
-      XX      LDP         10.0.2.2  implicit-null
-      XX      LDP         10.0.2.3  implicit-null
-      XX      LDP         10.0.2.3  implicit-null
+ Inbound Label  Type  Nexthop   Outbound Label  
+ -----------------------------------------------
+ XX             LDP   10.0.2.2  XX              
+ XX             LDP   10.0.2.2  implicit-null   
+ XX             LDP   10.0.2.2  implicit-null   
+ XX             LDP   10.0.2.2  implicit-null   
+ XX             LDP   10.0.2.3  implicit-null   
+ XX             LDP   10.0.2.3  implicit-null   
+
diff --git a/tests/topotests/ldp-topo1/r4/show_mpls_table.ref-1 b/tests/topotests/ldp-topo1/r4/show_mpls_table.ref-1
deleted file mode 100644 (file)
index b8cf5a2..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
- Inbound                            Outbound
-   Label     Type          Nexthop     Label
---------  -------  ---------------  --------
-      XX      LDP         10.0.2.2         3
-      XX      LDP         10.0.2.2         3
-      XX      LDP         10.0.2.2         3
-      XX      LDP         10.0.2.2        XX
-      XX      LDP         10.0.2.3         3
-      XX      LDP         10.0.2.3         3
diff --git a/tests/topotests/ldp-topo1/r4/show_mpls_table.ref-no-impl-null b/tests/topotests/ldp-topo1/r4/show_mpls_table.ref-no-impl-null
deleted file mode 100644 (file)
index b8cf5a2..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
- Inbound                            Outbound
-   Label     Type          Nexthop     Label
---------  -------  ---------------  --------
-      XX      LDP         10.0.2.2         3
-      XX      LDP         10.0.2.2         3
-      XX      LDP         10.0.2.2         3
-      XX      LDP         10.0.2.2        XX
-      XX      LDP         10.0.2.3         3
-      XX      LDP         10.0.2.3         3
index 409a5f54c84f4406e1fe482e184850b326048b25..f02f4c4e2184e2c41358a1f1fbef50f081ba9c35 100755 (executable)
@@ -77,12 +77,6 @@ from lib import topotest
 
 fatal_error = ""
 
-# Expected version of CLI Output - Appendix to filename
-#  empty string = current, latest output (default)
-#  "-1" ... "-NNN" previous versions (incrementing with each version)
-cli_version = ""
-
-
 #####################################################
 ##
 ##   Network Topology Definition
@@ -164,7 +158,6 @@ def teardown_module(module):
 def test_router_running():
     global fatal_error
     global net
-    global cli_version
 
     # Skip if previous fatal error condition is raised
     if (fatal_error != ""):
@@ -179,35 +172,12 @@ def test_router_running():
         fatal_error = net['r%s' % i].checkRouterRunning()
         assert fatal_error == "", fatal_error
 
-    # Detect CLI Version
-    # At this time, there are only 2 possible outputs, so simple check
-    output = net['r1'].cmd('vtysh -c "show mpls ldp discovery" 2> /dev/null').rstrip()
-
-    # Check if old or new format of CLI Output. Default is to current format
-    #
-    # Old (v1) output looks like this:
-    # Local LDP Identifier: 1.1.1.1:0
-    # Discovery Sources:
-    #   Interfaces:
-    #     r1-eth0: xmit/recv
-    #       LDP Id: 2.2.2.2:0, Transport address: 2.2.2.2
-    #           Hold time: 15 sec
-    #   Targeted Hellos:
-    #
-    # Current (v0) output looks like this:
-    # AF   ID              Type     Source           Holdtime
-    # ipv4 2.2.2.2         Link     r1-eth0                15
-    pattern = re.compile("^Local LDP Identifier.*")
-    if pattern.match(output):
-        cli_version = "-1"
-
     # For debugging after starting FRR/Quagga daemons, uncomment the next line
     # CLI(net)
 
 def test_mpls_interfaces():
     global fatal_error
     global net
-    global cli_version
 
     # Skip if previous fatal error condition is raised
     if (fatal_error != ""):
@@ -220,7 +190,7 @@ def test_mpls_interfaces():
     print("******************************************\n")
     failures = 0
     for i in range(1, 5):
-        refTableFile = '%s/r%s/show_mpls_ldp_interface.ref%s' % (thisDir, i, cli_version)
+        refTableFile = '%s/r%s/show_mpls_ldp_interface.ref'
         if os.path.isfile(refTableFile):
             # Read expected result from file
             expected = open(refTableFile).read().rstrip()
@@ -263,7 +233,6 @@ def test_mpls_interfaces():
 def test_mpls_ldp_neighbor_establish():
     global fatal_error
     global net
-    global cli_version
 
     # Skip if previous fatal error condition is raised
     if (fatal_error != ""):
@@ -279,22 +248,22 @@ def test_mpls_ldp_neighbor_establish():
         # Look for any node not yet converged
         for i in range(1, 5):
             established = net['r%s' % i].cmd('vtysh -c "show mpls ldp neighbor" 2> /dev/null').rstrip()
-            if cli_version != "-1":
-                # On current version, we need to make sure they all turn to OPERATIONAL on all lines
-                #
-                lines = ('\n'.join(established.splitlines()) + '\n').splitlines(1)
-                # Check all lines to be either table header (starting with ^AF or show OPERATIONAL)
-                header = r'^AF.*'
-                operational = r'^ip.*OPERATIONAL.*'
-                found_operational = 0
-                for j in range(1, len(lines)):
-                    if (not re.search(header, lines[j])) and (not re.search(operational, lines[j])):
-                        established = ""  # Empty string shows NOT established
-                    if re.search(operational, lines[j]):
-                        found_operational += 1
-                if found_operational < 1:
-                    # Need at least one operational neighbor
+
+            # On current version, we need to make sure they all turn to OPERATIONAL on all lines
+            #
+            lines = ('\n'.join(established.splitlines()) + '\n').splitlines(1)
+            # Check all lines to be either table header (starting with ^AF or show OPERATIONAL)
+            header = r'^AF.*'
+            operational = r'^ip.*OPERATIONAL.*'
+            found_operational = 0
+            for j in range(1, len(lines)):
+                if (not re.search(header, lines[j])) and (not re.search(operational, lines[j])):
                     established = ""  # Empty string shows NOT established
+                if re.search(operational, lines[j]):
+                    found_operational += 1
+            if found_operational < 1:
+                # Need at least one operational neighbor
+                established = ""  # Empty string shows NOT established
             if not established:
                 print('Waiting for r%s' %i)
                 sys.stdout.flush()
@@ -326,7 +295,6 @@ def test_mpls_ldp_neighbor_establish():
 def test_mpls_ldp_discovery():
     global fatal_error
     global net
-    global cli_version
 
     # Skip if previous fatal error condition is raised
     if (fatal_error != ""):
@@ -339,7 +307,7 @@ def test_mpls_ldp_discovery():
     print("******************************************\n")
     failures = 0
     for i in range(1, 5):
-        refTableFile = '%s/r%s/show_mpls_ldp_discovery.ref%s' % (thisDir, i, cli_version)
+        refTableFile = '%s/r%s/show_mpls_ldp_discovery.ref'
         if os.path.isfile(refTableFile):
             # Actual output from router
             actual = net['r%s' % i].cmd('vtysh -c "show mpls ldp discovery" 2> /dev/null').rstrip()
@@ -381,7 +349,6 @@ def test_mpls_ldp_discovery():
 def test_mpls_ldp_neighbor():
     global fatal_error
     global net
-    global cli_version
 
     # Skip if previous fatal error condition is raised
     if (fatal_error != ""):
@@ -394,7 +361,7 @@ def test_mpls_ldp_neighbor():
     print("******************************************\n")
     failures = 0
     for i in range(1, 5):
-        refTableFile = '%s/r%s/show_mpls_ldp_neighbor.ref%s' % (thisDir, i, cli_version)
+        refTableFile = '%s/r%s/show_mpls_ldp_neighbor.ref'
         if os.path.isfile(refTableFile):
             # Read expected result from file
             expected = open(refTableFile).read().rstrip()
@@ -405,17 +372,8 @@ def test_mpls_ldp_neighbor():
             actual = net['r%s' % i].cmd('vtysh -c "show mpls ldp neighbor" 2> /dev/null').rstrip()
 
             # Mask out changing parts in output
-            if cli_version == "-1":
-                # Mask out Timer in Uptime
-                actual = re.sub(r"Up time: [0-9][0-9]:[0-9][0-9]:[0-9][0-9]", "Up time: xx:xx:xx", actual)
-                # Mask out Port numbers in TCP connection
-                actual = re.sub(r"TCP connection: ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]):[0-9]+ - ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]):[0-9]+",
-                    r"TCP connection: \1:xxx - \2:xxx", actual)
-            else:
-                # Current Version
-                #
-                # Mask out Timer in Uptime
-                actual = re.sub(r"(ipv4 [0-9\.]+ +OPERATIONAL [0-9\.]+ +)[0-9][0-9]:[0-9][0-9]:[0-9][0-9]", r"\1xx:xx:xx", actual)
+            # Mask out Timer in Uptime
+            actual = re.sub(r"(ipv4 [0-9\.]+ +OPERATIONAL [0-9\.]+ +)[0-9][0-9]:[0-9][0-9]:[0-9][0-9]", r"\1xx:xx:xx", actual)
 
             # Fix newlines (make them all the same)
             actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1)
@@ -446,7 +404,6 @@ def test_mpls_ldp_neighbor():
 def test_mpls_ldp_binding():
     global fatal_error
     global net
-    global cli_version
 
     # Skip this test for now until proper sorting of the output
     # is implemented
@@ -463,7 +420,7 @@ def test_mpls_ldp_binding():
     print("******************************************\n")
     failures = 0
     for i in range(1, 5):
-        refTableFile = '%s/r%s/show_mpls_ldp_binding.ref%s' % (thisDir, i, cli_version)
+        refTableFile = '%s/r%s/show_mpls_ldp_binding.ref'
         if os.path.isfile(refTableFile):
             # Read expected result from file
             expected = open(refTableFile).read().rstrip()
@@ -474,16 +431,9 @@ def test_mpls_ldp_binding():
             actual = net['r%s' % i].cmd('vtysh -c "show mpls ldp binding" 2> /dev/null').rstrip()
 
             # Mask out changing parts in output
-            if cli_version == "-1":
-                # Mask out label
-                actual = re.sub(r"label: [0-9]+", "label: xxx", actual)
-                actual = re.sub(r"(\s+[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+[ ]+)[0-9]+", r"\1xxx", actual)
-            else:
-                # Current Version
-                #
-                # Mask out label
-                actual = re.sub(r"(ipv4 [0-9\./]+ +[0-9\.]+ +)[0-9][0-9] (.*)", r"\1xxx\2", actual)
-                actual = re.sub(r"(ipv4 [0-9\./]+ +[0-9\.]+ +[a-z\-]+ +)[0-9][0-9] (.*)", r"\1xxx\2", actual)
+            # Mask out label
+            actual = re.sub(r"(ipv4 [0-9\./]+ +[0-9\.]+ +)[0-9][0-9] (.*)", r"\1xxx\2", actual)
+            actual = re.sub(r"(ipv4 [0-9\./]+ +[0-9\.]+ +[a-z\-]+ +)[0-9][0-9] (.*)", r"\1xxx\2", actual)
 
             # Fix newlines (make them all the same)
             actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1)
@@ -527,7 +477,6 @@ def test_mpls_ldp_binding():
 def test_zebra_ipv4_routingTable():
     global fatal_error
     global net
-    global cli_version
 
     # Skip if previous fatal error condition is raised
     if (fatal_error != ""):
@@ -540,7 +489,7 @@ def test_zebra_ipv4_routingTable():
     print("******************************************\n")
     failures = 0
     for i in range(1, 5):
-        refTableFile = '%s/r%s/show_ipv4_route.ref%s' % (thisDir, i, cli_version)
+        refTableFile = '%s/r%s/show_ipv4_route.ref'
         if os.path.isfile(refTableFile):
             # Read expected result from file
             expected = open(refTableFile).read().rstrip()
@@ -562,9 +511,6 @@ def test_zebra_ipv4_routingTable():
             # now fix newlines of expected (make them all the same)
             expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1)
 
-            # Add missing comma before label (for old version)
-            actual = re.sub(r"([0-9]) label ", r"\1, label ", actual)
-
             # Fix newlines (make them all the same)
             actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1)
 
@@ -594,7 +540,6 @@ def test_zebra_ipv4_routingTable():
 def test_mpls_table():
     global fatal_error
     global net
-    global cli_version
 
     # Skip if previous fatal error condition is raised
     if (fatal_error != ""):
@@ -607,23 +552,16 @@ def test_mpls_table():
     print("******************************************\n")
     failures = 0
 
-    version = cli_version
-    if (version == ""):
-        # check for new output without implicit-null
-        output = net['r1'].cmd('vtysh -c "show mpls table" 2> /dev/null').rstrip()
-        if 'LDP         10.0.1.2         3' in output:
-            version = "-no-impl-null"
-
     for i in range(1, 5):
-        refTableFile = '%s/r%s/show_mpls_table.ref%s' % (thisDir, i, version)
+        refTableFile = '%s/r%s/show_mpls_table.ref'
         if os.path.isfile(refTableFile):
             # Read expected result from file
-            expected = open(refTableFile).read().rstrip()
+            expected = open(refTableFile).read()
             # Fix newlines (make them all the same)
             expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1)
 
             # Actual output from router
-            actual = net['r%s' % i].cmd('vtysh -c "show mpls table" 2> /dev/null').rstrip()
+            actual = net['r%s' % i].cmd('vtysh -c "show mpls table" 2> /dev/null')
  
             # Fix inconsistent Label numbers at beginning of line
             actual = re.sub(r"(\s+)[0-9]+(\s+LDP)", r"\1XX\2", actual)
@@ -672,7 +610,6 @@ def test_mpls_table():
 def test_linux_mpls_routes():
     global fatal_error
     global net
-    global cli_version
 
    # Skip if previous fatal error condition is raised
     if (fatal_error != ""):
index 254c137acdd15c0030fb15ae1398c1b17be6a699..6b1fe76b6e8d7f2aaa0b7be4ab3d415269181bb0 100644 (file)
@@ -4,7 +4,7 @@
     "installed":true,
     "nexthops":[
       {
-        "type":"SR",
+        "type":"SR (OSPF)",
         "outLabel":3,
         "distance":150,
         "installed":true,
@@ -17,7 +17,7 @@
     "installed":true,
     "nexthops":[
       {
-        "type":"SR",
+        "type":"SR (OSPF)",
         "outLabel":3,
         "distance":150,
         "installed":true,
@@ -30,7 +30,7 @@
     "installed":true,
     "nexthops":[
       {
-        "type":"SR",
+        "type":"SR (OSPF)",
         "outLabel":8300,
         "distance":150,
         "installed":true,
@@ -43,7 +43,7 @@
     "installed":true,
     "nexthops":[
       {
-        "type":"SR",
+        "type":"SR (OSPF)",
         "outLabel":8400,
         "distance":150,
         "installed":true,
@@ -56,7 +56,7 @@
     "installed":true,
     "nexthops":[
       {
-        "type":"SR",
+        "type":"SR (OSPF)",
         "outLabel":3,
         "distance":150,
         "installed":true,
@@ -69,7 +69,7 @@
     "installed":true,
     "nexthops":[
       {
-        "type":"SR",
+        "type":"SR (OSPF)",
         "outLabel":3,
         "distance":150,
         "installed":true,
index 0d73a409ed2bd929896c126ce57bbe7a070f73cc..79965d280a1b89e29101c28d2cce3d8ca8ae577f 100644 (file)
@@ -4,7 +4,7 @@
     "installed":true,
     "nexthops":[
       {
-        "type":"SR",
+        "type":"SR (OSPF)",
         "outLabel":20100,
         "distance":150,
         "installed":true,
@@ -17,7 +17,7 @@
     "installed":true,
     "nexthops":[
       {
-        "type":"SR",
+        "type":"SR (OSPF)",
         "outLabel":3,
         "distance":150,
         "installed":true,
@@ -30,7 +30,7 @@
     "installed":true,
     "nexthops":[
       {
-        "type":"SR",
+        "type":"SR (OSPF)",
         "outLabel":10400,
         "distance":150,
         "installed":true,
@@ -43,7 +43,7 @@
     "installed":true,
     "nexthops":[
       {
-        "type":"SR",
+        "type":"SR (OSPF)",
         "outLabel":3,
         "distance":150,
         "installed":true,
@@ -56,7 +56,7 @@
     "installed":true,
     "nexthops":[
       {
-        "type":"SR",
+        "type":"SR (OSPF)",
         "outLabel":3,
         "distance":150,
         "installed":true,
@@ -69,7 +69,7 @@
     "installed":true,
     "nexthops":[
       {
-        "type":"SR",
+        "type":"SR (OSPF)",
         "outLabel":3,
         "distance":150,
         "installed":true,
@@ -82,7 +82,7 @@
     "installed":true,
     "nexthops":[
       {
-        "type":"SR",
+        "type":"SR (OSPF)",
         "outLabel":3,
         "distance":150,
         "installed":true,
@@ -95,7 +95,7 @@
     "installed":true,
     "nexthops":[
       {
-        "type":"SR",
+        "type":"SR (OSPF)",
         "outLabel":3,
         "distance":150,
         "installed":true,
     "installed":true,
     "nexthops":[
       {
-        "type":"SR",
+        "type":"SR (OSPF)",
         "outLabel":3,
         "distance":150,
         "installed":true,
index b15f90afd1a801396281f7cf7a2db266b8a675b9..ceb2f7a0e51f951ff88e3c642cbd706b0b2b884f 100644 (file)
@@ -4,7 +4,7 @@
     "installed":true,
     "nexthops":[
       {
-        "type":"SR",
+        "type":"SR (OSPF)",
         "outLabel":8100,
         "distance":150,
         "installed":true,
@@ -17,7 +17,7 @@
     "installed":true,
     "nexthops":[
       {
-        "type":"SR",
+        "type":"SR (OSPF)",
         "outLabel":3,
         "distance":150,
         "installed":true,
@@ -30,7 +30,7 @@
     "installed":true,
     "nexthops":[
       {
-        "type":"SR",
+        "type":"SR (OSPF)",
         "outLabel":8400,
         "distance":150,
         "installed":true,
@@ -43,7 +43,7 @@
     "installed":true,
     "nexthops":[
       {
-        "type":"SR",
+        "type":"SR (OSPF)",
         "outLabel":3,
         "distance":150,
         "installed":true,
@@ -56,7 +56,7 @@
     "installed":true,
     "nexthops":[
       {
-        "type":"SR",
+        "type":"SR (OSPF)",
         "outLabel":3,
         "distance":150,
         "installed":true,
index d1238517f5fe9bc1503ceb1ca95a08da80d7699e..d7f54b224d665cb9511484d49eb12fce8730b01b 100644 (file)
@@ -4,7 +4,7 @@
     "installed":true,
     "nexthops":[
       {
-        "type":"SR",
+        "type":"SR (OSPF)",
         "outLabel":8100,
         "distance":150,
         "installed":true,
@@ -17,7 +17,7 @@
     "installed":true,
     "nexthops":[
       {
-        "type":"SR",
+        "type":"SR (OSPF)",
         "outLabel":3,
         "distance":150,
         "installed":true,
@@ -30,7 +30,7 @@
     "installed":true,
     "nexthops":[
       {
-        "type":"SR",
+        "type":"SR (OSPF)",
         "outLabel":8300,
         "distance":150,
         "installed":true,
@@ -43,7 +43,7 @@
     "installed":true,
     "nexthops":[
       {
-        "type":"SR",
+        "type":"SR (OSPF)",
         "outLabel":3,
         "distance":150,
         "installed":true,
@@ -56,7 +56,7 @@
     "installed":true,
     "nexthops":[
       {
-        "type":"SR",
+        "type":"SR (OSPF)",
         "outLabel":3,
         "distance":150,
         "installed":true,
@@ -69,7 +69,7 @@
     "installed":true,
     "nexthops":[
       {
-        "type":"SR",
+        "type":"SR (OSPF)",
         "outLabel":3,
         "distance":150,
         "installed":true,
index ade5bfd5010d661252620b87db3bfe32ee14064f..b65f93856ffbf4b0917b3629eb415c61c50b43dc 100644 (file)
@@ -1,6 +1,6 @@
 # Skip pytests example directory
 [pytest]
-norecursedirs = .git example-test example-topojson-test lib docker
+norecursedirs = .git example-test example-topojson-test lib docker bgp-ecmp-topo2
 
 [topogen]
 # Default configuration values
index d52824ff07d36c5f93cd5334aceabc9488ce91bd..8845df5fc737ae822e65b1facc2d6ae2eebfe5c1 100644 (file)
@@ -28,6 +28,7 @@ show bgp ipv6 update-groups advertised-routes
 show bgp ipv6 update-groups packet-queue
 show bgp ipv6 update-groups statistics
 show ip bgp statistics
+show bgp martian next-hop
 
 show bgp evpn route
 CMD_LIST_END
@@ -37,14 +38,17 @@ PROC_NAME:zebra
 CMD_LIST_START
 show zebra
 show zebra client summary
-show ip route
-
+show ip zebra route dump json
+show ipv6 zebra route dump json
+show ip nht vrf all
 show route-map
 show memory
-show interface
+show interface vrf all
 show vrf
+show zebra fpm stats
 show error all
 show work-queues
+show debugging hashtable
 show running-config
 show thread cpu
 show thread poll
old mode 100644 (file)
new mode 100755 (executable)
index 118ca11..c9ca9c3
@@ -1,3 +1,5 @@
+#!/usr/bin/python
+
 ########################################################
 ### Python Script to generate the FRR support bundle ###
 ########################################################
index 7713bb1ade5baa8aad9f4515e8f3091f4c54d0f9..c637db6eb1ed37bfe6e936c7761e4994664d3309 100644 (file)
@@ -16,6 +16,7 @@ sbin_SCRIPTS += \
        \
        tools/frrcommon.sh \
        tools/frrinit.sh \
+       tools/generate_support_bundle.py \
        tools/watchfrr.sh \
        # end
 
@@ -35,6 +36,7 @@ EXTRA_DIST += \
        tools/frr-reload \
        tools/frr-reload.py \
        tools/frr.service \
+       tools/generate_support_bundle.py \
        tools/multiple-bgpd.sh \
        tools/rrcheck.pl \
        tools/rrlookup.pl \
index 3ec2eb239d0378d28013014aaa124ebf9fc5dcbb..e56c6fbf4ef2d5350caf83beb92d6a914de86d27 100644 (file)
@@ -406,7 +406,9 @@ void vtysh_config_parse_line(void *arg, const char *line)
                                       == 0
                            || strncmp(line, "frr", strlen("frr")) == 0
                            || strncmp(line, "agentx", strlen("agentx")) == 0
-                           || strncmp(line, "no log", strlen("no log")) == 0)
+                           || strncmp(line, "no log", strlen("no log")) == 0
+                           || strncmp(line, "no ip prefix-list", strlen("no ip prefix-list")) == 0
+                           || strncmp(line, "no ipv6 prefix-list", strlen("no ipv6 prefix-list")) == 0)
                                config_add_line_uniq(config_top, line);
                        else
                                config_add_line(config_top, line);
index c27491e55c7709a0e9e17614696e7a0d9d761c11..30f606c202dfd94db51c43a6a2c16bae7c271d15 100644 (file)
@@ -19,3 +19,6 @@ watchfrr_watchfrr_SOURCES = \
        watchfrr/watchfrr_errors.c \
        watchfrr/watchfrr_vty.c \
        # end
+
+watchfrr/watchfrr_vty_clippy.c: $(CLIPPY_DEPS)
+watchfrr/watchfrr_vty.$(OBJEXT): watchfrr/watchfrr_vty_clippy.c
index c17d3817301339376f4c0d67cf18e7aed601f486..a6a910a1dbaed6604616ef823dcd38f9b29fd364 100644 (file)
@@ -159,6 +159,15 @@ struct daemon {
        struct thread *t_write;
        struct daemon *next;
        struct restart_info restart;
+
+       /*
+        * For a given daemon, if we've turned on ignore timeouts
+        * ignore the timeout value and assume everything is ok
+        * This is for daemon debugging w/ gdb after we have started
+        * FRR and realize we have something that needs to be looked
+        * at
+        */
+       bool ignore_timeout;
 };
 
 #define OPTION_MINRESTART 2000
@@ -191,6 +200,25 @@ static void phase_check(void);
 static void restart_done(struct daemon *dmn);
 
 static const char *progname;
+
+void watchfrr_set_ignore_daemon(struct vty *vty, const char *dname, bool ignore)
+{
+       struct daemon *dmn;
+
+       for (dmn = gs.daemons; dmn; dmn = dmn->next) {
+               if (strncmp(dmn->name, dname, strlen(dmn->name)) == 0)
+                       break;
+       }
+
+       if (dmn) {
+               dmn->ignore_timeout = ignore;
+               vty_out(vty, "%s switching to %s\n", dmn->name,
+                       ignore ? "ignore" : "watch");
+       } else
+               vty_out(vty, "%s is not configured for running at the moment",
+                       dname);
+}
+
 static void printhelp(FILE *target)
 {
        fprintf(target,
@@ -533,7 +561,9 @@ static int wakeup_init(struct thread *t_wakeup)
 static void restart_done(struct daemon *dmn)
 {
        if (dmn->state != DAEMON_DOWN) {
-               zlog_warn("wtf?");
+               zlog_warn(
+                       "Daemon: %s: is in %s state but expected it to be in DAEMON_DOWN state",
+                       dmn->name, state_str[dmn->state]);
                return;
        }
        if (dmn->t_wakeup)
@@ -961,6 +991,8 @@ static int wakeup_no_answer(struct thread *t_wakeup)
 
        dmn->t_wakeup = NULL;
        dmn->state = DAEMON_UNRESPONSIVE;
+       if (dmn->ignore_timeout)
+               return 0;
        flog_err(EC_WATCHFRR_CONNECTION,
                 "%s state -> unresponsive : no response yet to ping "
                 "sent %ld seconds ago",
@@ -1014,7 +1046,8 @@ void watchfrr_status(struct vty *vty)
                        (long)gs.restart.pid);
 
        for (dmn = gs.daemons; dmn; dmn = dmn->next) {
-               vty_out(vty, "  %-20s %s\n", dmn->name, state_str[dmn->state]);
+               vty_out(vty, "  %-20s %s%s", dmn->name, state_str[dmn->state],
+                       dmn->ignore_timeout ? "/Ignoring Timeout\n" : "\n");
                if (dmn->restart.pid)
                        vty_out(vty, "      restart running, pid %ld\n",
                                (long)dmn->restart.pid);
index c5f54769bd3083087f809b3a9868b911b5c55e75..ba6e94960f6d0a76320be55792336e9b6184f1f0 100644 (file)
@@ -41,4 +41,6 @@ extern void watchfrr_status(struct vty *vty);
  */
 extern bool check_all_up(void);
 
+extern void watchfrr_set_ignore_daemon(struct vty *vty, const char *dname,
+                                      bool ignore);
 #endif /* FRR_WATCHFRR_H */
index 9b844d67f25d0aa427d945c51d4d7a75d52710fb..c06cb89382e65528237be13425f2463b83472897 100644 (file)
@@ -134,6 +134,23 @@ DEFUN (show_watchfrr,
        return CMD_SUCCESS;
 }
 
+#ifndef VTYSH_EXTRACT_PL
+#include "watchfrr/watchfrr_vty_clippy.c"
+#endif
+
+DEFPY (watchfrr_ignore_daemon,
+       watchfrr_ignore_daemon_cmd,
+       "[no] watchfrr ignore DAEMON$dname",
+       NO_STR
+       "Watchfrr Specific sub-command\n"
+       "Ignore a specified daemon when it does not respond to echo request\n"
+       "The daemon to ignore\n")
+{
+       watchfrr_set_ignore_daemon(vty, dname, no ? false : true );
+
+       return CMD_SUCCESS;
+}
+
 void integrated_write_sigchld(int status)
 {
        uint8_t reply[4] = {0, 0, 0, CMD_WARNING};
@@ -168,6 +185,9 @@ void watchfrr_vty_init(void)
        integrated_write_pid = -1;
        install_element(ENABLE_NODE, &config_write_integrated_cmd);
        install_element(ENABLE_NODE, &show_debugging_watchfrr_cmd);
+
+       install_element(ENABLE_NODE, &watchfrr_ignore_daemon_cmd);
+
        install_element(CONFIG_NODE, &show_debugging_watchfrr_cmd);
        install_element(VIEW_NODE, &show_watchfrr_cmd);
 }
index 853d8238805ca9c677fd1344aa98c38386920797..0c629545706e47c4b04a5dbcf67801f138cff56a 100644 (file)
@@ -23,6 +23,11 @@ module frr-eigrpd {
   description
     "This module defines a model for managing FRR eigrpd daemon.";
 
+  revision 2019-09-09 {
+    description
+      "Changed interface references to use
+      frr-interface:interface-ref typedef";
+  }
   revision 2019-06-19 {
     description "Initial revision.";
     reference
@@ -94,9 +99,7 @@ module frr-eigrpd {
 
       leaf-list passive-interface {
         description "List of suppressed interfaces";
-        type string {
-          length "1..16";
-        }
+        type frr-interface:interface-ref;
       }
 
       leaf active-time {
index d3cc66dfaa81d6822297fb5d41ed8c0a1da90369..4f7f3beebd9aa9b356619c40d48a8373165d3902 100644 (file)
@@ -11,6 +11,10 @@ module frr-interface {
   description
     "This module defines a model for managing FRR interfaces.";
 
+  revision 2019-09-09 {
+    description
+      "Added interface-ref typedef";
+  }
   revision 2018-03-28 {
     description
       "Initial revision.";
@@ -43,4 +47,13 @@ module frr-interface {
       }
     }
   }
+
+  typedef interface-ref {
+    type leafref {
+      require-instance false;
+      path "/frr-interface:lib/frr-interface:interface/frr-interface:name";
+    }
+    description
+      "Reference to an interface";
+  }
 }
index 9180b0c5f3d2208f336b6594392a94db4805d559..3313dc2f202b08962ac62304c251024d8b11c505 100644 (file)
@@ -27,6 +27,11 @@ module frr-isisd {
   description
     "This module defines a model for managing FRR isisd daemon.";
 
+  revision 2019-09-09 {
+    description
+      "Changed interface references to use
+      frr-interface:interface-ref typedef";
+  }
   revision 2018-07-26 {
     description
       "Initial revision.";
@@ -296,7 +301,7 @@ module frr-isisd {
     description
       "Interface specific IS-IS notification data grouping";
     leaf interface-name {
-      type string;
+      type frr-interface:interface-ref;
       description
         "IS-IS interface name";
     }
index 07690793f0343c22d20bba79777f47fc8aeba332..94a9ebf3e1edbf18cbe12e7ac8f1fd978b1330f2 100644 (file)
@@ -24,6 +24,11 @@ module frr-ripd {
   description
     "This module defines a model for managing FRR ripd daemon.";
 
+  revision 2019-09-09 {
+    description
+      "Changed interface references to use
+      frr-interface:interface-ref typedef";
+  }
   revision 2017-12-06 {
     description
       "Initial revision.";
@@ -113,9 +118,7 @@ module frr-ripd {
           "Enable RIP on the specified IP network.";
       }
       leaf-list interface {
-        type string {
-          length "1..16";
-        }
+        type frr-interface:interface-ref;
         description
           "Enable RIP on the specified interface.";
       }
@@ -124,7 +127,15 @@ module frr-ripd {
         description
           "Offset-list to modify route metric.";
         leaf interface {
-          type string;
+          type union {
+            type frr-interface:interface-ref;
+            type enumeration {
+              enum '*' {
+                description
+                  "Match all interfaces.";
+              }
+            }
+          }
           description
             "Interface to match. Use '*' to match all interfaces.";
         }
@@ -168,18 +179,14 @@ module frr-ripd {
       }
       leaf-list passive-interface {
         when "../passive-default = 'false'";
-        type string {
-          length "1..16";
-        }
+        type frr-interface:interface-ref;
         description
           "A list of interfaces where the sending of RIP packets
            is disabled.";
       }
       leaf-list non-passive-interface {
         when "../passive-default = 'true'";
-        type string {
-          length "1..16";
-        }
+        type frr-interface:interface-ref;
         description
           "A list of interfaces where the sending of RIP packets
            is enabled.";
index b341b438a4d5a95cbb278cfb1ce04f4e81377bb4..831758af8604704fc5e5301c4217f20d5c73ed3e 100644 (file)
@@ -24,6 +24,11 @@ module frr-ripngd {
   description
     "This module defines a model for managing FRR ripngd daemon.";
 
+  revision 2019-09-09 {
+    description
+      "Changed interface references to use
+      frr-interface:interface-ref typedef";
+  }
   revision 2018-11-27 {
     description
       "Initial revision.";
@@ -71,9 +76,7 @@ module frr-ripngd {
           "Enable RIPng on the specified IPv6 network.";
       }
       leaf-list interface {
-        type string {
-          length "1..16";
-        }
+        type frr-interface:interface-ref;
         description
           "Enable RIPng on the specified interface.";
       }
@@ -82,7 +85,15 @@ module frr-ripngd {
         description
           "Offset-list to modify route metric.";
         leaf interface {
-          type string;
+          type union {
+            type frr-interface:interface-ref;
+            type enumeration {
+              enum '*' {
+                description
+                  "Match all interfaces.";
+              }
+            }
+          }
           description
             "Interface to match. Use '*' to match all interfaces.";
         }
@@ -118,9 +129,7 @@ module frr-ripngd {
         }
       }
       leaf-list passive-interface {
-        type string {
-          length "1..16";
-        }
+        type frr-interface:interface-ref;
         description
           "A list of interfaces where the sending of RIPng packets
            is disabled.";
index 4814f5bc1d027a28d232f639108a5103d11995c6..48cdceccf43e864cad9e12ff79afc354c36eb3e6 100644 (file)
@@ -20,6 +20,7 @@
 #include <zebra.h>
 
 #include "prefix.h"
+#include "ipaddr.h"
 
 #include <libyang/user_types.h>
 
@@ -53,6 +54,21 @@ static int ipv6_address_store_clb(const char *type_name, const char *value_str,
        return 0;
 }
 
+static int ip_address_store_clb(const char *type_name, const char *value_str,
+                               lyd_val *value, char **err_msg)
+{
+       value->ptr = malloc(sizeof(struct ipaddr));
+       if (!value->ptr)
+               return 1;
+
+       if (str2ipaddr(value_str, value->ptr)) {
+               free(value->ptr);
+               return 1;
+       }
+
+       return 0;
+}
+
 static int ipv4_prefix_store_clb(const char *type_name, const char *value_str,
                                 lyd_val *value, char **err_msg)
 {
@@ -83,6 +99,21 @@ static int ipv6_prefix_store_clb(const char *type_name, const char *value_str,
        return 0;
 }
 
+static int ip_prefix_store_clb(const char *type_name, const char *value_str,
+                              lyd_val *value, char **err_msg)
+{
+       value->ptr = malloc(sizeof(struct prefix));
+       if (!value->ptr)
+               return 1;
+
+       if (str2prefix(value_str, value->ptr) == 0) {
+               free(value->ptr);
+               return 1;
+       }
+
+       return 0;
+}
+
 struct lytype_plugin_list frr_user_types[] = {
        {"ietf-inet-types", "2013-07-15", "ipv4-address",
         ipv4_address_store_clb, free},
@@ -92,9 +123,13 @@ struct lytype_plugin_list frr_user_types[] = {
         ipv6_address_store_clb, free},
        {"ietf-inet-types", "2013-07-15", "ipv6-address-no-zone",
         ipv6_address_store_clb, free},
+       {"ietf-inet-types", "2013-07-15", "ip-address", ip_address_store_clb,
+        free},
        {"ietf-inet-types", "2013-07-15", "ipv4-prefix", ipv4_prefix_store_clb,
         free},
        {"ietf-inet-types", "2013-07-15", "ipv6-prefix", ipv6_prefix_store_clb,
         free},
+       {"ietf-inet-types", "2013-07-15", "ip-prefix", ip_prefix_store_clb,
+        free},
        {NULL, NULL, NULL, NULL, NULL} /* terminating item */
 };
index 657d1247e94638015ee97a26e9bb69f2876a52a5..99607c0d78a72b7a4a9f5b3b928d187e42c9f326 100644 (file)
@@ -36,7 +36,6 @@
 #include "vrf.h"
 #include "libfrr.h"
 #include "routemap.h"
-#include "frr_pthread.h"
 
 #include "zebra/zebra_router.h"
 #include "zebra/zebra_errors.h"
@@ -375,9 +374,6 @@ int main(int argc, char **argv)
 
        zrouter.master = frr_init();
 
-       /* Initialize pthread library */
-       frr_pthread_init();
-
        /* Zebra related initialize. */
        zebra_router_init();
        zserv_init();
index 0e7dc5ce9b8f7f389b8a6c9a0e52cdc63a8e918e..ffdc4dc51252349c16666ed3aa2c0ab272df1d99 100644 (file)
@@ -1750,88 +1750,146 @@ static void zread_vrf_unregister(ZAPI_HANDLER_ARGS)
        vrf_bitmap_unset(client->ridinfo, zvrf_id(zvrf));
 }
 
-static void zread_mpls_labels(ZAPI_HANDLER_ARGS)
+/*
+ * Handle request to create an MPLS LSP.
+ *
+ * A single message can fully specify an LSP with multiple nexthops.
+ *
+ * When the optional ZAPI_LABELS_FTN flag is set, the specified FEC (route) is
+ * updated to use the received label(s).
+ */
+static void zread_mpls_labels_add(ZAPI_HANDLER_ARGS)
 {
        struct stream *s;
-       enum lsp_types_t type;
-       struct prefix prefix;
-       enum nexthop_types_t gtype;
-       union g_addr gate;
-       ifindex_t ifindex;
-       mpls_label_t in_label, out_label;
-       uint8_t distance;
+       struct zapi_labels zl;
 
        /* Get input stream.  */
        s = msg;
+       if (zapi_labels_decode(s, &zl) < 0) {
+               if (IS_ZEBRA_DEBUG_RECV)
+                       zlog_debug("%s: Unable to decode zapi_labels sent",
+                                  __PRETTY_FUNCTION__);
+               return;
+       }
 
-       /* Get data. */
-       STREAM_GETC(s, type);
-       STREAM_GETL(s, prefix.family);
-       switch (prefix.family) {
-       case AF_INET:
-               STREAM_GET(&prefix.u.prefix4.s_addr, s, IPV4_MAX_BYTELEN);
-               STREAM_GETC(s, prefix.prefixlen);
-               if (prefix.prefixlen > IPV4_MAX_BITLEN) {
-                       zlog_debug(
-                               "%s: Specified prefix length %d is greater than a v4 address can support",
-                               __PRETTY_FUNCTION__, prefix.prefixlen);
-                       return;
-               }
-               STREAM_GET(&gate.ipv4.s_addr, s, IPV4_MAX_BYTELEN);
-               break;
-       case AF_INET6:
-               STREAM_GET(&prefix.u.prefix6, s, 16);
-               STREAM_GETC(s, prefix.prefixlen);
-               if (prefix.prefixlen > IPV6_MAX_BITLEN) {
-                       zlog_debug(
-                               "%s: Specified prefix length %d is greater than a v6 address can support",
-                               __PRETTY_FUNCTION__, prefix.prefixlen);
-                       return;
-               }
-               STREAM_GET(&gate.ipv6, s, 16);
-               break;
-       default:
-               zlog_debug("%s: Specified AF %d is not supported for this call",
-                          __PRETTY_FUNCTION__, prefix.family);
+       if (!mpls_enabled)
                return;
+
+       for (int i = 0; i < zl.nexthop_num; i++) {
+               struct zapi_nexthop_label *znh;
+
+               znh = &zl.nexthops[i];
+               mpls_lsp_install(zvrf, zl.type, zl.local_label, znh->label,
+                                znh->type, &znh->address, znh->ifindex);
+
+               if (CHECK_FLAG(zl.message, ZAPI_LABELS_FTN))
+                       mpls_ftn_update(1, zvrf, zl.type, &zl.route.prefix,
+                                       znh->type, &znh->address, znh->ifindex,
+                                       zl.route.type, zl.route.instance,
+                                       znh->label);
        }
-       STREAM_GETL(s, ifindex);
-       STREAM_GETC(s, distance);
-       STREAM_GETL(s, in_label);
-       STREAM_GETL(s, out_label);
+}
 
-       switch (prefix.family) {
-       case AF_INET:
-               if (ifindex)
-                       gtype = NEXTHOP_TYPE_IPV4_IFINDEX;
-               else
-                       gtype = NEXTHOP_TYPE_IPV4;
-               break;
-       case AF_INET6:
-               if (ifindex)
-                       gtype = NEXTHOP_TYPE_IPV6_IFINDEX;
-               else
-                       gtype = NEXTHOP_TYPE_IPV6;
-               break;
-       default:
+/*
+ * Handle request to delete an MPLS LSP.
+ *
+ * An LSP is identified by its type and local label. When the received message
+ * doesn't contain any nexthop, the whole LSP is deleted. Otherwise, only the
+ * listed LSP nexthops (aka NHLFEs) are deleted.
+ *
+ * When the optional ZAPI_LABELS_FTN flag is set, the labels of the specified
+ * FEC (route) nexthops are deleted.
+ */
+static void zread_mpls_labels_delete(ZAPI_HANDLER_ARGS)
+{
+       struct stream *s;
+       struct zapi_labels zl;
+
+       /* Get input stream.  */
+       s = msg;
+       if (zapi_labels_decode(s, &zl) < 0) {
+               if (IS_ZEBRA_DEBUG_RECV)
+                       zlog_debug("%s: Unable to decode zapi_labels sent",
+                                  __PRETTY_FUNCTION__);
                return;
        }
 
        if (!mpls_enabled)
                return;
 
-       if (hdr->command == ZEBRA_MPLS_LABELS_ADD) {
-               mpls_lsp_install(zvrf, type, in_label, out_label, gtype, &gate,
-                                ifindex);
-               mpls_ftn_update(1, zvrf, type, &prefix, gtype, &gate, ifindex,
-                               distance, out_label);
-       } else if (hdr->command == ZEBRA_MPLS_LABELS_DELETE) {
-               mpls_lsp_uninstall(zvrf, type, in_label, gtype, &gate, ifindex);
-               mpls_ftn_update(0, zvrf, type, &prefix, gtype, &gate, ifindex,
-                               distance, out_label);
+       if (zl.nexthop_num > 0) {
+               for (int i = 0; i < zl.nexthop_num; i++) {
+                       struct zapi_nexthop_label *znh;
+
+                       znh = &zl.nexthops[i];
+                       mpls_lsp_uninstall(zvrf, zl.type, zl.local_label,
+                                          znh->type, &znh->address,
+                                          znh->ifindex);
+
+                       if (CHECK_FLAG(zl.message, ZAPI_LABELS_FTN))
+                               mpls_ftn_update(0, zvrf, zl.type,
+                                               &zl.route.prefix, znh->type,
+                                               &znh->address, znh->ifindex,
+                                               zl.route.type,
+                                               zl.route.instance, znh->label);
+               }
+       } else {
+               mpls_lsp_uninstall_all_vrf(zvrf, zl.type, zl.local_label);
+
+               if (CHECK_FLAG(zl.message, ZAPI_LABELS_FTN))
+                       mpls_ftn_uninstall(zvrf, zl.type, &zl.route.prefix,
+                                          zl.route.type, zl.route.instance);
+       }
+}
+
+/*
+ * Handle request to add an MPLS LSP or change an existing one.
+ *
+ * A single message can fully specify an LSP with multiple nexthops.
+ *
+ * When the optional ZAPI_LABELS_FTN flag is set, the specified FEC (route) is
+ * updated to use the received label(s).
+ *
+ * NOTE: zebra will use route replace semantics (make-before-break) to update
+ * the LSP in the forwarding plane if that's supported by the underlying
+ * platform.
+ */
+static void zread_mpls_labels_replace(ZAPI_HANDLER_ARGS)
+{
+       struct stream *s;
+       struct zapi_labels zl;
+
+       /* Get input stream.  */
+       s = msg;
+       if (zapi_labels_decode(s, &zl) < 0) {
+               if (IS_ZEBRA_DEBUG_RECV)
+                       zlog_debug("%s: Unable to decode zapi_labels sent",
+                                  __PRETTY_FUNCTION__);
+               return;
+       }
+
+       if (!mpls_enabled)
+               return;
+
+       mpls_lsp_uninstall_all_vrf(zvrf, zl.type, zl.local_label);
+       if (CHECK_FLAG(zl.message, ZAPI_LABELS_FTN))
+               mpls_ftn_uninstall(zvrf, zl.type, &zl.route.prefix,
+                                  zl.route.type, zl.route.instance);
+
+       for (int i = 0; i < zl.nexthop_num; i++) {
+               struct zapi_nexthop_label *znh;
+
+               znh = &zl.nexthops[i];
+               mpls_lsp_install(zvrf, zl.type, zl.local_label, znh->label,
+                                znh->type, &znh->address, znh->ifindex);
+
+               if (CHECK_FLAG(zl.message, ZAPI_LABELS_FTN)) {
+                       mpls_ftn_update(1, zvrf, zl.type, &zl.route.prefix,
+                                       znh->type, &znh->address, znh->ifindex,
+                                       zl.route.type, zl.route.instance,
+                                       znh->label);
+               }
        }
-stream_failure:
-       return;
 }
 
 /* Send response to a table manager connect request to client */
@@ -2456,8 +2514,9 @@ void (*zserv_handlers[])(ZAPI_HANDLER_ARGS) = {
        [ZEBRA_INTERFACE_ENABLE_RADV] = NULL,
        [ZEBRA_INTERFACE_DISABLE_RADV] = NULL,
 #endif
-       [ZEBRA_MPLS_LABELS_ADD] = zread_mpls_labels,
-       [ZEBRA_MPLS_LABELS_DELETE] = zread_mpls_labels,
+       [ZEBRA_MPLS_LABELS_ADD] = zread_mpls_labels_add,
+       [ZEBRA_MPLS_LABELS_DELETE] = zread_mpls_labels_delete,
+       [ZEBRA_MPLS_LABELS_REPLACE] = zread_mpls_labels_replace,
        [ZEBRA_IPMR_ROUTE_STATS] = zebra_ipmr_route_stats,
        [ZEBRA_LABEL_MANAGER_CONNECT] = zread_label_manager_request,
        [ZEBRA_LABEL_MANAGER_CONNECT_ASYNC] = zread_label_manager_request,
index 5214f1f22d26cb8a7613bdc6b4caa3f4ad8b5204..8088ec1bfe2f048486d10f7d28aecadefd8ac78f 100644 (file)
@@ -34,6 +34,7 @@
 #include "routemap.h"
 #include "stream.h"
 #include "nexthop.h"
+#include "termtable.h"
 #include "lib/json.h"
 
 #include "zebra/rib.h"
@@ -124,6 +125,9 @@ static zebra_snhlfe_t *snhlfe_add(zebra_slsp_t *slsp,
 static int snhlfe_del(zebra_snhlfe_t *snhlfe);
 static int snhlfe_del_all(zebra_slsp_t *slsp);
 static char *snhlfe2str(zebra_snhlfe_t *snhlfe, char *buf, int size);
+static void mpls_lsp_uninstall_all_type(struct hash_bucket *bucket, void *ctxt);
+static void mpls_ftn_uninstall_all(struct zebra_vrf *zvrf,
+                                  int afi, enum lsp_types_t lsp_type);
 
 
 /* Static functions */
@@ -1111,6 +1115,7 @@ static char *nhlfe2str(zebra_nhlfe_t *nhlfe, char *buf, int size)
                inet_ntop(AF_INET, &nexthop->gate.ipv4, buf, size);
                break;
        case NEXTHOP_TYPE_IPV6:
+       case NEXTHOP_TYPE_IPV6_IFINDEX:
                inet_ntop(AF_INET6, &nexthop->gate.ipv6, buf, size);
                break;
        case NEXTHOP_TYPE_IFINDEX:
@@ -2294,6 +2299,42 @@ static int zebra_mpls_cleanup_fecs_for_client(struct zserv *client)
        return 0;
 }
 
+struct lsp_uninstall_args {
+       struct hash *lsp_table;
+       enum lsp_types_t type;
+};
+
+/*
+ * Cleanup MPLS labels registered by this client.
+ */
+static int zebra_mpls_cleanup_zclient_labels(struct zserv *client)
+{
+       struct vrf *vrf;
+       struct zebra_vrf *zvrf;
+
+       RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) {
+               struct lsp_uninstall_args args;
+
+               zvrf = vrf->info;
+               if (!zvrf)
+                       continue;
+
+               /* Cleanup LSPs. */
+               args.lsp_table = zvrf->lsp_table;
+               args.type = lsp_type_from_re_type(client->proto);
+               hash_iterate(zvrf->lsp_table, mpls_lsp_uninstall_all_type,
+                            &args);
+
+               /* Cleanup FTNs. */
+               mpls_ftn_uninstall_all(zvrf, AFI_IP,
+                                      lsp_type_from_re_type(client->proto));
+               mpls_ftn_uninstall_all(zvrf, AFI_IP6,
+                                      lsp_type_from_re_type(client->proto));
+       }
+
+       return 0;
+}
+
 /*
  * Return FEC (if any) to which this label is bound.
  * Note: Only works for per-prefix binding and when the label is not
@@ -2542,8 +2583,8 @@ static bool mpls_ftn_update_nexthop(int add, struct nexthop *nexthop,
  */
 int mpls_ftn_update(int add, struct zebra_vrf *zvrf, enum lsp_types_t type,
                    struct prefix *prefix, enum nexthop_types_t gtype,
-                   union g_addr *gate, ifindex_t ifindex, uint8_t distance,
-                   mpls_label_t out_label)
+                   union g_addr *gate, ifindex_t ifindex, uint8_t route_type,
+                   unsigned short route_instance, mpls_label_t out_label)
 {
        struct route_table *table;
        struct route_node *rn;
@@ -2562,7 +2603,7 @@ int mpls_ftn_update(int add, struct zebra_vrf *zvrf, enum lsp_types_t type,
        RNODE_FOREACH_RE (rn, re) {
                if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED))
                        continue;
-               if (re->distance == distance)
+               if (re->type == route_type && re->instance == route_instance)
                        break;
        }
 
@@ -2617,6 +2658,42 @@ int mpls_ftn_update(int add, struct zebra_vrf *zvrf, enum lsp_types_t type,
        return 0;
 }
 
+int mpls_ftn_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type,
+                      struct prefix *prefix, uint8_t route_type,
+                      unsigned short route_instance)
+{
+       struct route_table *table;
+       struct route_node *rn;
+       struct route_entry *re;
+       struct nexthop *nexthop;
+
+       /* Lookup table.  */
+       table = zebra_vrf_table(family2afi(prefix->family), SAFI_UNICAST,
+                               zvrf_id(zvrf));
+       if (!table)
+               return -1;
+
+       /* Lookup existing route */
+       rn = route_node_get(table, prefix);
+       RNODE_FOREACH_RE (rn, re) {
+               if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED))
+                       continue;
+               if (re->type == route_type && re->instance == route_instance)
+                       break;
+       }
+       if (re == NULL)
+               return -1;
+
+       for (nexthop = re->ng.nexthop; nexthop; nexthop = nexthop->next)
+               nexthop_del_labels(nexthop);
+
+       SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
+       SET_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED);
+       rib_queue_add(rn);
+
+       return 0;
+}
+
 /*
  * Install/update a NHLFE for an LSP in the forwarding table. This may be
  * a new LSP entry or a new NHLFE for an existing in-label or an update of
@@ -2749,12 +2826,34 @@ int mpls_lsp_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type,
        return 0;
 }
 
+int mpls_lsp_uninstall_all_vrf(struct zebra_vrf *zvrf, enum lsp_types_t type,
+                              mpls_label_t in_label)
+{
+       struct hash *lsp_table;
+       zebra_ile_t tmp_ile;
+       zebra_lsp_t *lsp;
+
+       /* Lookup table. */
+       lsp_table = zvrf->lsp_table;
+       if (!lsp_table)
+               return -1;
+
+       /* If entry is not present, exit. */
+       tmp_ile.in_label = in_label;
+       lsp = hash_lookup(lsp_table, &tmp_ile);
+       if (!lsp)
+               return 0;
+
+       return mpls_lsp_uninstall_all(lsp_table, lsp, type);
+}
+
 /*
- * Uninstall all LDP NHLFEs for a particular LSP forwarding entry.
+ * Uninstall all NHLFEs for a particular LSP forwarding entry.
  * If no other NHLFEs exist, the entry would be deleted.
  */
-void mpls_ldp_lsp_uninstall_all(struct hash_bucket *bucket, void *ctxt)
+static void mpls_lsp_uninstall_all_type(struct hash_bucket *bucket, void *ctxt)
 {
+       struct lsp_uninstall_args *args = ctxt;
        zebra_lsp_t *lsp;
        struct hash *lsp_table;
 
@@ -2762,17 +2861,19 @@ void mpls_ldp_lsp_uninstall_all(struct hash_bucket *bucket, void *ctxt)
        if (!lsp->nhlfe_list)
                return;
 
-       lsp_table = ctxt;
+       lsp_table = args->lsp_table;
        if (!lsp_table)
                return;
 
-       mpls_lsp_uninstall_all(lsp_table, lsp, ZEBRA_LSP_LDP);
+       mpls_lsp_uninstall_all(lsp_table, lsp, args->type);
 }
 
 /*
- * Uninstall all LDP FEC-To-NHLFE (FTN) bindings of the given address-family.
+ * Uninstall all FEC-To-NHLFE (FTN) bindings of the given address-family and
+ * LSP type.
  */
-void mpls_ldp_ftn_uninstall_all(struct zebra_vrf *zvrf, int afi)
+static void mpls_ftn_uninstall_all(struct zebra_vrf *zvrf,
+                                  int afi, enum lsp_types_t lsp_type)
 {
        struct route_table *table;
        struct route_node *rn;
@@ -2790,7 +2891,7 @@ void mpls_ldp_ftn_uninstall_all(struct zebra_vrf *zvrf, int afi)
                RNODE_FOREACH_RE (rn, re) {
                        for (nexthop = re->ng.nexthop; nexthop;
                             nexthop = nexthop->next) {
-                               if (nexthop->nh_label_type != ZEBRA_LSP_LDP)
+                               if (nexthop->nh_label_type != lsp_type)
                                        continue;
 
                                nexthop_del_labels(nexthop);
@@ -3047,7 +3148,6 @@ void zebra_mpls_print_lsp_table(struct vty *vty, struct zebra_vrf *zvrf,
        json_object *json = NULL;
        zebra_lsp_t *lsp = NULL;
        zebra_nhlfe_t *nhlfe = NULL;
-       struct nexthop *nexthop = NULL;
        struct listnode *node = NULL;
        struct list *lsp_list = hash_get_sorted_list(zvrf->lsp_table, lsp_cmp);
 
@@ -3063,15 +3163,23 @@ void zebra_mpls_print_lsp_table(struct vty *vty, struct zebra_vrf *zvrf,
                                             json, JSON_C_TO_STRING_PRETTY));
                json_object_free(json);
        } else {
-               vty_out(vty, " Inbound                            Outbound\n");
-               vty_out(vty, "   Label     Type          Nexthop     Label\n");
-               vty_out(vty, "--------  -------  ---------------  --------\n");
+               struct ttable *tt;
+
+               /* Prepare table. */
+               tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
+               ttable_add_row(tt, "Inbound Label|Type|Nexthop|Outbound Label");
+               tt->style.cell.rpad = 2;
+               tt->style.corner = '+';
+               ttable_restyle(tt);
+               ttable_rowseps(tt, 0, BOTTOM, true, '-');
 
                for (ALL_LIST_ELEMENTS_RO(lsp_list, node, lsp)) {
                        for (nhlfe = lsp->nhlfe_list; nhlfe;
                             nhlfe = nhlfe->next) {
-                               vty_out(vty, "%8d  %7s  ", lsp->ile.in_label,
-                                       nhlfe_type2str(nhlfe->type));
+                               struct nexthop *nexthop;
+                               const char *out_label_str;
+                               char nh_buf[NEXTHOP_STRLEN];
+
                                nexthop = nhlfe->nexthop;
 
                                switch (nexthop->type) {
@@ -3081,45 +3189,47 @@ void zebra_mpls_print_lsp_table(struct vty *vty, struct zebra_vrf *zvrf,
 
                                        zns = zebra_ns_lookup(NS_DEFAULT);
                                        ifp = if_lookup_by_index_per_ns(
-                                                       zns,
-                                                       nexthop->ifindex);
-                                       if (ifp)
-                                               vty_out(vty, "%15s", ifp->name);
-                                       else
-                                               vty_out(vty, "%15s", "Null");
-
+                                               zns, nexthop->ifindex);
+                                       snprintf(nh_buf, sizeof(nh_buf), "%s",
+                                                ifp ? ifp->name : "Null");
                                        break;
                                }
                                case NEXTHOP_TYPE_IPV4:
                                case NEXTHOP_TYPE_IPV4_IFINDEX:
-                                       vty_out(vty, "%15s",
-                                               inet_ntoa(nexthop->gate.ipv4));
+                                       inet_ntop(AF_INET, &nexthop->gate.ipv4,
+                                                 nh_buf, sizeof(nh_buf));
                                        break;
                                case NEXTHOP_TYPE_IPV6:
                                case NEXTHOP_TYPE_IPV6_IFINDEX:
-                                       vty_out(vty, "%15s",
-                                               inet_ntop(AF_INET6,
-                                                         &nexthop->gate.ipv6,
-                                                         buf, BUFSIZ));
+                                       inet_ntop(AF_INET6, &nexthop->gate.ipv6,
+                                                 nh_buf, sizeof(nh_buf));
                                        break;
                                default:
                                        break;
                                }
 
                                if (nexthop->type != NEXTHOP_TYPE_IFINDEX)
-                                       vty_out(vty, "  %8s\n",
-                                               mpls_label2str(
-                                                       nexthop->nh_label
-                                                               ->num_labels,
-                                                       &nexthop->nh_label
-                                                                ->label[0],
-                                                       buf, BUFSIZ, 1));
+                                       out_label_str = mpls_label2str(
+                                               nexthop->nh_label->num_labels,
+                                               &nexthop->nh_label->label[0],
+                                               buf, BUFSIZ, 1);
                                else
-                                       vty_out(vty, "\n");
+                                       out_label_str = "-";
+
+                               ttable_add_row(tt, "%u|%s|%s|%s",
+                                              lsp->ile.in_label,
+                                              nhlfe_type2str(nhlfe->type),
+                                              nh_buf, out_label_str);
                        }
                }
 
-               vty_out(vty, "\n");
+               /* Dump the generated table. */
+               if (tt->nrows > 1) {
+                       char *table = ttable_dump(tt, "\n");
+                       vty_out(vty, "%s\n", table);
+                       XFREE(MTYPE_TMP, table);
+               }
+               ttable_del(tt);
        }
 
        list_delete(&lsp_list);
@@ -3289,4 +3399,5 @@ void zebra_mpls_init(void)
                mpls_enabled = 1;
 
        hook_register(zserv_client_close, zebra_mpls_cleanup_fecs_for_client);
+       hook_register(zserv_client_close, zebra_mpls_cleanup_zclient_labels);
 }
index d983221cb533fbda2019132e8a0558aefd7adbcd..157f43ca9879031e3f82f43dc304b68576f6ebdc 100644 (file)
@@ -269,8 +269,15 @@ void zebra_mpls_print_fec(struct vty *vty, struct zebra_vrf *zvrf,
  */
 int mpls_ftn_update(int add, struct zebra_vrf *zvrf, enum lsp_types_t type,
                    struct prefix *prefix, enum nexthop_types_t gtype,
-                   union g_addr *gate, ifindex_t ifindex, uint8_t distance,
-                   mpls_label_t out_label);
+                   union g_addr *gate, ifindex_t ifindex, uint8_t route_type,
+                   unsigned short route_instance, mpls_label_t out_label);
+
+/*
+ * Uninstall all NHLFEs bound to a single FEC.
+ */
+int mpls_ftn_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type,
+                      struct prefix *prefix, uint8_t route_type,
+                      unsigned short route_instance);
 
 /*
  * Install/update a NHLFE for an LSP in the forwarding table. This may be
@@ -291,15 +298,10 @@ int mpls_lsp_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type,
                       union g_addr *gate, ifindex_t ifindex);
 
 /*
- * Uninstall all LDP NHLFEs for a particular LSP forwarding entry.
- * If no other NHLFEs exist, the entry would be deleted.
- */
-void mpls_ldp_lsp_uninstall_all(struct hash_bucket *bucket, void *ctxt);
-
-/*
- * Uninstall all LDP FEC-To-NHLFE (FTN) bindings of the given address-family.
+ * Uninstall all NHLFEs for a particular LSP forwarding entry.
  */
-void mpls_ldp_ftn_uninstall_all(struct zebra_vrf *zvrf, int afi);
+int mpls_lsp_uninstall_all_vrf(struct zebra_vrf *zvrf, enum lsp_types_t type,
+                              mpls_label_t in_label);
 
 /*
  * Uninstall all Segment Routing NHLFEs for a particular LSP forwarding entry.
@@ -426,7 +428,7 @@ static inline uint8_t lsp_distance(enum lsp_types_t type)
                return (route_distance(ZEBRA_ROUTE_BGP));
        case ZEBRA_LSP_NONE:
        case ZEBRA_LSP_SHARP:
-       case ZEBRA_LSP_SR:
+       case ZEBRA_LSP_OSPF_SR:
                return 150;
        }
 
@@ -448,8 +450,12 @@ static inline enum lsp_types_t lsp_type_from_re_type(int re_type)
        switch (re_type) {
        case ZEBRA_ROUTE_STATIC:
                return ZEBRA_LSP_STATIC;
+       case ZEBRA_ROUTE_LDP:
+               return ZEBRA_LSP_LDP;
        case ZEBRA_ROUTE_BGP:
                return ZEBRA_LSP_BGP;
+       case ZEBRA_ROUTE_OSPF:
+               return ZEBRA_LSP_OSPF_SR;
        case ZEBRA_ROUTE_SHARP:
                return ZEBRA_LSP_SHARP;
        default:
@@ -469,7 +475,7 @@ static inline int re_type_from_lsp_type(enum lsp_types_t lsp_type)
                return ZEBRA_ROUTE_LDP;
        case ZEBRA_LSP_BGP:
                return ZEBRA_ROUTE_BGP;
-       case ZEBRA_LSP_SR:
+       case ZEBRA_LSP_OSPF_SR:
                return ZEBRA_ROUTE_OSPF;
        case ZEBRA_LSP_NONE:
                return ZEBRA_ROUTE_KERNEL;
@@ -496,8 +502,8 @@ static inline const char *nhlfe_type2str(enum lsp_types_t lsp_type)
                return "LDP";
        case ZEBRA_LSP_BGP:
                return "BGP";
-       case ZEBRA_LSP_SR:
-               return "SR";
+       case ZEBRA_LSP_OSPF_SR:
+               return "SR (OSPF)";
        case ZEBRA_LSP_SHARP:
                return "SHARP";
        case ZEBRA_LSP_NONE:
index ee2956d3ea78b1895cb44ae0805773e1dd1df509..35df02a19ab469df002e6d66ad0d39625a03bbea 100644 (file)
@@ -122,6 +122,33 @@ static void nexthop_set_resolved(afi_t afi, const struct nexthop *newhop,
        _nexthop_add(&nexthop->resolved, resolved_hop);
 }
 
+/* Checks if nexthop we are trying to resolve to is valid */
+static bool nexthop_valid_resolve(const struct nexthop *nexthop,
+                                 const struct nexthop *resolved)
+{
+       /* Can't resolve to a recursive nexthop */
+       if (CHECK_FLAG(resolved->flags, NEXTHOP_FLAG_RECURSIVE))
+               return false;
+
+       switch (nexthop->type) {
+       case NEXTHOP_TYPE_IPV4_IFINDEX:
+       case NEXTHOP_TYPE_IPV6_IFINDEX:
+               /* If the nexthop we are resolving to does not match the
+                * ifindex for the nexthop the route wanted, its not valid.
+                */
+               if (nexthop->ifindex != resolved->ifindex)
+                       return false;
+               break;
+       case NEXTHOP_TYPE_IPV4:
+       case NEXTHOP_TYPE_IPV6:
+       case NEXTHOP_TYPE_IFINDEX:
+       case NEXTHOP_TYPE_BLACKHOLE:
+               break;
+       }
+
+       return true;
+}
+
 /*
  * Given a nexthop we need to properly recursively resolve
  * the route.  As such, do a table lookup to find and match
@@ -287,8 +314,7 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
                                if (!CHECK_FLAG(match->status,
                                                ROUTE_ENTRY_INSTALLED))
                                        continue;
-                               if (CHECK_FLAG(newhop->flags,
-                                              NEXTHOP_FLAG_RECURSIVE))
+                               if (!nexthop_valid_resolve(nexthop, newhop))
                                        continue;
 
                                SET_FLAG(nexthop->flags,
@@ -308,8 +334,7 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
                                if (!CHECK_FLAG(match->status,
                                                ROUTE_ENTRY_INSTALLED))
                                        continue;
-                               if (CHECK_FLAG(newhop->flags,
-                                              NEXTHOP_FLAG_RECURSIVE))
+                               if (!nexthop_valid_resolve(nexthop, newhop))
                                        continue;
 
                                SET_FLAG(nexthop->flags,
index ff4bfb10f7268e14160b458ba5a825a6187882b6..5428b6eaef2050e8c0424380779b3539863e3098 100644 (file)
@@ -2097,14 +2097,6 @@ static unsigned int process_subq(struct list *subq, uint8_t qindex)
        return 1;
 }
 
-
-/*
- * Perform next-hop tracking processing after RIB updates.
- */
-static void do_nht_processing(void)
-{
-}
-
 /* Dispatch the meta queue by picking, processing and unlocking the next RN from
  * a non-empty sub-queue with lowest priority. wq is equal to zebra->ribq and
  * data
@@ -3303,9 +3295,6 @@ static int rib_process_dplane_results(struct thread *thread)
 
        } while (1);
 
-       /* Check for nexthop tracking processing after finishing with results */
-       do_nht_processing();
-
        return 0;
 }
 
index 666ebb70e82f0bded0413e34417f0052c696e509..bcaf1b520441888b6c922d07dd7e67eb9e8271b8 100644 (file)
@@ -1198,13 +1198,6 @@ static int zebra_client_cleanup_rnh(struct zserv *client)
                                                 RNH_IMPORT_CHECK_TYPE);
                        zebra_cleanup_rnh_client(zvrf_id(zvrf), AFI_IP6, client,
                                                 RNH_IMPORT_CHECK_TYPE);
-                       if (client->proto == ZEBRA_ROUTE_LDP) {
-                               hash_iterate(zvrf->lsp_table,
-                                            mpls_ldp_lsp_uninstall_all,
-                                            zvrf->lsp_table);
-                               mpls_ldp_ftn_uninstall_all(zvrf, AFI_IP);
-                               mpls_ldp_ftn_uninstall_all(zvrf, AFI_IP6);
-                       }
                }
        }
 
index 88d2091394c99dcf74ee0e5a8e7b6c33cdc0b7e9..364f5755d8235237d89c734839ab92d8e72895d4 100644 (file)
@@ -78,11 +78,6 @@ static int zebra_route_match_add(struct vty *vty, const char *command,
                retval = CMD_WARNING_CONFIG_FAILED;
                break;
        case RMAP_COMPILE_SUCCESS:
-               if (type != RMAP_EVENT_MATCH_ADDED) {
-                       route_map_upd8_dependency(type, arg, index->map->name);
-               }
-               break;
-       case RMAP_DUPLICATE_RULE:
                /*
                 * Nothing to do here
                 */
@@ -116,7 +111,7 @@ static int zebra_route_match_delete(struct vty *vty, const char *command,
                rmap_name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, index->map->name);
        }
 
-       ret = route_map_delete_match(index, command, arg);
+       ret = route_map_delete_match(index, command, arg, type);
        switch (ret) {
        case RMAP_RULE_MISSING:
                vty_out(vty, "%% Zebra Can't find rule.\n");
@@ -127,10 +122,6 @@ static int zebra_route_match_delete(struct vty *vty, const char *command,
                retval = CMD_WARNING_CONFIG_FAILED;
                break;
        case RMAP_COMPILE_SUCCESS:
-               if (type != RMAP_EVENT_MATCH_DELETED && dep_name)
-                       route_map_upd8_dependency(type, dep_name, rmap_name);
-               break;
-       case RMAP_DUPLICATE_RULE:
                /*
                 * Nothing to do here
                 */
index 38de01e228926561e58469c4b7d89f78085fc401..7984481093c45e5f01eb34a47304584f42c08ffb 100644 (file)
@@ -1384,35 +1384,37 @@ DEFPY (show_route_detail,
 
 DEFPY (show_route_summary,
        show_route_summary_cmd,
-       "show\
-         <\
-          ip$ipv4 route [vrf <NAME$vrf_name|all$vrf_all>]\
-            summary [prefix$prefix]\
-          |ipv6$ipv6 route [vrf <NAME$vrf_name|all$vrf_all>]\
-           summary [prefix$prefix]\
-        >",
+       "show <ip$ipv4|ipv6$ipv6> route [vrf <NAME$vrf_name|all$vrf_all>] \
+            summary [table (1-4294967295)$table_id] [prefix$prefix]",
        SHOW_STR
        IP_STR
-       "IP routing table\n"
-       VRF_FULL_CMD_HELP_STR
-       "Summary of all routes\n"
-       "Prefix routes\n"
        IP6_STR
        "IP routing table\n"
        VRF_FULL_CMD_HELP_STR
        "Summary of all routes\n"
+       "Table to display summary for\n"
+       "The table number\n"
        "Prefix routes\n")
 {
        afi_t afi = ipv4 ? AFI_IP : AFI_IP6;
        struct route_table *table;
 
+       if (table_id == 0)
+               table_id = RT_TABLE_MAIN;
+
        if (vrf_all) {
                struct vrf *vrf;
                struct zebra_vrf *zvrf;
 
                RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
-                       if ((zvrf = vrf->info) == NULL
-                           || (table = zvrf->table[afi][SAFI_UNICAST]) == NULL)
+                       if ((zvrf = vrf->info) == NULL)
+                               continue;
+
+                       table = zebra_vrf_table_with_table_id(afi,
+                                                             SAFI_UNICAST,
+                                                             zvrf->vrf->vrf_id,
+                                                             table_id);
+                       if (!table)
                                continue;
 
                        if (prefix)
@@ -1426,7 +1428,9 @@ DEFPY (show_route_summary,
                if (vrf_name)
                        VRF_GET_ID(vrf_id, vrf_name, false);
 
-               table = zebra_vrf_table(afi, SAFI_UNICAST, vrf_id);
+               table = zebra_vrf_table_with_table_id(afi,
+                                                     SAFI_UNICAST,
+                                                     vrf_id, table_id);
                if (!table)
                        return CMD_SUCCESS;